【问题标题】:Migrating from Webpack 1.x to 2.x从 Webpack 1.x 迁移到 2.x
【发布时间】:2017-03-11 21:50:06
【问题描述】:

在 Webpack 1.x 中,我曾经定期执行以下操作:

require.ensure([ './mod2.js' ], ( require ) => {
    setTimeout(() => {
        // some later point in time, most likely through any kind of event
        var data = require( './mod2.js' ); // actual evaluating the code
    },1100);
}, 'myModule2');

使用这种技术,我们能够通过网络传输 webpack-bundle,但在稍后的某个时间点评估来自该包的实际内容(JavaScript 代码)。此外,使用require.ensure,我们可以命名捆绑包,在本例中为 myModule2,因此当捆绑发生执行 webpack 时我们可以看到名称/别名。

在 Webpack 2.x 中,新的方法是使用 System.import。虽然我现在喜欢接收 Promise 对象,但这种风格有两个问题。上述代码的等效项如下所示:

System.import( './mod2.js' ).then( MOD2 => {
    // bundle was transferred AND evaluated at this point   
});
  • 现在如何拆分传输和评估?
  • 我们如何才能命名捆绑包?

Github 上的 Webpack documentation 表示如下:

全动态要求现在默认失败

现在只有一个表达式的依赖项(即 require(expr)) 创建一个空上下文而不是完整的上下文 目录。

最好重构此代码,因为它不适用于 ES6 模块。如果这是 不可能你可以使用 ContextReplacementPlugin 来提示 编译器正确解析。

我不确定这是否在这种情况下起作用。他们还在那里谈论代码拆分,但非常简短,他们没有提到任何“问题”或如何解决。

【问题讨论】:

  • 为什么不在一个变量中捕获promise,然后在另一个代码段中触发.then
  • @Claies 我看不出这有什么帮助。承诺仍将处理“两个”操作,转移 + 评估。如果我们有两个单独的承诺,那将是一件事情。

标签: javascript webpack webpack-2


【解决方案1】:

tl;dr: System.resolveSystem.register 做大部分你想做的事。这个答案的其余部分是为什么require.ensure 不能以及System.import 如何调用其他人。

认为 ES6 模块会阻止它正常工作,尽管通过相关规范遵循它很棘手,所以我可能完全错了。

也就是说,让我们从一些参考资料开始:

  1. WhatWG module loader
  2. ES6 specification on modules (§15.2)
  3. CommonJS module specification
  4. fantastic 2ality article on ES6 modules

第一个参考解释了更多行为,尽管我不完全确定它的规范化程度。后者解释了 JS 端的实现细节。由于还没有平台实现这一点,我没有关于它在现实生活中如何实际工作的参考资料,我们将不得不依赖规范。

The require that has been available 在 webpack 1.x 中是 CommonJS 和 AMD 要求的混搭。 CommonJS 方面在 ref#3 中进行了描述,特别是“模块上下文”部分。没有提到require.ensure,AMD“规范”(例如它)也没有提到,所以这纯粹是 webpack 的发明。也就是说,该功能从来都不是真实的,在某种意义上被指定为官方和花哨的地方。

也就是说,我认为require.ensure 与 ES6 模块冲突。调用System.import 应该从Loader object 调用import method。 ref#2 中的相关部分没有明确说明,但§10.1 确实提到将加载程序附加到System

Loader.prototype.import method 的参与度并不高,只有第 4 步是我们感兴趣的:

  1. 返回使用实现处理程序转换 Resolve(loader, name, referrer) 的结果,当使用参数键调用该处理程序时,将运行以下步骤:
    1. 让条目为 EnsureRegistered(loader, key)。
    2. 返回使用实现处理程序转换 LoadModule(entry, "instantiate") 的结果,调用该处理程序时,将运行以下步骤:
      1. 返回 EnsureEvaluated(条目)。

流程是解析-注册-加载-评估,您想在加载和评估之间中断。但是请注意,加载阶段调用LoadModule 并将stage 设置为"instantiate"。这意味着并且可能需要模块已经通过RequestTranslate 进行了翻译,它会在尝试找到模块的入口点等时进行大量繁重的解析。

从它的声音来看,这已经完成了比你想要的更多的工作。由于模块加载的基础知识需要一个已知的入口点,我认为没有办法避免使用从System 公开的调用来解析和部分评估模块。你已经知道了。

问题是System.import 不可能知道——直到解析之后——模块是必须评估的 ES6 模块还是可以延迟的 webpack 包。必须进行解析以确定是否需要解析,从而导致鸡与蛋的问题。

到目前为止,我们一直遵循从System.importLoader 的路径。 import 调用指示我们处于导入的哪个阶段,假设您想要完成完整的端到端加载过程。底层调用,如Loader.prototype.load,提供对这些阶段的细粒度控制。

我不确定你将如何调用前两个阶段(获取和翻译),但如果你能够翻译和注册一个模块,以后的调用应该简单地评估并返回它。

如果规范是准确的,这应该通过System.loader 属性公开(在支持实现中),并且具有您需要调用的方法。您无法访问大部分流程,因此我建议您不要这样做,而是设置您的代码,以便在加载模块时不会运行任何重要内容。如果这不可行,您需要通过注册重新创建流程,但停止评估。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    • 2020-08-24
    相关资源
    最近更新 更多