传统代码迁移到 ES Module 综合案例
本节目标
- 用一个「传统全局脚本 → ESM」的综合案例串起前面所有知识
- 掌握迁移步骤:拆分文件 → 加 export/import → 处理依赖方向
- 知道迁移中常见的坑(循环依赖、全局变量)
假设一段「全局脚本」要迁移成 ESM:
// 迁移前:app.js(全局,互相读全局)
var users = []
function addUser(u) { users.push(u) }
function render() { return users.length }
// 迁移后:拆成两个 ESM 模块
// store.mjs
export const users = []
export function addUser(u) { users.push(u) }
// view.mjs
import { users } from './store.mjs'
export function render() { return users.length }
// 入口 main.mjs
import { addUser } from './store.mjs'
import { render } from './view.mjs'
addUser({ name: 'Tom' })
console.log(render()) // 1迁移步骤清单:
- 按「单一职责」把大文件拆成小模块,每个文件只做一件事。
- 给每个模块加
export(要对外暴露的)/import(要用的)。 - 检查依赖方向,尽量单向;发现循环依赖就抽公共逻辑到第三方块。
- 把原全局变量改成「模块内状态」或「显式传入」。
名词解释
迁移(Migration):把「旧形态代码」改成「新形态」且行为不变的过程。模块迁移的核心动作是「拆文件 + 显式 import/export + 理顺依赖方向」。它不是重写功能,而是「换组织方式」,所以务必「每步可运行、可对比」,别一次性大改。
依赖方向理顺:迁移时最常见的坑是「拆完发现 A 引 B、B 引 A」。处理法是「提取公共依赖到第三方块 C」,让 A、B 都只引 C,依赖变单向。这是模块化的通用整容术——遇见环就抽中间层。
课后练习
练习 1:迁移时为什么「每步可运行」比「一次大改」安全?
答案:模块化迁移容易引入「漏 export、循环依赖、作用域错」等隐形 bug。每拆一个文件就跑一次、行为不变,问题能立刻定位到「刚动的那步」;一次大改则出错后无从排查。小步快跑是迁移铁律。
练习 2:原代码用全局变量 CONFIG 存配置,迁移成 ESM 后怎么处理?
答案:三种:① 抽到
config.mjs导出,import使用(推荐,单一来源);② 作为函数参数显式传入(最纯,但调用处要改);③ 挂到模块内export const CONFIG = {...}。避免再当全局——那等于没迁移。
总结
迁移是「把知识变成能力」的练兵场。我的观点:迁移最忌「推倒重来」——你以为在重写,其实在引入新 bug。正确姿势是「小步、可运行、行为对比」:每拆一个模块就验证一次,确保对外行为不变。依赖方向是迁移的灵魂,遇到环就「抽中间层」破环,这招通用。另外,全局变量别「换个地方继续全局」(挂到某个模块再到处 import 同效),要真正变成「显式 import 或显式传参」。迁移的目标不是「用上 ESM 语法」,而是「依赖关系变清晰、可测试、可维护」——语法只是手段。