Skip to content

Convoluted way of using @svelte/package inside a monorepoΒ #11866

@andresgutgon

Description

@andresgutgon

Describe the problem

πŸ‘‹ Hi, how are you? πŸ˜ƒ I hope everything is all right.

We are developing a monorepo with pnpm workspaces and Turbo repo.

This is our monorepo file structure

/
└── fun-with-monorepo
    β”œβ”€β”€ apps
    β”‚   └── server (SvelteKit main app
    └── packages
        └── svelte-ui

NOTE: apps/server and packages/svelte-ui both are SvelteKit apps.

We have several goals with @fun-with-monorepo/svelte-ui package

  1. We want to have a great dev experience in the monorepo by not having a build
    step inside this package and let our main app in ./apps/server compile the
    .svelte and .ts files in this package. Way faster, feels like developing
    in the app.
  2. We want to have the easiest Storybook setup. And that's by being this package
    another SveltKit app.
  3. We want to use the official way in Svelte to author npm packages. And that's by
    using their packaging npm module called @svelte/package.
  4. We want our package published in npmjs.com

So as you can points (1) and (2) are about our dev experience as monorepo
developers. And points (3) and (4) are about shipping this package as an npmjs
UI library other people can use.

The problem?

Right, the problem. Here starts the funny part. Before 2023 svelte-package was
modifing your package.json and Svelte maintainers felt (I think) that was not a
good idea (and I agree). Rich Harris can explain better than I do. But long story short we want 2 different things while we're developing this package inside the monorepo and when we build it for others to use.

The difference resides in the package.json exports field. For comparison
here is what we want in dev and production build:

Development

// package.json
"exports": {
  ".": {
    "types": "./src/lib/index.ts",
    "import": "./src/lib/index.ts"
  }
}

Production

// package.json
"exports": {
  ".": {
    "types": "./dist/index.d.ts",
    "import": "./dist/index.js"
  }
}

As you can see in dev we point directly to the .src/lib source code because we
know our Storybook or our other SveltKit app (the main app) in ./apps/server are doing
the work of transpiling all the *.{ts,svelte} files. Nice!

On the other hand on production we want to point exports field in
package.json to ./dist folder that was produced by svelte-package.

Describe the proposed solution

No solution, at least nothing I can think that can be applied. But I'm here to listen to alternatives. : )

Alternatives considered

Weeell, as always with code is all about trade-offs. We would't had this problem
if this package was not a SvelteKit app and we didn't use svelte-package. We
could do our own rollup plugin and ship it this way. But I think that by staying with the official
way we're more aligned with svelte ecosystem.

Sooo, what's the solution?

The solution is to put in git the development version of exports pointing to ./src/lib so this way dev experience is fantastic. And when we do the building we modify on runtime the package.json with a prebuid script that you can see in this same folder. This script is used in the scripts field in the package.json like this:

// package.json
"scripts": {
  "build:vite": "vite build",
  "prebuild": "node ./scripts/hack-svelte-package/prebuild.js",
  "buildAndPackage": "pnpm run build:vite && pnpm run package",
  "build": "pnpm run prebuild && pnpm run buildAndPackage",
}

All is perfect for one little thing. After we run pnpm build our package.json gets modified

    "./*": {
-      "types": "./src/lib/ui/*/index.ts",
-      "import": "./src/lib/ui/*/index.ts",
-      "svelte": "./src/lib/ui/*/index.svelte"
+      "types": "./dist/ui/*/index.d.ts",
+      "svelte": "./dist/ui/*/index.js"
     }

And this is bad, very bad. So the solution for this is to check if exports
field contains ./dist in it. It never should. We acomplish that with a custom
eslint rule you can find in ./eslint-local-rules.cjs

image

I hope you enjoyed as much as I did this little fairy tale 😹

Importance

would make my life easier

Additional Information

I'm not sure if the goal of svelte-package is to place nice with monorepos. I'm not asking for an official solution. I'm just adding here my 2cents to see if someone have a better solution of if this solution can help others.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions