尧图精选

在 Encore.ts 中使用 Turborepo 构建 Monorepo:共享包编译、prebuild 钩子与部署实践

🕒 发布时间:2026/9/15 20:21:26 📁 来源:尧图网络
在 Encore.ts 中使用 Turborepo 构建 Monorepo共享包编译、prebuild 钩子与部署实践【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encoreEncore 是面向现代云原生后端的基础设施平台其 TypeScript 运行时Encore.ts在启动时会解析整个应用的结构。当应用位于 Turborepo monorepo 中并依赖需要先编译的共享包时依赖的构建顺序就成为了关键问题。本指南基于 docs/ts/develop/monorepo/turborepo.md 展开介绍如何在 Turborepo monorepo 中接入 Encore 应用通过 Turborepo 的构建管线解决本地开发时的依赖构建顺序并利用 Encore 的prebuild钩子保证云端部署与 Docker 导出时依赖同样被正确编译。读完本文你将掌握完整的 monorepo 目录规划、turbo.json任务依赖编排、encore.app钩子配置以及本地与部署两条运行路径的完整实战方案。为什么 Encore 应用需要先构建共享包Turborepo 是 JavaScript/TypeScript monorepo 的构建系统build system它通过任务缓存与依赖图调度来加速 monorepo 中的构建流程。在一个典型的 Turborepo monorepo 中packages/目录下往往存放着工具函数库、共享类型定义等需要先由 TypeScript 编译成 JavaScript 的包而apps/下的业务应用则在运行时 import 这些包。对于 Encore 来说这一点尤为关键Encore 在启动时会解析parse你的整个应用包括所有被 import 的源码。如果共享包只有.ts源码而尚未编译产出dist/目录Encore 解析应用时就无法找到这些依赖的编译产物导致启动或构建失败。因此在 monorepo 场景下共享包必须先构建、后运行。围绕这一核心约束需要解决两个场景的依赖构建顺序本地开发Local development在运行encore run之前先用 Turborepo 构建依赖包部署Deployment在通过 Encore Cloud 部署或导出 Docker 镜像时自动执行依赖构建——这一步由 Encore 的prebuild钩子完成。项目结构一个典型的 Turborepo Encore 布局一个典型的混合布局如下apps/backend是 Encore 应用packages/shared是需要编译的共享库my-turborepo/ ├── apps/ │ └── backend/ # Encore application │ ├── encore.app │ ├── package.json │ ├── tsconfig.json │ └── article/ │ └── article.ts ├── packages/ │ └── shared/ # Shared library requiring build │ ├── package.json │ ├── tsconfig.json │ ├── src/ │ │ └── index.ts │ └── dist/ # Built output │ └── index.js ├── turbo.json ├── package.json └── package-lock.json其中packages/shared/dist/是tsc编译后的产物目录它会被package.json的main/exports字段指向是 Encore 应用实际 import 的目标。配置 Turborepo 与共享包根目录 package.jsonnpm workspaces 与 packageManager在 monorepo 根目录的package.json中声明 npm workspaces让npm install一次安装所有子包依赖并声明 Turborepo 脚本{ name: my-turborepo, private: true, packageManager: npm10.0.0, scripts: { build: turbo run build, dev: turbo run dev }, devDependencies: { turbo: ^2.0.0, typescript: ^5.0.0 }, workspaces: [ apps/*, packages/* ] }packageManager字段是 Turborepo 的必需字段用于确定包管理器的版本应调整为你实际安装的 npm 版本可通过npm --version查看。workspaces中的apps/*与packages/*将 Encore 应用与共享包都纳入统一依赖管理。turbo.json用任务依赖编排构建顺序根目录turbo.json定义构建管线。关键在于repo/backend#dev任务必须依赖repo/shared#build从而保证本地执行 dev 任务时共享包已被编译{ $schema: https://turbo.build/schema.json, tasks: { build: { dependsOn: [^build], outputs: [dist/**] }, repo/backend#dev: { dependsOn: [repo/shared#build], cache: false, persistent: true }, dev: { cache: false, persistent: true } } }各任务字段含义build.dependsOn: [^build]每个包的 build 任务依赖其依赖包^表示仅依赖项不含自身的 build自上而下递归构建build.outputs: [dist/**]声明构建产物目录供 Turborepo 远程/本地缓存使用repo/backend#dev.dependsOn: [repo/shared#build]显式指定 backend 的 dev 任务在 shared 包构建完成后才执行cache: falsepersistent: truedev 这类长驻进程任务不缓存、视为常驻任务避免 Turborepo 误以为 dev 已“完成”。共享包编译产物与类型声明共享包需要把 TypeScript 编译为 JavaScript 并暴露产物。packages/shared/package.json{ name: repo/shared, version: 1.0.0, private: true, type: module, main: ./dist/index.js, types: ./dist/index.d.ts, exports: { .: { types: ./dist/index.d.ts, default: ./dist/index.js } }, scripts: { build: tsc }, devDependencies: { typescript: ^5.0.0 } }packages/shared/tsconfig.json负责把src/编译到dist/并生成.d.ts类型声明{ compilerOptions: { outDir: dist, rootDir: src, moduleResolution: bundler, module: ES2022, target: ES2022, declaration: true }, include: [src], exclude: [node_modules, dist] }packages/shared/src/index.ts给出共享类型与工具函数的示例——这些内容在前端与后端之间共享// Types shared between frontend and backend export interface Article { slug: string; title: string; preview: string; } export interface CreateArticleRequest { title: string; content: string; } // Utility functions export function slugify(text: string): string { return text .toLowerCase() .trim() .replace(/[^\w\s-]/g, ) .replace(/\s/g, -); } export function truncate(text: string, maxLength: number): string { if (text.length maxLength) return text; return text.slice(0, maxLength - 3) ...; }配置 Encore 应用encore.app 与 prebuild 钩子Encore 应用需要两处关键配置一是encore.app中使用prebuild钩子在部署期间构建依赖二是package.json中声明对共享包的依赖。创建 Encore 应用在apps/backend目录下执行encore app init --lang ts创建 Encore 应用。从源码看encore app init会生成一个encore.app文件其 lang 字段为typescript参见 cli/cmd/encore/app/initialize.go 中tsEncoreAppData模板以及 pkg/appfile/appfile.go 中LangTS typescript的定义。appfile包还表明encore.app文件pkg/appfile/appfile.go 中的Name encore.app预期位于 Encore 应用的根目录通常是 Git 仓库根目录。encore.appprebuild 钩子在生成的encore.app文件中添加prebuild钩子{ id: generated-id, lang: typescript, build: { hooks: { prebuild: npx turbo build --filterrepo/backend^... } } }prebuild钩子会在通过 Encore Cloud 部署或使用 Encore CLI 导出 Docker 镜像时执行。过滤器repo/backend^...指示 Turborepo 构建repo/backend的全部依赖项其中^排除了 backend 自身只构建它的依赖即repo/shared。从 Encore 源码可以看到钩子机制的实现encore.app的build.hooks配置在 pkg/appfile/appfile.go 中定义为Hooks结构包含PreBuild与PostBuild两个钩子每个Hook既可以写成字符串也可以写成带command与env的对象形式Hook.UnmarshalJSON同时支持两种格式pkg/appfile/appfile.go。在导出 Docker 镜像的流程中cli/daemon/export/export.go 会在解析应用之前检查hooks.PreBuild.IsSet()若已配置则在应用根目录执行该钩子随后才进入bld.Parse解析与编译阶段——这印证了文档中的核心主张prebuild 钩子在 Encore 解析应用前执行保证共享包产物就绪。package.json声明依赖apps/backend/package.json声明对共享包与encore.dev运行时的依赖{ name: repo/backend, version: 1.0.0, type: module, scripts: { dev: encore run }, dependencies: { repo/shared: *, encore.dev: latest } }encore.dev是 Encore.ts 的官方运行时依赖提供encore.dev/api等模块repo/shared通过*直接引用 workspace 内的共享包。在 Encore 服务中导入共享包完成上述配置后即可在 Encore 服务中直接 import 共享包的类型与函数。以apps/backend/article/article.ts为例定义一个对外暴露的 POST APIimport { api } from encore.dev/api; import type { Article, CreateArticleRequest } from repo/shared; import { slugify, truncate } from repo/shared; export const create api( { expose: true, method: POST, path: /article }, async ({ title, content }: CreateArticleRequest): PromiseArticle { return { slug: slugify(title), title: title, preview: truncate(content, 100), }; }, );类型与函数分别通过import type与普通 import 引入create端点接收CreateArticleRequest复用共享包中的slugify与truncate生成文章 slug 与摘要。这里import type只引入类型编译期擦除而slugify、truncate是运行时值需要确保共享包已构建出对应 JS 产物。运行与部署安装依赖从 monorepo 根目录一次性安装所有 workspace含 Turborepo 与各子包的依赖$ npm install本地开发两条路径本地开发需要先构建共享包再运行encore run。可以从 monorepo 根目录手动执行$ npx turbo run build $ cd apps/backend encore run也可以直接使用 Turborepo 的dev任务由turbo.json中的依赖关系自动处理构建顺序$ npx turbo run dev --filterrepo/backendturbo.json中的repo/backend#dev任务配置保证了repo/shared在 backend 的 dev 任务启动前完成构建。注意prebuild钩子只在部署或 Docker 导出时执行不会在本地开发时运行因此本地仍需依赖 Turborepo 自身来完成依赖构建。部署prebuild 钩子自动构建通过 Encore Cloud 部署或导出 Docker 镜像时encore.app中的prebuild钩子会自动运行 Turborepo 构建管线npx turbo build --filterrepo/backend^...确保共享包产物在应用解析前就绪之后 Encore 的 CI/CD 再对应用进行解析与编译打包。部署 monorepo 的根目录配置将 monorepo 部署到 Encore Cloud 时需要在应用设置中把根目录指向 Encore 应用所在目录Settings General Root Directory例如apps/backend让 Encore Cloud 定位到encore.app所在位置。关键要点本地开发运行encore run之前先执行npx turbo run build或使用npx turbo run dev --filterrepo/backend让 Turborepo 自动处理依赖构建顺序prebuild 钩子encore.app中的prebuild钩子在部署Encore Cloud或 Docker 导出时运行而非本地开发时——这是 Encore 在解析应用前完成依赖构建的关键机制对应实现见 cli/daemon/export/export.go 与 pkg/appfile/appfile.goTurborepo 过滤器--filterrepo/backend^...只构建 backend 的依赖^排除包自身避免重复构建 backend 本体共享包必须编译由于 Encore 启动时解析整个应用依赖共享包必须预先编译出dist/产物并确保main/exports/types指向正确的构建输出。同类场景如需了解 Nx 集成方案可参考 docs/ts/develop/monorepo/nx.md。若使用 Go 语言构建 Encore 应用其 monorepo 集成方式与此不同可参见 docs/go/cli/cli-reference.md 了解 CLI 相关能力。【免费下载链接】encoreThe infrastructure platform for the intelligence era项目地址: https://gitcode.com/GitHub_Trending/encor/encore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →