现代的浏览器原生支持运行模块化的功能,不需要通过 Webpack,ESbuild 等工具构建打包。例如现在的 Vite 就是利用了浏览器支持原生模块的特性,才能够在启动的时候不需要提前编译。本文将介绍下如果在浏览器运行原生模块
在 Vite 官网的 NPM 依赖解析和预构建 描述到
那么为什么要做预构建呢?主要是因为浏览器的原生模块运行不支持 import { add } from './math';
这种写法,需要先转为 import { add } from './math.js';
才能支持,下面通过实例来验证一下。
项目创建
根据下面的目录结构新创建文件
|- math.js
|- main.js
|- index.html
math.js
是用工具类,main.js
是项目的入口文件,index.html
是项目的首页。对应的代码如下:
math.js文件
export const add = (a, b) => a + b;
main.js文件
import { add } from "./math";
document.getElementById("btn").onclick = () => {
alert(add(3, 4));
};
index.html文件
<!DOCTYPE html>
<html lang="en">
<body>
<button id="btn">click</button>
<script src="./main.js"></script>
</body>
</html>
代码很简单,一个页面有一个按钮,引入 main.js 文件,main.js 调用了 math.js 模块的 add
方法,我们直接浏览器本地打开,发现报错了
Access to script at 'file:///xxx/xxx/main.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.
意思是本地加载 script 脚本有跨域限制,必须要通过 http,data,chrome,chrome-extension,chrome-untrusted,https 协议才能加载。
http 服务
我们启动一个静态资源服务,通过 http 来访问,通过 http://localhost:8080/
来访问,打开控制台,发现又报错了
main.js:1 Uncaught SyntaxError: Cannot use import statement outside a module
意思是不能在没有声明 module 的情况下使用 import 语句,我们来给 script 标签新增一个 type="module"
属性
<!DOCTYPE html>
<html lang="en">
<body>
<button id="btn">click</button>
<script type="module" src="./main.js"></script>
</body>
</html>
重新访问,发现又报错了,
main.js:1 GET http://localhost:8080/math net::ERR_ABORTED 404 (Not Found)
原因是,浏览器原生模块不支持不带文件名后缀,毕竟是通过 http 请求,所以我们需要把 math 文件名改为 math.js,修改 main.js 文件,这也是为什么 Vite 需要通过 esbuild 预构建处理。
import { add } from "./math.js";
document.getElementById("btn").onclick = () => {
alert(add(3, 4));
};
这时候运行没报错,点击 click 按钮,发现弹出了 7。完美运行原生模块成功!!!