You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript AWS栈单仓项目中正确构建、配置并打包共享代码?

如何在TypeScript AWS栈单仓项目中正确构建、配置并打包共享代码?

我来帮你梳理一下这个问题——你遇到的核心是npm workspaces单仓里的共享lib包在AWS Lambda打包和本地调试时的模块解析/编译问题,咱们一步步拆解解决:

一、先搞定共享库(lib)的基础配置

首先得让lib能正确编译成可执行的JS,同时被其他包识别:

  1. 修改packages/lib/package.json:
    {
      "name": "@my-monorepo/lib",
      "version": "1.0.0",
      "main": "./build/index.js",
      "types": "./build/index.d.ts",
      "type": "commonjs",
      "scripts": {
        "build": "tsc"
      }
    }
    
    • 把main指向编译后的JS文件,而非源TS文件
    • 添加types字段让TS能找到类型声明
    • 增加build脚本专门编译lib代码
  2. 修改packages/lib/tsconfig.json,指定编译输出目录:
    {
      "extends": "../../tsconfig.base.json",
      "compilerOptions": {
        "outDir": "./build",
        "rootDir": "./"
      },
      "include": ["**/*"]
    }
    
  3. 在根package.json里加个快捷编译命令:
    {
      "scripts": {
        "build:lib": "npm run build --workspace=@my-monorepo/lib"
      }
    }
    
    运行npm run build:lib就能把lib编译到build目录了。

二、修复CDK Lambda打包的“找不到模块”问题

你之前犯了个小错误:把@my-monorepo/lib加到了nodeModules数组里——这个配置是告诉CDK“这些依赖从npm拉取,不要打包进代码”,但你的lib是本地包,npm仓库根本没有它,所以Lambda运行时自然找不到。

咱们要让esbuild(CDK NodejsFunction默认用的打包工具)把lib的代码直接内联到Lambda的打包文件里:

export class LambdaStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const prototypeLambda = new NodejsFunction(this, "PrototypeLambda", {
      functionName: "prototypeLambda",
      handler: "routesHandler",
      runtime: Runtime.NODEJS_18_X,
      timeout: Duration.minutes(3),
      entry: "../lambda/test.ts",
      // 只保留真正的第三方依赖ulid,移除本地的@my-monorepo/lib
      bundling: {
        externalModules: ["ulid"],
        // 可选:如果esbuild解析@my-monorepo/lib路径有问题,手动指定别名
        esbuildArgs: {
          "--resolve-alias": "@my-monorepo/lib=../lib"
        }
      },
      tsconfig: "../lambda/tsconfig.json"
    });
  }
}

这样配置后,esbuild会把lib的代码直接打包进Lambda的index.js,部署后就不会出现找不到模块的错误了。

三、解决本地Serverless调试的SyntaxError

本地调试时出现Cannot use import statement outside a module,是因为你直接引用了lib的TS源文件(之前lib的main是index.ts),Node.js没法直接执行TS代码。推荐用下面这个方案:

用Serverless esbuild插件自动打包TS

配置Serverless Framework的esbuild插件,让它打包lambda时自动处理TS引用,包括lib的TS文件:
在lambda目录的serverless.yml里添加:

plugins:
  - serverless-esbuild

custom:
  esbuild:
    bundle: true
    minify: false
    sourcemap: true
    platform: node
    target: node18
    external:
      - ulid # 第三方依赖可以用本地node_modules,不用打包
    resolveExtensions: [.ts, .js]

这样esbuild会把lambda代码和lib的TS代码一起编译打包成JS,本地调试时就不会有语法错误了。

如果你不想用插件,也可以先运行npm run build:lib编译lib,再启动Serverless调试——此时lambda会引用编译后的JS文件,Node.js能正常执行。

四、优化TS配置确保跨包类型正常

修改根tsconfig.base.json,添加paths配置让TS能正确解析@my-monorepo/lib的路径:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "declaration": true,
    "sourceMap": true,
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@my-monorepo/lib": ["packages/lib/index.ts"]
    }
  },
  "exclude": ["node_modules"],
  "include": ["packages/**/*"]
}

lambda和web的tsconfig都继承这个base,这样TS编译和类型提示都会正常工作,前端Vite的引用也不会受影响。

关于直接用相对路径的疑问

你提到直接用import { random } from "../lib"能工作,这确实是最简单的方式,但用包名@my-monorepo/lib引用的好处是:

  • 依赖关系更清晰,符合npm包规范
  • 以后lib目录结构变化时,不用修改所有引用的相对路径
  • 方便后续扩展(比如把lib发布到私有npm仓库)

至于bundle大小,只要你在lib里只放类型、验证schema和工具函数,完全不用担心——esbuild会自动tree-shake掉未使用的代码,体积不会有明显增长。

最后总结操作流程

  1. 配置lib的编译脚本和输出路径,确保生成可执行的JS和类型文件
  2. 调整CDK Lambda配置,让esbuild把lib代码内联打包,而非当作外部依赖
  3. 配置Serverless esbuild插件,解决本地调试的TS执行问题
  4. 优化TS paths配置,确保跨包类型解析正确

这样就能彻底解决你遇到的本地调试语法错误、部署后找不到模块的问题,同时保持单仓的规范结构~

备注:内容来源于stack exchange,提问作者Tsar Bomba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 09:44:39