准备工做: npm init -y
初始化一个项目 npm i webpack webpack-cli -D
建立一个webpack.config.js文件node
const path = require('path')
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist')
},
mode: 'development',
}
复制代码
经过实现一个简单的字符串替换loader来了解下loader的工做原理webpack
// index.js
console.log('yuxiaoyu')
// 建立一个loader文件夹 先建立个replaceLoader.js
// loader就是一个函数,须要用声明式函数,由于要取到上下文中的this,这个函数接受一个参数,是咱们要打包的源码
module.exports = function(source) {
console.log(source, this.query)
return source.replace('yuxiaoyu', '于晓俞')
}
// 而后修改webpack.config.js
const path = require('path')
module.exports = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist')
},
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
use: {
loader: path.resolve(__dirname, 'loader/replaceLoader.js'),
options: {
name: '实现loader'
}
}
}
]
}
}
复制代码
npx webpack
以后,咱们能够在main.js中看到index.js中的字符串已经被替换掉了 使用this.callback来返回多个结果信息,而不单单是源码web
/*
this.callback()接受四个参数
err,content,sourceMap,meta
*/
// 修改replaceLoader.js
module.exports = function(source) {
console.log(source, this.query)
// return source.replace('yuxiaoyu', '于晓俞')
this.callback(null, source.replace('yuxiaoyu', '于晓俞'))
}
复制代码
结果一样能够正常编译npm
官方提供this.async处理loader内的异步markdown
// 修改loader
module.exports = function(source) {
console.log(source, this.query)
// 咱们使用this.async来处理,他会返回this.callback
// 定义一个异步处理,告诉webpack,这个loader里有异步事件,在里面调用下这个异步
// callback 就是 this.callback 注意参数的使用
const callback = this.async()
setTimeout(() => {
callback(null, source.replace('yuxiaoyu', '于晓俞'))
}, 3000)
}
复制代码
// 再建立一个同步的replaceLoaderSync.js
module.exports = function(source) {
return source.replace('于晓俞', '程序猿')
}
//修改webpack.config.js文件
module: {
rules: [
{
test: /\.js$/,
use: [
path.resolve(__dirname, 'loader/replaceLoaderSync.js'),
{
loader: path.resolve(__dirname, 'loader/replaceLoader.js'),
options: {
name: '实现loader'
}
}
]
}
]
}
复制代码
咱们写的配置文件地址写法过于繁琐,怎么能像咱们npm i 下载的loader那样,直接写个loader名称就好了呢?这就须要咱们再配置下webpack.config.jsapp
// 配置resolveLoader, 告诉webpack去哪里查找loader,先去node_modules里查找,找不到再去loader文件夹汇总
resolveLoader: {
modules: ['node_modules', './loader']
},
module: {
rules: [
{
test: /\.js$/,
use: [
// 改为文件名
'replaceLoaderSync',
{
// 改为文件名
loader: 'replaceLoader',
options: {
name: '实现loader'
}
}
]
}
]
}
复制代码
一样能够编译成功!
异步
plugin: 开始打包,在某个时刻,帮助咱们处理一些什么事情的机制
一个插件由如下构成:
async
一个具名 JavaScript 函数。
在它的原型上定义 apply 方法。
指定一个触及到 webpack 自己的 事件钩子。
操做 webpack 内部的实例特定数据。
在实现功能后调用 webpack 提供的 callback。
咱们实现一个功能,在编译完成后,在输出文件时,同时输出一个txt文本
函数
// 建立一个plugin文件夹 建立文件TxtWebpackPlugin.js
/*
插件是由一个构造函数(此构造函数上的 prototype 对象具备 apply 方法)的所实例化出来的。这个 apply 方法在安装插件时,会被 webpack compiler 调用一次。apply 方法能够接收一个 webpack compiler 对象的引用,从而能够在回调函数中访问到 compiler 对象。
*/
class TxtWebpackPlugin {
constructor() {}
apply(compiler) {
// compiler.hooks中存放这各类钩子,emit在编译成功时输出文件前执行的事件
// 有些插件 hooks 是异步的。想要 tap(触及) 某些 hooks,咱们可使用同步方式运行的 tap 方法,或者使用异步方式运行的 tapAsync 方法或 tapPromise 方法。
compiler.hooks.emit.tapAsync('TxtWebpackPlugin', (compilation, callback) => {
// 处理异步的事情
let content = '生成的文件列表:\n'
for (var filename in compilation.assets) {
content += filename + '\n'
}
compilation.assets['filelist.txt'] = {
source: function () {
return content
},
size: function () {
return content.length
}
}
callback()
});
}
}
module.exports = TxtWebpackPlugin
复制代码