前言:项目一直在用webpack 打包,也系统的跟着B站的视频教程去学过,但是总是觉得差了点什么,有些配置还是不知道,决定把一些例子写下来总结下知识点,顺便学习下webpack5。
webpack 的loader 基础作用相当于一个项目插件,能够将指定文件统一的处理,是一个函数,相当于源码经过这个函数,出去变成了想要的目标。
官方描述:
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或 “load(加载)” 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS 文件!
多余的不多赘述,看官方文档loader,介绍的很详细。这篇主要通过实战记录自定义loader,了解loader工作的整个过程。
loader 可以看做一个函数,输入是源码,输出是经过loader 加工之后的。
自定义loader格式:
/**
*
* @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 会替换英雄名和技能,增加详细说明。
hero-loader.js:
module.exports = function (source) {
console.log(source);
return source.replace("德玛西亚","英雄联盟保健哥:德玛西亚!")
}
这样一个loader 就创建完成了,接下来使用loader
在webpack.config.js
文件里:
{
test:/\.js$/,
use: "./src/custom-loader/hero-loader.js", // 看这里,看这里
}
这里use
存放自定义loader 文件 存放路径
新建hero.js:
exports.hero ='德玛西亚'
新建index.js:
import hero from "./hero.js";
console.log(hero);
接下来执行webpack
打包命令打包,生成dist 下文件,具体webpack 配置见源码。
将打包后的文件引入index.html ,并在浏览器打开。
结果德玛西亚已经替换成了更详细的介绍成功了。
skill-loader:
module.exports = function (source) {
return source.replace("大宝剑","R技能是:大宝剑!")
}
resolveLoader:{
alias:{
'skill-loader':resolve(__dirname,'src/custom-loader/skill-loader.js')
}
}
skill.js:
exports.skill = '大宝剑'
index.js 引入:
import skill from "!skill-loader!./skill.js";
console.log(skill);
打包之后的文件:
/***/ "./src/hero.js":
/*!*********************!*\
!*** ./src/hero.js ***!
\*********************/
/***/ ((__unused_webpack_module, exports) => {
eval("/*\n * @Author: ZY\n * @Date: 2022-02-14 16:26:29\n * @LastEditors: ZY\n * @LastEditTime: 2022-02-14 16:27:33\n * @FilePath: /webpack-demo/packages/loader-demo/src/hero.js\n * @Description: 文件描述\n */\n\nexports.hero ='英雄联盟保健哥:德玛西亚!'\n\n//# 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: ZY\n * @Date: 2022-02-14 11:44:14\n * @LastEditors: ZY\n * @LastEditTime: 2022-02-14 16:48:22\n * @FilePath: /webpack-demo/packages/loader-demo/src/index.js\n * @Description: 文件描述\n */\n\n\n\n\nconsole.log(_hero_js__WEBPACK_IMPORTED_MODULE_0__);\nconsole.log(_skill_loader_skill_js__WEBPACK_IMPORTED_MODULE_1__);\n\n//# 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: ZY\n * @Date: 2022-02-14 16:26:35\n * @LastEditors: ZY\n * @LastEditTime: 2022-02-14 16:28:04\n * @FilePath: /webpack-demo/packages/loader-demo/src/skill.js\n * @Description: 文件描述\n */\n\nexports.skill = 'R技能是:大宝剑!'\n\n//# sourceURL=webpack:///./src/skill.js?./src/custom-loader/skill-loader.js");
/***/ })
可以对比看一下内联和webpack rule 配置有什么区别
index.html 引入打包js之后运行结果:
了解基础loader使用之后,看看loader 的其他高级接口。
官网很详细这里就不一一赘述(官网loader接口)
设置loader 的时候有一些需要外界环境的变量,这些变量可以在配置中设置。
webpack config提供 loader 配置options。下面是一个小例子,来演示这个情景。
这个loader 的意思很明白,我要选择英雄,通过loader 打包到浏览器,告诉我选择的什么英雄。
这里会利用loader 接口:
select-hero-loader.js :
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
}
这里针对于单个文件使用其实使用内联的方式更简单,但是这里为了联系所以采用rule 的方式配置,保留之前的loader。
{
test:/\.js$/,
use: [
"./src/custom-loader/hero-loader.js",
{
loader:"select-hero-loader",
options:{
heroName:'寒冰射手'
}
}
] // 看这里,看这里
}
这两个自定义loader ,你在loader 里加上log 是可以验证运行顺序的,是自下而上执行,感兴趣自己验证。
select.js :
module.exports = function selectHero() {
console.log(`您选择了英雄`);
}
index.js :
import skill from "!skill-loader!./skill.js";
selectHero()
执行webpack 打包,运行到浏览器: