1. 与webpack类似的工具还有哪些?谈谈你为什么最终选择(或放弃)使用webpack?
grunt
最老牌的打包工具,它运用配置的思想来写打包脚本,一切皆配置
缺点:
- 配置项太多
- 而且不同的插件会有自己的扩展字段
- 学习成本高,运用的时候需要明白各种插件的配置规则和配合方式。
glup
- 基于nodejs流的打包工具。配置文件 gulpfile.js。
- 定位是基于任务流的自动化构建工具。
- Gulp 是通过task 对整个开发过程进行构建
优点:
- 流式的写法简单直观
- API 简单,代码量少
- 易于学习和使用
- 适合多页面应用开发
缺点:
- 异常处理比较麻烦
- 工作流程顺序难以精确控制
- 不太适合单页后者自定义模块的开发
使用 glup 进行babel 转译的例子:
//glupfile.js
const gulp = require("gulp");
const babel = require("gulp-babel");
function defaultTask(callback) {
gulp
.src("src/app.js")//读取源文件
.pipe(
babel({//传给babel任务
presets: ["@babel/preset-env"],
})
).pipe(gulp.dest("dist"));//写到dist里
callback();
}
exports.default = defaultTask;
parcel
- parcel 是快读、零配置的web应用程序打包器
- 目前Parcel 只能用于构建运行在浏览器的网页中,这也是他的出发点和关注点
优点:
- parcel 内置了常见场景的构建方案及其依赖,无需再安装各种依赖
- parcel 能以HTML为入口,自动检测和打包依赖资源
- parcel 默认支持热模块替换,真正的开箱即用
缺点:
- 不支持SourceMap
- 不支持Tree Shaking
- 配置不灵活
webpack
- Webpack 是模块化管理工具和打包工具。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、AMD 模块、ES6 模块、CSS、图片等。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。
- 还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载
- Webpack 的定位是模块打包器,而 Gulp/Grunt 属于构建工具。Webpack 可以代替 Gulp/Grunt 的一些功能,但不是一个职能的工具,可以配合使用。
优点:
- 可以模块化的打包任何资源
- 适配任何模块系统
- 适合SPA单页应用的开发
缺点:
- 学习成本高,配置复杂
- 通过 babel编译后的 js 代码打包后体积过大
rollup
Rollup 是下一代 ES6 模块化工具,它最大的亮点是利用 ES6 模块设计,生成更简洁、更简单的代码。尽可能高效地构建出能够直接被其它 JavaScript 库引用的模块。
- 基于权衡,Rollup 目前还不支持代码拆分(Code Splitting)和模块的热更新(HMR)
一般而言,对于应用使用 Webpack,对于类库使用 Rollup; - 需要代码拆分(Code Splitting),或者很多静态资源需要处理,再或者构建的项目需要引入很多 CommonJS 模块的依赖时,使用 webpack。
- 代码库是基于 ES6 模块,而且希望代码能够被其他人直接使用,使用 Rollup。
优点:
用标准化的格式(ES6)来写代码,通过减少死代码尽可能地缩小包体积
2. Loader和Plugin 的不同
- Loader直译为加载器,webpack 将一切文件视为模块,但是 webpack 原生只能解析 js/json 文件,如果想将其他文件也打包的话,就会用到 Loader。所以 Loader 的作用是让 webapack 拥有了加载和解析其他文件的能力。
- Plugin 直译为插件。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。在webpack运行的声明周期中会广播许多事件,Plugin可以监听这些事件,在合适的时机通过 webpack 提供的 API 改变输出结果。
3.webpack的构建流程
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译; 确定入口:根据配置中的 entry 找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第 4 步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会。
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果