背景
浏览器层面的esModule
在设计的时候不太完美,只能import外部JS,如果某个<script type="module">
是通过内联代码直接写在HTML
里面的反而没法导入:
<script type="module">export default 123;</script>
<script type="module">
// 无法导入上面的模块代码
</script>
只能改成下面这样:
// test.js
export default 123;
然后再导入单独的JS文件:
<script type="module">
import test from './test.js';
console.log(test);
</script>
hack
虽然这么做没啥实际意义,但我就偏不信这个邪,非得试试,实现之后可以比较方便写一些简单测试代码。既然浏览器只能导入外部JS文件,那我们就给它生成外部文件就好了:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>测试内联代码导入导出</title>
<script>
// 预编译带 text/babel 的script标签,处理 import
function preCompileInlineModuleScript() {
const srcMap = {}; // 存储所有内联模块的blob src地址
[...document.querySelectorAll('script[type="text/module"]')]
.map((script, idx) => {
// 如果未通过 data-module 指定模块名,生成类似 module0 的默认名称
const moduleName = script.dataset?.module || `module${idx}`;
const url = URL.createObjectURL(new Blob([script.textContent], { type: 'text/javascript' }));
srcMap[moduleName] = url;
return script;
})
.forEach(script => {
const { src, textContent, dataset } = script;
if (!textContent) {
return;
}
// 自动检索类似 `import Demo from 'demo'` 这样的代码
const newContent = textContent.replace(/(?<=import .+['"])(.+)(?=['"][;\n])/g, (m, src) => srcMap[src] || src);
const ele = document.createElement('script');
ele.textContent = newContent;
ele.type = 'module';
script.parentNode.insertBefore(ele, script); // 依次插在原script前面
script.remove();
});
}