Open ArthurWangCN opened 2 years ago
webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。 更多的功能需要借助loaders和plugins完成。比如说:在代码中有一张图片需要进行打包,webpack可以把图片读出来,但是不能将图片当做js代码来读,所以需要一个加载器loader来帮助我们把图片的二进制数据转变为js代码,loader的作用说白了就是将一种形式的代码通过逻辑转变成另一种形式的代码,转换后的代码webpack就能识别了。
Loader 就是将 Webpack 不认识的内容转化为认识的内容。
常见的loader:
示例:
const config = {
// ...
module: {
rules: [
{
test: /\.css$/, //匹配所有的 css 文件
use: ['style-loader','css-loader', 'postcss-loader']
}
]
},
// ...
}
由示例得出,loader 支持链式传递,从右向左取值/执行。
https://blog.csdn.net/Niall_Tonshall/article/details/123082976
功能:移除 JavaScript 上下文中未引用的代码。
CommonJS规范无法确定在实际运行前需要或者不需要某些模块,所以CommonJS不适合tree-shaking机制。
在JavaScript模块化方案中,只有ES6的模块方案:import()引入模块的方式采用静态导入,可以采用一次导入所以的依赖包再根据条件判断的方式,获取不需要的包,然后执行删除操作。
Tree-shaking的实现原理
利用ES6模块特性:
代码删除:
实现原理可以简单的概况:
他们都是JavaScript模块构建打包工具。
特性:
资源:
webpack 相对来说拥有更大的社区支持,资源更加齐全,文档更加完整,有更完整的插件库,如热更新及web-server等。
结论:
Webpack对于代码分割和静态资源导入有着“先天优势”,并且支持热模块替换(HMR),而Rollup并不支持,所以当项目需要用到以上,则可以考虑选择Webpack。但是,Rollup对于代码的Tree-shaking和ES6模块有着算法优势上的支持,若你项目只需要打包出一个简单的bundle包,并是基于ES6模块开发的,可以考虑使用Rollup。其实Webpack从2.0开始支持Tree-shaking,并在使用babel-loader的情况下支持了es6 module的打包了,实际上,Rollup已经在渐渐地失去了当初的优势了。但是它并没有被抛弃,反而因其简单的API、使用方式被许多库开发者青睐,如React、Vue等,都是使用Rollup作为构建工具的。而Webpack目前在中大型项目中使用得非常广泛。最后,用一句话概括就是:在开发应用时使用 Webpack,开发库时使用 Rollup。
在编写 loader 前,我们首先需要了解 loader 的本质:
代码如下所示:
// 导出一个函数,source为webpack传递给loader的文件源内容
module.exports = function(source) {
const content = doSomeThing2JsString(source);
// 如果 loader 配置了 options 对象,那么this.query将指向 options
const options = this.query;
// 可以用作解析其他模块路径的上下文
console.log('this.context');
/** this.callback 参数:
* error:Error | null,当 loader 出错时向外抛出一个 error
* content:String | Buffer,经过 loader 编译后需要导出的内容
* sourceMap:为方便调试生成的编译后内容的 source map
* ast:本次编译生成的 AST 静态语法树,之后执行的 loader 可以直接使用这个 AST,进而省去重复生成 AST 的过程
*/
this.callback(null, content); // 异步
return content; // 同步
}
一般在编写loader的过程中,保持功能单一,避免做多种功能。如less文件转换成 css文件也不是一步到位,而是 less-loader、css-loader、style-loader几个 loader的链式调用才能完成转换。
由于webpack基于发布订阅模式,在运行的生命周期中会广播出许多事件,插件通过监听这些事件,就可以在特定的阶段执行自己的插件任务
在之前也了解过,webpack编译会创建两个核心对象:
如果自己要实现plugin,也需要遵循一定的规范:
实现plugin的模板如下:
class MyPlugin {
// Webpack 会调用 MyPlugin 实例的 apply 方法给插件实例传入 compiler 对象
apply (compiler) {
// 找到合适的事件钩子,实现自己的插件功能
compiler.hooks.emit.tap('MyPlugin', compilation => {
// compilation: 当前打包构建流程的上下文
console.log(compilation);
// do something...
})
}
}
在 emit 事件发生时,代表源文件的转换和组装已经完成,可以读取到最终将输出的资源、代码块、模块及其依赖,并且可以修改输出资源的内容
loader
webpack 默认支持处理 JS 与 JSON 文件,其他类型都处理不了,这里必须借助 Loader 来对不同类型的文件的进行处理。
Loader 就是将 Webpack 不认识的内容转化为认识的内容。
如 安装 css-loader 来处理 CSS
plugins
如果我想打包后的资源文件,例如:js 或者 css 文件可以自动引入到 Html 中,就需要使用插件 html-webpack-plugin