【问题标题】:Webpack 4 closure issues with a shared bundle共享包的 Webpack 4 关闭问题
【发布时间】:2018-05-09 22:58:35
【问题描述】:

我正在尝试从 3 升级到 Webpack 4,但在共享包的关闭时遇到了问题。

我的 webpack 设置为创建一个 shared.js 文件,在 a.jsb.js 之间共享我的代码。特别是,在shared.js 包中,有一个带有store 变量的索引文件。我们只导出一个名为getStore() 的函数,它返回store。对getStore 的调用发生在我们a.jsb.js 文件的不同位置。

我们页面上的脚本列表如下所示:

/** some html **/
<script src=""/scripts/shared.js""></script>
<script src=""/scripts/a.js""></script>
<script src=""/scripts/b.js""></script>

在 Webpack 3 中,当第一次从 a.js 调用 shared.js 中的 getStore() 代码(即将到来的调用)时,它会创建一个 store 实例,然后调用从getStore() 打电话。从a.jsgetStore() 的任何后续调用,它不再创建store 的实例,而是从getStore() 返回相同的值。然后在a.js 完成并且b.js 运行之后,当b.js 调用getStore() 时,它不会实例化store,而是使用a.js 使用的相同实例。在这种情况下,storea.jsb.js 是同一个实例。

但是在 Webpack 4 中,行为有所不同。当a.js调用shared.js中的代码时,当代码第一次引用getStore()时,与之前类似,它会创建一个store的新实例,而a.js运行并调用getStore()时返回相同实例。但是,当b.js 初始引用shared.js 代码时,它不会使用相同的实例a.js,而是创建store 的新实例,并且在b.js 的整个脚本运行过程中,它调用getStore() 时引用第二个store。在这种情况下,store 有两个实例,每个实例对于 a.jsb.js 都是唯一的。

不确定导致此问题的 Webpack 4 有什么不同。我们从使用 Webpack 3 中的 CommonChunksPlugin 切换到现在使用内置的优化设置。以下是它们的配置方式。

网页包 3:

plugins: [..., new webpack.optimize.CommonsChunkPlugin({
    name: 'shared',
    filename: '[name].js',
    minChunks: 2
})]

网页包 4:

optimization: {
    splitChunks: {
        cacheGroups: {
            shared: {
                name: 'shared',
                chunks: 'initial',
                minChunks: 2
            }
        }
    }
}

两种 Webpack 配置输出的文件大小大致相同,在调试和查看调用堆栈时,对 getStore() 的调用来自各自的 a/b.js 文件。

有没有解释为什么 a.jsb.js 在 Webpack 4 中获得 shared.js store 对象的单独实例,而在 Webpack 3 中获得相同的实例?当脚本相互依赖时,它们的闭包/作用域应该如何处理共享代码?

【问题讨论】:

    标签: javascript webpack webpack-4


    【解决方案1】:

    如果你想通了,我想知道,但我想分享我的发现。

    TL;DR:拆分块在调用它的每个库的公共块中实例化模块的新实例。

    从一开始,你的 webpack 库应该有如下功能。

    var r = n(34);
    

    这会调用该库中检索模块的方法:

    function n(t) {
     if (n[t])
       return n[t].exports;
     var e = n[t] = {
       i: t,
       l: !1,
       exports: {}
     };
     return s[t].call(e.exports, e, e.exports, o),
     e.l = !0,
     e.exports
        }
    

    我找不到任何文档,但t 是一个用于引用模块的数字(记住这一点)。 s 是包含库可以使用的所有模块的对象,n 是包含库已经使用的所有模块的对象,本质上是缓存它们。当 n[t] 不存在时,webpack 会在 n 和调用 return s[t].call(e.exports, e, e.exports, o) 中添加一个通用对象。

    假设t 是 34,webpack 会调用下面的方法

        34: function(e, t, n) {
            "use strict";
            n.r(t);
            var r = n(36);
            t.default = function() {
                var e = r.a.pageLevelOOM && r.a.adinfoOOMHeader
                  , t = r.a.pageLevelOOM && r.a.serverOOMHeader;
                return r.a.adinfoOverride ? e : t
            }
        },
    

    快速附注,常用块添加到webpackJsonp 下的窗口中。如果您在浏览器的控制台中输入window.webpackJsonp[0][1],您将看到一个具有数字键且值是函数的对象。

    这里的关键部分是 webpack 本质上将每个模块实例化为这样的公共块。因此,每个库都会在公共块中拥有自己的模块版本。

    【讨论】:

      猜你喜欢
      • 2018-12-16
      • 2015-03-31
      • 1970-01-01
      • 2019-03-31
      • 1970-01-01
      • 2021-06-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多