Webpack: Loader 开发分享

news/2024/7/10 18:04:00 标签: webpack, module, loader, transpiler, plugin

Webpack: Loader 开发分享

文章目录

  • Webpack: Loader 开发分享
  • 正文
    • 1. Concept 概念
    • 2. Configuration 配置实例
    • 3. Custom 自定义 Loader
      • 3.1 配置自定义 Loader
      • 3.2 内嵌 loader(路径指定)
      • 3.3 Loader 写法
    • 4. 实战:jsonc-loader
  • 其他资源
    • 参考连接
    • 完整代码示例

正文

1. Concept 概念

Webpack 的理念告诉我们万物皆模块(Module),然而一个完整的前端网页不仅仅只有 JavaScript,还会有其他各类文件的参与(CSS、HTML、静态资源)

因此 Webpack 作为一个 Module Bundler 将整个打包过程拆分成不同的模块分别负责不同的任务,详细就不展开说了。

今天要来搞的就是所谓的 Loader 的部分,一言以蔽之就是:

Loader 负责将非 JS 的文件转换成 JS 模块后导入

例如我们常会用的

import './xxx.css'

实际上这样导入就不是标准 JavaScript 能看懂的范畴了,因此就要借助 Loader 的能力转换成 JS 模块后再导入

2. Configuration 配置实例

在 Wwebpack 中配置 Loader 的方法官方也写的很详细了,简单来说就是写在配置文件的 module.rules 项当中

module.exports = {
  module: {
    rules: [
      // ...
    ]
  }
}

第一种写法只配置单一个 loader

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/,
        use: 'html-loader'
      }
    ]
  }
}

要使用多个 loader 可以传入一个数组,生效的顺序为由后往前

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}

另外如果想要针对某一个 loader 传入配置参数,将名字改成对象就可以了

module.exports = {
  module: {
    rules: [
      {
        test: /\.module.(sass|scss)$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: '[path][name]__[local]--[hash:base64:5]',
              },
              sourceMap: true,
            },
          },
          'sass-loader',
        ],
      },
    ]
  }
}

如上面最后一个例子,配置了一个启用了 CSS Module 和 Sass 语法的解析,先后经过 sass-loader、css-loader、style-loader,最后被引入代码当中

其中为 css-loader 特别配置了模块化方案的参数

3. Custom 自定义 Loader

那么我们要怎么自己来写一个 loader 呢,就好像 Vue 一样写了一个 loader 来支持 .vue 文件的解析一样,看着就很屌

3.1 配置自定义 Loader

配置自定义 loader 有很多种方式

  1. 第一种:引入相对路径(只用一次的时候)
const path = require('path');

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: path.resolve('path/to/loader.js'),
            options: {
              /* ... */
            },
          },
        ],
      },
    ],
  },
};
  1. 第二种:配置 loader 查找范围(推荐)
const path = require('path');

module.exports = {
  //...
  resolveLoader: {
    modules: ['node_modules', path.resolve(__dirname, 'loaders')],
  },
};

使用第二种就可以直接在 loader 属性写名字就行了

loader_149">3.2 内嵌 loader(路径指定)

当然要使用内联的 loader 的时候就必须使用第二种写法

require('./loader!./lib');

像是上面这样写 webpack 就会知道加载 ./lib 这个东西之后要先经过 loader 的转换

内嵌的时候甚至也能为 loader 配置参数

require('./loader1?xyz!loader2!./resource?rrr');

这样写老实说可读性还是挺差的,所以通常在 loader 的 runtime 写法中比较常见,正常用的时候还是避免内嵌到路径当中

3.3 Loader 写法

接下来进入正题,loader 到底该怎么写。

首先先看看模块结构

module.exports = function (source) {
  // loader
};

一个 loader 必须导出一个 funciton 函数(这里应该是不能用箭头函数的,因为 webpack 会通过 this 将 context 注入进来,不过我也不太确定hh,this 还是要学好啊hh)

loader 的返回就很多种了

  • 同步一个返回值:直接 return output
  • 同步多个返回值:使用 this.callback
  • 异步:使用 callback = this.async()

详细使用还是去查文档吧,这里写了也没意思

loader_189">4. 实战:jsonc-loader

最后我们给出一个 loader 的实战,用于解析 jsonc 格式的文件

由于 Node 默认就支持导入 .json 文件,但是意外的发现不能用 jsonc,所以可以来试一把,主要任务就是把注释删了就可以了

const removeComment = (s) => {
  return s.replace(/\/\/.*$/gm, '');
};

const removeWhiteSpace = (s) => {
  return s.replace(/[ \n\t]*/g, '');
};

module.exports = function (source) {
  console.log(`Solve jsonc: '${source}'`);

  const noComment = removeComment(source);
  console.log(`noComment: '${noComment}'`);

  const noWhiteSpace = removeWhiteSpace(noComment);
  console.log(`noWhiteSpace: '${noWhiteSpace}'`);

  const data = JSON.parse(noWhiteSpace);
  console.log(`Parsed data:`, data);

  const res = JSON.stringify(data);
  console.log(`res: ${res}`);

  return `module.exports = ${res}`;
}

直接上代码,还是比较简单的,使用正则表达式分别删除注释、清理空白符、使用 parse 反序列化确保 json 格式正确,最后反序列化并加上 module.exports 作为模块默认导出对象

写好 loader 之后要去配置文件里面配置一下

const path = require('path');

const config = {
  // ...
  resolveLoader: {
    modules: [path.resolve(__dirname, 'loaders'), 'node_modules'],
  },
  module: {
    rules: [
      {
        test: /\.jsonc/,
        use: 'jsonc-loader',
      },
    ],
  },
};

module.exports = config;

首先是 resolveLoader 来配置 loader 目录,然后加入一个 rule

最后的测试代码稍微贴一下

  • /src/index.js
console.log('sample', require('./sample.jsonc'));

然后分别使用 Node 直接运行 & 使用 webpack 编译后运行的结果

  • Node 直接运行脚本
$ node src/index.js
Hello world
~/webpack_loader_custom_json_parse/src/sample.jsonc:3
  "name": "superfree",
        ^

SyntaxError: Unexpected token ':'
  • Webpack 编译后运行
$ webpack && node dist/main.js

✔ Webpack
  Compiled successfully in 124.86ms

asset main.js 283 bytes [emitted] [minimized] (name: main)
./src/index.js 103 bytes [built] [code generated]
./src/sample.jsonc 70 bytes [built] [code generated]
webpack 5.64.3 compiled successfully in 127 ms
Hello world
sample { name: 'superfree', age: 22, courses: [ 'math', 'cs' ] }

其他资源

参考连接

TitleLink
Writing a Loader - Webpackhttps://webpack.js.org/contribute/writing-a-loader/
Loader Interface - Webpackhttps://webpack.js.org/api/loaders/
require(id) - Nodehttps://nodejs.org/dist/latest-v16.x/docs/api/modules.html#requireid
JSON Loader - npmhttps://www.npmjs.com/package/json-loader
webpack-contrib/json-loader - Githubhttps://github.com/webpack-contrib/json-loader
手把手教你撸一个 Webpack Loaderhttps://blog.csdn.net/lszy16/article/details/79162960
简单实用的webpack-html-include-loader(附开发详解)https://cloud.tencent.com/developer/article/1607507

完整代码示例

https://github.com/superfreeeee/Blog-code/tree/main/front_end/webpack/webpack_loader_custom_json_parse


http://www.niftyadmin.cn/n/735108.html

相关文章

df命令、du命令、磁盘分区

为什么80%的码农都做不了架构师?>>> df命令 查看磁盘空间使用情况 df -[MGh][rootyolks1 ~]# df 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/sda3 18658304 1074316 17583988 6% / devtmpfs 923632 0 923632…

JS Web API: Stream API 解析

JS Web API: Stream API 解析 文章目录JS Web API: Stream API 解析正文1. Stream 概念 & 类型2. ReadableStream3. WritableStream4. pipeTo 传递数据4.1 自定义流对接4.2 pipeTo5. TransformStream & pipeThrough5.1 TransformStream 的创建5.2 自定义流通道5.3 Tran…

Rust: Box 智能指针进阶 - Rc、RefCell、Weak

Rust: Box 智能指针进阶 - Rc、RefCell、Weak 文章目录Rust: Box 智能指针进阶 - Rc、RefCell、Weak正文1. Box 类型复习2. 自定义模拟 Box 类型3. 递归类型定义4. Box 进阶:Rc5. Box 进阶:RefCell6. 循环依赖 & Weak7. 结论其他资源参考连接完整代码…

C++: SDL2 开发环境配置(Mac+CLion)

C: SDL2 开发环境配置(MacCLion) 文章目录C: SDL2 开发环境配置(MacCLion)正文1. 环境配置2. 安装依赖2.1 使用 Homebrew 安装 SDL22.2 项目 CMakeLists.txt 配置文件3. SDL2 初试3.1 App 类声明3.2 Init 实现3.3 Execute 实现3.4…

Rust Closure 闭包解析(匿名函数)

Rust Closure 闭包解析(匿名函数) 文章目录Rust Closure 闭包解析(匿名函数)正文1. 简单闭包 - 纯粹的匿名函数2. 捕获上下文 & FnOnce、FnMut、Fn 类型验证其他资源参考连接完整代码示例正文 闭包与匿名函数是现代语言对与函…

Rust 构建 Wasm 模块

Rust 构建 Wasm 模块 文章目录Rust 构建 Wasm 模块正文1. 安装1.1 使用 Rustup 安装 Rust1.2 安装 wasm-pack1.3 CLion 配置2. 手动构建 Rust to Wasm 项目2.1 创建项目2.2 配置文件 Cargo.toml2.3 模块导出函数 & 打包2.4 前端项目展示3. 使用 wasm-pack 模版构建3.1 配置…

JS Math.radom()随机变换

//随机变换元素背景色//Math.random() * (大 - 小) 小 function color () {var r parseInt(Math.random() * 256);var g parseInt(Math.random() * 256);var b parseInt(Math.random() * 256);return rgb( r , g , b ); }setInterval(changColor.style.background …

mime 源码解析(Npm library)

mime 源码解析(Npm library) 文章目录mime 源码解析(Npm library)正文0. 基本信息1. 源码解析1.0 MIME 类型定义1.1 标准版 vs 轻量版(lite)1.2 Mime 类1.3 define1.4 getType & getExtension2. 构建依赖2.0 项目打包 & 发布2.1 mime-db 引入2.2 划分 standard/other3.…