模块化标准

90 阅读3分钟

JavaScript 模块化完全指南

1. 模块化的演进之路

1.1 为什么需要模块化?

想象你在建造一座大楼:

  • 🏗️ 没有模块化:所有材料堆在一起,工人随意取用

    // 全局变量满天飞
    var userName = "张三";
    var userAge = 18;
    function getUserInfo() { /*...*/ }
    function updateUserInfo() { /*...*/ }
    // 1000个函数和变量...
    
  • 🏢 有了模块化:材料分类存放,按需使用

    // user.js - 用户模块
    export const userService = {
      getUserInfo() { /*...*/ },
      updateUserInfo() { /*...*/ }
    };
    
    // order.js - 订单模块
    import { userService } from './user.js';
    

1.2 模块化解决的问题

问题没有模块化有了模块化
命名冲突window.name 被覆盖模块作用域隔离
依赖管理手动排序 script 标签自动依赖加载
代码组织一个文件数千行按功能拆分模块
代码复用复制粘贴代码导入导出模块

2. 模块化规范的进化史

2.1 原始时代 - 全局变量(2000-2009)

就像原始人用石头打猎:简单但危险

// jQuery 时代的经典写法
(function($) {
    // jQuery 插件代码
    $.fn.myPlugin = function() { /*...*/ };
})(jQuery);

2.2 CommonJS - Node.js 的选择(2009)

像搭积木一样组织代码:

// math.js
exports.add = (a, b) => a + b;

// main.js
const { add } = require('./math');
console.log(add(2, 3)); // 5

特点:

  • ✅ 同步加载,适合服务器
  • ❌ 不适合浏览器(需要等待)

2.3 AMD - 异步模块定义(2011)

就像网上购物:先下单,到货再通知你

// 经典案例:RequireJS
define(['jquery', 'lodash'], function($, _) {
    return {
        init: function() {
            $('.btn').on('click', _.debounce(function() {
                // 处理点击事件
            }, 300));
        }
    };
});

2.4 UMD - 通用模块定义(2011)

像瑞士军刀:一个模块,到处运行

// 著名库 Lodash 的包装方式
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // 浏览器全局变量
        root.myLib = factory(root.jQuery);
    }
}(this, function($) {
    // 实际的模块代码
    return {
        // 公共API
    };
}));

2.5 ES Modules - 现代标准(2015+)

像现代化的城市:规范、高效、可扩展

// 静态导入 - 编译时确定依赖
import React, { useState } from 'react';

// 动态导入 - 按需加载
const loadChart = async () => {
    const { Chart } = await import('echarts');
    // 使用图表
};

3. 真实项目中的模块化最佳实践

3.1 React 项目的模块组织

// 👎 不好的实践
// BigComponent.js - 一个文件包含所有逻辑
export default function BigComponent() {
    // 数百行代码...
}

// 👍 好的实践
// components/User/index.js
export { default } from './User';
// components/User/User.js
export default function User() { /*...*/ }
// components/User/useUser.js
export function useUser() { /*...*/ }
// components/User/styles.js
export const styles = { /*...*/ }

3.2 Vue 项目的模块化

// 👎 不好的实践 - 所有功能写在一个组件里
export default {
    data() { /*...*/ },
    methods: { /* 几十个方法 */ },
    // 几百行代码...
}

// 👍 好的实践 - 按功能拆分
// useUserState.js
export function useUserState() { /*...*/ }
// useUserActions.js
export function useUserActions() { /*...*/ }
// UserList.vue
import { useUserState, useUserActions } from './composables';

4. 模块化工具链

4.1 开发环境

  • Vite: 闪电般的启动速度

    npm create vite@latest my-app -- --template react-ts
    
  • Webpack: 功能全面的打包工具

    // webpack.config.js
    module.exports = {
      entry: './src/index.js',
      output: {
        filename: '[name].[contenthash].js',
        chunkFilename: '[name].[contenthash].js'
      }
    };
    

4.2 生产环境优化

  • 代码分割: 按需加载

    // React.lazy 示例
    const UserDashboard = React.lazy(() => 
      import('./UserDashboard')
    );
    
  • Tree Shaking: 清除死代码

    // 👎 不利于 Tree Shaking
    export default {
      helper1() { /*...*/ },
      helper2() { /*...*/ }
    };
    
    // 👍 有利于 Tree Shaking
    export function helper1() { /*...*/ }
    export function helper2() { /*...*/ }
    

5. 未来趋势

5.1 原生 ESM

<!-- 现代浏览器已支持 -->
<script type="module">
  import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
</script>

5.2 Import Maps

<!-- 更优雅的依赖管理 -->
<script type="importmap">
{
  "imports": {
    "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js",
    "@/utils/": "/src/utils/"
  }
}
</script>

5.3 Package Exports

{
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    },
    "./package.json": "./package.json"
  }
}

6. 总结与建议

选择建议

场景推荐方案原因
新项目ES Modules现代标准,工具支持好
库开发UMD + ESM兼容性好,支持 Tree Shaking
Node.jsESM未来趋势,性能更好

最佳实践清单

  • ✅ 使用 ES Modules 语法
  • ✅ 小而专注的模块
  • ✅ 明确的模块边界
  • ✅ 避免循环依赖
  • ✅ 合理的代码分割
  • ✅ 优化加载性能