reactjs - Monorepo pnpm com Typescript, conflitos de aliases de caminho entre dependências locais durante a compilação
Eu tenho um PNPM com monorepo TurbeRepo, usei este modelo. Neste monorepo, eu tenho um aplicativo NextJS que utiliza um pacote ui-shared (código compartilhado local, não é realmente um pacote npm).
O ui-shared é feito no estilo de, mas meu pacote é, claro, muito maior. Com um index.ts que exporta todos os componentes e utilitários compartilhados.
ATUALIZAÇÃO: Adicionado um repositório mínimo que reproduz o problema
Ao construir o ui-shared, ele é construído com sucesso, mas quando construo o app Nextjs, a construção do ui-shared falha, pois não consegue resolver o caminho a partir do tsconfig. Então, após alguns dias de investigação, consegui identificar o que acredito ser o problema. Quando o app Next é construído, ele também constrói o ui-shared e isso falha porque o caminho agora é baseado no Nextjs e não na própria biblioteca. Não tenho certeza se esta é a causa, mas acredito que seja, e não sei como posso corrigir isso.
(Pacote compartilhado ou pacote é como vou me referir a ui-shared)
Construir o pacote compartilhado resulta em sucesso
ESM ⚡️ Build success in 112ms
ESM dist/index.mjs 220.69 KB
DTS Build start
DTS ⚡️ Build success in 4792ms
Partes do package.json
"main": "./src/index.ts",
"module": "./dist/index.mjs",
"types": "./src/index.ts",
"scripts": {
"lint": "eslint *.ts*",
"build": "tsup ./src/index.ts --format esm,cjs --dts --external react",
"dev": "tsup ./src/index.ts --format esm,cjs --watch --dts --external react"
},
O tsconfig do pacote
{
"extends": "tsconfig/react-library.json",
"compilerOptions": {
"baseUrl": ".",
"resolveJsonModule": true,
"allowJs": true,
"paths": {
"@/*": ["src/*"]
}
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["dist", "build", "node_modules"]
}
Quando eu executo a construção do aplicativo NextJs, recebo este erro
pnpm build
> @company/[email build /work/company/monorepo/apps/business
> next build
See more info here: https://nextjs.org/docs/messages/invalid-next-config
info - Skipping linting
info - Checking validity of types .Failed to compile.
../../packages/ui-shared/src/components/AnimatedLoadingMedia.tsx:9:23
Type error: Cannot find module '@/utils/clsxm' or its corresponding type declarations.
7 | } from "react";
8 |
> 9 | import { clsxm } from "@/utils/clsxm";
| ^
10 |
11 | type AnimatedLoadingMediaProps = {
12 | isVideo: boolean;
> Build error occurred
Error: Call retries were exceeded
at ChildProcessWorker.initialize (/work/company/monorepo/node_modules/.pnpm/[email _twoewwu6sg7cdf3ao6njtbftne/node_modules/next/dist/compiled/jest-worker/index.js:1:11661)
at ChildProcessWorker._onExit (/work/company/monorepo/node_modules/.pnpm/[email _twoewwu6sg7cdf3ao6njtbftne/node_modules/next/dist/compiled/jest-worker/index.js:1:12599)
at ChildProcess.emit (node:events:390:28)
at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12) {
type: 'WorkerError'
}
Aplicativo Nextjs tsconfig
{
"extends": "tsconfig/nextjs.json",
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"baseUrl": ".",
"module": "esnext",
"paths": {
"@/*": ["src/*"],
"@": ["src"],
"@public/*": ["public/*"],
"@public": ["public"]
},
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
De alguma forma, a biblioteca precisa resolver seus próprios caminhos quando está sendo construída a partir do Next.js. Ou melhor ainda, a biblioteca deveria ser construída em seu próprio escopo e o Next.js só deveria consumir os resultados. Eu não faço ideia se isso pode funcionar assim
Eu tentei adicionar bibliotecas de terceiros, como tsc-alias, tsconfig-path e assim por diante. Mas a compilação continua falhando. Eu tentei ver e de alguma forma impedir o Next.js de construir o pacote, mas não consegui encontrar um jeito.
Resposta #1
Depois de muitas horas batendo minha cabeça contra isso, acabei usando apenas o próprio nome do pacote como um alias.
package.json:
{
"name": "@pkg/utils",
...
}
tsconfig:
"baseUrl": ".",
"paths": {
"@pkg/utils/*": ["./src/*"]
}
// /packages/utils/src/bar.ts
import someSiblingUtil from '@pkg/utils/foo.util';
Não tenho 100% de certeza, mas a razão pela qual acho que isso está funcionando é que, quando o próprio pacote está importando o arquivo, ele usa o alias ./src, mas quando é importado em um aplicativo que depende dele, o aplicativo vê a referência @pkg/utils e simplesmente a lê da mesma forma que importa a dependência do pacote para si mesmo.
