浅析前端4种模块化方案

705 阅读3分钟

浅析前端4种模块化方案

一. 什么是模块化

前端模块化是指一个大型的前端应用程序拆分成多个小模块,每个模块都有自己的功能与职责,可以独立独立开发、测试和部署。目前,前端模块化方案主要有四种:AMDCommonJSES6模块UMD

二. 四种模块化方案介绍

1. AMD(Asynchronous Module Definition)

AMD是一种异步模块定义规范,它允许模块在加载时异步地加载和执行。AMD最初是由RequireJS提出的,它的主要特点是支持异步加载按需加载。AMD模块定义的语法如下:

//1)使用define(function(){})函数定义模块
define(function(){
    //模块代码
})

//2)使用define(['module1','module2'],function(){})定义有依赖的模块
define(['module1','module2'],function(module1,module2) {
    //模块代码
}

其中,第一个参数是一个数组,表示当前模块依赖的其他模块;第二个参数是一个回调函数,表示当前模块的代码。下面是AMD模块的基本使用:

  • 要加载AMD模块加载器,可以在HTML文件中使用<script>标签来引入AMD模块加载器的JS文件。
    1. 下载RequireJS:可以从RequireJS官网
    2. 在HTML文件中引入RequireJS:在HTML文件中使用<script>标签来引入RequireJS的JS文件,例如:
    <script src="path/to/require.js"></script>
    
    其中,path/to/require.js是RequireJS的JS文件路径。
  • 主模块app.js引入其他模块,使用require函数;require.config配置其他模块的路径。下面是该例子的基本结构:

Snipaste_2023-05-08_21-36-12.png

  • 下面的两个模块一个是处理用户信息模块,另一个是用于处理订单信息模块。我们使用AMD模块来定义,并在主模块中异步加载它们。

    1. 定义用户信息模块。在回调函数中,我们定义了一个userInfo对象,并将其作为模块的导出对象。
    //定义userInfo 
    define(function() {
        var userInfo = {
            name: '张三',
            age: 18,
            sex: '男'
        }
        return userInfo;
    })
    
    1. 定义订单信息模块。在回调函数中,我们定义了一个orderInfo对象,并将其作为模块的导出对象。
    //定义orderInfo
    define(function() {
        var orderInfo = {
            id: 1,
            date: '2023-05-08',
            amount: 100
        }
        return orderInfo;
    })
    
  • 最后,我们在主模块中异步加载这两个模块,并使用它们。在主模块中,我们使用require函数来异步加载两个模块,第一个参数是一个数组,表示需要加载的模块;第二个参数是一个回调函数,表示模块加载完成后的处理逻辑。在回调函数中,我们使用导出对象来访问模块的数据。

(function() {
    //require.config配置其他模块的路径。
    require.config({
        //基本路径
        baseUrl: './js/',
        paths: {
            userInfo: './module/userInfo',
            orderInfo: './module/orderInfo'
        }
    });

    //主模块异步加载userInfo和orderInfo
    require(['userInfo', 'orderInfo'], function(userInfo, orderInfo) {
        console.log(`userInfo.name:${userInfo.name}`);
        console.log(`orderInfo.amount:${orderInfo.amount}`);
    })
})()
  • 浏览器控制台的输出结果

Snipaste_2023-05-08_21-46-15.png

2. CommonJS

CommonJS是一种同步模块定义规范,它主要用于服务器端JavaScript,例如:Node.js。CommonJS的主要特点是支持同步加载模块缓存。CommonJS模块的语法如下:

//用于当前模块的导出对象
var module={};
module.exports=module;

//加载其他模块
var module = require('module');

其中,require函数用于加载其他模块,返回模块的导出对象;module.exports用于当前模块的导出对象。

以下是使用CommonJS模块的步骤:

  1. 定义模块:在JS文件中定义userInfo模块,使用module.exports来导出
var userInfo = {
    name: '张三',
    age: 18,
    sex: '男'
}

module.exports = userInfo;
  1. 加载模块:在JS文件中使用require函数来加载模块
var userInfo = require('./userInfo');

console.log(`${userInfo.name}-${userInfo.sex}-${userInfo.age}`)
//输出结果:张三-男-18

3. ES6模块

ES6模块是一种标准化的模块定义规范,它主要用于浏览器端JavaScript。ES6模块化的主要特点是支持静态分析编译时优化。ES6模块定义的语法如下:

import module1 from 'module1';
import module2 from 'module2';

//模块代码
export default {
    message:'Hello World'
}

其中,import语句用于加载其他模块,返回模块的导出对象;export语句用于定义当前模块的导出对象。

下面是如何使用ES6模块定义一个模块:

  1. 第一种暴露方式:分别暴露
//定义模块,分别暴露
export let name = '张三';

export function way() {
    console.log('我可以用这种方式');
}
  1. 第二种暴露方式:统一暴露
//定义模块,统一暴露
let name = '张三';

function way() {
    console.log('我可以用这种方式');
}

export { name, way }
  1. 第三种暴露方式:默认暴露
//定义模块,默认暴露
export default {
    name: '张三',
    way: function() {
        console.log('我可以用这种方式');
    }
}

ES6引入模块数据语法汇总:

  1. 通用导入方式:
import * as m from './src/js/m.js'
console.log(m);
  1. 解构赋值引入:
//引入m.js模块的内容
import {name,way} from './src/js/m.js'
console.log(name);

//如果导入多个文件,变量名字相同,ES6提供了重命名的方法
import {name as username,way} from './src/js/m.js'
console.log(username);

//引入m.js模块内容
import {default as m} from './src/js/m.js'
console.log(m);
  1. 简便引入(只针对默认暴露)
import m from './src/js/m.js'
console.log(m);

4.UMD(Universal Module Definition)

UMD是一种通用模块定义规范,它可以同时支持AMDCommonJS全局变量三种模块定义方式。UMD的主要特点是兼容性好,可以在不同的环境中使用。UMD模块定义的语法如下:

(function(root,factory) {
    if(typeof define === 'function' && define.amd) {
        define(['module1'],['module2'],factory);
    }else if(typeof exports === 'object') {
        module.exports = factory(require('module1'),require('module2'));
    }else {
        root.myModule = factory(root.module1,root.module2);
    }
}(this,function(module1,module2) {
    //模板代码
})); 

其中,第一个参数是一个自执行函数,用于判断当前环境;第二个参数是一个回调函数,表示当前模块的代码。例如,以下代码是如何使用UMD模块:

  1. 定义模块:在JS文件中使用UMD模块定义,例如:
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node.js/CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals (root is window)
    root.myModule = factory(root.jQuery);
  }
}(this, function ($) {
  // 模块代码
}));

  1. 加载模块:在JS文件中使用require函数或define函数来加载模块,例如:
// 加载模块
require(['myModule'], function (myModule) {
  // 使用myModule模块
});

// 或者

define(['myModule'], function (myModule) {
  // 使用myModule模块
});