繁体   English   中英

Webpack 2 - 代码拆分顶级依赖项

[英]Webpack 2 - Code splitting top-level dependencies

最终编辑

tl; dr决议这是不可能的。 虽然下面的最佳答案确实有一些很好的信息。


contacts.js考虑下面的代码。 这是一个动态加载的模块,在代码中的其他地方使用System.import按需加载。

如果SharedUtil1也被用于在其中也动态加载与其它模块System.import ,我将如何去了解有SharedUtility1 所有这些模块的排除 ,只有按需加载第一次它的需要?

SharedUtil1顶级System.import将无法工作,因为我的导出依赖于它:导出只能放在模块代码的顶层,而不能放在任何类型的回调中。

Webpack可以实现吗? 我的版本是2.0.7测试版。

import SharedUtil1 from '../../SharedUtilities/SharedUtility1';

class Contacts{
    constructor(data){
        this.data = data;
        this.sharedUtil1 = new SharedUtil1();
    }
}

export default Contacts;

更新1

我认为捆绑加载器是我想要的,但是没有,它将你导入的模块转换为一个不同的函数,一旦它完成异步加载,你就可以通过回调来访问实际的模块。 这意味着你不能透明地使模块X异步加载而不对代码进行重大更改,更不用说你回到最初描述的问题,如果你的顶级模块依赖于现在的异步加载依赖,没有办法导出它,因为导出必须在顶层。

Webpack中是否有办法表示依赖加载依赖关系X(如果需要),并且有任何导入模块导入它以透明地等待导入过程? 我认为这个用例对于任何远程大型应用程序都是必不可少的 ,所以我不得不认为我只是遗漏了一些东西。

更新2

根据彼得的回答,我试图让重复数据删除工作,因为commonChunk插件与端点之间共享代码有关,正如他所提到的,并且由于require.ensure将加载的代码放入回调中,从而阻止您从ES6 export任何代码取决于它。

就重复数据删除而言, contacts.jstasks.js都像这样加载相同的sharedUtil

import SharedUtil1 from '../../sharedUtilities/sharedUtility1';

我试过运行webpack

webpack --optimize-dedupe

并且还通过添加

plugins: [
    new webpack.optimize.DedupePlugin()
]

到webpack.config。 在这两种情况下,虽然sharedUtil代码仍然放在联系人和任务包中。

阅读完博客文章后,我终于明白了你的意图。 我对“顶级依赖”这个词感到有些困惑。

您有两个模块( async-aasync-b ),它们可以从任何地方(这里是模块main )按需加载,并且都有共享模块的引用( shared )。

- - -> on-demand-loading (i. e. System.import)
---> sync loading (i. e. import)

main - - -> async-a ---> shared
main - - -> async-b ---> shared

默认情况下,webpack会创建一个这样的块树:

---> chunk uses other chunk (child-parent-relationship)

entry chunk [main] ---> on-demand chunk 1 [async-a, shared]
entry chunk [main] ---> on-demand chunk 2 [async-b, shared]

shared < async-a/b或同一用户使用async-aasync-b的概率很低时,这很好。 这是默认值,因为它是最简单的行为,可能是您所期望的:一个System.import =>一个块。 在我看来,这也是最常见的情况。

但是如果shared > = async-a/b并且用户加载async-aasync-b的概率很高,则有一个更有效的分块选项:(有点难以可视化):

entry chunk [main] ---> on-demand chunk 1 [async-a]
entry chunk [main] ---> on-demand chunk 2 [async-b]
entry chunk [main] ---> on-demand chunk 3 [shared]

When main requests async-a: chunk 1 and 3 is loaded in parallel
When main requests async-b: chunk 2 and 3 is loaded in parallel
(chunks are only loaded if not already loaded)

这不是默认行为,但有一个插件可以将其归档:异步模式下的CommonChunkPlugin 它在一堆块中找到公共/共享模块,并创建一个包含共享模块的新块。 在异步模式下,它会将新块与原始(但现在更小)的块并行加载。

new CommonsChunkPlugin({
    async: true
})

// This does: (pseudo code)
foreach chunk in application.chunks
  var shared = getSharedModules(chunks: chunk.children, options)
  if shared.length > 0
    var commonsChunk = new Chunk(modules: shared, parent: chunk)
    foreach child in chunk.children where child.containsAny(shared)
      child.removeAll(shared)
      foreach dependency in chunk.getAsyncDepenendenciesTo(child)
        dependeny.addChunk(commonsChunk)

请记住,CommonsChunkPlugin有一个minChunks选项来定义模块何时作为shared线程化(随意提供一个自定义函数来选择模块)。

下面是一个详细说明设置和输出的示例: https//github.com/webpack/webpack/tree/master/examples/extra-async-chunk

另一个配置更多: https//github.com/webpack/webpack/tree/master/examples/extra-async-chunk-advanced

如果我已经正确理解了您,那么当不同的代码块将其声明为依赖项时,您希望防止多次加载相同的依赖项。

是的,这是可能的; 如何做到这取决于您的应用程序中的上下文以及它是在ES6还是ES5中。

ECMA脚本5

Webpack 1是在ECMA Script 5中构建的,通常使用CommonJS或RequireJS语法进行模块导出和导入。 使用此语法时,可以使用以下功能来防止重复的代码:

  • 重复数据删除通过创建duplciate函数的副本而不是重新定义它们来防止重复文件包含在已编译的代码中。
  • 命名的Chunks允许将块声明为依赖项但不立即计算; 所有出现的相同块都将使用相同的实例。
  • CommonsChunkPlugin允许在多个入口点共享块(仅适用于多个页面网站)。

重复数据删除

webpack文档

如果您使用一些具有很酷依赖树的库,则可能会出现某些文件相同的情况。 Webpack可以找到这些文件并对其进行重复数据删除。 这可以防止在包中包含重复的代码,而是在运行时应用该函数的副本。 它不会影响语义。

重点是我的,而不是来源

如文档所述,代码拆分保持不变; 需要sharedUtil1每个模块sharedUtil1应该将require声明为正常。 为了防止多次加载相同的依赖项,启用了webpack设置,该设置使webpack在运行时包含它们之前显式检查文件是否有重复。

使用--optimize-dedupe resp启用此选项。 new webpack.optimize.DedupePlugin()

命名大块

webpack文档

require.ensure函数接受另外的第3个参数。 这必须是一个字符串。 如果两个分割点传递相同的字符串,则它们使用相同的块...如果模块位于多个子块中,则require.include可能很有用。 require.include中的require.include将包含模块,子块中的模块实例将消失。

简而言之,模块的加载被延迟到编译后期。 这允许在包含重复定义之前将其删除。 该文档提供了示例。

常见的块插件

webpack文档

CommonsChunkPlugin可以将多个条目块中出现的模块移动到新的条目块(公共块)。 运行时也会移动到commons块。 这意味着旧的条目块现在是初始块。

这非常特定于在多个页面之间共享块,这在其他情况下是不相关的。

ECMA脚本6

对高级模块导入功能的支持是......正在进行的工作。 要了解事物的位置,请参阅以下链接:

以下是ES6模块和webpack的一个很好的总结: 带有TypeScript和Webpack的ES6模块

以上信息很可能会过时。

建议

为了你自己的理智,我建议:

如果优化很重要 :当Webpack 2稳定并发布时,恢复为CommonJS / RequireJS语法并升级到ECMA Script 6。

如果ECMA Script 6语法很重要 :使用标准ECMA Script 6导入导出格式并在可用时添加优化功能。

尝试在sill不稳定的webpack中使用高级模块加载功能有太多的变化2.等待事情稳定下来,一些非常好的插件在尝试之前变得可用。

根据Webpack创建者,这是不可能的。 干净利落。 有关Webpack和ES6的大量其他有用信息,请参阅Peter的答案。

粘贴的图像是误解的结果。 请参阅上面相同的用户答案。

在此输入图像描述

System.import已在Webpack中弃用。 Webpack现在支持import() ,这需要使用polyfill来实现承诺。

代码拆分 - 使用import()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM