前端工程模块化
为什么需要模块化
当前端工程到达一定规模后,就会出现下面的问题:
- 全局变量污染:多个文件中定义的全局变量容易冲突
- 依赖混乱:多个文件之间的依赖关系复杂,难以维护
上面的问题,共同导致了代码文件难以细分,难以维护模块化就是为了解决上面两个问题出现的。
模块化是指把一个大的程序臃肿的代码细分成一个个小的文件,每个文件都是一个模块,通过模块化可以提高代码的可维护性和可读性。可以有效解决项目体量大时全局变量污染以及依赖混乱的问题。
模块化规范
- CommonJS CMJ 社区提出的模块化规范,Node.js 遵循这个规范
- ES module ECMAScript 6 的模块化规范,浏览器原生支持
node环境
CommonJS
CommonJS如何实现模块化
node天生支持CommonJS模块化标准
node规定:
- node中的每个js文件都是一个CMJ模块,通过node命令运行的模块,叫做入口模块
- 模块中的所有全局定义的变量、函数、都不会污染到其他模块
- 模块可以使用
module.exports
暴露(导出)一些内容给其他模块使用,也可以使用require("模块路径")
引入(导入)其他模块的内容(模块路径必须以./
或../
开头) - 模块有缓存机制,模块在第一次加载后会被缓存,再次加载时会优先读取缓存使用缓存结果。后续对该模块导入时,不会重新加载,而是直接读取缓存结果。
CommonJS模块化的实现
因为浏览器可以同时运行多个js文件,而node只能运行一个,所以我们会有一个主要启动文件,别的功能通过引入模块的方式实现
入口模块
1 | // index.js |
功能模块
1 | // math.js |
运行结果
1 | math.js被加载了 |
ES module
ES module如何实现模块化
ES module是ES6提出的模块化规范,浏览器原生支持,Node.js从13.2版本开始支持
依赖类型:
- 静态依赖:在编译时就能确定依赖关系
- 动态依赖:在运行时才能确定依赖关系
ES module的依赖关系在编译时就能确定,所以ES module的依赖关系是静态的,而CommonJS的依赖关系是动态的。
ES module模块化的实现
ES module也是区分入口模块和功能模块的,入口模块通过import
导入功能模块,功能模块通过export
导出内容。但是ES module的导出有两种方式:
- 默认导出:使用
export default
导出,一个模块只能有一个默认导出 - 具名导出:使用
export
导出,可以导出多个
一个模块可以有多个具名导出,但是只能有一个默认导出。他们两个可以同时存在。
入口模块
1 | // index.js |
注意:
- 静态导入的代码必须写在文件最前面,也不能写在代码块中
- 静态导入的导入路径必须是一个常量,不能是变量
- 动态导入的导入路径必须是一个变量,不能是常量
- 静态导入的导入路径必须以
./
或../
开头 - 动态导入的导入路径可以以
./
或../
开头,也可以没有开头(表示从根路径开始找)
功能模块
1 | // math.js |
总结
- CommonJS主要通过入口模块和功能模块配合,入口模块引入功能模块实现功能
- ES module 类似结构但语法更灵活,支持更多导入导出方式
以现在来看,目前使用ES module的情况更多,因为浏览器原生支持,而且ES module的依赖关系是静态的,更加方便管理。但是在Node.js中,CommonJS还是很常用的,因为Node.js是CommonJS的天然支持者,而且CommonJS的模块化规范在Node.js中已经被广泛使用,所以在Node.js中使用CommonJS也是很常见的。