We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
官网上的定义:
loader 是一个转换器,用于对源代码进行转换。
例如 babel-loader 可以将 ES6 代码转换为 ES5 代码;sass-loader 将 sass 代码转换为 css 代码。
babel-loader
sass-loader
sass
css
一般 loader 的配置代码如下:
module: { rules: [ { test: /\.js$/, use: [ // loader 的执行顺序从下到上 { loader: path.resolve('./src/loader2.js'), }, { loader: path.resolve('./src/loader1.js'), }, ] } ] },
rules 数组包含了一个个匹配规则和具体的 loader 文件。
上述代码中的 test: /\.js$/ 就是匹配规则,表示对 js 文件使用下面的两个 loader。
test: /\.js$/
而 loader 的处理顺序是自下向上的,即先用 loader1 处理源码,然后将处理后的代码再传给 loader2。
loader2 处理后的代码就是最终的打包代码。
loader 其实是一个函数,它的参数是匹配文件的源码,返回结果是处理后的源码。下面是一个最简单的 loader,它什么都没做:
module.exports = function (source) { return source }
这么简单的 loader 没有挑战性,我们可以写一个稍微复杂一点的 loader,它的作用是将 var 关键词替换为 const:
var
const
module.exports = function (source) { return source.replace(/var/g, 'const') }
写完之后,我们来测试一下,测试文件为:
function test() { var a = 1; var b = 2; var c = 3; console.log(a, b, c); } test()
wepback.config.js 配置文件为:
wepback.config.js
const path = require('path') module.exports = { mode: 'development', entry: { main: './src/index.js' }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.js$/, use: [ { loader: path.resolve('./src/loader1.js'), }, ] } ] }, }
运行 npm run build,得到打包文件 bundle.js,我们来看一看打包后的代码:
npm run build
bundle.js
eval("function test() {\r\n const a = 1;\r\n const b = 2;\r\n const c = 3;\r\n console.log(a, b, c);\r\n}\r\n\r\ntest()\n\n//# sourceURL=webpack:///./src/index.js?");
可以看到,代码中的 var 已经变成了 const。
刚才实现的 loader 是一个同步 loader,在处理完源码后用 return 返回。
return
下面我们来实现一个异步 loader:
module.exports = function (source) { const callback = this.async() // 由于有 3 秒延迟,所以打包时需要 3+ 秒的时间 setTimeout(() => { callback(null, `${source.replace(/;/g, '')}`) }, 3000) }
异步 loader 需要调用 webpack 的 async() 生成一个 callback,它的第一个参数是 error,这里可设为 null,第二个参数就是处理后的源码。当你异步处理完源码后,调用 callback 即可。
async()
error
null
callback
下面来试一下异步 loader 到底有没生效,这里设置了一个 3 秒延迟。我们来对比一下打包时间:
上图是调用同步 loader 的打包时间,为 141 ms;下图是调用异步 loader 的打包时间,为 3105 ms,说明异步 loader 生效了。
如果想看完整 demo 源码,请点击我的 github。
webpack 在整个编译周期中会触发很多不同的事件,plugin 可以监听这些事件,并且可以调用 webpack 的 API 对输出资源进行处理。
这是它和 loader 的不同之处,loader 一般只能对源文件代码进行转换,而 plugin 可以做得更多。plugin 在整个编译周期中都可以被调用,只要监听事件。
对于 webpack 编译,有两个重要的对象需要了解一下:
Compiler 和 Compilation 在插件开发中最重要的两个资源就是 compiler 和 compilation 对象。理解它们的角色是扩展 webpack 引擎重要的第一步。
compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
compilation 对象代表了一次资源版本构建。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
这两个组件是任何 webpack 插件不可或缺的部分(特别是 compilation),因此,开发者在阅读源码,并熟悉它们之后,会感到获益匪浅。
我们看一下官网的定义,webpack 插件由以下部分组成:
简单的说,一个具有 apply 方法的函数就是一个插件,并且它要监听 webpack 的某个事件。下面来看一个简单的示例:
function Plugin(options) { } Plugin.prototype.apply = function (compiler) { // 所有文件资源都被 loader 处理后触发这个事件 compiler.plugin('emit', function (compilation, callback) { // 功能完成后调用 webpack 提供的回调 console.log('Hello World') callback() }) } module.exports = Plugin
写完插件后要怎么调用呢?
先在 webpack 配置文件中引入插件,然后在 plugins 选项中配置:
const Plugin = require('./src/plugin') module.exports = { ... plugins: [ new Plugin() ] }
这就是一个简单的插件了。
下面我们再来写一个复杂点的插件,它的作用是将经过 loader 处理后的打包文件 bundle.js 引入到 index.html 中:
index.html
function Plugin(options) { } Plugin.prototype.apply = function (compiler) { // 所有文件资源经过不同的 loader 处理后触发这个事件 compiler.plugin('emit', function (compilation, callback) { // 获取打包后的 js 文件名 const filename = compiler.options.output.filename // 生成一个 index.html 并引入打包后的 js 文件 const html = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="${filename}"></script> </head> <body> </body> </html>` // 所有处理后的资源都放在 compilation.assets 中 // 添加一个 index.html 文件 compilation.assets['index.html'] = { source: function () { return html }, size: function () { return html.length } } // 功能完成后调用 webpack 提供的回调 callback() }) } module.exports = Plugin
OK,执行一下,看看效果。
完美,和预测的结果一模一样。
完整 demo 源码,请看我的 github。
想了解更多的事件,请看官网介绍 compiler 钩子。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
loader
官网上的定义:
例如
babel-loader
可以将 ES6 代码转换为 ES5 代码;sass-loader
将sass
代码转换为css
代码。一般 loader 的配置代码如下:
rules 数组包含了一个个匹配规则和具体的 loader 文件。
上述代码中的
test: /\.js$/
就是匹配规则,表示对 js 文件使用下面的两个 loader。而 loader 的处理顺序是自下向上的,即先用 loader1 处理源码,然后将处理后的代码再传给 loader2。
loader2 处理后的代码就是最终的打包代码。
loader 的实现
loader 其实是一个函数,它的参数是匹配文件的源码,返回结果是处理后的源码。下面是一个最简单的 loader,它什么都没做:
这么简单的 loader 没有挑战性,我们可以写一个稍微复杂一点的 loader,它的作用是将
var
关键词替换为const
:写完之后,我们来测试一下,测试文件为:
wepback.config.js
配置文件为:运行
npm run build
,得到打包文件bundle.js
,我们来看一看打包后的代码:可以看到,代码中的
var
已经变成了const
。异步 loader
刚才实现的 loader 是一个同步 loader,在处理完源码后用
return
返回。下面我们来实现一个异步 loader:
异步 loader 需要调用 webpack 的
async()
生成一个 callback,它的第一个参数是error
,这里可设为null
,第二个参数就是处理后的源码。当你异步处理完源码后,调用callback
即可。下面来试一下异步 loader 到底有没生效,这里设置了一个 3 秒延迟。我们来对比一下打包时间:
上图是调用同步 loader 的打包时间,为 141 ms;下图是调用异步 loader 的打包时间,为 3105 ms,说明异步 loader 生效了。
如果想看完整 demo 源码,请点击我的 github。
plugin
webpack 在整个编译周期中会触发很多不同的事件,plugin 可以监听这些事件,并且可以调用 webpack 的 API 对输出资源进行处理。
这是它和 loader 的不同之处,loader 一般只能对源文件代码进行转换,而 plugin 可以做得更多。plugin 在整个编译周期中都可以被调用,只要监听事件。
对于 webpack 编译,有两个重要的对象需要了解一下:
plugin 的实现
我们看一下官网的定义,webpack 插件由以下部分组成:
简单的说,一个具有 apply 方法的函数就是一个插件,并且它要监听 webpack 的某个事件。下面来看一个简单的示例:
写完插件后要怎么调用呢?
先在 webpack 配置文件中引入插件,然后在 plugins 选项中配置:
这就是一个简单的插件了。
下面我们再来写一个复杂点的插件,它的作用是将经过 loader 处理后的打包文件
bundle.js
引入到index.html
中:OK,执行一下,看看效果。
完美,和预测的结果一模一样。
完整 demo 源码,请看我的 github。
想了解更多的事件,请看官网介绍 compiler 钩子。
参考资料
The text was updated successfully, but these errors were encountered: