Open Samgao0312 opened 2 years ago
Loader本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
默认情况下,在遇到import或者load加载模块的时候,webpack只支持对js文件打包。像css、sass、png等这些类型的文件的时候,webpack则无能为力,这时候就需要配置对应的loader进行文件内容的解析。在加载模块的时候,执行顺序如,如下图所示。
关于配置Loader的方式,有常见的三种方式: - 配置方式(推荐):在 webpack.config.js文件中指定 loader - 内联方式:在每个 import 语句中显式指定 loader - Cli 方式:在 shell 命令中指定它们
关于Loader的配置,我们通常是写在 module.rules 属性中,属性介绍如下:
下面是一个module.rules的示例代码:
module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } }, { loader: 'sass-loader' } ] } ] } };
从上述代码可以看到,在处理 css 模块的时候,use属性中配置了三个 loader 分别处理 css 文件。因为 loader 支持链式调用,链中的每个 loader 会处理之前已处理过的资源,最终变为 js 代码。 顺序为相反的顺序执行,即上述执行方式为sass-loader、css-loader、style-loader。
除此之外,loader的特性还有如下:
可以通过 loader 的预处理函数,为 JS 生态系统提供更多能力。用户现在可以更加灵活地引入细粒度逻辑,例如:压缩、打包、语言翻译和更多其他特性。
在页面开发过程中,除了需要导入一些场景 JS 文件外,还需要配置响应的 loader 进行加载。Webpack常见的Loader如下:
下面以css-loader为例子,来说明Loader的使用过程。首先,我们在项目中安装css-loader插件。
npm install --save-dev css-loader
然后将规则配置到module.rules中,比如:
rules: [ ..., { test: /\.css$/, use: { loader: "css-loader", options: { // 启用/禁用 url() 处理 url: true, // 启用/禁用 @import 处理 import: true, // 启用/禁用 Sourcemap sourceMap: false } } } ]
Plugin就是插件,基于事件流框架Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Webpack中的 Plugin 也是如此,Plugin赋予其各种灵活的功能,例如:打包优化、资源管理、环境变量注入等,它们会运行在 webpack 的不同阶段(钩子 / 生命周期),贯穿了 Webpack 整个编译周期。
使用的时候,通过配置文件导出对象中 plugins 属性传入 new 实例对象即可。
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装 const webpack = require('webpack'); // 访问内置的插件 module.exports = { ... plugins: [ new webpack.ProgressPlugin(), new HtmlWebpackPlugin({ template: './src/index.html' }), ], };
Plugin从本质上来说,就是一个具有 apply 方法 JS 对象。apply 方法会被 webpack compiler 调用,并且在整个编译生命周期都可以访问 compiler 对象。
const pluginName = 'ConsoleLogOnBuildWebpackPlugin'; class ConsoleLogOnBuildWebpackPlugin { apply(compiler) { compiler.hooks.run.tap(pluginName, (compilation) => { console.log('webpack 构建过程开始!'); }); } } module.exports = ConsoleLogOnBuildWebpackPlugin;
我们可以使用上面的方式,来获取 Plugin 在编译生命周期钩子。如下:
Weebpack中,常见的plugin有如下一些:
下面通过clean-webpack-plugin来看一下插件的使用方法。首先,需要安装clean-webpack-plugin插件。
npm install --save-dev clean-webpack-plugin
然后,引入插件即可使用。
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); module.exports = { ... plugins: [ ..., new CleanWebpackPlugin(), ... ] }
Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为 Webpack 只认识 JS,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
Plugin 就是插件,基于事件流框架Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
我们知道,Loader本质上来说就是一个函数,函数中的 this 作为上下文会被 webpack 填充,因此我们不能将 loader 设为一个箭头函数。该函数接受一个参数,为 webpack 传递给 loader 的文件源内容。
同时,函数中 this 是由 webpack 提供的对象,能够获取当前 loader 所需要的各种信息。函数中有异步操作或同步操作,异步操作通过 this.callback 返回,返回值要求为 string 或者 Buffer,如下。
// 导出一个函数,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; // 同步 }
Webpack的Plugin是基于事件流框架Tapable,由于webpack基于发布订阅模式,在运行的生命周期中会广播出许多事件,插件通过监听这些事件,就可以在特定的阶段执行自己的插件任务。
同时,Webpack编译会创建两个核心对象:compiler和compilation。
如果需要自定义Plugin,也需要遵循一定的规范: - 插件必须是一个函数或者是一个包含 apply 方法的对象,这样才能访问compiler实例 - 传给每个插件的 compiler 和 compilation 对象都是同一个引用,因此不建议修改 - 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住
下面是一个自定Plugin的模板:
class MyPlugin { // Webpack 会调用 MyPlugin 实例的 apply 方法给插件实例传入 compiler 对象 apply (compiler) { // 找到合适的事件钩子,实现自己的插件功能 compiler.hooks.emit.tap('MyPlugin', compilation => { // compilation: 当前打包构建流程的上下文 console.log(compilation); // do something... }) } }
在 emit 事件被触发后,代表源文件的转换和组装已经完成,可以读取到最终将输出的资源、代码块、模块及其依赖,并且可以修改输出资源的内容。
1、Loader (加载器)
1.1 什么是 Loader
Loader本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
默认情况下,在遇到import或者load加载模块的时候,webpack只支持对js文件打包。像css、sass、png等这些类型的文件的时候,webpack则无能为力,这时候就需要配置对应的loader进行文件内容的解析。在加载模块的时候,执行顺序如,如下图所示。![image](https://user-images.githubusercontent.com/18101244/178925875-fa4d5472-ee8a-44f6-8a1b-29476075e34d.png)
关于配置Loader的方式,有常见的三种方式: - 配置方式(推荐):在 webpack.config.js文件中指定 loader - 内联方式:在每个 import 语句中显式指定 loader - Cli 方式:在 shell 命令中指定它们
配置方式
关于Loader的配置,我们通常是写在 module.rules 属性中,属性介绍如下:
下面是一个module.rules的示例代码:
1.2 Loader特性
从上述代码可以看到,在处理 css 模块的时候,use属性中配置了三个 loader 分别处理 css 文件。因为 loader 支持链式调用,链中的每个 loader 会处理之前已处理过的资源,最终变为 js 代码。 顺序为相反的顺序执行,即上述执行方式为sass-loader、css-loader、style-loader。
除此之外,loader的特性还有如下:
可以通过 loader 的预处理函数,为 JS 生态系统提供更多能力。用户现在可以更加灵活地引入细粒度逻辑,例如:压缩、打包、语言翻译和更多其他特性。
1.3 webpack中常见的loader
在页面开发过程中,除了需要导入一些场景 JS 文件外,还需要配置响应的 loader 进行加载。Webpack常见的Loader如下:
下面以css-loader为例子,来说明Loader的使用过程。首先,我们在项目中安装css-loader插件。
然后将规则配置到module.rules中,比如:
2、Plugin(插件)
2.1 什么是plugin
Plugin就是插件,基于事件流框架Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Webpack中的 Plugin 也是如此,Plugin赋予其各种灵活的功能,例如:打包优化、资源管理、环境变量注入等,它们会运行在 webpack 的不同阶段(钩子 / 生命周期),贯穿了 Webpack 整个编译周期。![image](https://user-images.githubusercontent.com/18101244/178928110-4a337a8a-cedb-46ed-8b0f-cfa040b45821.png)
使用的时候,通过配置文件导出对象中 plugins 属性传入 new 实例对象即可。
2.2 特性
Plugin从本质上来说,就是一个具有 apply 方法 JS 对象。apply 方法会被 webpack compiler 调用,并且在整个编译生命周期都可以访问 compiler 对象。
我们可以使用上面的方式,来获取 Plugin 在编译生命周期钩子。如下:
2.3 常见的Plugin
Weebpack中,常见的plugin有如下一些:
下面通过clean-webpack-plugin来看一下插件的使用方法。首先,需要安装clean-webpack-plugin插件。
然后,引入插件即可使用。
3、Loader 和 Plugin 的区别
Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为 Webpack 只认识 JS,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
Plugin 就是插件,基于事件流框架Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
4、如何自定义 Loader 和 Plugin
4.1 自定义 Loader
我们知道,Loader本质上来说就是一个函数,函数中的 this 作为上下文会被 webpack 填充,因此我们不能将 loader 设为一个箭头函数。该函数接受一个参数,为 webpack 传递给 loader 的文件源内容。
同时,函数中 this 是由 webpack 提供的对象,能够获取当前 loader 所需要的各种信息。函数中有异步操作或同步操作,异步操作通过 this.callback 返回,返回值要求为 string 或者 Buffer,如下。
4.2 自定义 Plugin
Webpack的Plugin是基于事件流框架Tapable,由于webpack基于发布订阅模式,在运行的生命周期中会广播出许多事件,插件通过监听这些事件,就可以在特定的阶段执行自己的插件任务。
同时,Webpack编译会创建两个核心对象:compiler和compilation。
如果需要自定义Plugin,也需要遵循一定的规范: - 插件必须是一个函数或者是一个包含 apply 方法的对象,这样才能访问compiler实例 - 传给每个插件的 compiler 和 compilation 对象都是同一个引用,因此不建议修改 - 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住
下面是一个自定Plugin的模板:
在 emit 事件被触发后,代表源文件的转换和组装已经完成,可以读取到最终将输出的资源、代码块、模块及其依赖,并且可以修改输出资源的内容。