浅谈ESM

321 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情

引言

常用模块化规范 AMD CMD UMD COMMONJS,从 ES6 开始, JavaScript 才真正意义上有自己的模块化规范,ES6 不再是使用闭包和函数封装的方式进行模块化,而是从语法层面提供了模块化的功能。

ES6 模块中不存在 require, module.exports, __filename 等变量,CommonJS 中也不能使用 import。两种规范是不兼容的,一般来说平日里写的 ES6 模块代码最终都会经由 Babel, Typescript 等工具处理成 CommonJS 代码。

使用 Node 原生 ES6 模块需要将 js 文件后缀改成 mjs,或者 package.json "type" 字段改为 "module",通过这种形式告知 Node 使用ES Module 的形式加载模块。

支持情况

  • Safari 10.1
  • Chrome 61
  • Firefox 54 (有可能需要你在about:config页面设置启用dom.moduleScripts.enabled)
  • Edge 16

如果相兼容低版本浏览器,可以通过补丁包支持:
webpack 可以通过@babel/preset-env @babel/plugin-transform-runtime
vite 可以通过vite-plugin-inspect

竞品对比

image.png

使用

<script type="module">
  import message from './message.js'
  console.log(message) // hello world
</script>
<script nomodule>
  alert('your browsers can not supports es modules! please upgrade it.')
</script>

nomodule的处理方案是这样的: 支持type="module"的浏览器会忽略包含nomodule属性的script脚本执行。
而不支持type="module"的浏览器则会忽略type="module"脚本的执行。
这是因为浏览器默认只解析type="text/javascript"的脚本,而如果不填写type属性则默认为text/javascript。
也就是说在浏览器不支持module的情况下,nomodule对应的脚本文件就会被执行。

命令指南

导入导出命名,基本上与nodejs的命令相同,此处省略一万字

省略一万字

webpack

vue3的兴起带来了vite,目前vite对vue、react友好,大有取代一哥webpack的趋势,那么如何在webpack中使用 ESM呢?

module.exports = {
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'dist'),
    environment: { module: true }
  },
  experiments: {
    outputModule: true
  },
  plugins: [
			new HtmlWebpackPlugin({
				title: 'loading...',
				favicon: resolve(__dirname, '../public/favicon.ico'),
				template: resolve(__dirname, '../public/index.html'),
				output: resolve(projectAbsolutePath, './dist/index.html'),
				inject: false
			})
		],
}

关闭自动注入,改为手动注入,如果项目中的依赖使用了cdn,也需要调整:

<!DOCTYPE html>
<html lang="zn">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>
      <%= htmlWebpackPlugin.options.title %>
    </title>
    [[[mutation-monitor]]]
  </head>
  <body>
    <div id="app"></div>
    [[[cdn-injected]]]
    <script type="module">
      import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.7.8/dist/vue.esm.browser.js'
    </script>
    <script type="module" src="/main.js"></script>
    <noscript>
      <strong>We're sorry but 【<%= htmlWebpackPlugin.options.title %>】 doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
    </noscript>
  </body>
</html>

Vite

vite构建工具全面支持 vue、react,并且已经全面使用了esModule,直接下载使用即可。

JavaScriptTypeScript
vanillavanilla-ts
vuevue-ts
reactreact-ts
preactpreact-ts
litlit-ts
sveltesvelte-ts