文章目录
- 项目目录
 - 搭建项目
 - my-raw-loader
 - 参数
 - schema-utils
 
- tpl-loader
 
项目目录
让我们实现一些简易的loader,从大量的简易loader的实现过程中学习编写如何 webpack loader
├── loaders                     # loader目录
├── src                         # 业务代码
│   │── index.html
│   └── index.js										
├── .gitignore
├── package.json
├── package-lock.json
└── webpack.config.js			# webpack 配置文件
 
搭建项目
mkdir loaders
cd loaders
npm init -y
 
npm i -D webpack webpack-cli html-webpack-plugin webpack-dev-server loader-utils
 
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
  mode: 'development',
  plugins: [
    new HtmlWebpackPlugin({
      title: '自定义 webpack loader',
      template: './src/index.html',
    }),
  ],
};
 
src/index.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
 
src/index.js
import text from './happy-new-year.txt';
const textDom = document.createElement('p');
textDom.style.cssText = 'width: 200px;height: 200px;background-color: pink;';
textDom.innerText = text;
document.body.appendChild(textDom);
 
my-raw-loader
src/happy-new-year.txt
🎉🎉🎆🎆🧨🧨
新年快乐!大吉大利!
🎉🎉🎆🎆🧨🧨
 
执行 npx webpack-dev-server,会发现编译报错了

那么下面我们就实现 my-raw-loader 来抛砖引玉!
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
  mode: 'development',
  module: {
    rules: [
      {
        test: /.txt$/,
        use: [
          {
            loader: path.resolve(__dirname, 'loaders/my-raw-loader'),
            options: {
              esModule: true,
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: '自定义 webpack loader',
      template: './src/index.html',
    }),
  ],
};
 
loaders/my-raw-loader.js
function myRawLoader(source) {
  console.log('source', source);
}
module.exports = myRawLoader;
 
执行 npx webpack-dev-server 可以看到打印结果,这个参数是一个字符串

参数
修改 loaders/my-raw-loader.js
function myRawLoader(source) {
  // 提取给定的 loader 选项,
  // 从 webpack 5 开始,this.getOptions 可以获取到 loader 上下文对象。它用来替代来自 loader-utils 中的 getOptions 方法。
  const { esModule } = this.getOptions();
  console.log('esModule:', esModule);
  // 这里一定要返回字符串或者 buffer
  if (!esModule) {
    return `module.exports = ${JSON.stringify(source)}`;
  }
  return `export default ${JSON.stringify(source)}`;
}
module.exports = myRawLoader;
 
执行 npx webpack-dev-server可以看到通过 this.getOptions() 获取到了当前 loader 的配置,并且编译未报错,访问 http://localhost:8080/ 页面得偿所愿!成功读取并渲染了原始文本内容。


schema-utils
schema-utils 由webpack 官方提供, 它配合 loader-utils,用于保证 loader 选项,进行与 JSON Schema 结构一致的校验
const { validate } = require('schema-utils');
const schema = {
  type: 'object',
  properties: {
    esModule: {
      type: 'boolean',
    }
  },
  "additionalProperties": false // 是否允许不存在的选项传入
};
function myRawLoader(source) {
  const options = this.getOptions();
  validate(schema, options, {
    name: 'my-raw-loader',
    baseDataPath: 'options',
  });
  // 提取给定的 loader 选项,
  // 从 webpack 5 开始,this.getOptions 可以获取到 loader 上下文对象。它用来替代来自 loader-utils 中的 getOptions 方法。
  console.log('esModule:', options.esModule);
  // 这里一定要返回字符串或者 buffer
  if (!options.esModule) {
    return `module.exports = ${JSON.stringify(source)}`;
  }
  return `export default ${JSON.stringify(source)}`;
}
module.exports = myRawLoader;
 
如果传入未定义的选项,则会发生编译报错
{
  test: /.txt$/,
  use: [
    {
      loader: path.resolve(__dirname, 'loaders/my-raw-loader'),
      options: {
        esModule2: true,
      },
    },
  ],
},
 

tpl-loader
待续,马上…


















