Webpack 4 到 5:自定义插件:用compilation.hooks.processAssets 替换compilation.assets 突变

mat*_*unn 5 flask reactjs webpack webpack-5

我在使用编译挂钩processAssets来镜像自定义插件中已弃用的 Webpack 4 功能时遇到问题。

该插件的目的是将 js/css 文件的 chunkhash 写入 python 文件,Flask 服务器使用该文件根据用户的会话和角色(例如公共、私有、管理员等)分离网页的功能)。

该插件的主要内容(资产的直接突变)如下。

compiler.hooks.emit.tapAsync("WriteHashesPlugin", (compilation, cb) => {
    //For each bundle, write the name and the corresponding hash.
    compilation.chunks.forEach(chunk => {
        lines.push("__" + chunk.name + "_hash__ = '" + chunk.renderedHash + "'")
    });
    const content = lines.join("\n");

    compilation.assets[this.filename] = { // <= this.filename = "{relative_path}/bundles.py"
        source: () => content,
        size: () => content.length
    }
    cb();
})
Run Code Online (Sandbox Code Playgroud)

这段代码仍然“可以”创建/更新 python 文件,但我当然不想使用已弃用的语法。构建输出中的警告消息:

(node:38072) [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning: Compilation.assets will be frozen in future, all modifications are deprecated.
BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation.
        Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
        Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.
Run Code Online (Sandbox Code Playgroud)

我已经实现了compilation.hooks.processAssets而不是直接访问资产;但是,我无法让它按预期工作。

compiler.hooks.emit.tapAsync("WriteHashesPlugin", (compilation, cb) => {
    //For each bundle, write the name and the corresponding hash.
    compilation.chunks.forEach(chunk => {
        lines.push("__" + chunk.name + "_hash__ = '" + chunk.renderedHash + "'")
    });
    const content = lines.join("\n");

    // The below code block compiles but doesn't get run
    compilation.hooks.processAssets.tap({
        name: 'WriteHashesPlugin',
        stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
        additionalAssets: true
    }, () => {
        compilation.emitAsset(
            this.filename,
            content
        );
    });
    cb();
})
Run Code Online (Sandbox Code Playgroud)

我也尝试过compilation.updateAsset在舞台上使用PROCESS_ASSETS_STAGE_ADDITIONS,但没有成功。

无论如何,我都不是 webpack 专家,但过去几天我一直在浏览文档并尝试理解源代码。我对自己做错的事情有一些想法:

  • compiler.hooks.emit修改资产不是编译过程中适当的步骤(也许在编译过程中的某个时刻,资产不会被更改?)。
  • compilation.emitAsset不是要使用的合适的编译挂钩。
  • 我误解了构建输出中的弃用警告,我应该做一些完全不同的事情。
  • 有一种更好的方法可以使 Flask 可以使用 chunkhashes。
  • 你们中的一个人可以为我阐明其他一些事情。

mat*_*unn 4

感谢@chiborg 的评论,我通过一些调整就可以使该代码正常运行。

正如这篇文章中所写,

首先,您需要从 webpack 引入 {sources} 类,这将帮助我们对资产进行原始源更改(无论其优化或资产类型如何):

const { sources } = require('webpack');
Run Code Online (Sandbox Code Playgroud)

适当使用的钩子是compiler.hooks.compilation.tap代替compiler.hooks.emit.tapAsync; 一旦更改,钩子内的其余代码必须移至compilation.hooks.processAssets

/**
 * Writes build version and bundle hashes to a new file, with the dir
 * specified in this.filename.
 */
compiler.hooks.compilation.tap("WriteHashesPlugin", compilation => {
    compilation.hooks.processAssets.tap({
        name: 'WriteHashesPlugin',
        stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
    }, () => {
        const lines = [];
        // Write build version
        lines.push("__version__ = '" + this.version + "'");
        // For each bundle, write the name and the corresponding hash.
        compilation.chunks.forEach(chunk => {
            lines.push("__" + chunk.name + "_hash__ = '" + chunk.renderedHash + "'");
        });
        const content = lines.join("\n");
        // write bundles.py to assets
        compilation.emitAsset(
            this.filename,
            new sources.RawSource(content)
        );
    });
});
Run Code Online (Sandbox Code Playgroud)

compilation.chunks在钩子外部访问时为空processAssets,但将所有内容移至钩子中使其按预期工作。

  • 我建议使用“const {sources}=require('webpack');”而不是“constsources=compilation.compiler.webpack.sources;”,以确保您引用的 Webpack 实例与实际运行的 Webpack 实例相同。插入。如果您的“node_modules”中恰好有多个版本的 Webpack,并且您的插件将使用 pnpm/yarn/npm 符号链接,这可以避免头痛/错误/困难的调试。 (2认同)