使用Remix+Turborepo时Cloudflare Pages本地开发返回404
将Remix + Cloudflare单应用迁移到Turborepo管理的Remix monorepo架构后,Wrangler无法识别构建后的Remix应用,所有路由均返回404错误。该配置在单仓库环境下可正常运行。
已做排查步骤
- 反复检查package.json配置
- 将构建路径从相对路径改为绝对路径
- 检查tsconfig.json配置
- 检查vite.config.json配置
- 把monorepo构建文件夹内容复制到单应用构建文件夹,反之亦然,两者在单应用环境下均可运行,但monorepo环境下不行
- 删除app文件夹下的node_modules
异常现象
Remix和Vite构建完成后不会生成index.html文件,手动创建空的index.html后,Wrangler能识别并返回该文件。
相关配置文件
apps/alertdown/package.json
{"name": "@alertdown/app","private": true,"sideEffects": false,"type": "module","scripts": {"build": "remix vite:build","dev": "remix vite:dev","lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .","start": "dotenv wrangler pages dev ./build/client","tsc": "tsc --noEmit","extract": "lingui extract --clean","compile": "lingui compile","w:deploy": "npm run build && wrangler pages deploy ./build/client --project-name=alertdown","w:deploy:prod": "npm run build && wrangler pages deploy ./build/client --project-name=alertdown --branch=production","preview": "npm run build && wrangler pages dev ./build/client","build-cf-types": "wrangler types","icons": "npx @svgr/cli --ext=jsx --out-dir app/assets/generated/icons -- app/assets/icons","icons:watch": "npm-watch icons","stripe:webhook": "stripe listen --forward-to http://localhost:5173/api/webhooks/stripe","analyze": "vite-bundle-visualizer"},"dependencies": {"@alertdown/auth": "workspace:*","@alertdown/configs": "workspace:*","@alertdown/core": "workspace:*","@alertdown/db": "workspace:*","@alertdown/email": "workspace:*","@alertdown/storage": "workspace:*","@alertdown/stripe": "workspace:*","@remix-run/node": "^2.11.1","@remix-run/react": "^2.11.1","@remix-run/serve": "^2.11.1","isbot": "^5.1.14","react": "^18.3.1","react-dom": "^18.3.1","vite-plugin-commonjs": "^0.10.1","vite-tsconfig-paths": "^5.0.1"},"devDependencies": {"@remix-run/dev": "^2.11.1","@types/react": "^18.3.3","@types/react-dom": "^18.3.0","@vitejs/plugin-react": "^4.3.1","@vitest/coverage-v8": "^2.0.5","@vitest/ui": "^2.0.5","eslint": "^9.9.0","fluid-tailwind": "^1.0.3","prettier": "^3.3.3","typescript": "~5.5.4","vite": "^5.4.0","vite-plugin-babel-macros": "^1.0.6","vite-plugin-dts": "~4.0.2","vitest": "^2.0.5","wrangler": "^3.71.0"},"engines": {"node": "20"}}
turbo.json
{"$schema": "https://turbo.build/schema.json","tasks": {"build": {"dependsOn": ["^build"],"outputs": ["dist/**"]},"dev": {"cache": false},"preview": {}}}
wrangler.toml
name = "alertdown" compatibility_date = "2024-04-05" compatibility_flags = ["nodejs_compat"]
Vite 配置
import { vitePlugin as remix, cloudflareDevProxyVitePlugin as remixCloudflareDevProxy, } from '@remix-run/dev' import { defineConfig } from 'vite' import tsconfigPaths from 'vite-tsconfig-paths' import { lingui } from '@lingui/vite-plugin' import macrosPlugin from 'vite-plugin-babel-macros' import tailwindcss from 'tailwindcss' import { getLoadContext } from './load-context' export default defineConfig({ plugins: [ remixCloudflareDevProxy({ getLoadContext, }), remix(), tsconfigPaths(), lingui(), macrosPlugin(), ], css: { postcss: { plugins: [tailwindcss()], }, }, })
tsconfig.json
{"$schema": "https://json.schemastore.org/tsconfig","include": ["**/*.ts","**/*.tsx","**/.server/**/*.ts","**/.server/**/*.tsx","**/.client/**/*.ts","**/.client/**/*.tsx"],"compilerOptions": {"lib": ["DOM", "DOM.Iterable", "ES2022"],"isolatedModules": true,"esModuleInterop": true,"jsx": "react-jsx","module": "ESNext","moduleResolution": "Bundler","resolveJsonModule": true,"target": "ES2022","strict": true,"allowJs": true,"forceConsistentCasingInFileNames": true,"baseUrl": ".","experimentalDecorators": true,"emitDecoratorMetadata": true,"noEmit": true,"types": ["@remix-run/cloudflare", "vite/client"],"skipLibCheck": true}}
修正Turbo构建输出配置
当前turbo.json中build任务的outputs只包含dist/**,但Remix Vite构建会生成build/目录(包含client和server文件夹),需要把build/**也加入outputs:"build": { "dependsOn": ["^build"], "outputs": ["dist/**", "build/**"] }确保Turbo正确缓存和传递Remix的构建产物,避免monorepo中构建产物不完整。
指定Wrangler的入口函数路径
在wrangler.toml中明确指定Remix的server入口,解决monorepo环境下Wrangler无法自动识别的问题:[[pages_functions]] entry = "./build/server/entry.server.js"确保路径是相对于app目录的正确位置,对应Remix构建后的server入口文件。
明确Remix Vite构建的输出目录
在vite.config.ts中添加Remix的build配置,强制指定输出目录,避免monorepo路径解析异常:remix({ buildDirectory: "./build", serverBuildPath: "./build/server/entry.server.js", clientBuildDirectory: "./build/client", })保证Remix在指定位置生成完整的server端代码和client资源。
验证monorepo依赖安装正确性
在monorepo根目录执行依赖安装命令,而非仅在app目录安装。通过npm list @alertdown/core验证workspace依赖是否正确链接到本地包。固定Wrangler运行的工作目录
执行Wrangler命令时,确保在app目录下运行,或在命令中添加--cwd apps/alertdown参数,避免Wrangler在根目录找不到正确的构建产物和配置:npm run preview -- --cwd apps/alertdown检查Remix构建产物完整性
确认build/server目录下存在entry.server.js及相关server bundle文件。如果缺失,排查Turbo是否触发了Remix的完整构建流程,或是否有依赖构建失败导致Remix构建中断。
内容的提问来源于stack exchange,提问作者Jose A

