Nodejs学习笔记-模块化

/post/node-module article cover image

主要记录了前端项目中Commonjs、AMD、 CMD、ESmodule模块化区别及特点。

模块化

在没有模块化之前可以通过立即函数调用表达式(IIFE)来解决,命名冲突等问题。

<u>模块化规范的出现主要解决以下问题:</u>

  • 多人协作开发中没有规范的混乱场景,避免命名冲突及全局混淆
  • 便于代码的组织、拆分及复用
  • 采用模块化类库规范项目管理进行模块化开发
    • Browserify
    • Gulp
    • Grunt
    • Webpack
    • ...

服务端的模块化

Commonjs

开始于一个ServerJS项目提出的用于服务端的模块化规范,后为了体现其广泛性更改为Commonjs,也简称为CJS。

  • 使用exports、module.exports导出
  • 使用require导入。
js
// 设置主文件
seajs.use('./index.tsx');
// 配置
seajs.config({
  base: '/', // 基础路径
  alias: {  // 模块别名
  	jquery: './lib/jquery'
  },
  paths: { // 路径别名
  	bar: './bar'
  }
})

// 定义模块foo.js
define(function(require, exports, module) {
	// 也可以使用条件异步加载
    if (flag) {
    	require.async('bar/bar.js', function() {

        })
    }

	module.exports = {
		foo: 'xxx'
    }
})

// 使用模块index.js
define(function(require, exports, module) {
	var foo = require('./foo.js');

})

特点

  • 兼顾了浏览器异步记载和Nodejs的书写规范
  • 依赖的自动加载和配置使得项目的配置关联度更高,加上插件社区能很好满足当时时期的开发需求

UMD(Universal Module Definition)

是对AMD和CMD规范的整合规范写法.

js
// 定义一个可以同兼容amd/commonjs的模块
(function (global, factory) {
	// AMD
    if (typeof define === 'function' && define.amd) {
        define(['xxx'], factory);
    }
    // Node/CommonJS
    else if (typeof module === 'object' && module.exports) {
        module.exports = factory();
    }
    // window
    else {
        global['xxx'] = factory();
    }
}(window, function () {
    // return ...;
}));

而且不管 AMD、CMD 还是 CommonJS 都没有统一浏览器和客户端的模块化规范。

由此ECMAScript官方提出一个标准的模块加载方式: ESModule

ES Module

  • export、export default导出
  • import xxx from 'xxx' 或 import()导入
js
// badge.js
export var name = 'xxx';

// 异步导入
if (flag) {
	import('../modules/foo').then(res => console.log(res))
}

// index.tsx
import { name } from './badge.js';

特点

  • 现代浏览器的支持,不支持版本可使用systemjs兼容
  • 静态解析,便于构建工具执行前的优化操作,但不能在条件中引入可以使用动态引入
  • 异步加载并且实时绑定, export导出时会创建模块环境记录(module environment record)
  • Nodejs9+也支持了ES Module 需要将后缀改为.mjs

commonjs和esmodule交互

  1. 通常情况下,CommonJS不能加载ES Module
  • 因为CommonJS是同步加载的,但是ES Module必须经过静态分析等,无法在这个时候执行JavaScript代码;
  • 但是这个并非绝对的,某些平台在实现的时候可以对代码进行针对性的解析,也可能会支持;
  • Node当中是不支持的;
  1. 多数情况下,ES Module可以加载CommonJS
  • ES Module在加载CommonJS时,会将其module.exports导出的内容作为default导出方式来使用;
  • 这个依然需要看具体的实现,比如webpack中是支持的、Node最新的Current版本也是支持的;
  • 但是在最新的LTS版本中就不支持;