Node.js中CommonJS与ES模块导入方式哪个更优?附Koa项目示例
在Node.js项目中选择CommonJS还是ES模块?
问题描述
在Node.js项目里,到底用const <变量名> = require(<包名>);这种CommonJS导入语法,还是import '<组件名>' from '<包名>';这种ES模块导入语法更合适?能不能结合提供的Koa后端项目代码给出优化示例?
两种语法的对比与选择建议
CommonJS
- Node.js传统模块化方案,无需额外配置即可直接运行
- 支持动态导入(可在代码任意位置根据条件加载模块)
- 适合维护旧项目,或依赖大量仅支持CommonJS的第三方包的场景
ES模块(ESM)
- ECMAScript官方标准模块化方案,与前端模块化语法统一,适配全栈项目
- 支持静态分析,可实现Tree Shaking优化打包体积
- 兼容
import()动态导入、顶层await等新特性 - 需要Node.js 14.13.0+(12.x版本需加
--experimental-modules参数),且需配置项目启用ESM
结论:新项目优先选ES模块,能享受标准语法与新特性;旧项目继续用CommonJS即可,避免不必要的迁移成本。以下是将你的Koa项目改造为ES模块的完整示例。
项目改造为ES模块的示例
1. 修改package.json
添加"type": "module"字段,告知Node.js项目使用ES模块:
{ "name": "backend", "version": "1.0.0", "description": "", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "lkh-krishen", "license": "ISC", "dependencies": { "@koa/router": "^10.1.1", "koa": "^2.13.4", "koa-bodyparser": "^4.3.0", "mongodb": "^4.7.0" } }
2. 修改index.js
替换require为import,本地文件导入需添加扩展名:
import Koa from 'koa'; import bodyParser from 'koa-bodyparser'; import productRoutes from './routes/products.routes.js'; import promotionRoutes from './routes/promotions.routes.js'; const app = new Koa(); app.use(bodyParser()); app.use(productRoutes.routes()).use(productRoutes.allowedMethods()); app.use(promotionRoutes.routes()).use(promotionRoutes.allowedMethods()); app.listen(3000, () => { console.log("Application is running on port 3000"); });
3. 修改dal/index.js
替换require为import,用export default导出MongoDB客户端:
import { MongoClient } from "mongodb"; const client = new MongoClient('mongodb://localhost:27017', { useNewUrlParser: true, useUnifiedTopology: true }); client.connect(err => { if(err){ console.error(err); process.exit(-1); } console.log("Successfully connected to MongoDB"); }); export default client;
4. 修改dal/products.dao.js
替换require为import,用export导出DAO方法:
import client from './index.js'; import { ObjectId } from 'mongodb'; const products = client.db('store').collection('products'); export const save = async ({name, description, qty, price}) => { const result = await products.insertOne({name, description, qty, price}); return await getById(result.insertedId); } export const getAll = async () => { const cursor = await products.find(); return cursor.toArray(); } export const getById = async (id) => { return await products.findOne({_id: ObjectId(id)}); } export const update = async (id, {name, description, qty, price}) => { const result = await products.replaceOne({_id: ObjectId(id)}, {name, description, qty, price}); return result.ops[0]; } export const removeById = async id => { await products.deleteOne({_id: ObjectId(id)}); }
5. 修改api/products.api.js
替换require为import,用export导出API方法:
import { getAll, save, update, getById, removeById } from '../dal/products.dao.js'; export const createProduct = async ({name, description, qty, price}) => { const product = { name, description, qty, price } return await save(product); } export const getProducts = async () => { return await getAll(); } export const getProduct = async id => { return await getById(id); } export const deleteProduct = async id => { return await removeById(id); } export const updateProduct = async (id, {name, description, qty, price}) => { return await update(id, {name, description, qty, price}); }
6. 修改routes/products.routes.js
替换require为import,用export default导出路由,同时修正原代码中的两处错误:
import Router from '@koa/router'; import { createProduct, deleteProduct, updateProduct, getProduct, getProducts } from '../api/products.api.js'; const router = new Router ({ prefix: '/products' }); router.get('/', async ctx => { ctx.body = await getProducts(); }); router.post('/', async ctx => { let product = ctx.request.body; product = await createProduct(product); ctx.response.status = 200; ctx.body = product; }); router.get('/:id', async ctx => { const id = ctx.params.id; ctx.body = await getProduct(id); }); router.delete('/:id', async ctx => { const id = ctx.params.id; // 修正原代码的router.params.id错误 ctx.body = await deleteProduct(id); }); router.put('/:id', async ctx => { const id = ctx.params.id; let product = ctx.request.body; product = await updateProduct(id, product); // 修正原代码漏传id参数的错误 ctx.response.status = 200; ctx.body = product; }); export default router;
内容的提问来源于stack exchange,提问作者Real Zilver
相关产品推荐
相关产品推荐

