[译] 浏览器中的 ECMAScript 模块

原文链接:
ECMAScript modules in browsers

作者:Jake Archibald

浏览器如今能够运用 ES 模块(module)了!它们是:

  • Safari 10.1
  • Chrome 61
  • Firefox 60
  • Microsoft Edge 16
<script type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Modules are pretty cool.');
</script>
// utils.mjs
export function addTextToBody(text) {
  const div = document.createElement('div');
  div.textContent = text;
  document.body.appendChild(div);
}

在线演示

您只需要在 script 元素上增加 type=module,浏览器就会将内联剧本或外部剧本作为 ECMAScript module 处置惩罚。

关于模块(module)已经有一些很棒的文章,然则我想分享一些在我测试和浏览范例的时刻学到的浏览器特有的内容。

现在还不支撑的某些 import 用法

// 已支撑:
import {foo} from 'https://jakearchibald.com/utils/bar.mjs';
import {foo} from '/utils/bar.mjs';
import {foo} from './bar.mjs';
import {foo} from '../bar.mjs';

// 不支撑:
import {foo} from 'bar.mjs';
import {foo} from 'utils/bar.mjs';

有用的模块途径说明符必需相符以下前提之一:

  • 一个完全的非相对URL,如许在将其传给 new URL(moduleSpecifier) 的时刻才不会报错。
  • / 开首的。
  • ./ 开首的。
  • ../ 开首的。

其他情势的说明符保存供未来运用,比方导入内置模块。

运用 nomodule 来向后兼容

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

在线演示

支撑 type=module 的浏览器会疏忽属性为 nomodule 的剧本。这意味着您能够给支撑模块的浏览器供应模块树,同时给其他浏览器供应一个降级版本。

浏览器题目

  • Firefox 浏览器不支撑 nomodule (issue)。已在 Firefox nightly 中修复!
  • Edge 浏览器不支撑 nomodule (issue)。已在 Edge 16 中修复!
  • Safari 浏览器不支撑 nomodule。已在 Safari 11 中修复!关于 10.1,这里有一个异常智慧的替换方法

默许状况下耽误实行

<!-- 这个剧本的实行会晚于… -->
<script type="module" src="1.mjs"></script>

<!-- …这个剧本… -->
<script src="2.js"></script>

<!-- …然则会在这个剧本之前实行。 -->
<script defer src="3.js"></script>

在线演示

实行的递次是:2.js1.mjs3.js

script 在猎取时期会壅塞 HTML 剖析器,几乎太糟糕了。关于通例剧本,您能够运用 defer 来防止壅塞,固然这也会推延剧本的实行,直到文档完成剖析,并与其他耽误剧本一同保护实行递次。模块剧本的默许表现行动就像 defer ——当它正在猎取时,没有方法让一个模块剧本壅塞 HTML 剖析器。

模块剧本运用和增加了 defer 的通例剧本雷同的实行行列。

内联剧本也是延时的

<!-- 这个剧本的实行会晚于… -->
<script type="module">
  addTextToBody("Inline module executed");
</script>

<!-- …这个剧本… -->
<script src="1.js"></script>

<!-- …和这个剧本… -->
<script defer>
  addTextToBody("Inline script executed");
</script>

<!-- …然则会在这个剧本之前实行。 -->
<script defer src="2.js"></script>

在线演示

实行递次是1.js ,内联剧本,内联剧本,2.js

通例的内联剧本会疏忽 defer ,但是内联模块剧本却老是被耽误,不管它们有无导入任何东西。

Async 对内联、外部模块一样实用

<!-- 一旦猎取了导入,就会实行此操纵 -->
<script async type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Inline module executed.');
</script>
<!-- 一旦猎取了剧本和它的导入,就会实行此操纵 -->
<script async type="module" src="1.mjs"></script>

在线演示

疾速下载的剧本会在慢速下载的剧本之前实行。

与通例剧本一样,async 会让剧本在下载过程当中不会壅塞 HTML 剖析器,而且尽快地实行。与通例剧本差别,async 也实用于内联模块。

与平常的 async 一样,剧本不会根据它们出如今 DOM 中的递次实行。

浏览器题目

  • Firefox 浏览器不支撑内联模块剧本上的 async (issue)。已在 Firefox 59 中修复!

模块仅实行一次

<!-- 1.mjs 仅实行一次 -->
<script type="module" src="1.mjs"></script>
<script type="module" src="1.mjs"></script>
<script type="module">
  import "./1.mjs";
</script>

<!-- 但是,一般的剧本却实行屡次 -->
<script src="2.js"></script>
<script src="2.js"></script>

在线演示

假如您明白 ES 模块,您就会晓得您虽然能够引入它们很屡次,然则它们却仅仅会实行一次。固然,这一样实用于HTML中的剧本模块 – 特定URL的模块剧本每页只实行一次。

浏览器题目

  • Edge 实行屡次模块 (issue)。已修复,然则还没宣布(愿望 Edge 17 会带上这个修复内容)。

老是运用 CORS

<!-- 该剧本不会实行, 由于它不能经由过程 CORS 搜检 -->
<script type="module" src="https://….now.sh/no-cors"></script>

<!-- 该剧本不会实行, 由于它引入的剧本之一不能经由过程 CORS 搜检 -->
<script type="module">
  import 'https://….now.sh/no-cors';

  addTextToBody("This will not execute.");
</script>

<!-- 该剧本会实行,由于它经由过程了 CORS 搜检 -->
<script type="module" src="https://….now.sh/cors"></script>

在线演示

与通例剧本差别,模块剧本(及其引入的内容)是经由过程 CORS 猎取的。这就意味着跨域的模块剧本必需返回有用的 CORS 相应头 ,比方 Access-Control-Allow-Origin: *

浏览器题目

  • Firefox 加载 Demo 页面失利 (issue)
  • Edge 加载没有 CORS header 的模块剧本 (issue)。 已在 Edge 16 中修复!

不照顾凭据

<!-- 照顾凭据猎取(cookie 等) -->
<script src="1.js"></script>

<!-- 不照顾凭据猎取 -->
<script type="module" src="1.mjs"></script>

<!-- 照顾凭据猎取 -->
<script type="module" crossorigin src="1.mjs?"></script>

<!-- 不照顾凭据猎取 -->
<script type="module" crossorigin src="https://other-origin/1.mjs"></script>

<!-- 照顾凭据猎取 -->
<script type="module" crossorigin="use-credentials" src="https://other-origin/1.mjs?"></script>

在线演示

假如请求来自雷同的源,大多数基于 CORS 的 API 会发送凭据(cookie 等),然则 fetch() 和模块剧本倒是破例的——非您请求它们,不然它们不会发送凭据除。

您能够经由过程增加 crossorigin 属性来向同源模块增加凭据(这对我来讲好像有点新鲜,我在范例中对此提出质疑)。假如您盘算向其他的源也发送凭据,运用 crossorigin="use-credentials"。注重其他源必需运用 Access-Control-Allow-Credentials:true 的相应头来相应。

另外,另有一个与“模块只实行一次”划定规矩相干的题目。模块由其URL标记,因而假如初次请求了一个模块而不照顾凭据,然后再次照顾凭据请求该模块,那末第二次取得的依然是不照顾凭据的模块。 这就是为啥我在上面的URL中运用 问号 ? 的缘由,使它们成为唯一的。

更新: 上面的状况能够很快就会发作转变。fetch() 和模块剧本默许都邑向同源的 URL 发送凭据。Issue

浏览器题目

  • Chrome 运用凭据请求同源模块(issue)。已在 Chrome 61 中修复!
  • Safari 纵然增加了 crossorigin 属性,也不运用凭据请求同源模块(issue)。
  • Edge 纵然增加了 crossorigin 属性,也不运用凭据请求同源模块(issue)。已在 Edge 16 中修复!
  • Edge 默许请求同源模块的时刻照顾了凭据(issue)。

MIME 范例

差别于通例剧本,模块剧本必需是有用的 JavaScript MIME 范例中的一种范例,不然模块就不会实行。HTML 规范发起运用 text/javascript

浏览器题目

  • Edge 实行无效的 MIME 范例剧本(issue

这就是我现在学到的内容啦。毋庸置疑,我对 ES 模块上岸浏览器觉得异常高兴!

机能发起,动态导入等等!

请查阅有关 Web Fundamentals 的文章,深切相识模块运用状况。

    原文作者:司楠
    原文地址: https://segmentfault.com/a/1190000017785408
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞