前端工程化-工具
脚手架
- yeoman 大而全已有的generator 或者自己自定义generator
- plop 小而美 在项目中快速使用,例如快速生成模板文件
- 自己利用inquirer 或者ejs等npm 包实现自己的自定义脚手架工具
自定义小工具
npm script 工作流
npm run 实际上是 npm run-script 命令的简写
当我们运行 npm run xxx 时,基本步骤如下:
从 package.json 文件中读取 scripts 对象里面的全部配置;
以传给 npm run 的第一个参数作为键,本例中为 xxx,在 scripts 对象里面获取对应的值作为接下来要执行的命令,如果没找到直接报错;
在系统默认的 shell 中执行上述命令,系统默认 shell 通常是 bash
连接命令
npm script 串行:&& 连接命令
"test": "npm run lint:js && npm run lint:css"
npm script 并行:& 连接命令
"test": "npm run lint:js & npm run lint:css & wait"
加 & wait是因为类似异步请求,只负责触发多条命令不管收集,如果并行的命令执行时间差异非常大,就会出现进程退出之后某些结果才输出
利用 npm-run-all 来实现多条命令的串行和并行,更多命令使用见文档
"test": "npm-run-all --parallel lint:* mocha"
添加参数
npm run lint:js -- --fix
pre 和 post 钩子
举例来说,运行 npm run test 的时候,分 3 个阶段:
检查 scripts 对象中是否存在 pretest 命令,如果有,先执行该命令;
检查是否有 test 命令,有的话运行 test 命令,没有的话报错;
检查是否存在 posttest 命令,如果有,执行 posttest 命令;
使用环境变量
获取变量
npm run lint:js -- --fix
使用变量
"dummy": "echo $npm_package_name"
在 git hooks 中运行 npm script
例如 husky、lint-staged 结合来对 git 提交前检查代码规范
Npm Script 优点是内置,无须安装其他依赖。缺点是功能太简单,不能方便地管理多个任务之间的依赖
常见自动化构建工具
构建是在做哪些事?
代码转换:将TypeScript编译成JavaScript、将SCSS编译成CSS等。
文件优化:压缩JavaScript、CSS、HTML代码,压缩合并图片等。
代码分割:提取多个页面的公共代码,提取首屏不需要执行部分的代码让其异步加载。
模块合并:在采用模块化的项目里会有很多个模块和文件,需要通过构建功能将模块分类合并成一个文件。
自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器。
代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
自动发布:更新代码后,自动构建出线上发布代码并传输给发布系统
前端构建演变
YUI Compressor: https://github.com/yui/yuicompressor, YUI压缩器是一种JavaScript和CSS压缩器,除了删除注释和空格外,还使用尽可能小的变量名来混淆局部变量。
Grunt:https://github.com/gruntjs/grunt, Grunt是一个JavaScript任务运行器,本身就使用JavaScript开发,灵活的管理任务间的依赖和 执行定义的任务。
Gulp:https://github.com/gulpjs/gulp, gulp是基于流的自动化构建工具,除了管理和执行任务,还支持监听读写文件。
fis3:https://github.com/fex-team/fis3, 集成了web开发中常用的构建功能,如资源定位,文件编译,压缩,雪碧图等。
rollup:https://github.com/rollup/rollup, 专注于ES6模块化,可将一小段代码编译成更大或更复杂的内容,例如库或应用程序。
webpack:https://github.com/webpack/webpack, 一切皆模块,支持模块打包及丰富的插件扩展功能。
parcel:https://github.com/parcel-bundler/parcel, 极速零配置Web应用打包工具, 新兴地打包工具。
vite: https://github.com/vitejs/vite,开发服务器极速启动,面向未来。
Grunt
Grunt是一个JavaScript任务运行器,本身就使用JavaScript开发,灵活的管理任务间的依赖和 执行定义的任务。
通过配置项来配置打包脚本
Gulp
Gulp的最大特点是引入了流的概念,同时提供了一系列常用的插件去处理流,流可以在插件之间传递
Gulp的优点是好用又不失灵活,既可以单独完成构建,也可以和其他工具搭配使用。其缺点和Grunt类似,集成度不高,要写很多配置后才可以用,无法做到开箱即用。
gulp主要用到node中的两个模块,fileSystem和stream,文件系统可以对文件进行操作。
Webpack
webpack是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源,已经支持 tree-shaking,sideEffects 标记副作用,来进行tree-shaking
Rollup
跟 webpack 比 rollup 更小巧,默认自动开启tree-shaking,专注于ES6的模块打包工具。
能针对ES6源码进行Tree Shaking:rollup 不看你引入了什么函数,而是看你调用了什么函数。如果你手动在模块顶部引入函数,但又没调用,rollup 是不会引入的。tree-shaking的消除原理是依赖于ES6的模块特性。
ES Modules 导入的模块会被预解析,以便在代码运行前导入; 在 CommonJS 中,模块将在运行时解析;这也是 esm 能容易被 tree-shaking 而 cjs 不能的原因。
优:
输出结果更扁平
自动移除未引用代码
打包结果依然完全可读
缺:
加载非ESM第三方模块比较复杂
模块最终都被打包到一个函数中,无法实现HMR(热替换)
浏览器环境中,代码拆分功能依赖AMD库
amd – 异步模块定义,用于像RequireJS这样的模块加载器
cjs – CommonJS,适用于 Node 和 Browserify/Webpack
esm – 将软件包保存为 ES 模块文件,在现代浏览器中可以通过 <script type=module>
标签引入
iife – 一个自动执行的功能,适合作为 <script>
标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。)
umd – 通用模块定义,以amd,cjs 和 iife 为一体
system - SystemJS 加载器格式
Parcel
Parcel 使用 worker 进程去启用多核编译。同时有文件系统缓存,即使在重启构建后也能快速再编译。
Parcel 号称零配置开箱即用,是因为他尽可能多地从代码本身推断,并将现有的配置文件用于其他工具(例如 .babelrc)
开箱即用的代码分割,热模块重新加载,css 预处理器,开发服务器,缓存等等!
Vite
Vite 主要包括两个部分,一个基于 ESM 的利用 esbuild 的开发服务器,另一个部分是基于 Rollup 的配置化的打包器
Esbuild 是 Vite 为何如此快速的原因,它比传统 tsc 快 20-30 倍。Vite 用 esbuild 替代 Rollup 进行预打包,速度也非常快。
Esbuild 比其他 JavaScript 打包程序快100倍(用Go语言编写)
为啥生产模式不用 esbuild?
其实也想用,但是 esbuild 目前对生产包支持不够健壮,很多配置无法通过 esbuild 实现。所以目前而言,Rollup 是一个好选择,虽然远比 esbuild 慢。
目前「esbuild」支持的功能:
加载器
压缩
打包
Tree shaking
Source map 生成
将 JSX 和较新的 JS 语法移植到 ES6
目前对于「JavaScript」语法转化不支持的特性有:
Top-level await
async await
BigInt 等
截止2021年3月:
案例
案例 | 打包方案 |
---|---|
vue/react | rollup 生成umd、cjs、es格式的js文件 |
antd | gulp + webpack + tsc / babel gulp的作用主要是打包流程管理, 拷贝文件(less/ts/ts类型声明文件),处理less, 拷贝并转译less 为css。tsc及babel 则用于转译 静态ts文件, 逐个输出到指定目录es/lib目录下,webpack主要用于模块化处理,将打包后的模块编译到 dist下的 antd.js antd.min.js 以及及其他css文件等 |
日常spa应用 | webpack功能强大,生态丰富,基本之前gulp可以进行的操作处理,现在webpack也都可以做。同时支持热更新,支持tree shaking 、动态加载、代码拆分、文件指纹、代码压缩、静态资源处理等,支持多种打包方式,打包后冗余代码和不明含义的代码多 |
模块化标准
CommonJS(node)、AMD(浏览器端,异步) 、CMD (同步,类似CommonJS)
目前两种的模块标准:
在浏览器端是ES Modules 主流前端模块化方案
node环境中是CommonJS
ES Modules 特性
通过给script设置type="module" 来设置
- 自动使用严格模式
use strict
- 每个 ES Module 都是运行在单独的私有作用域
- ESM 是通过 CORS 方式请求外部 JS 模块的
- ESM 的 script 标签默认是延迟执行 (和使用defer属性一样)