|
Commonjs
什么是 CommonJs
模块化产生的原因
- 随着前端页面复杂度的提升,依赖的第三方库的增加,导致的 js 依赖混乱,全局变量的污染,和命名冲突
- 单个 js 文件内容太多,导致了维护困难,拆分成为多个文件又会发生第一点描述的问题
- v8 引擎的出现,让 js 有了媲美编译型语言的运行速度,大大激励了前端开发者
CommonJS 的使用环境
- nodejs 实现了 CommonJS 模块化规范
CommonJs 有哪些规定
- 每一个文件就是一个模块
- 模块中的变量和函数不会污染全局(解决了全局污染和命名冲突)
- 提供给外部使用的内容需要导出
- 使用其他模块的内容需要导入 (模块的导入和导出共同解决了 js 依赖混乱的问题)
- 模块不会重复加载,模块第一次导入后会将第一次导入的结果缓存,下次导入时,直接使用缓存的结构
- 省略一些细碎的内容在下面代码中提及.....
commonJS 语法
- //这是导入一个模块,module.js;commonjs中规定require导入模块时可以省略.js后缀
- const module1 = require("./module1");
- //如果没有寻找到dir.js文件,而发现了dir路径,则寻找dir路径下package.json 的main属性指定的文件
- //如果package.json未指定路径,则触发默认规则 依次查找查找 index.js index.json
- const module2 = require("./dir");
- //如果require不是相对路径,则会去node_module中寻找该模块,重复module1 和module2 的步骤
- //如果没有node_modules 或node_modules 中不存在模块则继续向上级目录寻找node_modules,直到根目录
- const module3 = require("module3");
复制代码- module.exports = {
- //这里输入导出的内容
- };
- //这也是导出
- exports.a = "a";
- //注意 module.exports导出和exports[属性名]导出不可共存
- //module.exports会覆盖掉exports导出的内容
复制代码 简易实现类 nodejs 模块化环境
- const fs = require("fs");
- const Path = require("path");
- const vm = require("vm");
- const ModuleStack = [];
- function isRootDirectory(path) {
- // Windows 根路径
- const windowsRootDirectory = /^[a-zA-Z]:\\$/;
- // Unix/Linux 根路径/
- const unixRootDirectory = /^\//;
- return windowsRootDirectory.test(path) || unixRootDirectory.test(path);
- }
- function isRelativeDirectory(path) {
- //匹配 ../ 或者 ./开头的路径
- const relativeDirectory = /^(\.\.\/|\.\/).+/;
- return relativeDirectory.test(path);
- }
- // 计算node_modules路径
- let computePaths = (dirname) => {
- let paths = [];
- let path = dirname;
- let node_modules = "./node_modules";
- while (
- !isRootDirectory(path) ||
- !paths.includes(Path.resolve(path, node_modules))
- ) {
- paths.push(Path.resolve(path, node_modules));
- path = Path.resolve(path, "../");
- }
- return paths;
- };
- function myRequire(path) {
- let truelyPath;
- if (isRelativeDirectory(path)) {
- // 获取真实路径
- truelyPath = Path.resolve(__dirname, path);
- } else {
- //获取可能的node_modules路径
- let paths = computePaths(__dirname);
- for (const item of paths) {
- truelyPath = Path.resolve(item, path);
- if (fs.existsSync(truelyPath)) {
- break;
- }
- }
- if (!truelyPath) {
- throw new Error("Can't find module " + path);
- }
- }
- // 如果缓存中有,直接返回
- if (myRequire.cache[truelyPath]) {
- return myRequire.cache[truelyPath].exports;
- }
- // 读取文件内容
- const content = fs.readFileSync(path, "utf-8");
- // 包装代码
- const wrapper = [
- "(function (exports, require, module, __filename, __dirname) { \n",
- "\n})",
- ];
- // 拼接代码
- const wrapperContent = wrapper[0] + content + wrapper[1];
- // 获取文件路径和文件名
- let dirname = Path.dirname(truelyPath);
- let filename = truelyPath;
- let parentModule =
- ModuleStack.length > 0 ? ModuleStack[ModuleStack.length - 1] : null;
- // 模块对象
- const Module = {
- id: Object.keys(myRequire.cache).length > 0 ? filename : ".",
- path: dirname,
- exports: {},
- parent: parentModule,
- filename: filename,
- loaded: false,
- children: [],
- paths: computePaths(dirname),
- };
- if (parentModule) {
- parentModule.children.push(Module);
- }
- //模块入栈
- ModuleStack.push(Module);
- // 需要运行的函数
- const moduleScope = vm.runInThisContext(wrapperContent);
- // 运行代码
- moduleScope.call(
- Module.exports,
- Module.exports,
- myRequire,
- Module,
- filename,
- dirname
- );
- // 标记模块已加载
- Module.loaded = true;
- //模块出栈
- ModuleStack.pop();
- // 缓存模块
- myRequire.cache[truelyPath] = Module;
- return Module.exports;
- }
- myRequire.cache = Object.create(null);
复制代码 模块化的意义
- 解决在模块化出现之前的js依赖混乱,全局污染命名冲突的问题
- 模块化的出现让js代码可以拆分为多个模块共同协作,单个js文件过长的问题,降低了维护难度。
- 模块化的出现让js开发大型项目出现了可能
ps:当前内容为学习commonjs理解,内容正确性请谨慎甄别。
来源:https://www.cnblogs.com/jiangyun/p/18141885
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|