loader: 对css js img 特殊文件vue 各种模块的处理
统一原则: 遵循Webpack制定的设计规则和结构,输入与输出均为字符串,各个Loader完全独立,即插即用
loader默认导出一个函数,接受匹配到的文件资源字符串和SourceMap,我们可以修改文件内容字符串后再返回给下一个loader进行处理,因此最简单的一个loader如下:
module.exports = function(source, map){
return source
}
异步loader: 有时候会进行异步操作,一种方法是通过async/await,阻塞操作执行;另一种方法可以通过loader本身提供的回调函数callback
处理参数: 配置loader时,一般是通过options属性来传递的.借助一个官方的包loader-utils帮助处理
获取options参数
const options = getOptions(this);
示例: 生产环境清除console.log
- 根目录创建loader文件夹,创建cleanlog-loader.js
const { getOptions } = require('loader-utils')
module.exports = function(source, map){
const option = getOptions(this)
console.log('清除')
if (process.env.NODE_ENV === 'production' && option.clear) {
source = source.replace(/console\.log\(.*\);?/g, "")
}
return source
}
- 使用cleanlog-loader, 放在configureWebpack函数形式 + exclude排除项。
/console.log(.*);?/g 正则不适合 node_modules 里面的文件
configureWebpack: (config) => {
config.module.rules.push({
test: /\.(js|vue)$/,
exclude: /node_modules/,
use: [{
loader: './loader/cleanlog-loader',
options: {
clear: true
}
}]
})
}
plugin 对webpack 编译或构建功能的扩展
plugin的本质是类. 工作流程如下:
- webpack启动,执行new myPlugin(options),初始化插件并获取实例
- 初始化complier对象,调用myPlugin.apply(complier)给插件传入complier对象
- 插件实例获取complier,通过complier监听webpack广播的事件,通过complier对象操作webpack
可以通过apply函数中注入的compiler对象进行注册事件
compiler不仅有同步的钩子,通过tap函数来注册,还有异步的钩子,通过tapAsync和tapPromise来注册
这里又有一个compilation对象,它和上面提到的compiler对象都是Plugin和webpack之间的桥梁:
compiler对象包含了 Webpack 环境所有的的配置信息。这个对象在启动 webpack 时被一次性建立,并配置好所有可操作的设置,包括 options,loader 和 plugin。当在 webpack 环境中应用一个插件时,插件将收到此 compiler 对象的引用。可以使用它来访问 webpack 的主环境。compilation对象包含了当前的模块资源、编译生成资源、变化的文件等。当运行webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
compiler和compilation的区别在于:
- compiler代表了整个webpack从启动到关闭的生命周期,而compilation只是代表了一次新的编译过程
- compiler和compilation暴露出许多钩子,我们可以根据实际需求的场景进行自定义处理
示例: 在打包目录生成一个filelist.md文件,文件的内容是将所有构建生成文件展示在一个列表中
- 根目录创建plugins/FileListPlugin.js
class FileListPlugin {
constructor (options = {}) {
this.options = options
}
apply(compiler){
compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback)=>{
var filelist = 'In this build:\n\n';
// 遍历所有编译过的资源文件,
// 对于每个文件名称,都添加一行内容。
for (var filename in compilation.assets) {
filelist += '- ' + filename + '\n';
}
// 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
compilation.assets['filelist.md'] = {
source: function() {
return filelist;
},
size: function() {
return filelist.length;
}
};
callback();
})
}
}
module.exports = FileListPlugin
- FileListPlugin 使用
vue.config.js 添加config.plugins.push(new FileListPlugin())
const FileListPlugin = require('./plugins/FileListPlugin')
configureWebpack: (config) => {
config.plugins.push(new FileListPlugin())
}