如果我们有 webpack 创建的不同捆绑包,并且我们require.ensure
要在以后的某个时间动态传输+ eval ,则会通过< em> jsonPadding 和一些webpack js魔术。如果我们有
require.ensure([ ], ( require ) => {
console.log('before...');
var data = require( './myModule.js' );
console.log('after...');
}, 'myModule')
完全转移和评估该模块时会遇到 "after..."
。如果碰巧是这个块 / 模块非常大,包含图像,css和诸如此类的东西,那么当webpack javascript代码解包时,加载将几乎锁定浏览器包含其所有组件的包。
问题:有没有办法“挂钩”require
魔法?例如,对于以下内容进行回调将是一个梦想的场景:
依此类推,假设我们传输的包中包含大量数据。一般来说,让我很难有一个很好的选择来动态地异步传输整个bundle,但仍然必须以完全同步/阻塞的方式加载那个bundle。
答案 0 :(得分:4)
让我先说我知道这可能是一个'烦人'的答案,因为它没有直接回答你的问题而是提供了一个 另类,务实,解决浏览器悬挂问题。一世 我自己使用这种模式来管理上下文中的资产加载 一个沉重的3D网页游戏。
我写这个是一个答案,而不是一个评论,所以它可能会起作用 其他遇到同样问题的人。如果这确实回答你的 case,我很乐意提供实际的代码来实现和生成 这些模块。
如果我理解正确,基本上你想要的是一种将MyModule
分解成离散组件的方法,这些组件可以在一个require.ensure
的上下文中进行原子加载和评估,但是处理评估以便不一切都进行评估,导致浏览器挂起。
另一种看待这种情况的方法是使用require
和ensure
方法本身作为加载/评估机制。考虑MyModule.js
,这是一个包含依赖项Css1, Css2, ... CssN
以及JS1, JS2, ... JSN
和图片的大型加载模块。
我的建议是将其细分为SuperMyModule.js
,这需要MyModuleLogic.js
以及所有CSS,图片和JS。
节点,您可以在SuperMyModule.js
中执行:
let myModuleLogic = require("myModuleLogic");
console.log('JS was evaluated');
require.ensure(['image1.png'], ( require ) => {
let data = require( './images1.png' );
console.log('image[1] was evaluated');
// register that resource was evaluated/fire event
})
require.ensure(['style1.css'], ( require ) => {
let data = require( './style1.css' );
console.log('css[1] was evaluated');
// register that resource was evaluated/fire event
})
//after all resources evaluated/fire callback or event
然后在原始文件中,就像您要求的那样:
require.ensure([ ], ( require ) => {
console.log('before...');
let myModule = require( './superMyModule.js' );
console.log('after...');
})
如果你将模块实例设置为事件发射器,可能会挂钩加载资源,如下所示:
require.ensure([ ], ( require ) => {
let myModule = require( './superMyModule.js' );
myModule.on("loadResource", myCallback)
})
答案 1 :(得分:1)
我想我自己对这个话题感到困惑,所以我的问题可能不够精确,无法得到适当的回答。但是,我对整个“commonJS动态模块加载”上下文的误解是,require.ensure()
只会传输模块代码(分别是webpack创建的 Chunk )通过电线。之后,传输的 Chunk 基本上只是一个大的ECMAscript文件,就在浏览器中,缓存但尚未评估。对整个 Chunk 的评估仅在实际的require()
调用中发生。
说完了,你完全掌握了如何解耦和评估模块 / Chunk 的各个部分。例如,在我的原始问题中,某些 CSS文件中的模块requires()
,某些图像和某些 HTML ,所有这些都在require.ensure()
电话上异步转移。以require()
(以及评估)这些部分的方式完全取决于您,您可以在必要时自行解除这些调用。
例如,模块看起来像这样:
<强> Module1.js 强>
"use strict";
import { io } from 'socket.io-client';
document.getElementById( 'foo' ).addEventListener('click', ( event ) => {
let partCSS = require( 'style/usable!./someCoolCSS.css' ),
moarCSS = require( 'style/usable!./moarCoolCSS.css' ),
tmpl = require( './myTemplate.html' ),
image1 = require( './foo.jpg' ),
image2 = require( './bar.png' );
}, false);
当然,当其他一些模块调用时,所有这些文件都已包含在传输到客户端的Chunk中:
require.ensure([ 'Module1.js' ], ( require ) => {
}, 'Module1');
这是我的困惑。现在,我们可以在require()
内自己进行module1.js
次调用。如果我们确实需要大量文件,我们甚至可以使用setTimeout
/ setImmediate
失控定时器来解除每个require()
调用之间的同步评估(如果必要或需要)。
对于一个非常简单的故事实际上是一个很长的答案。
<强> TL; DR:强>
“ require.ensure
通过网络传输整个块。此块包含所有文件,这些文件是受保护模块中require()
调用的一部分。但这些文件不得到自动评估。只有在运行时匹配实际的require()
调用时才会发生这种情况(此时由webpackJSONP调用表示)“
答案 2 :(得分:0)
您可以卸载主线程并避免使用worker loader进行阻塞。
下行:在主窗口和工作人员之间传递了额外的消息。
https://github.com/webpack/worker-loader
您还可以尝试在大型模块中发送加载事件,以跟踪更细微的进度。
进一步参考:
答案 3 :(得分:0)
如果您想通过require.ensure
以及其他Promise开始加载异步JavaScript包,请按以下步骤操作:
const requireEnsurePromise = new Promise((resolve) => {
require.ensure(['./modulePath'], function (requireEnsure) {
console.log('The module is fetched but not evaluated yet');
resolve(requireEnsure.bind(null, require.resolve('./modulePath')));
});
});
Promise.all([
fetch('/api/relevant/stuff').then(response => response.json()),
requireEnsurePromise,
]).then((values) => {
if (values[0]) {
// DO STUFF
}
console.log('right before module is evaluated');
const evaluatedModule = values[1]();
});
Webpack静态地确定模块路径对应于Webpack内部表示(可以是整数或字符串)。每当Webpack识别require.ensure([], fn)
模式时,它都会查看fn
回调的函数体并执行此操作。为了延迟以Promise方式获取JavaScript包之后的评估时间,require('./modulePath')
成功回调中不能出现require.ensure
,因为它将评估模块。 Webpack会将require('./modulePath')
翻译为类似__webpack_require__(2343423)
的内容,这就是您希望在此方案中避免使用它的原因。