Webpack中如何编写一个自定义的loader

更新日期: 2020-02-10 阅读: 2.3k 标签: webpack

基本Loader

webpack中loader是一个CommonJs风格的函数,接收输入的源码,通过同步或异步的方式替换源码后进行输出。

module.exports = function(source, sourceMap, meta) {
  
}
  • source是输入的内容
  • sourceMap是可选的
  • meta是模块的元数据,也是可选的

需要注意的是,该导出函数必须使用function,不能使用箭头函数,因为loader编写过程中会经常使用到this访问选项和其他方法。

我们先编写一个基本的Loader,完成的工作很简单,那就是把输出的字符串进行替换。

1.新建loader-example目录,执行npm初始化,并安装webpack

mkdir loader-example
cd loadeer-example
npm init -y
npm install webpack webpack-cli

2.构建项目目录

|----loader # loader目录
        |----replace-loader.js # 替换字符串的Loader
|----src   # 应用源码
        |----index.js # 首页
|----package.json
|----webpack.config.js

3.编写loader/replace-loader.js

module.exports = function(source) {
  return source.replace(/World/g, 'Loader');
};

本例中我们Loader只是简单的将源码中的”World“替换成了”Loader“。

4.编写src/index.js

console.log('Hello World');

5.编写webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index',
  target: 'node', // 我们编译为Node.js环境下的JS,等下直接使用Node.js执行编译完成的文件
  output:{
    path: path.resolve(__dirname, 'build'),
    filename: '[name].js'
  },
  module:{
    rules:[
      {
        test:/\.js$/,
        use: 'replace-loader'
      }
    ]
  },
  resolveLoader: {
      modules: ['./node_modules', './loader'] // 配置loader的查找目录
  }
};

6.编写package.json

{
  "scripts":{
    "build":"webpack"
  }
}

7.执行构建

npm run build

8.构建完成后,执行build/main.js

node build/main.js

此时终端输出如下,我们编写的Loader工作正常。

Hello Loader


Loader选项

我们使用第三方loader时经常可以看到传递选项的情况:

{
  test:/\.js$/,
  use:[
    {
      loader:'babel-loader',
      options:{
        plugins:['@babel/transform-runtime'],
        presets:['@babel/env']
      }
    }
  ]
}

在Loader编写时,Webpack中官方推荐通过loader-utils来读取配置选项,我们需要先安装。

npm install loader-utils

我们给刚才编写的replace-loader传递一个选项,允许自定义替换结果。

const loaderUtils = require('loader-utils');

module.exports = function(source) {
    const options = loaderUtils.getOptions(this);
  return source.replace(/World/g, options.text);
};

接下来编辑webpack.config.js,给replace-loader传递选项。

module.exports = {
  module:{
    rules:[
      {
        test:/\.js$/,
        use:[
          {
            loader:'replace-loader',
            options:{
              text: 'Webpack4'
            }
          }
        ]
      }
    ]
  },
  resolveLoader:{
    modules: ['./node_modules', './loader']
  }
};

执行构建之后用Node.js执行build/main.js,可以看到输出的内容已经发生变化了。

Hello Webpack4


异步Loader

在Loader中,如果存在异步调用,那么就无法直接通过return返回构建后的结果了,此时需要使用到Webpack提供的回调函数将数据进行回调。

Webpack4给Loader提供了this.async()函数,调用之后返回一个callback,callback的签名如下:

function callback(
  err: Error|null,
  content: string|Buffer,
  sourceMap?:SourceMap,
  meta?: any
)

例如我们需要在loader中调用setTimeout进行等待,则相应的代码如下:

module.exports = function(source) {
  const callback = this.async();
  setTimeout(() => {
    const output = source.replace(/World/g, 'Webpack4');
    callback(null, output);
  }, 1000);
}

执行构建,Webpack会等待一秒,然后再输出构建内容,通过Node.js执行构建后的文件,输出如下

Hello Webpack4


"Raw" Loader

默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw,loader 可以接收原始的 Buffer。比如处理非文本文件时(如图片等等)。

module.exports = function(source) {
  assert(source instanceof Buffer);
  return someSyncOperation(source);
};
module.exports.raw = true; // 设置当前Loader为raw loader, webpack会将原始的Buffer对象传入


读取loader配置文件

babel-loader在使用时可以加载.babelrc配置文件来配置plugins和presets,减少了webpack.config.js的代码量,便于维护。接下来我们编写一个i18n-loader,通过读取语言配置文件完成语言转换。

项目结构

|----loader
        |----i18n-loader.js # loader
|----i18n
        |----zh.json # 中文语言包
|----src
        |----index.js # 入口文件
|----webpack.config.js

i18n/zh.json

{
    "hello": "你好",
    "today": "今天"
}

loader/i18n-loader.js

const loaderUtils = require('loader-utils');
const path = require('path');

module.exports = function (source) {
    const options = loaderUtils.getOptions(this);
    const locale = options ? options.locale : null;

    // 读取语言配置文件
    let json = null;
    if (locale) {
        const filename = path.resolve(__dirname, '..', 'i18n', `${locale}.json`);
        json = require(filename);
    }

    // 读取语言标记 {{}}
    const matches = source.match(/\{\{\w+\}\}/g); 
    for (const match of matches) {
        const name = match.match(/\{\{(\w+)\}\}/)[1].toLowerCase();
        if (json !== null && json[name] !== undefined) {
            source = source.replace(match, json[name]);
        } else {
            source = source.replace(match, name);
        }
    }
    return source;
}

src/index.js

console.log('{{Hello}}, {{Today}} is a good day.');

webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index',
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: '[name].js'
    },
    target: 'node',
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'i18n-loader',
                        options: { // 传递选项
                            locale: 'zh'
                        }
                    }
                ]
            }
        ]
    },
    resolveLoader: {
        modules: ['./node_modules', './loader']
    }
};

package.json

{
  "scripts":{
    "build":"webpack"
  }
}

执行构建

npm run build

构建完毕后使用Node.js执行build/main.js输出如下:

你好, 今天 is a good day.

可以看到i18n-loader成功读取了配置文件。


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/8166

相关推荐

WebPack中Plugins的使用和整理,以及常用的Plugins插件

Plugins是webpack的基础,我们都知道webpage的plugin是基于事件机制工作的,这样最大的好处是易于扩展。讲解如果扩展内置插件和其他插件,以及我们常用的Plugins插件

Webpack 4正式发布了!

新版 Webpack 中我们所做的每一个更新目的都在于此,为了当大家在使用 Webpack 的时候敏捷连续毫无顿挫感。 webpack 4 进行构建性能测试,得出的结果非常有趣。结果很惊人,构建时间降低了 60%-98%!

大多数项目中会用到的webpack小技巧

webpack技巧的总结:进度汇报、压缩、复数文件打包、分离app文件与第三方库文件、资源映射、输出css文件、开发模式、分析包的大小、更小的react项目、更小的Lodash、引入文件夹中所有文件、清除extract-text-webpack-plugin日志。

什么是webpack?Webpack的核心概念

Webpack已经流行好久了,但很多同学使用webpack时还是一头雾水,一下看到那么多文档、各种配置、各种loader、plugin立马就晕头转向了。我也不例外,以至于很长一段时间对webpack都是一知半解的状态

如何写 Webpack 配置文件

本文从一个小Demo开始,通过不断增加功能来说明webpack的基本配置,只针对新手。webpack基本的配置就可以熟悉了,会引入loader,配置loader选项,会设置alias,会用plugins差不多。

webpack项目轻松混用css module

本文讲述css-loader开启css模块功能之后,如何与引用的npm包中样式文件不产生冲突。比如antd-mobilenpm包的引入。在不做特殊处理的前提下,样式文件将会被转译成css module。

Vue -- webpack 项目自动打包压缩成zip文件

这段时间用 Vue2.0 开发项目,每次打包都会用到 npm run build 命令,但是每次部署时给后端发包都要手动zip压缩,这样一两次还行,但遇到项目板块测试和临时加急功能测试的时候,一天可能就要打包好多次,这就很烦了。

webpack3 升级 webpack4踩坑记录

安装webpack4最新版本;这个在webpack3中,webpack本身和它的CLI是在同一个包中,webpack4中将两个分开管理。记得添加mode用来告知 webpack 使用相应环境的内置优化

Vue中使用webpack别名的方法

Vue中使用webpack别名的方法,需要引入公共文件,但是公共文件的文件路径里当前文件很远,那么就会形成上面示例中的那种路径很长的情况。而因为文件目录是约定俗成的,不可轻易更改,无法修改相对路径。那么该怎么办呢?

通用、封装、简化 webpack 配置

现在,基本上前端的项目打包都会用上 webpack,因为 webpack 提供了无与伦比强大的功能和生态。但在创建一个项目的时候,总是免不了要配置 webpack,很是麻烦。简化 webpack 配置的一种方式是使用社区封装好的库,比如 roadhog。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!