《webpack5 实战四》之loader

2022-03-09 11:36:47 浏览数 (1)

前言:项目一直在用webpack 打包,也系统的跟着B站的视频教程去学过,但是总是觉得差了点什么,有些配置还是不知道,决定把一些例子写下来总结下知识点,顺便学习下webpack5。

文章目录

  • 系列文章目录
    • 前言
    • 一、最简单的自定义loader
      • 准备工作
      • 1. 新建自定义loader 文件
      • 2. 使用自定义loader
      • 3. 使用验证
    • 二、loader内联方式
      • 目标
      • 1. 新建自定义loader 文件
      • 2. webpack config 配置别名加载
      • 3. 内联使用
      • 4. 执行webpack 命令验证
    • 三、Loader 接口
    • 四、Loader 传参
      • 1. 新建select-hero-loader
      • 2. webpack config 配置
      • 3. 使用验证
    • 四、总结
      • Loder 特性

前言

webpack 的loader 基础作用相当于一个项目插件,能够将指定文件统一的处理,是一个函数,相当于源码经过这个函数,出去变成了想要的目标。

官方描述:

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或 “load(加载)” 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS 文件!

多余的不多赘述,看官方文档loader,介绍的很详细。这篇主要通过实战记录自定义loader,了解loader工作的整个过程。

一、最简单的自定义loader

准备工作

loader 可以看做一个函数,输入是源码,输出是经过loader 加工之后的。

自定义loader格式:

代码语言:javascript复制
/**
 *
 * @param {string|Buffer} content 源文件的内容
 * @param {object} [map] 可以被 https://github.com/mozilla/source-map 使用的 SourceMap 数据
 * @param {any} [meta] meta 数据,可以是任何内容
 */
function webpackLoader(content, map, meta) {
  // 你的 webpack loader 代码
}

下面目标是创建一个英雄联盟英雄说明loader,loader 会替换英雄名和技能,增加详细说明。

1. 新建自定义loader 文件

hero-loader.js:

代码语言:javascript复制
module.exports = function (source) {
  console.log(source);
  return  source.replace("德玛西亚","英雄联盟保健哥:德玛西亚!")
}

这样一个loader 就创建完成了,接下来使用loader

2. 使用自定义loader

webpack.config.js 文件里:

代码语言:javascript复制
 {
                test:/.js$/,
                use: "./src/custom-loader/hero-loader.js",   // 看这里,看这里
            }

这里use 存放自定义loader 文件 存放路径

3. 使用验证

新建hero.js:

代码语言:javascript复制
exports.hero ='德玛西亚'

新建index.js:

代码语言:javascript复制
import hero from "./hero.js";
console.log(hero);

接下来执行webpack 打包命令打包,生成dist 下文件,具体webpack 配置见源码。

将打包后的文件引入index.html ,并在浏览器打开。

结果德玛西亚已经替换成了更详细的介绍成功了。

二、loader内联方式

目标

  • 通过内联的方式使用loader
  • 别名载入loader

1. 新建自定义loader 文件

skill-loader:

代码语言:javascript复制
module.exports = function (source) {
  return  source.replace("大宝剑","R技能是:大宝剑!")
}

2. webpack config 配置别名加载

代码语言:javascript复制
   resolveLoader:{
        alias:{
            'skill-loader':resolve(__dirname,'src/custom-loader/skill-loader.js')
        }
    }

3. 内联使用

skill.js:

代码语言:javascript复制
exports.skill = '大宝剑'

index.js 引入:

代码语言:javascript复制
import skill from "!skill-loader!./skill.js";
console.log(skill);

4. 执行webpack 命令验证

打包之后的文件:

代码语言:javascript复制
/***/ "./src/hero.js":
/*!*********************!*
  !*** ./src/hero.js ***!
  *********************/
/***/ ((__unused_webpack_module, exports) => {

eval("/*n * @Author: ZYn * @Date: 2022-02-14 16:26:29n * @LastEditors: ZYn * @LastEditTime: 2022-02-14 16:27:33n * @FilePath: /webpack-demo/packages/loader-demo/src/hero.jsn * @Description: 文件描述n */nnexports.hero ='英雄联盟保健哥:德玛西亚!'nn//# sourceURL=webpack:///./src/hero.js?");

/***/ }),

/***/ "./src/index.js":
/*!**********************!*
  !*** ./src/index.js ***!
  **********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);n/* harmony import */ var _hero_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./hero.js */ "./src/hero.js");n/* harmony import */ var _skill_loader_skill_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !skill-loader!./skill.js */ "./src/custom-loader/skill-loader.js!./src/skill.js");n/*n * @Author: ZYn * @Date: 2022-02-14 11:44:14n * @LastEditors: ZYn * @LastEditTime: 2022-02-14 16:48:22n * @FilePath: /webpack-demo/packages/loader-demo/src/index.jsn * @Description: 文件描述n */nnnnnconsole.log(_hero_js__WEBPACK_IMPORTED_MODULE_0__);nconsole.log(_skill_loader_skill_js__WEBPACK_IMPORTED_MODULE_1__);nn//# sourceURL=webpack:///./src/index.js?");

/***/ }),

/***/ "./src/custom-loader/skill-loader.js!./src/skill.js":
/*!**********************************************************!*
  !*** ./src/custom-loader/skill-loader.js!./src/skill.js ***!
  **********************************************************/
/***/ ((__unused_webpack_module, exports) => {

eval("/*n * @Author: ZYn * @Date: 2022-02-14 16:26:35n * @LastEditors: ZYn * @LastEditTime: 2022-02-14 16:28:04n * @FilePath: /webpack-demo/packages/loader-demo/src/skill.jsn * @Description: 文件描述n */nnexports.skill = 'R技能是:大宝剑!'nn//# sourceURL=webpack:///./src/skill.js?./src/custom-loader/skill-loader.js");

/***/ })

可以对比看一下内联和webpack rule 配置有什么区别

  • 收集代码map的时候key是不同的,内两方式会加上loader path

index.html 引入打包js之后运行结果:

三、Loader 接口

了解基础loader使用之后,看看loader 的其他高级接口。

官网很详细这里就不一一赘述(官网loader接口)

四、Loader 传参

设置loader 的时候有一些需要外界环境的变量,这些变量可以在配置中设置。

webpack config提供 loader 配置options。下面是一个小例子,来演示这个情景。

1. 新建select-hero-loader

这个loader 的意思很明白,我要选择英雄,通过loader 打包到浏览器,告诉我选择的什么英雄。

这里会利用loader 接口:

  • query 或者 getOptions 获取变量
  • resourcePath 定位使用loaderjs 使用

select-hero-loader.js :

代码语言:javascript复制
module.exports = function (source) {
 const {heroName} =  this.query
 //也可以查出options map
//  const {heroName} =  this.getOptions()
 if (heroName && this.resourcePath.endsWith('select.js')) {
  this.callback(null,source.replace('您选择了英雄',`您选择了英雄:${heroName}`))
 }
  return source
}

2. webpack config 配置

这里针对于单个文件使用其实使用内联的方式更简单,但是这里为了联系所以采用rule 的方式配置,保留之前的loader。

代码语言:javascript复制
{
                test:/.js$/,
                use: [
                    "./src/custom-loader/hero-loader.js",
                    {
                        loader:"select-hero-loader",
                        options:{
                            heroName:'寒冰射手'
                        }
                    }
                ]   // 看这里,看这里
            }

这两个自定义loader ,你在loader 里加上log 是可以验证运行顺序的,是自下而上执行,感兴趣自己验证。

3. 使用验证

select.js :

代码语言:javascript复制
module.exports = function selectHero() {
  console.log(`您选择了英雄`);
}

index.js :

代码语言:javascript复制
import skill from "!skill-loader!./skill.js";
selectHero()

执行webpack 打包,运行到浏览器:

四、总结

Loder 特性

  • loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何操作。
  • loader 可以通过 options 对象配置(仍然支持使用 query 参数来设置选项,但是这种方式已被废弃)。 除了常见的通过 package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块。
  • 插件(plugin)可以为 loader 带来更多特性。
  • loader 能够产生额外的任意文件。

0 人点赞