【问题标题】:Is it possible to let webpacks System.import use ajax (for progress events)?是否可以让 webpacks System.import 使用 ajax(用于进度事件)?
【发布时间】:2016-06-13 10:15:58
【问题描述】:

所以我刚刚更新到 webpack 2 并且有了我的第一个工作设置,其中 webpack 通过查看 System.import 调用自动创建块。好甜!

但是,我使用 ajax 调用加载初始块,以便我可以 show the progress while loading

所以我的问题是,我能否以某种方式覆盖或更改 System.import 的函数,以便它使用我可以监听事件的 ajax 请求,而不是使用 <script> 标签加载块?

【问题讨论】:

    标签: javascript ajax progress-bar webpack webpack-2


    【解决方案1】:

    不,很遗憾没有。 webpack 2 将System.import() 转换为普通的require.ensure() 调用,它只使用<script> 标签。即使是官方的WHATWG Loader Spec 也没有提供此类事件的API。对于这个问题,我已经 created an issue

    关于 webpack:有一种方法可以实现你自己的require.ensure()。然而,由于块加载是 webpack 的一个组成部分,这需要深入一点。我不确定这对你有多重要,但你可能会对 webpack 内部的工作方式感兴趣,所以让我们来看看:

    在 webpack 中,所有内部功能都以插件的形式实现。通过这种方式,webpack 能够支持很多不同的特性和环境。因此,如果您对 webpack 中的实现方式感兴趣,最好 a) 查看WebpackOptionsApply 或 b) 搜索特定的字符串/代码 sn-p。

    块加载很大程度上取决于给定的target,因为您需要为每个环境提供不同的实现。 Webpack 允许您定义自定义目标。当你传入一个函数而不是字符串时,webpack 会使用 compiler 实例调用该函数。在那里您可以应用所有必需的插件。由于我们的自定义目标与web 目标几乎一样,我们只需从web 目标复制所有内容:

    // webpack.config.js
    
    const NodeSourcePlugin = require("webpack/lib/node/NodeSourcePlugin");
    const FunctionModulePlugin = require("webpack/lib/FunctionModulePlugin");
    const LoaderTargetPlugin = require("webpack/lib/LoaderTargetPlugin");
    const JsonpChunkTemplatePlugin = require("webpack/lib/JsonpChunkTemplatePlugin");
    const JsonpHotUpdateChunkTemplatePlugin = require("webpack/lib/JsonpHotUpdateChunkTemplatePlugin");
    
    function customTarget(compiler) {
        compiler.apply(
            new JsonpTemplatePlugin(compiler.options.output),
            new FunctionModulePlugin(compiler.options.output),
            new NodeSourcePlugin(compiler.options.node),
            new LoaderTargetPlugin("web")
        );
    }
    
    module.exports = {
        entry:  require.resolve("./app/main.js"),
        output: {
            path: path.resolve(__dirname, "dist"),
            filename: "bundle.js"
        },
        target: customTarget
    };
    

    如果您查看每个插件,您会发现JsonpTemplatePlugin 负责加载块。所以让我们用自己的实现来替换它。我们称之为XHRTemplatePlugin

    function customTarget(compiler) {
        compiler.apply(
            new XHRTemplatePlugin(compiler.options.output),
            new FunctionModulePlugin(compiler.options.output),
            new NodeSourcePlugin(compiler.options.node),
            new LoaderTargetPlugin("my-custom-target")
        );
    }
    

    我们的XHRTemplatePlugin负责提供主块、每个子块中的代码以及热更新:

    function XHRTemplatePlugin() {}
    
    XHRTemplatePlugin.prototype.apply = function (compiler) {
        compiler.plugin("this-compilation", function(compilation) {
            compilation.mainTemplate.apply(new XHRMainTemplatePlugin());
            compilation.chunkTemplate.apply(new XHRChunkTemplatePlugin());
            compilation.hotUpdateChunkTemplate.apply(new XHRHotUpdateChunkTemplatePlugin());
        });
    };
    

    也许,您也可以重复使用 JsonpChunkTemplatePluginJsonpHotUpdateChunkTemplatePlugin 插件,但这取决于您的用例/实现。

    您的XHRMainTemplatePlugin 现在可能如下所示:

    function XHRMainTemplatePlugin() {}
    
    XHRMainTemplatePlugin.prototype.apply = function (mainTemplate) {
        mainTemplate.plugin("require-ensure", function(_, chunk, hash) {
            return this.asString([
                // Add your custom implementation here
                "fetch()"
            ]);
        });
    };
    

    这里不再赘述,因为我认为这个答案已经够长了。但我建议创建一个真正的小示例项目并检查 webpack 创建的输出。内部的 webpack 插件乍一看可能有点吓人,但它们中的大多数都很短而且只做一件事。你也可以从他们身上得到一些灵感。

    【讨论】:

    • 非常感谢。我之前创建了一个小型 webpack 插件,这非常适合让我 - 或其他任何人 - 开始实现它。我需要与我的雇主/客户核实他是否希望进度条如此糟糕,但无论哪种方式,当我做任何与 webpack 插件相关的事情时,我都会回到这里。感谢您的努力和非常明确的答案
    • 不客气。我希望这个答案能为其他开发人员提供更多关于 webpack 内部的见解。如果您发布插件,请告诉我。关于您的客户:恕我直言,与收益相比,实现您自己的块加载的技术开销太多。您还可以使用不需要进度事件的微调器。
    猜你喜欢
    • 2012-10-03
    • 2011-08-10
    • 2010-10-07
    • 2011-02-17
    • 2013-10-03
    • 2015-11-02
    • 1970-01-01
    • 2021-10-05
    • 2023-03-28
    相关资源
    最近更新 更多