Docker 和 TypeScript 简介:为什么需要容器化
现代 Web 开发离不开确保环境一致性的工具。Docker 已成为打包、交付和运行应用程序的事实标准。与 TypeScript(一种编译为 JavaScript 的强类型语言)结合使用时,容器化为创建可扩展且可靠的服务提供了强大的工具。
为什么要容器化 TypeScript 应用程序?首先,它解决了“在我机器上能运行”的问题。其次,简化了生产环境和 CI/CD 中的部署。第三,允许隔离依赖项和 Node.js 版本。在本文中,我们将探讨如何为 TypeScript 应用程序创建 Docker 镜像,配置多阶段构建,并使用 docker-compose 进行本地开发。
TypeScript 开发者的 Docker 基础
在编写代码之前,我们先回顾一下 Docker 的基本概念:镜像(image)——创建容器的模板;容器(container)——镜像的运行实例;Dockerfile——构建镜像的指令。
对于基于 Node.js 的 TypeScript 应用程序,我们需要:
- Node.js 运行时(通常使用
node:18-alpine或node:20-alpine镜像以获得最小体积) - 安装依赖项(
npm install或yarn install) - 将 TypeScript 编译为 JavaScript(
tsc) - 运行编译后的应用程序
考虑一个简单的 TypeScript 应用程序示例(文件 src/index.ts):
import express from 'express';
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.send('Hello from TypeScript + Docker!');
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
以及 tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
现在,我们为这个应用程序创建 Dockerfile。
为 TypeScript 应用程序创建 Dockerfile
基本的 Dockerfile 可能如下所示:
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
这里使用了 multi-stage build(多阶段构建)。第一阶段(builder)将 TypeScript 编译为 JavaScript,第二阶段(runner)仅包含编译后的代码和运行时依赖项。这减小了最终镜像的大小——TypeScript 源码和开发依赖项不会包含在内。
重要提示:我们使用 npm ci(纯净安装)而不是 npm install,以确保可重现性和速度。
优化 Dockerfile:层缓存
Docker 会缓存每一层(指令)。为了加快构建速度,请先复制不常更改的文件。例如,package.json 和 package-lock.json 在所有源码之前复制,这样代码更改不会导致重新安装依赖项。
此外,可以添加 .dockerignore:
node_modules
dist
.git
*.md
.gitignore
.env
这可以防止不必要的文件进入构建上下文。
用于本地开发的 docker-compose
为了方便本地开发,请使用 docker-compose.yml。它允许应用程序以自动重新加载的方式运行(使用 nodemon 或