AI教你常识之 pnpm + Express + ESM + 静态文件服务

96 阅读3分钟

在上一个项目基础上,升级为支持 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 的 __dirname
  • express.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

✅ 第八步:浏览器访问测试

  1. 👉 http://localhost:3000
    → 自动加载 public/index.html(Express 默认找 index.html)

  2. 👉 http://localhost:3000/index.html
    → 明确访问 HTML

  3. 👉 http://localhost:3000/api/hello
    → 查看 JSON API 响应

  4. 👉 查看开发者工具 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.png
  • http://localhost:3000/uploads/avatar.jpg

🧠 为什么选择 ESM?

  • ✅ 现代 JavaScript 标准
  • ✅ 支持 Tree-shaking(打包优化)
  • ✅ 未来趋势(Node.js 官方推荐)
  • ✅ 与前端框架(React/Vue)统一语法

🎉 恭喜你!

你已成功创建一个:

✅ 使用 ESM 模块(import/export)的 Express 项目
✅ 支持静态文件服务(HTML/CSS/JS/图片)
✅ 使用 pnpm 高效管理依赖
✅ 结构清晰,可扩展性强