简体   繁体   English

如何在 Javascript 中检查脚本是否作为 ES6 模块运行(以便它可以“导出”)?

[英]How do I check if a script is running as a ES6 module (so that it can `export`), in Javascript?

I'd like to make a Javascript file that我想制作一个 Javascript 文件

  • export s its content (eg a class) if it can export (eg it has been loaded with <script type="module"> ) export s 它的内容(例如一个类),如果它可以export (例如它已经加载了<script type="module">
  • and otherwise, assigns its content into the global variable such as window and global .否则,将其内容分配给全局变量,例如windowglobal

For example, let's assume such a file print.js .例如,让我们假设这样一个文件print.js

Case A案例A

One can use it like:可以像这样使用它:

<script type="module">
    import print_things from "./print.js";
    print_things("Javascript innovation");
</script>

Case B案例B

or,或者,

<script src="./print.js"></script>
<script>
    print_things("Hmmmmmmm.");
</script>

Currently, using export makes the script throw an error in Case B : Uncaught SyntaxError: Unexpected token export .目前,使用export会使脚本在案例 B中抛出错误: Uncaught SyntaxError: Unexpected token export So it has to know whether export is available on the environment whereon it runs, in order to support the both use cases.因此,它必须知道export在其运行的环境中是否可用,以支持这两种用例。 How do I do this?我该怎么做呢?

Check out UMD (universal module definition).查看UMD (通用模块定义)。 Namely, this example这个例子

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['exports', 'b'], function (exports, b) {
            factory((root.commonJsStrictGlobal = exports), b);
        });
    } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
        // CommonJS
        factory(exports, require('b'));
    } else {
        // Browser globals
        factory((root.commonJsStrictGlobal = {}), root.b);
    }
}(typeof self !== 'undefined' ? self : this, function (exports, b) {
    // Use b in some fashion.

    // attach properties to the exports object to define
    // the exported module properties.
    exports.action = function () {};
}));

Browsers that understand type=module should ignore scripts with a nomodule attribute.理解type=module的浏览器应该忽略带有nomodule属性的脚本。 This means you can serve a module tree to module-supporting browsers while providing a fall-back to other browsers.这意味着您可以为支持模块的浏览器提供模块树,同时为其他浏览器提供回退。

<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

( Note: you probably shouldn't use this in the real world , but it is totally valid and does exactly what you want.) 注意:你可能不应该在现实世界中使用它,但它完全有效的,并且完全符合你的要求。)
Here's an implementation of your print.js :这是您的print.js的实现:

function print_things(msg) {
   console.log(msg)
}
if(0)typeof await/2//2; export default print_things

 <script type=module> // (renamed to avoid name collision) import print_things2 from "https://12Me21.github.io/external/print.js" print_things2("Javascript innovation") </script> <script src="https://12Me21.github.io/external/print.js"></script> <script> print_things("Hmmmmmmm.") </script>
This syntax will "hide" the export statement from non-module scripts, because await/2//2; ... 此语法将从非模块脚本中“隐藏”导出语句,因为await/2//2; ... await/2//2; ... is parsed differently depending on context: await/2//2; ...根据上下文进行不同的解析:

  • In a module or async function :模块异步函数中:
    await (operator) /2/ (regexp) / (divide) 2 (number) await (运算符) /2/ (正则表达式) / (除) 2 (数字)
  • In a normal script :在普通脚本中:
    await (variable) / (divide) 2 (number) //2 ... ( comment ) await (variable) / (divide) 2 (number) //2 ... ( comment )

When it's parsed as a comment, the rest of the line is ignored.当它被解析为注释时,该行的其余部分将被忽略。 So, the export statement is only visible to module scripts.因此, export语句仅对模块脚本可见。

Here is the relevant part of the specification: 15.8 Async Function Definitions > Syntax > AwaitExpression > Note 1这是规范的相关部分: 15.8 Async Function Definitions > Syntax > AwaitExpression > Note 1

Compatibility兼容性

As a non-module script, it should work in any browser (even ancient versions of Internet Explorer etc.), and is still valid with "use strict" enabled作为一个非模块脚本,它应该可以在任何浏览器中运行(甚至是 Internet Explorer 的旧版本等),并且在启用"use strict"的情况下仍然有效

However, loading it as a module requires support for "top-level await", which was added a few years after modules themselves (~2021 vs ~2018), so keep that in mind.但是,将其作为模块加载需要支持“顶级等待”,这是在模块本身之后几年添加的(~2021 vs~2018),所以请记住这一点。
(It also works with nodejs, in either mode) (它也适用于 nodejs,在任何一种模式下)

I've used this trick in a library that I wrote, and it's been working fine in multiple environments for several months.我在自己编写的库中使用了这个技巧,几个月来它在多个环境中都运行良好。 However, it has caused some problems with external tools (frameworks, compilers, minifiers, etc.)但是,它导致了一些外部工具(框架、编译器、压缩器等)的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM