在上一个项目基础上,升级为支持 ESM 模块 + 静态文件服务的 Express + pnpm 项目。这是现代 Node.js 开发的标准配置,非常适合初学者掌握前沿实践。
🚀 创建支持 ESM + 静态文件服务的 Express + pnpm 项目(完整步骤)
✅ 使用
import/export(ESM)替代require/module.exports(CommonJS)
✅ 支持托管 HTML、CSS、JS、图片等静态资源
✅ 保持 pnpm 高效依赖管理
✅ 第一步:创建项目目录 & 初始化
mkdir express-esm-static
cd express-esm-static
pnpm init
✅ 第二步:配置 package.json 支持 ESM
编辑 package.json,添加 "type": "module":
{
"name": "express-esm-static",
"version": "1.0.0",
"description": "Express with ESM and static file serving",
"type": "module", 👈👈👈 关键!启用 ESM
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
💡
type: "module"告诉 Node.js 使用 ES 模块语法(import/export),而不是 CommonJS(require)
✅ 第三步:安装依赖
pnpm add express
pnpm add -D nodemon
✅ 第四步:创建静态资源目录
mkdir public
在 public/ 目录下创建:
📄 public/index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>我的 Express 静态页面</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<h1>🎉 欢迎来到我的 Express 静态站点!</h1>
<img src="/images/express.png" alt="Express Logo" width="200">
<p>这是通过 Express 静态文件服务加载的页面。</p>
<script src="/js/app.js"></script>
</body>
</html>
📁 创建子目录并添加资源:
mkdir -p public/css public/js public/images
📄 public/css/style.css
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
background-color: #f0f8ff;
}
h1 {
color: #4a90e2;
}
📄 public/js/app.js
console.log('🎉 静态 JS 文件加载成功!');
alert('你好!这是从 public/js/app.js 加载的脚本。');
🖼️ 下载一个 Express 图标(可选)
你可以从官网下载或使用任意图片:
👉 下载地址(右键另存为):expressjs.com/images/expr…
👉 保存为:public/images/express.png
或者用命令行(如果支持 curl):
curl https://expressjs.com/images/express-facebook-share.png -o public/images/express.png
✅ 第五步:创建入口文件 index.js(使用 ESM)
// index.js —— 注意:使用 import,不是 require!
import express from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
// 解决 __dirname 在 ESM 中不可用的问题
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const PORT = process.env.PORT || 3000;
// 👇 静态文件服务:所有 public/ 下的文件可通过根路径访问
app.use(express.static(path.join(__dirname, 'public')));
// 中间件:解析 JSON
app.use(express.json());
// API 路由示例(测试用)
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from Express ESM API!' });
});
// 启动服务器
app.listen(PORT, () => {
console.log(`✅ Server is running at http://localhost:${PORT}`);
console.log(`📂 静态页面访问: http://localhost:${PORT}/index.html`);
console.log(`📡 API 测试: http://localhost:${PORT}/api/hello`);
});
💡 重要说明:
import express from 'express'—— ESM 语法fileURLToPath+path.dirname—— 替代 CommonJS 的__dirnameexpress.static(...)—— 托管静态文件
✅ 第六步:配置脚本(已包含在 package.json 中)
确保你的 package.json 包含:
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
}
✅ 第七步:运行项目
pnpm dev
终端应输出:
✅ Server is running at http://localhost:3000
📂 静态页面访问: http://localhost:3000/index.html
📡 API 测试: http://localhost:3000/api/hello
✅ 第八步:浏览器访问测试
-
👉 http://localhost:3000
→ 自动加载public/index.html(Express 默认找 index.html) -
👉 http://localhost:3000/index.html
→ 明确访问 HTML -
👉 http://localhost:3000/api/hello
→ 查看 JSON API 响应 -
👉 查看开发者工具 Console
→ 应看到🎉 静态 JS 文件加载成功!和弹窗
📂 最终项目结构
express-esm-static/
├── index.js
├── package.json
├── pnpm-lock.yaml
├── .gitignore (可选,内容见下文)
└── public/
├── index.html
├── css/
│ └── style.css
├── js/
│ └── app.js
└── images/
└── express.png
✅(可选)创建 .gitignore
node_modules/
.pnpm-debug.log*
.env
.DS_Store
dist/
🎁 Bonus:自定义 404 页面
在 index.js 最后添加:
// 404 处理中间件
app.use((req, res) => {
res.status(404).send('<h1>404 - 页面走丢了 😢</h1><a href="/">返回首页</a>');
});
现在访问不存在的路径如 http://localhost:3000/xxx 会看到友好提示。
💡 常见问题与说明
❓ 为什么需要 fileURLToPath 和 __dirname?
在 ESM 中,__dirname 不再默认可用。这是 Node.js ESM 的标准做法:
import { fileURLToPath } from 'url';
import path from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
❓ 可以不写 .html 后缀访问页面吗?
可以!Express 的 static 中间件默认会查找 index.html:
👉 访问 http://localhost:3000/ = http://localhost:3000/index.html
❓ 如何托管多个静态目录?
app.use('/assets', express.static(path.join(__dirname, 'public')));
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
然后访问:
http://localhost:3000/assets/images/express.pnghttp://localhost:3000/uploads/avatar.jpg
🧠 为什么选择 ESM?
- ✅ 现代 JavaScript 标准
- ✅ 支持 Tree-shaking(打包优化)
- ✅ 未来趋势(Node.js 官方推荐)
- ✅ 与前端框架(React/Vue)统一语法
🎉 恭喜你!
你已成功创建一个:
✅ 使用 ESM 模块(import/export)的 Express 项目
✅ 支持静态文件服务(HTML/CSS/JS/图片)
✅ 使用 pnpm 高效管理依赖
✅ 结构清晰,可扩展性强