记录搭建与使用过程情况
turbo
Turborepo 是什么?
Turborepo 是适用于 JavaScript 和 TypeScript 代码库的高性能构建系统。它专为扩展 monorepos 而设计,同时还能加快单包工作区中的工作流程。
从个人开发人员到世界上最大的企业工程组织,Turborepo 通过轻量级方法优化您需要在存储库中运行的任务,节省了数年的工程时间和数百万美元的计算成本。
这是他的介绍,我只使用了很小一部分,以下记录使用以及打包的dockerfile
我的项目需求,一个web项目,需要实现
mobile版本,但是需要分包发布,不能直接使用一个web包进行动态适配
所以找到了turbo
使用pnpm与pnpm-workspace共同实现
pingx-app/
|
|──apps
| |──web
| └──mobile
|
|──packages
| |──assets-config
| |──eslint-config
| |──redux-store
| |──tailwind-config
| |──theme-config
| |──types-config
| |──typescript-config
| |──ui
| └──utils-config
|──pnpm-workspace.yaml
|
└───turbo.json
assets-config//静态文件导出
eslint-config// 一些eslint设置
redux-store//redux配置
tailwind-config//tailwind配置
theme-config//主题配置
types-config//type与enums配置
typescript-config//typescript配置
ui// 公共UI
utils-config// 请求之类的
turbo官网遇到的问题
packages/ui中样式失效问题本项目使用了tailwindcss, 在主项目web,mobile中都需要进行tailwind引入,以及在ui中也需要进行引入,并且在ui中需要将组件内部使用的css进行导出,然后在主项目中引入
会造成如下原因
1、ui中style需要使用tailwindcss指令进行css生成合并;导致在主项目使用时需要时刻关注是否有新的tailwindcss生成,每次都需要重新运行整个项目
2、每次本地build之后整个node_modules就失效,需要删除重新拉取依赖
docker打包遇到的问题
在
docker中设置变量,有时候会失效,跟node环境有关 在docker中设置的变量只能在dockerfile中生效,无法在项目中生效
jsonweb:
build:
args:
- VERSION=20
- dev=dev
- BASE_DEV_URL=请求地址
- PORT=3002
- CONTAINER_NAME=web
context: .
dockerfile: ./apps/web/Dockerfile
restart: always
container_name: web
ports:
- 3002:3002
以上生效的只有
VERSION,dev,PORT,CONTAINER_NAME在dockerfile中使用时生效
-dev
docker-compose.dev.yml
-test
docker-compose.test.yml
指令运行:
多项目同事打包:
docker-compose -f docker-compose.test.yml -f docker-compose.dev.yml up
dockerfile中变量使用1、VERSION: 指定node版本
2、PORT: 指定node启动后的端口号
3、CONTAINER_NAME: 指定主项目目录名
docker-compose.yml使用需要在项目根目录
需要配置变量,dockerfile文件地址
需要指定端口
jsonversion: "3"
services:
web:
build:
args:
- VERSION=20
- dev=dev
- PORT=3002
- CONTAINER_NAME=web
context: .
dockerfile: ./apps/web/Dockerfile
restart: always
environment:
- dev=dev
container_name: web
ports:
- 3002:3002
# networks:
# - app_network
mobile:
build:
args:
- VERSION=20
- dev=production
- PORT=3003
- CONTAINER_NAME=mobile
context: .
dockerfile: ./apps/mobile/Dockerfile
restart: always
container_name: mobile
ports:
- 3003:3003
# networks:
# - app_network
# Define a network, which allows containers to communicate
# with each other, by using their container name as a hostname
# networks:
# app_network:
# external: true
dockerfile相关代码
dockerfileARG VERSION # Alpine image FROM node:${VERSION}-alpine AS alpine ARG BASE_DEV_URL ARG PORT ARG dev ARG CONTAINER_NAME RUN apk update RUN apk add --no-cache libc6-compat # ENV CONTAINER_NAME=web # Setup pnpm and turbo on the alpine base FROM alpine as base RUN npm install pnpm turbo@2.0.6 --global RUN pnpm config set store-dir ~/.pnpm-store # Prune projects FROM base AS pruner WORKDIR /app COPY . . RUN turbo prune --scope=${CONTAINER_NAME} --docker # Build the project FROM base AS builder WORKDIR /app # Copy lockfile and package.json's of isolated subworkspace COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml COPY --from=pruner /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml COPY --from=pruner /app/out/json/ . # First install the dependencies (as they change less often) RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm install --frozen-lockfile # Copy source code of isolated subworkspace COPY --from=pruner /app/out/full/ . RUN turbo build --filter=${CONTAINER_NAME} # RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm prune --prod --no-optional # RUN rm -rf ./**/*/src # Final image FROM alpine AS runner RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nodejs USER nodejs WORKDIR /app # COPY --from=builder --chown=nodejs:nodejs /app . COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/next.config.mjs . COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/package.json . # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing # COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/.next/standalone/apps/${CONTAINER_NAME} ./ COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/.next/standalone ./ COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/.next/static ./apps/${CONTAINER_NAME}/.next/static COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/public ./apps/${CONTAINER_NAME}/public # RUN rm -rf ./apps/${CONTAINER_NAME}/node_modules WORKDIR /app/apps/${CONTAINER_NAME} # ARG PORT=3002 # ENV dev=production ENV BASE_DEV_URL=${BASE_DEV_URL} ENV dev=${dev} ENV PORT=${PORT} EXPOSE ${PORT} CMD ["node", "server.js"]
在现代前端开发中,如何高效地构建和部署应用程序是一个重要话题。本文将详细分析一个使用多阶段构建的 Dockerfile,该文件专门用于构建和部署基于 Node.js 的应用程序。
dockerfileARG VERSION FROM node:${VERSION}-alpine AS alpine
这个 Dockerfile 从 Alpine Linux 版本的 Node.js 镜像开始。Alpine Linux 以其小巧的体积和安全性著称,非常适合容器化部署。通过使用 ARG 指令,我们可以在构建时灵活指定 Node.js 的版本。
dockerfileRUN apk update RUN apk add --no-cache libc6-compat
这一阶段更新 Alpine 的包管理器并安装 libc6-compat。这是许多 Node.js 应用程序所需的兼容性库。
dockerfileFROM alpine as base RUN npm install pnpm turbo@2.0.6 --global RUN pnpm config set store-dir ~/.pnpm-store
在 base 阶段,我们安装了两个重要工具:
dockerfileFROM base AS pruner WORKDIR /app COPY . . RUN turbo prune --scope=${CONTAINER_NAME} --docker
pruner 阶段使用 Turbo 的 prune 命令来优化工作空间。这个步骤:
dockerfileFROM base AS builder WORKDIR /app COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml COPY --from=pruner /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml COPY --from=pruner /app/out/json/ .
builder 阶段负责实际的应用程序构建:
dockerfileFROM alpine AS runner RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nodejs USER nodejs
runner 阶段创建了最终的生产镜像:
dockerfileCOPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/.next/standalone ./ COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/.next/static ./apps/${CONTAINER_NAME}/.next/static COPY --from=builder --chown=nodejs:nodejs /app/apps/${CONTAINER_NAME}/public ./apps/${CONTAINER_NAME}/public
特别注意文件的所有权设置和目录结构的保持。
dockerfileENV BASE_DEV_URL=${BASE_DEV_URL} ENV dev=${dev} ENV PORT=${PORT} EXPOSE ${PORT} CMD ["node", "server.js"]
最后设置环境变量和暴露端口,使用 node 命令启动服务器。
--no-cache 标志避免 apk 缓存这个 Dockerfile 展示了现代前端应用的容器化最佳实践,特别适用于基于 Next.js 的应用程序部署。
无效内容
BASE_DEV_URL使用无效,可剔除
dev使用无效可剔除
指定turbo版本原因,打包需要依赖于turbo, 不指定时会导致自动升级 使用pnpm install --frozen-lockfile原因,拉取依赖时,要求按照pnpm-lock.yaml进行拉取,确保与本地依赖一致,减少打包问题
dockerfile中作用于项目的变量失效解决方案关键解决
env.mjs: 提供变量
next.config.mjs: 设置变量使用
例子:
BASE_DEV_URL,dev在env.mjs中设置
JavaScriptimport { createEnv } from "@t3-oss/env-nextjs"
import { z } from "zod"
const BASE_DEV_URL = 'http://xxxx.com'
.toString()
.trim()
const dev = "dev".toString().trim()
const apps = "web".toString().trim()
// dev使用代理时设置
const isVpn = "false".toString().trim();
// vpn端口,ip默认: 127.0.0.1
const vpn_port = "4780".toString().trim();
export const env = createEnv({
server: {
ANALYZE: z
.enum(["true", "false"])
.optional()
.transform((value) => value === "true"),
BASE_DEV_URL: z.string().optional(),
dev: z.string().optional(),
isVpn: z.string().optional(),
vpn_port: z.string().optional(),
apps: z.string().optional(),
},
client: {},
runtimeEnv: {
ANALYZE: process.env.ANALYZE,
BASE_DEV_URL,
dev,
isVpn,
vpn_port,
apps
},
})
**next.config.mjs**中设置
jsonenv: {
BASE_DEV_URL: process.env.BASE_DEV_URL || env.BASE_DEV_URL || "",
dev: process.env.dev || env.dev || "",
isVpn: process.env.isVpn || env.isVpn || "false",
vpn_port: process.env.vpn_port || env.vpn_port || "",
apps: process.env.apps || env.apps || "",
}
变量解释
BASE_DEV_URL请求地址
dev:设置当前环境
isVpn: 设置是否需要使用vpn
vpn_port: 设置vpn端口
apps: 设置在某些情况下剔除一些配置的变量标识
json//next.config.mjs的rewrites中
async rewrites() {
return [
{
source: "/api/:path*",
destination: `${process.env.BASE_DEV_URL || env.BASE_DEV_URL}/api/:path*`
}
]
}
在axios封装中使用
TypeScriptconst useRequest: AxiosInstance = axios.create({
xsrfCookieName: 'xsrf-token',
baseURL: processConfig.BASE_DEV_URL,// processConfig是在utils中将process.env变量全写进去的对象
timeout: 20000,
});
...
//判断是否是客户端
if (config.isClient) {
config.baseURL = ''; // 清除baseURL
token = Cookies.get('token') || '';
} else {
//服务端照旧
}
...
if (process.env.isVpn === "true" && process.env.vpn_port) {
config.proxy = {
host: '127.0.0.1',
port: Number(process.env.vpn_port),
protocol: "http"
}
}


本文作者:还是夸张一点
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!