loader.js (将所有含有“小明”字符串 全都改为“老王”)
module.exports = function (source){
return source.replace('小明','老王')
}
复制
webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js' //入口文件
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: path.resolve('./src/loader.js'), //我们自己实现的loader
},
]
}
]
},
}
复制
index.js(入口文件)
function test() {
console.log('你好我是小明')
}
test()
复制
编译后等待输出结果:
bound.js
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/***/ (() => {
eval("function test() {\n console.log('你好我是老王')\n}\n\ntest()\n\n\n//# sourceURL=webpack:///./src/index.js?"); //小明变成老王了
/***/ })
/******/ });
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = {};
/******/ __webpack_modules__["./src/index.js"]();
/******/
/******/ })()
;
复制
上述打包耗时:77ms
loader.js如下
module.exports = function (source) {
const callback = this.async()
// 由于有 3 秒延迟,所以打包时需要 3+ 秒的时间
setTimeout(() => {
callback(null, `${source.replace('小明', '老王')}`)
}, 3000)
}
复制
上述打包耗时:3083ms
对于 webpack 编译,有两个重要的对象需要了解一下:
Compiler 和 Compilation 在插件开发中最重要的两个资源就是 compiler 和 compilation 对象。理解它们的角色是扩展 webpack 引擎重要的第一步。
复制
compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。
复制
compilation 对象代表了一次资源版本构建。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
复制
plugin.js
function Plugin(options) { }
Plugin.prototype.apply = function (compiler) {
// 所有文件资源都被 loader 处理后触发这个事件
compiler.plugin('emit', function (compilation, callback) {
// 功能完成后调用 webpack 提供的回调
console.log('Hello World')
callback()
})
}
module.exports = Plugin
复制
使用:
const Plugin = require('./src/plugin')
module.exports = {
...
plugins: [
new Plugin()
]
}
复制
更复杂的例子:
经过 loader 处理后的打包文件 bundle.js 引入到 index.html 中:
function Plugin(options) { }
Plugin.prototype.apply = function (compiler) {
// 所有文件资源经过不同的 loader 处理后触发这个事件
compiler.plugin('emit', function (compilation, callback) {
// 获取打包后的 js 文件名
const filename = compiler.options.output.filename
// 生成一个 index.html 并引入打包后的 js 文件
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="${filename}"></script>
</head>
<body>
</body>
</html>`
// 所有处理后的资源都放在 compilation.assets 中
// 添加一个 index.html 文件
compilation.assets['index.html'] = {
source: function () {
return html
},
size: function () {
return html.length
}
}
// 功能完成后调用 webpack 提供的回调
callback()
})
}
module.exports = Plugin
复制
使用方式如上
结果:会生成一个html并且自动引入了bound.js