使用loader-runner调试
定义:loader-runner 允许你在不安装webpack的情 况下运行loaders
// run-loader.js
const {runLoaders} = require('loader-runner');
const fs = require('fs');
const path = require('path');
runLoaders({
// 资源的绝对路径
resource: path.join(__dirname, './src/demo.txt'),
// oader 的绝对路径
loaders: [
// path.join(__dirname, './src/raw-loader.js')
{
loader: path.join(__dirname, './src/raw-loader.js'),
options: {
name: 'test'
}
}
],
context: {
minimize: true
},
// 使用fs来读取内容
readResource: fs.readFile.bind(fs)
}, (err, result) => {
err ? console.log(err) : console.log(result);
});
// raw-loader.js
module.exports = function(source) {
// 通过loader-utils的 getOptions 方法获取参数
// loader-utils 3.0.0 版本已经移除getOptions方法,通过this.query直接获取参数
const {name} = loaderUtils.getOptions(this);
console.log('name',name)
const json = JSON.stringify(source)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
// 结果直接返回,如果想抛出异常:throw new Error('Error')
// return `export default ${json}`;
// 更多是使用callback返回-同步写法
// this.callback(new Error('Error'), json);
this.callback(null, json);
}
执行命令:node run-loader.js
异步:
const loaderUtils = require('loader-utils');
const fs = require('fs');
const path = require('path');
module.exports = function(source) {
// 可以使用 this.cacheable(false) 关掉缓存
this.cacheable(false);
const json = JSON.stringify(source)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
// 异步处理
const callback = this.async();
fs.readFile(path.join(__dirname, './async.txt'),'utf-8',(err, data) => {
callback(null, data);
});
}
执行结果:
通过this.emitFile进行文件写入
const loaderUtils = require("loader-utils");
module.exports = function(content) {
const url = loaderUtils.interpolateName(this, "[hash].[ext]", {
content});
// 将文件内容放到指定的位置
this.emitFile(url, content);
const path = `__webpack_public_path__ + ${JSON.stringify(url)};`;
return `export default ${path}`; };
插件编写
插件没有像 loader 那样的独立运行环境,只能在 webpack 里面运行。
例如,写一个zip插件:
// webpack.config.js
const path = require('path');
const ZipPlugin = require('./plugins/zip-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
},
mode: 'production',
plugins: [
new ZipPlugin({
filename: 'offline'
})
]
}
const JSZip = require('jszip');
const path = require('path');
const RawSource = require('webpack-sources').RawSource;
const { Compilation } = require('webpack');
const zip = new JSZip();
module.exports = class ZipPlugin {
constructor(options) {
this.options = options;
}
// 每个插件都有一个apply方法,接收一个compiler对象
// 插件执行时会进入到apply方法
apply(compiler) {
// 使用异步钩子-文件生成
compiler.hooks.emit.tapAsync('ZipPlugin', (compilation, callback) => {
// 创建一个目录
const folder = zip.folder(this.options.filename);
// 处理compilation
for (let filename in compilation.assets) {
// console.log(compilation.assets[filename])
const source = compilation.assets[filename].source();
folder.file(filename, source);
// console.log('source',source)
}
zip.generateAsync({
type: 'nodebuffer'
}).then((content) => {
// console.log(content)
// 可以获取到经过webpack处理的各种各样的信息
// console.log(compilation.options)
const outputPath = path.join(
compilation.options.output.path,
this.options.filename + '.zip'
);
// 绝对路径转换成相对路径
const outputRelativePath = path.relative(
compilation.options.output.path,
outputPath
);
compilation.assets[outputRelativePath] = new RawSource(content);
callback();
});
});
}
}
执行命令:npm run build 后输出结果