在 Plain JS Script 之前和之后加载 ES6 模块依赖项
Load ES6 Module dependencies before and after Plain JS Script
我有一个纯 JS 脚本 parser.js
(从工具生成),它依赖于 ES6 模块 lexer.js
中定义的变量。在我的 ES6 模块中,我已经将变量导出到 window
object,因此可以从 parser.js
访问它们。但是,我需要在 运行 脚本之前以某种方式 运行 那个 ES6 模块。而且好像也没有什么办法。
尝试 1:尝试在包含我的脚本之前同步加载 ES6 模块
我在 HTML 中尝试过这样的事情。
<script src="lexer.js" type="module"></script>
<script src="parser.js"></script>
但似乎运行顺序不对。 lexer.js
运行 秒后 parser.js
尝试 2:尝试在 ES6 模块中同步加载脚本
我尝试像这样围绕我的解析器脚本创建一个包装器 ES6 模块
// use import to run the module and load variables into the window
import { lexer } from './lexer.js';
// load parser script synchronously
var req = new XMLHttpRequest();
req.open('GET', 'parser.js', false);
req.send(null);
eval(req.responseText);
但是,似乎同步 XMLHttpRequests 已被弃用并且不再起作用(编辑:实际上它们起作用,请参阅下面的 ),而且我找不到任何其他方式来同步加载脚本.总的来说,我会说 ES6 模块系统和旧的 javascript include 系统之间的不兼容性,令人沮丧。
P.S。作为参考,我使用的代码生成工具是 Nearley grammar compiler,它允许我从语法中引用我的词法分析器,并生成一个普通的 JS 解析器。
编辑:@yong-quan 提出了一个巧妙的解决方案,只需将 defer
放入脚本包含标记中,例如
<script src="lexer.js" type="module"></script>
<script src="parser.js" defer></script>
这似乎只是将parser.js
的执行推迟到最后。但是,我没有提到我实际上有一个名为 interpreter.js
的 ES6 模块需要在 parser.js
之后调用。很抱歉没有早点提到这一点,我认为无论对我的第一个问题有效的解决方案也能解决我的第二个问题。我修复了标题以阐明我需要 ES6 模块到 运行 在 之前和 我的普通 JS 脚本之后。本质上,我需要将这个纯 JS 脚本集成到我的模块依赖关系图中。
EDIT2:我错了,延迟解决方案有效。请参阅下面的@Aviad 或我自己的回答
我认为这里的良好做法是为此创建某种下载管理器(例如通过使用 webpack 块 loading/dynamic 导入)
另一种选择是使用 defer
属性。
请注意,defer
表示脚本 运行 按照它们遇到的顺序 ,因此您可以假设在调用 [= 时加载了 parser.js
13=] 如果顺序正确。
链接:
- Order of exec with
defer
- Webpack dynamic imports
所以我使用@Aviad 的 (在上面发布)解决了这个问题,并将 defer
添加到我所有的脚本中,例如:
<script src="lexer.js" type="module" defer></script>
<script src="parser.js" defer></script>
<script src="interpreter.js" type="module" defer></script>
它开始以正确的顺序加载它们。整洁的!尽管我认为需要注意这一点很重要,但我还没有找到 ES6 模块加载顺序的实际规范,因此似乎无法保证加载顺序(除了一个模块依赖另一个模块的情况外,在它会首先加载依赖项)。因此,虽然 defer
技巧目前有效,但我认为它有可能在未来失效。
我还想提一下,事实证明我的 XMLHttpRequest 同步脚本加载确实有效,我只是 运行 遇到了一些范围界定问题。我不得不从 window
的范围调用 eval
,因为通常 parser.js
在 HTML 中作为 <script>
标记加载,所以它期望范围成为 window
,所以我需要 eval()
来模仿它,就像这样:
// load parser script synchronously
var req = new XMLHttpRequest();
req.open('GET', 'parser.js', false);
req.send(null);
eval.call(window, req.responseText);
所以我想如果需要的话我有后备方案。我也在考虑手动将 parser.js
转换为 ES6 模块,但这省去了我每次 re-generate 时都要转换它的麻烦。感谢@Aviad 的解决方案!
我有一个纯 JS 脚本 parser.js
(从工具生成),它依赖于 ES6 模块 lexer.js
中定义的变量。在我的 ES6 模块中,我已经将变量导出到 window
object,因此可以从 parser.js
访问它们。但是,我需要在 运行 脚本之前以某种方式 运行 那个 ES6 模块。而且好像也没有什么办法。
尝试 1:尝试在包含我的脚本之前同步加载 ES6 模块
我在 HTML 中尝试过这样的事情。
<script src="lexer.js" type="module"></script>
<script src="parser.js"></script>
但似乎运行顺序不对。 lexer.js
运行 秒后 parser.js
尝试 2:尝试在 ES6 模块中同步加载脚本
我尝试像这样围绕我的解析器脚本创建一个包装器 ES6 模块
// use import to run the module and load variables into the window
import { lexer } from './lexer.js';
// load parser script synchronously
var req = new XMLHttpRequest();
req.open('GET', 'parser.js', false);
req.send(null);
eval(req.responseText);
但是,似乎同步 XMLHttpRequests 已被弃用并且不再起作用(编辑:实际上它们起作用,请参阅下面的
P.S。作为参考,我使用的代码生成工具是 Nearley grammar compiler,它允许我从语法中引用我的词法分析器,并生成一个普通的 JS 解析器。
编辑:@yong-quan 提出了一个巧妙的解决方案,只需将 defer
放入脚本包含标记中,例如
<script src="lexer.js" type="module"></script>
<script src="parser.js" defer></script>
这似乎只是将parser.js
的执行推迟到最后。但是,我没有提到我实际上有一个名为 interpreter.js
的 ES6 模块需要在 parser.js
之后调用。很抱歉没有早点提到这一点,我认为无论对我的第一个问题有效的解决方案也能解决我的第二个问题。我修复了标题以阐明我需要 ES6 模块到 运行 在 之前和 我的普通 JS 脚本之后。本质上,我需要将这个纯 JS 脚本集成到我的模块依赖关系图中。
EDIT2:我错了,延迟解决方案有效。请参阅下面的@Aviad 或我自己的回答
我认为这里的良好做法是为此创建某种下载管理器(例如通过使用 webpack 块 loading/dynamic 导入)
另一种选择是使用 defer
属性。
请注意,defer
表示脚本 运行 按照它们遇到的顺序 ,因此您可以假设在调用 [= 时加载了 parser.js
13=] 如果顺序正确。
链接:
- Order of exec with
defer
- Webpack dynamic imports
所以我使用@Aviad 的 defer
添加到我所有的脚本中,例如:
<script src="lexer.js" type="module" defer></script>
<script src="parser.js" defer></script>
<script src="interpreter.js" type="module" defer></script>
它开始以正确的顺序加载它们。整洁的!尽管我认为需要注意这一点很重要,但我还没有找到 ES6 模块加载顺序的实际规范,因此似乎无法保证加载顺序(除了一个模块依赖另一个模块的情况外,在它会首先加载依赖项)。因此,虽然 defer
技巧目前有效,但我认为它有可能在未来失效。
我还想提一下,事实证明我的 XMLHttpRequest 同步脚本加载确实有效,我只是 运行 遇到了一些范围界定问题。我不得不从 window
的范围调用 eval
,因为通常 parser.js
在 HTML 中作为 <script>
标记加载,所以它期望范围成为 window
,所以我需要 eval()
来模仿它,就像这样:
// load parser script synchronously
var req = new XMLHttpRequest();
req.open('GET', 'parser.js', false);
req.send(null);
eval.call(window, req.responseText);
所以我想如果需要的话我有后备方案。我也在考虑手动将 parser.js
转换为 ES6 模块,但这省去了我每次 re-generate 时都要转换它的麻烦。感谢@Aviad 的解决方案!