Reputation: 27
I have a monorepo that is utilizing PNPM workspaces. I've been working in development mode for some time now and following the turborepo guide. It says that my internal packages, the ones that I intend to share can be exported using the main index.ts
file. This has worked all throughout development and has resulted in an amazing development experience but now I wanted to build this and I noticed that when I build my application I get errors because my main application is trying to import TypeScript code.
I knew that I would have to go and change the export in the package but the problem with this is that now I have to actually build my internal package and export JavaScript files and whenever I need to work in development I have to switch it back to the TypeScript files.
Is there any way that I can still have this amazing development experience while also being able to run builds. Please help me I've been struggling with this all day.
Upvotes: 2
Views: 1420
Reputation: 13580
Disclaimer: This example uses npm
and tsx
instead of ts-node
and pnpm
but the concepts apply to both stacks.
I've created an example repo on GitHub: https://github.com/morganney/monorepo-mix.
If you want a full-stack example where a ui
package consumes an internal components
package from a build, check out https://github.com/morganney/busmap.
This is difficult to answer for your specific use case as you have not provided any code, however, I'll provide a general solution not specific to turborepo, but instead general to TypeScript and monorepos.
The solution is primarily based on two things:
tsx
.package.json
with custom user conditions.Project structure:
.
├── package.json
├── tsconfig.json
└── packages/
├── components/
│ ├── src/
│ │ ├── folder/
│ │ │ └── file.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ └── package.json
└── app/
├── src/
│ └── index.ts
├── index.html
├── vite.config.ts
├── tsconfig.json
└── package.json
packages/components/package.json
"name": "components",
"description": "Provides dependencies",
"type": "module",
"main": "dist",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"development": "./src/index.ts",
"default": "./dist/index.js"
}
},
"./package.json": "./package.json"
}
The key here is "development": "./src/index.ts"
.
packages/app/package.json
"name": "app",
"description": "Consumes dependencies.",
"type": "module",
"scripts": {
"dev": "tsx --conditions=development ../../node_modules/.bin/vite",
"dev:build": "vite"
},
"dependencies": {
"components": "^1.0.0"
}
The key here is "dev": "tsx --conditions=development ../../node_modules/.bin/vite"
packages/components/src/index.ts
I don't like barrel files, but just for the example:
export * from './folder/file.js'
packages/components/src/folder/file.ts
export const speak = (words: string[], ending: "." | "?" | "!") =>
`${words.join(" ")}${ending}`;
packages/app/src/index.ts
import { speak } from "components";
console.log(speak(["Hello", "monorepo", "world"], "!"));
const p = document.createElement("p");
const text = document.createTextNode(
speak(["Hello", "monorepo", "world"], "!"),
);
p.appendChild(text);
document.body.appendChild(p);
Now from the workspace root you can run npm run dev -w app
and load http://localhost:5173/ to see Hello monorepo world!
on the page or console logs. You can also edit packages/components/src/folder/file.ts
and see a live update.
If you want to develop against a build of components
, then first run npm run build -w components
and then run npm run dev:build -w app
.
Upvotes: 3