如何在 webpack 发出之前检查由 webpack 编译的文件
How to inspect files compiled by webpack before they are emitted
我正在使用 webpack (v4) 为我的 UI 应用程序打包资产。我想要 运行 一个函数,该函数最好在 将文件发送到输出目录之前 检查已编译资产的内容是否存在无效字符串。在提出最初的方法时,我很高兴地偶然发现了 webpack hooks,这似乎正是我完成任务所需要的。
不幸的是,文档有点缺乏,或者至少我在查看它之后仍然有一些不确定性。我的第一个挑战是确定使用哪个钩子。似乎我需要一个编译器挂钩(而不是编译挂钩),而 emit hook 似乎是我感兴趣的那个。接下来,这是我目前所拥有的:
plugins: [
{
apply(compiler: webpack.Compiler) {
compiler.hooks.emit.tap('ValidateEmittedAssetsPlugin', (compilation) => {
const { assets } = compilation;
Object.entries(assets).forEach(([pathname, source]) => {
const contents = (source as Buffer).buffer.toString();
if (contents.indexOf(SOME_INVALID_STRING) > -1) {
console.log('File contained invalid string. Failing build.');
return false;
}
// Trying to toString() source.buffer hasn't worked so I've also tried
// the following also to no avail.
//
// const file = compilation.getAsset(pathname);
// const contents = file.source.buffer.toString();
}
});
return true;
});
},
},
]
我能够成功地遍历要发出的文件,但我无法获取这些资产的内容。因为它们(我猜)在内存中,所以我不能使用 fs
之类的东西从文件系统中读取文件。我也尝试使用 compilation.getAsset()
(如上所述)但无济于事。所以我的挑战是在 emit
挂钩中获取内存资产的内容。
如何使用 webpack hooks 在编译资源发出前检查它的内容?
如果你想控制发射资产你必须使用compiler.hooks.shouldEmit
钩子,它的return值你可以实际控制。您无法使用 compiler.hooks.emit
挂钩控制。两者都在发射资产之前执行,但 shouldEmit
允许控制发射资产。
一旦你从 compilation.asset
获得条目,你可以调用 compilation.getAsset(<asset_name>)
来获取资产和 asset.source.source()
return你的内容。
您可以根据自己的喜好使用 emit
或 shouldEmit
挂钩。
我更喜欢使用单独的 js 文件来管理输出,而不是将逻辑插入到 module.plugin
数组中。您还可以将配置传递给构造函数以更好地控制输出。
AssetValidatorPlugin.js
const PLUGIN_NAME = 'AssetValidatorPlugin';
class AssetValidatorPlugin {
constructor(options){
this.options = options;
}
apply(compiler) {
// to check content of emitted assets
compiler.hooks.emit.tap(PLUGIN_NAME, (compilation) => {
let assets = Object.entries(compilation.assets);
assets.forEach(([fileName]) => {
const asset = compilation.getAsset(fileName);
const assetContent = asset.source.source();
console.log(assetContent);
})
});
// to check content of emitted assets and prevent when fail to pass checks
compiler.hooks.shouldEmit.tap(PLUGIN_NAME, (compilation) => {
let allCheckPassed = true;
let assets = Object.entries(compilation.assets);
const logger = compiler.getInfrastructureLogger(PLUGIN_NAME);
logger.info('Asset check');
for (let fileIndex = 0; fileIndex < assets.length; fileIndex++) {
const [fileName] = assets[fileIndex];
logger.info(`validating ${fileName}`)
const asset = compilation.getAsset(fileName);
const assetContent = asset.source.source();
if (assetContent.indexOf('some inane string') > -1) {
logger.error(`invalid string found in ${fileName} `);
allCheckPassed = false;
break;
}
};
logger.info('Asset check completed');
if (allCheckPassed)
logger.info('asset emit proceeded');
else
logger.warn('asset emit aborted');
if(this.options.stopEmitOnError)
return allCheckPassed;
return true;
});
}
}
module.exports = AssetValidatorPlugin;
并将其添加到 webpack.config.js
const AssetValidatorPlugin = require('./AssetValidatorPlugin');
module.exports= {
entry: {...},
module:{...},
plugins: [
new AssetValidatorPlugin({stopEmitOnError: true}),
...
]
};
已在 Webpack 上测试 v4/v5 两个挂钩的工作原理相同。您也可以通过同样的方式获取资产内容。
我正在使用 webpack (v4) 为我的 UI 应用程序打包资产。我想要 运行 一个函数,该函数最好在 将文件发送到输出目录之前 检查已编译资产的内容是否存在无效字符串。在提出最初的方法时,我很高兴地偶然发现了 webpack hooks,这似乎正是我完成任务所需要的。
不幸的是,文档有点缺乏,或者至少我在查看它之后仍然有一些不确定性。我的第一个挑战是确定使用哪个钩子。似乎我需要一个编译器挂钩(而不是编译挂钩),而 emit hook 似乎是我感兴趣的那个。接下来,这是我目前所拥有的:
plugins: [
{
apply(compiler: webpack.Compiler) {
compiler.hooks.emit.tap('ValidateEmittedAssetsPlugin', (compilation) => {
const { assets } = compilation;
Object.entries(assets).forEach(([pathname, source]) => {
const contents = (source as Buffer).buffer.toString();
if (contents.indexOf(SOME_INVALID_STRING) > -1) {
console.log('File contained invalid string. Failing build.');
return false;
}
// Trying to toString() source.buffer hasn't worked so I've also tried
// the following also to no avail.
//
// const file = compilation.getAsset(pathname);
// const contents = file.source.buffer.toString();
}
});
return true;
});
},
},
]
我能够成功地遍历要发出的文件,但我无法获取这些资产的内容。因为它们(我猜)在内存中,所以我不能使用 fs
之类的东西从文件系统中读取文件。我也尝试使用 compilation.getAsset()
(如上所述)但无济于事。所以我的挑战是在 emit
挂钩中获取内存资产的内容。
如何使用 webpack hooks 在编译资源发出前检查它的内容?
如果你想控制发射资产你必须使用compiler.hooks.shouldEmit
钩子,它的return值你可以实际控制。您无法使用 compiler.hooks.emit
挂钩控制。两者都在发射资产之前执行,但 shouldEmit
允许控制发射资产。
一旦你从 compilation.asset
获得条目,你可以调用 compilation.getAsset(<asset_name>)
来获取资产和 asset.source.source()
return你的内容。
您可以根据自己的喜好使用 emit
或 shouldEmit
挂钩。
我更喜欢使用单独的 js 文件来管理输出,而不是将逻辑插入到 module.plugin
数组中。您还可以将配置传递给构造函数以更好地控制输出。
AssetValidatorPlugin.js
const PLUGIN_NAME = 'AssetValidatorPlugin';
class AssetValidatorPlugin {
constructor(options){
this.options = options;
}
apply(compiler) {
// to check content of emitted assets
compiler.hooks.emit.tap(PLUGIN_NAME, (compilation) => {
let assets = Object.entries(compilation.assets);
assets.forEach(([fileName]) => {
const asset = compilation.getAsset(fileName);
const assetContent = asset.source.source();
console.log(assetContent);
})
});
// to check content of emitted assets and prevent when fail to pass checks
compiler.hooks.shouldEmit.tap(PLUGIN_NAME, (compilation) => {
let allCheckPassed = true;
let assets = Object.entries(compilation.assets);
const logger = compiler.getInfrastructureLogger(PLUGIN_NAME);
logger.info('Asset check');
for (let fileIndex = 0; fileIndex < assets.length; fileIndex++) {
const [fileName] = assets[fileIndex];
logger.info(`validating ${fileName}`)
const asset = compilation.getAsset(fileName);
const assetContent = asset.source.source();
if (assetContent.indexOf('some inane string') > -1) {
logger.error(`invalid string found in ${fileName} `);
allCheckPassed = false;
break;
}
};
logger.info('Asset check completed');
if (allCheckPassed)
logger.info('asset emit proceeded');
else
logger.warn('asset emit aborted');
if(this.options.stopEmitOnError)
return allCheckPassed;
return true;
});
}
}
module.exports = AssetValidatorPlugin;
并将其添加到 webpack.config.js
const AssetValidatorPlugin = require('./AssetValidatorPlugin');
module.exports= {
entry: {...},
module:{...},
plugins: [
new AssetValidatorPlugin({stopEmitOnError: true}),
...
]
};
已在 Webpack 上测试 v4/v5 两个挂钩的工作原理相同。您也可以通过同样的方式获取资产内容。