透视前端工程化之一:模板功能设计

蔚1 2020-11-13 06:33:07
前端 模板 工程化 工程 透视


1 项目模板

我们的项目框架都是基于项目模板生成的。学过 JS 的知道:

function Person(name = 'ant') {
this.name = name;
}
let man = new Person();

这里 Personman 的原型对象。同样项目模板相当于对象 Person,具体的项目相当于 man。通过项目模板,我们可以事先将项目所需要的功能点定义好,使用的时候只需要像实例化一个对象一样,简单地 new 一下就搞定了。大大地减少重复劳动,屏蔽项目配置的复杂度。

在动手搭建之前,有必要对我们的项目模板进行一个整体规划,然后按照规划逐个实现。

2 支持哪些功能

2.1 代码检查

JavaScript 是一个动态的弱类型语言,在开发中比较容易出错。同时由于每个人的编码习惯和风格不尽相同,写出的代码风格迥异,时间久了很难维护。因为没有编译程序, JavaScript 代码错误通常需要在执行过程中不断调试,效率很低。

但是,我们不可能人肉进行代码检查,因为当代码量很大的时候,需要耗费很大的精力。所以代码检查我们借助 ESLint 来实现。ESLint 可以让程序员在编码的过程中就发现问题,避免将问题带到执行时。

为什么使用 ESLint?

  • ESLint 的所有规则都是可拔插的。ESLint 不限制开发人员的编码风格。因为其设计的初衷就是为了让开发人员创建符合自己编码风格的规则。当然 ESLint 有一套内置的默认规则。但是可以修改甚至自定义自己的规则一切都是可拔插的。
  • 每条规则可以自由地开关。开发人员可以根据自己项目的需要决定是否开启某条规则。也可以修改检查结果的告警等级,决定抛错还是只是警告。

一个简单的示例:

let foo = bar;
1:5 - 'foo' is assigned a value but never used. (no-unused-vars)

如果我们在 ESLint 配置文件中启用了 no-unused-vars 规则。那么当代码中出现定义未使用的变量时,就会给出错误提示。

至于 CSS 的检查,这里我们使用 stylelint 来处理。stylelint 功能非常强大,可以支持 scss、sass、less 以及 sugarss 的语法检查。此外,stylelint 和 ESlint 类似,也是提供了插件机制,开发者可以自己来定义规则,根据自己的团队定制一套统一的规范,避免样式错误。

我们看一个简单的示例。

有下面这样一段 css 代码:

/* */
a { color: #FFF; }

stylelint 规则如下:

"rules": {
"comment-no-empty": true,
"color-hex-case": "lower"
}

stylelint 提示注释内容不能为空,字体颜色的 16 进制表示字母不允许大写。

1:1 error Unexpected empty comment (comment-no-empty)
3:12 error Expected "#FFF" to be "#fff" (color-hex-case)

2.2 本地开发环境

在日常开发中,前端开发经常做的是完成部分功能和页面的开发后,去刷新一下浏览器,看一下效果是否符合预期。所以能有一个本地 Web 服务器加载我们的页面,并且当代码变动的时候自动刷新页面,可以减少开发同学的切换成本,提升开发效率。

我们在模板中使用 webpack-dev-server 作为 一个简单的 Web 服务器,由于 webpack-dev-server 内置了模块热替换(Hot Module Replacement 或 HMR),页面被修改后自动重新加载。

// package.json
"scripts": {
"dev": "webpack-dev-server --open"
}

在 Webpack 配置文件中完成 dev-server 的配置后,我们只需要在 package.json 文件中添加一个 script 命令。在进行开发时,只需要一个简单的 npm run dev 命令就可以启动本地服务器。

2.3 mock server

前后端分离后,双方有清晰的边界,后端负责业务逻辑的编写,前端负责视图逻辑的开发,双方的数据传输通过 API 实现。前后端共同约定一份接口文档,接口文档中规定了接口名称、入参、出参以及数据结构等。

但仅仅有一份静态的接口文档还远远不够,我们需要的是在开发的阶段就能像在线上一样去调用服务端接口获取数据。

所以,Mock 是前后端分离模式下一项必备的功能。

我们采取的做法是在项目模板中实现一个 mock server,来响应本地请求。同时假数据通过 mockjs 来生成。

由于我们的本地开发环境与 mock server 运行在不同的端口上,因此我们还需要在 Webpack 中提供的 proxy 功能将我们的请求转发到 mock server 上去。

graph LR
A(dev server)-->B(proxy server)
B(proxy server)-->C(mock server)

2.4 构建

现在的前端开发基本上都是采用了模块化的开发方式,而且在代码中使用了大量的 es6+ 语言特性。但宿主浏览器中对新特性的支持不一。我们的代码无法直接运行在浏览器中,所以需要对代码进行构建打包,将代码编译成浏览器都可运行的代码。

// webpack.config.js
...
output: {
path: path.join(__dirname, './build'),
publicPath: opt.publicPath,
// 给线上环境的资源添加hash
filename: 'js/[name]' + hash(needHash, 'chunk') + '.js',
chunkFilename: 'js/[name]' + hash(needHash, 'chunk') + '.js',
}
...
plugins: [
...
new webpack.optimize.UglifyJsPlugin({
compress: {
// 删除console和警告
drop_console: true,
warnings: false
}
})
...
]

由于目标代码的应用场景不同,我们需要针对不同的环境来进行构建。比如,针对测试环境运行的代码,由于需要不断进行调试,我们一般不清除代码中的注释和 console。由于代码部署无需考虑备份,不给构建出的文件添加 hash。线上环境构建的时候,我们需要尽可能减小文件的体积,同时需要考虑部署后不覆盖线上资源,所以需要在构建时剔除代码中的注释和调试语句,对代码进行混淆压缩,给文件添加 hash。

现在绝大多数现代浏览器都已经支持了原生的 ES2015,编译后的包通常都比原生的 ES2015+ 代码会更冗长,运行更慢。所以因为要支持更老的浏览器而为它们交付笨重的代码是一种浪费。我们在模板中可以针对现代浏览器打出体积更小的包。

  • 现代版的包在被支持的浏览器中通过 <script type="module"> 进行加载,使用 <link rel="modulepreload"> 进行预加载。
  • 旧版本的包会通过 <script nomodule> 加载,支持 ES modules 的浏览器会忽略该引用。

2.5 部署

构建完成后,最后一步就是把前端资源发布到服务器了。假定我们的前端项目都是完全的前后端分离的,这意味着前端的资源需要和服务端分开部署。

比如,我们为专门准备一个 OSS 服务器用来部署入口文件,准备另一个 OSS 服务器部署 js、css 和图片等资源。

// package.json
"scripts": {
// 假定我们的部署逻辑在deploy.js中
"deploy": "node deploy.js"
}

部署我们会用到两个 npm 包,一个是 vinyl-ftp,专门用以登录我们的 OSS 服务器,另一个包是 vinyl-fs,用来将本地的资源发布到远程服务器。最后我们在 package.json 文件中配置 deploy 命令。部署操作只需要执行 npm run deploy 即可。

2.6 Qdebug

相信大家在测试过程中,有一个问题经常会遇到。总是有测试同学把一些本属于服务端的 bug 提给前端。前端同学看到 bug 后,按照复现步骤排查一遍,“咦!这个问题是接口中数据有问题导致的!”赶紧转给服务端同学,并且心中有一丝不爽。

所以,很有必要开发一个小工具辅助测试同学,为他们分析 bug 产生的原因,准确指派 bug 提供事实依据。

因此,我们在项目模板中要实现一个 Qdebug 小工具。

<script>
// 初始化
var debug = new QDebug();
</script>

Qdebug 基于 vconsole 进行扩展,可以将接口请求中的详细接口数据打印出来,同时会生成一个当前前端代码的版本号。测试同学通过版本号就可以知道前端的资源是不是已经更新,通过查看详细的接口数据就可以准确判断 bug 的归属。

2.7 自动化测试

自动化测试在 Web 工程中扮演重要的角色。自动化测试还可以与持续集成进行结合,通过机器来保证工程的质量,提升团队整体的效能。因此在前端工程化的建设过程中,自动化测试也是很重要的一环。

自动化测试根据粒度的不同,基本可以分为:单元测试、接口测试、端到端测试(也叫功能测试)。在前端工程中得到应用的主要是接口测试和端到端测试。

单元测试,是站在开发人员的视角,把代码划分成一个个的代码单元逐个进行测试,看返回的结果是否符合预期。

我们通过 Karma+Mocha+Chai 来实现单元测试功能。执行单元测试很简单也是通过 npm script 来调用,例如:

npm run test:uinit

端到端测试是站在用户的视角,把 Web 应用当成一个黑盒,模拟用户的真实使用场景,比如在页面中输入文字,点击搜索。看测试结果是不是符合预期。端到端测试框架有不少,比如 Nightwatch、TestCafe、CasperJS。在本模板中,我们选用 Nightwatch 来实现端到端测试,主要是因为使用 Nigthwatch 编写的代码非常简洁。

执行端到端测试很简单通过 npm script 来调用,例如:

npm run test:e2e

3 目录结构

说完了模板要实现的主要功能后,我们来看一下项目模板的整体目录结构:

boilerplate-vue
├── package.json
├── README.md
├── .gitignore
├── .babelrc
├── config
├── build
├── mock
├── test
| ├── unit
| └── e2e
├── src
| ├── assets
│ ├── components
│ ├── router
│ ├── pages
│ ├── app.js
│ └── App.vue
└── public
├── index.html
└── favicon.ico

主要的一些目录和文件功能如下:

  • src 中存放业务代码。其中 src/app.js 是项目构建的入口文件,src/App.vue是视图层的入口文件,src/pages 中放置不同的页面,src/components 中放置 Vue 组件,src/router 中放置 router 相关的文件,src/assets 中放置静态资源如图片、字体等。
  • mock 存放 Mock 的假数据。
  • test 用于放置测试相关的文件。
  • build 用于放置构建相关的文件。
  • config 用于放置配置相关的文件。
  • public 用于放置公用的静态资源,如 HTML 入口模板文件、站点的小图标。
  • package.json npm 模块的配置文件。
  • .babelrc babel 的配置文件。
  • .gitignore 用于指定哪些文件不提交到 Git 仓库。
  • README.md 项目的介绍和使用文档。

总结

本节我们对模板的功能进行了系统的规划和目录结构设计。模板功能覆盖了开发阶段、测试阶段、构建阶段、部署阶段。文中对各个功能的实现所需要用到的技术和工具也进行了简单的介绍,大家对每个部分有个大概的印象即可,之后可以在实践中加强练习。

笔者有一个前端工程化的实践型课程刚刚上线——《透视前端工程化》

点击了解《透视前端工程化》

以 Vue 为例,结合笔者在团队中的工程化实践,带领大家从零开始搭建一个脚手架,将搭建脚手架用到的技术点逐一拆解,希望大家看完后,每个人都对脚手架和工程化思想有个较深入地理解。

课程目录

开篇词:到底什么是前端工程化

第一部分:模板设计

第01课:模板功能设计
第02课:Webpack 基本介绍
第03课:搭建项目模板框架
第04课:前端模块化解决方案
第05课:搭建本地开发环境
第06课:搭建本地 Mock 服务
第07课:引入代码检查工具
第08课:自动生成雪碧图
第09课:根据浏览器构建
第10课:根据环境构建
第11课:集成移动端调试工具
第12课:引入单元测试
第13课:引入 e2e 测试
第14课:Webpack 构建性能优化
第15课:添加部署功能
第16课:聚合项目配置并模板化

第二部分:命令行设计

第17课:cli 功能设计(上)
第18课:cli 功能设计(下)

结语:开放的心态才是更高阶的工程化

相信在学完本课程后,大家至少有以下几点收获:

  • 对前端工程化有一个系统认知;
  • 能独立设计一套前端工程化解决方案;
  • 知识广度上有大幅提升;
  • 进入更好的平台,获得更好的薪酬。

感兴趣的话,还望大家多多支持!


作者简介:

王超,现任快狗打车(原58速运)前端负责人。

先后任职于人人网、奇虎360,8 年知名互联网工作经验。

从 0 到 1 组建了快狗前端团队,负责团队技术体系的搭建,形成了以 Webpack 和 Vue 为基础、 Node.js 中间层为补充的,自动化、工程化、组件化的快狗前端技术体系。

版权声明
本文为[蔚1]所创,转载请带上原文链接,感谢
https://gitchat.blog.csdn.net/article/details/93988279

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple