loader
构建过程中用来转换代码的,不能够影响到构建流程,在构建过程中,匹配到对应的文件loader,就会去执行,转换代码; 为什么npm上的loader只需要安装,不需要require,写上名称,因为webpack默认会自己在node_modules里面resolve 格式:
基础定义
// 不可以使用箭头函数,会丢失上下文
module.exports = function(source) {
return source;
}
input和output都必须是string;
如何使用
- 在loader中直接写字符串,但是,需要在resolveLoader中,声明字符串的别名
const path = require("path");
module.exports = {
module: {
rules: [{
test: /\.js$/,
exclude: './node_modules',
use: ['babel-loader', 'customer-loader']
},]
},
resolveLoader: {
alias: {
'customer-loader': path.join(__dirname, 'customer-loader');
}
}
}
- 或者在loader中直接用绝对路径
const path = require("path/posix");
module.exports = {
module: {
rules: [{
test: /\.js$/,
exclude: './node_modules',
use: ['babel-loader', path.join(__dirname, 'customer-loader')]
},]
},
}
工具箱-context
在loader的context上有什么东西呢?让我们来探索一下吧
loader api文档
- this.resourcePath 当前处理文件的路径
- this.rootContext 当先运行的context根目录
- this.emitFile(name: string, content: Buffer|string, sourceMap: {...}) 向dist提交一个文件
- this.getOptions() 获取webpack设置的配置
- this.getLogger() 获取logger对象,可以提交warning啊之类的
- schema-utils 用于判断当前loader传入的option是否符合规定
plugins
webpack的plugins可以做很多事情,它遍布在webpack的各个生命周期,只要有事件广播出来,他都可以在对应的事件回调中,对资源进行处理;
基础定义
参数是compiler对象,代表了webpack从启动到结束的整个生命周期;基本结构就是一个class,使用的时候需要new 创建一个实例;
module.exports = class BundleSize {
constructor(options) {
this.options = options;
}
apply(compiler) {
console.log('BundleSize', compiler);
}
}
开发一个plugins
const fs = require('fs');
const path = require('path');
module.exports = class BundleSize {
constructor(options) {
this.options = options || {
sizeLimit: 3,
};
}
apply(compiler) {
console.log('BundleSize', compiler);
compiler.hooks.done.tap('BundleSizePlugin', (stats) => {
console.log(stats);
const { path: outpath } = stats.compilation.options.output;
const bundlePathArr = [];
stats.compilation.chunks.forEach(item => {
console.log(item);
item.files.forEach(filename => {
bundlePathArr.push(filename);
});
});
// 打包生成的资源/普通资源做区分
// 这里用assets会把
// Object.keys(stats.compilation.assets)
bundlePathArr.forEach(filename => {
const bundlePath = path.join(outpath, filename);
const { size } = fs.statSync(bundlePath);
console.log(size);
if (size > this.options.sizeLimit) {
stats.compilation.logger.warn(`file: ${bundlePath} max ${this.options.sizeLimit}, please optimize this\n`)
}
})
})
}
}
plugins上常用hooks和对象
待补充
如何划分二者的边界
loader只做代码解析转换 plugin非常强大,可以做执行和生成代码以外的任何事情;同时,plugin不应该做转换代码这种工作