在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来提示 编译器正确解析。
我不确定在这种情况下是否起作用。他们还谈到了那里的代码分裂,但它很简单,他们没有提到任何"问题"或者如何解决。
答案 0 :(得分:5)
tl; dr: System.resolve
和System.register
完成您想要的大部分工作。这个答案的其余部分是require.ensure
不能以及System.import
如何调用其他人的原因。
我认为 ES6模块阻止了这项工作,虽然遵循相关规范是很棘手的,所以我可能完全错了。
那就是说,让我们从一些参考文献开始:
第一个参考文献解释了更多的行为,尽管我并不完全确定它是如何规范化的。后者解释了JS方面的实现细节。由于没有平台实现这一点,我没有参考它在现实生活中的实际工作方式,我们将不得不依赖规范。
webpack 1.x中的 The require
that has been available是CommonJS和AMD要求的mashup。其中的CommonJS方面在ref#3中描述,特别是“模块上下文”部分。没有提到require.ensure
,AMD的“规范”(例如它)也没有,所以这纯粹是webpack的一项发明。也就是说,这个特征从来都不是真实的,因为它被指定为官方和花哨的地方。
那就是说,我认为require.ensure
与ES6模块冲突。致电System.import
时,应从import
method调用Loader
object。参考文献2中的相关部分没有明确说明,但§10.1确实提到将加载器附加到System
。
Loader.prototype.import
method并非非常重要,第4步是唯一让我们感兴趣的人:
- 使用履行处理程序返回转换Resolve(loader,name,referrer)的结果,当使用参数键调用时,运行以下步骤:
醇>
- 让条目为EnsureRegistered(loader,key)。
- 返回使用履行处理程序转换LoadModule(entry,“instantiate”)的结果,该处理程序在调用时运行以下步骤:
- 返回EnsureEvaluated(条目)。
流程是resolve-register-load-evaluate,您希望在load和evaluate之间中断。但请注意,加载阶段调用LoadModule
并将stage
设置为"instantiate"
。这意味着并且可能要求模块已经通过RequestTranslate
进行了翻译,Loader.prototype.load
在尝试查找模块的入口点等时进行了大量的解析。
从声音来看,这已经做了比你想要的更多的工作。由于模块加载的基础知识需要一个已知的入口点,我认为没有办法避免使用System
中公开的调用来解析和部分评估模块。你已经知道了。
问题是System.import
在解析之前不可能知道模块是否是必须要评估的ES6模块或者可以延迟的webpack包。必须进行解析以确定我们是否需要解析,从而导致鸡与蛋的问题。
到目前为止,我们一直在关注从System.import
到Loader
的路径。假设您希望完成整个端到端加载过程,import
调用将决定我们处于哪个导入阶段。底层调用,如{{3}},可以对这些阶段进行细粒度控制。
我不确定你将如何调用前两个阶段(fetch和translate),但是如果你能够翻译和注册一个模块,以后的调用应该只是评估并返回它。
如果规范准确,则应通过System.loader
属性公开(在支持实现中),并且具有您需要调用的方法。您无法访问流的大部分内容,因此我建议不要这样做,而是设置代码,以便在加载模块时没有重要的运行。如果那是不可能的,你需要通过注册重新创建流程,但不要羞于评估。