Webpack 2 - 代码拆分顶级依赖关系

时间:2016-02-19 20:51:42

标签: javascript webpack webpack-2

最终修改

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

contacts.js开始考虑以下代码。这是一个动态加载的模块,在代码中的其他位置System.import按需加载。

如果SharedUtil1也用于动态加载了System.import的其他模块,我将如何排除SharedUtility1 排除< / strong>来自所有这些模块,并且仅按需加载第一次需要它?

System.import的顶级SharedUtil1无法正常工作,因为我的导出依赖于它:导出只能放在模块代码的顶层,没有任何形式的回调。

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

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

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

export default Contacts;

更新1

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

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

更新2

Per Peter的回答,我试图让重复数据删除工作,因为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代码仍然放在联系人和任务包中。

4 个答案:

答案 0 :(得分:15)

阅读完博客文章后,我终于明白了你的意图。我对#34;顶级依赖关系&#34;。

这个词感到有些困惑

您有两个模块(async-aasync-b),它们可以从任何地方按需加载(此处为模块main),并且两者都有共享模块的引用({{ 1}})。

shared

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

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

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

---> 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] &lt; { shared或同一用户使用async-a/basync-a的概率很低。它是默认值,因为它是最简单的行为,可能是您所期望的:一个async-b =&gt;一块。在我看来,它也是最常见的情况。

但如果System.import&gt; = shared并且用户加载async-a/basync-a的概率很高,则会有更高效的分块选项:(有点难以想象):

async-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

请记住,CommonsChunkPlugin有一个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) 选项来定义模块何时被线程化为minChunks(随意提供一个自定义函数来选择模块)。

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

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

答案 1 :(得分:11)

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

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

ECMA Script 5

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

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

重复数据删除

来自webpack documentation

  

如果您使用一些具有很酷依赖树的库,则可能会发生   有些文件是相同的。 Webpack可以找到这些文件和   重复删除它们。这可以防止包含重复的代码   您的捆绑包,而是在运行时应用该函数的副本。的它   不会影响语义。

强调是我的,而不是来源

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

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

命名为Chunks

来自webpack documentation

  

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

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

Common Chunk Plugin

来自webpack documentation

  

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

这非常特定于多个页面之间共享块,在其他情况下无关紧要。

ECMA Script 6

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

以下是ES6模块和webpack的一个很好的总结:ES6 Modules with TypeScript and Webpack

以上信息很可能会过时。

建议

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

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

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

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

答案 2 :(得分:1)

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

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

enter image description here

答案 3 :(得分:0)

Webpack中已弃用

System.import。 Webpack现在支持import(),这需要使用polyfill进行承诺。

Code Splitting - Using import()