实现一个 webpack loader

小闹心

小闹心

2020-09-16

官网上的定义:loader 是一个转换器,用于对源代码进行转换。

例如 babel-loader 可以将 ES6 代码转换为 ES5 代码。sass-loader 将 sass 代码转换为 css 代码。

一般 loader 的配置代码如下:

module: {  rules: [    {      test: /\.js$/,      use: [        {          loader: path.resolve("./loader1.js")        },        {          loader: path.resolve("./loader2.js")        }      ]    }  ]}

rules 数组包含了一个个匹配规则和具体的 loader 文件。

上述代码中的 test: /\.js$/ 就是匹配规则,表示对 js 文件使用下面的两个 loader。

而 loader 的处理顺序是自下向上的,即先用 loader2 处理源码,然后将处理后的代码再传给 loader1。

loader2 处理后的代码就是最终的打包代码。

loader 的实现

loader 其实是一个函数,它的参数是匹配文件的源码,返回结果是处理后的源码。下面是一个最简单的 loader,它什么都没做:

module.exports = function (source) {  return source}

这么简单的 loader 没有挑战性,我们可以写一个稍微复杂一点的 babel-loader:

const loaderUtils = require("loader-utils")const babel = require("@babel/core")function loader (source) {  let cb = this.async()  let options = loaderUtils.getOptions(this)  babel.transform(source, {    ...options,    sourceMap: true,    filename: this.resourcePath.split("/").pop()  }, function (err, r) {    cb(err, r.code, r.map)  })}module.exports = loader

异步 loader 需要调用 webpack 的 async() 生成一个 callback,它的第一个参数是 error,第二个参数就是处理后的源码。当你异步处理完源码后,调用 callback 即可。

loader-utils 是一个 webpack 工具类,通过一些方法配合 loader 处理文件。loader 是可以配置 options 参数,然后内部可以直接通过 getOptions 获取。

module: {  rules: [    {      test: /\.js$/,      use: [        {          loader: path.resolve("./loader/loader1.js"),          options: {            presets: ["@babel/preset-env"]          }        }      ]    }  ]}

babel-loader 使用的是 @babel/core 处理代码转换的,但是 @babel/core 本身不转换代码,它是调用 @babel/preset-env 插件转换的。

精彩推荐

粤ICP备16095388号-1