[前端工程化] 前端模块化讲解

[前端工程化] 前端模块化讲解

·

1 min read

前端最常用的两种模块化规范分别是esmcjs

ESM 和 CJS 两种模块化规范混用

浏览器环境下

首先,在浏览器环境下,不存在这esmcjs混用的情况,因为浏览器只支持esm模块化。你使用任何脚手架的项目,在开发时可能使用了cjs模块化对反,但是最终它的打包产物必须是esm的才可以运行在浏览器环境下

打包后浏览器运行的代码htmljs文件一般是这样的:

  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="module" src="./m1.js"></script>
  <script type="module" src="./m2.js"></script>
</head>
<body>

</body>
</html>
  • m1.js
import { m2 } from './m2.js';
console.log("引入了m2", m2);
  • m2.js
export const m2 = "m2"

当然,一般不会直接使用es6,而是会去做一些pollyfill来适配各种浏览器

Node 环境下

node环境下,我给出的结论是:在同一个包内,是没有办法实现esmcjs两种模块化规范混用的

但是,你在你当前开发的项目下配置了package.json中的type = module,然后使用esm import去引入一个只有cjs产物的node_modules包中的导出是完全可以的

我们在node项目中自建一个local-test的本地测试的npm包,然后这个包只有cjs的导出,其结构如下:

  • index.js
module.exports = {
  name: "local-test"
}
  • package.json
{
  "name": "local-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

然后我们在我们自己的node项目中使用esm进行引入:

  • index.js
import localTest from 'local-test';
console.log(localTest.name);

发现它是可以正确地运行的:

但是这里要注意,我们使用esm导入cjs包时,使用的是默认导入,因为cjsmodule.exports对于esm来说就是默认导出,即export default这种格式的,所以我们不能使用import { xxx } from "xxx"这样的具名导入来引入cjs模块

在 Typescript 下的模块化

如果你用的是ts来开发项目,它同样也支持esmcjs两种模块化规范

浏览器环境下

在浏览器环境中,想要使用ts就必须要经过编译,而且在你使用框架的情况下,肯定要结合打包工具,要么vite,要么webpack

当使用vite打包的时候,对你的代码进行语法树解析时,是在node环境下运行的,并且vite只支持使用esm模块化,这就意味着你的vite项目不能使用require进行导入

Node 环境下

由于ts没有运行时,所以在node环境中要跑ts首先要把ts编译为js,所以我们直接用ts-node来帮助我们完成这个工作,使用ts-node时的体验就好像使用jsnode运行时一样;ts-node实际上就是在node环境下适配了ts并帮你编译好

使用node-ts开发项目时,package.json中的type = module字段对ts模块化规范的影响同样生效,你使用require进行引入,就不能添加type = module;否则你使用import进行引入,那么你就要添加该字段,不然都会报错