esm 本身出现就是为了 让web 模块化的, 结果 浏览器 esm 运行不了 import lodash from 'lodash ' 然后为了解决方案来了 browserify =>webpack , 然后问题又来了: node.js 本身 不支持esm 然后你们这样写 node.js 又得用babel转换! ( 语法不支持 esmify 转换), webpack |browserify 去打包,编译了… 不然就没法运行 然后看了半天人家的打包配置: 把async 语法都编译成 node.js 低版本的东西了…(我不知道怎么禁用 ) 要调试怎么办 生成 .map 文件嘛 ;然后各种百度谷歌找配置方法。 浏览器和node.js 共同的解决方案:
- 采用目前的require , 浏览器中对代码做语法解析,采用ast 语法 搜寻出 require(“module”) ;然后按一定的规则预先加载所需模块,这样是个好解决方法。 (语法解析有var 变量提前定义, 以及eval 语法分析, 再加require 语法分析是一个可行方案。)
- 这种方法 不会因为 require 加载模块而导致js 阻塞。而对于没有加载到的动态模块,可以采用用配置文件并预先加载到缓存,不执行模块内容;
- 语法一致性
我是把 ESM 作为开发模式,实际使用还是分别编译为 cjs 和 amd 两个包。 mjs 在浏览器上的规范实在不够,比如模块路径映射管理
实际项目中是用 TS 开发,然后通过 tsc 输出为 ESM 格式,接着用 rollup 打包。 webpack 太复杂了
都已经 2019 年了啊,还在都是发布 2 个版本,一个是 cjs 的,一个是 esm 的。
ems 可以通过 <script src="/_js/main.mjs" type="module"></script>
,带来的额外收益就是,所有支持 esm 的浏览器都可以支持 es6 的全部语法。
为了兼容旧浏览器,我们再发布一个 es5 的版本,通过 <script src="/_js/legacy.js" nomodule></script>
加载。
如果你明确知道目标浏览器的版本,可以直接部署 es5+ 版本代码。我司的所有内部系统都是这么发布的,只为最新的 Chrome 稳定版发布。
@waitingsong 有毒 tsc 转成esm 的格式 还要打包 ,你这个更坑 了嘛<~>
@waitingsong 你还不如用cjs 直接开发 毕竟 cjs npm 的包是全支持系列 ;还可以直接运行在node.js
再打包 ,反正浏览器横竖都要打包的…
@justjavac esm 的模块你不能直接饮用三方模块
@spitWind 可以引用,现在有些前卫的库已经在分发esm格式的包了,unpkg上很多包加个?module就是esm导出的
@codehz 目前是;现在 支持相对路径; import(url)
不支持import “lodash” ;你从网络 加载的是可以不过 这样前后端就不能同构了 ; node.js 也不支持…url的包把; 而且node 写法一直都是import lodash from "lodash"
你还是得编译; 所以还不如使用cjs 规范 反正都得用上打包工具 ,至少 node.js能直接运行
@spitWind cjs 不支持摇树优化。所以我 tsconfig.json 里面 module 设置为 es6,这样 tsc 编译为 esm 的 js 文件,然后用 rollup 打包为 umd, cjs, amd 三种格式
@spitWind 打包是为了缩减网络请求,而 babel 才是为了把 es6+ 编译成 es5 的。
在我的例子中,<script src="/_js/main.mjs" type="module"></script>
只是把 mjs 文件做了 bundle 而已,把多个 mjs 压缩成 1 个或者几个(code-splitting),这样可以在使用 esm 特性的同时也使用了所有的 es6 语法。
而 <script src="/_js/legacy.js" nomodule></script>
是通过 babel 做编译,然后再 webpack 打包。
你文中提到的“又得用babel 去打包”。babel 不是打包工具,而且在支持 esm 的浏览器中,babel 也不是必须的,但是对于浏览器而言,打包才是刚需。即使在没有 esm,没有 cjs,没有 amd 的时代,就已经有各种打包工具了。
@i5ting 强烈建议狼书里面加入相关内容
@justjavac 已更正