浏览器执行es6模块,如何原生执行import、export语句?
发布于 作者:苏南大叔 来源:程序如此灵动~
计算机代码世界更新太快,现在浏览器不用babel编译,就可以执行es6模块了。也就是说,如果不考虑兼容性的问题的话,在浏览器环境下,使用js的新语法,也是可能的了。喜大普奔?(假装喜大普奔ing)。

大家好,这里是苏南大叔的“程序如此灵动”博客,这里记录苏南大叔和计算机代码的故事。本文记录谷歌浏览器原生支持import和export等es6 module语句的故事。本文测试环境:win10,chrome@100.0.4896.60,ie11@21h2,edge@100.0.1185.29。
准备素材
如果大家对于es6 module的import和export是怎么回事,还不是很清楚的话。可以先查看下面的文章:
这里就简述一个最简单常见的情况了:lib.js:
export default function() {
console.log("苏南大叔的测试代码");
}主体test.html引用代码:
import aa from './lib.js';
aa();最正确的使用姿势
先说一下最正确的使用姿势:
<script type="module">
import aa from './lib.js';
aa();
</script>然后把test.html和lib.js文件放到www容器里面,通过浏览器访问站点的方式使用。

错误的使用姿势
浏览器里面对于es6模块化的js,也不是无条件支持的。下面是一些错误的使用方式范例:
错误一:直接双击.html文件
Access to script at 'file:///<path>/lib.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https
错误二:不写type="module"
Uncaught SyntaxError: Cannot use import statement outside a module
错误三:被导入文件的路径写法
这里,还需要注意一个写法,就是import from后面的文件路径,不支持那种不带有任何路径修饰的写法。比如:lib.js不行,目前本文的测试中是永远不会通过的,比如至少都需要一个./。虽然大家的意识里面,两者是同一个意思。但是,这里的测试环境下,就是不一样的结果。
Uncaught TypeError: Failed to resolve module specifier "lib.js". Relative references must start with either "/", "./", or "../".
错误四:不被浏览器认识的header
可以简单的保存相关文件为.js。那么,本错误并不会被显示。
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.
因为根据以往经验来说,es6的代码需要保存为.mjs文件。而这个格式是属于自定义格式,服务器往往会识别为application/octet-stream,而不是需要的application/javascript。这种情况下,浏览器是不会执行的这种类型的代码的。
这里还是以nginx为例,配置一下mime.types:
application/javascript mjs;相关经验:
兼容性检测 nomodule
对于古老版本的浏览器,不支持type="module"属性的浏览器,可以通过下面的方法执行别的js。比如:
<script nomodule src="nomodule.js"></script>这种情况下,nomodule.js会被下载,只不过不会被执行罢了。或者:
<script nomodule>
alert("this browser not support es6 module");
</script>在本文中,最新版本的chrome@100.0.4896.60是支持module的,所以上述代码并不会被执行。截图如下:

如果想测试被执行的效果,可以使用win10电脑里面自带的ie@21h2,就是不支持module的,但是自带的edge@100.0.1185.29是支持module的。截图如下:


为啥edge和chrome的版本号这么相似?
只会执行一次
对于同一个mjs(或者说设置type='module'的.js),它只会执行一次,无论加载了几次。
<script type="module" src="1.mjs"></script>
<script type="module" src="1.mjs"></script>
<script type="module">
import "./1.mjs";
</script>如上1.mjs里面的代码只会执行一次。
参考文献
- https://newsn.net/say/nginx-apache-font.html
- https://newsn.net/say/es6-module.html
- https://newsn.net/say/node-run-es6.html
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules
综述
chrome里面支持es6 module,但是不能双击html查看效果,记得放置在容器里面。es6 module需要保存为.mjs文件,但是这个后缀容器一般不认识,不会发出合适的header信息,导致浏览器无法识别。所以,保存为.js文件,也许是更加明智的选择。
也许浏览器原生支持这种写法后,似乎就有理由放弃webpack+babel的组合了。但是,这真的是本文的结论么?更多文章: