Rich, web-friendly editor UI framework for SolidJS + TypeScript
solid-stage docs local-development.md
3.8 kB · 95 lines
Markdown
at main

Developing against a local checkout #

When you want to hack on solid-stage and your app at the same time — try a fix in the library, see it in your app, repeat — point your app at a local build instead of the published package. This page covers that link: workflow and its gotchas.

Everything here is link-only. Each step is a workaround for the fact that your app and the library are two separate installs. A normal consumer on the published package needs none of it — so when you switch back to the registry dependency, undo all of it (the dedupe, the cast). Each one is flagged below with when to remove it.

1. Point your app at the local package #

Use the link: protocol in your app's package.json, pointing at the package directory (the thing that gets published — it resolves through the same exports map and dist/ as the real package):

// your-app/package.json
{
  "dependencies": {
    "@dolphinspired/solid-stage": "link:../solid-stage/packages/solid-stage"
  }
}

Then pnpm install. (If the two live in one monorepo/workspace, use "workspace:*" instead — same effect, no relative path.)

2. Rebuild the library after every change #

The linked package serves its built dist/, not src/ — byte-for-byte what npm would publish. So source edits don't reach your app until you rebuild:

cd ../solid-stage
pnpm --filter @dolphinspired/solid-stage build   # vite build + tsc (.d.ts)

This is the trap that bites most often: a change to a .tsx or to the CSS / tokens is invisible to your app until you rebuild, because the app consumes dist/style.css and dist/*.js, never the source. If you're iterating fast, pnpm --filter @dolphinspired/solid-stage exec vite build --watch rebuilds the JS + CSS on save — but it skips the .d.ts step, so run the full build again before you trust types.

3. Dedupe Solid in your app's Vite config #

The linked package resolves its own copy of solid-js. Two Solid instances means broken reactivity — signals created in one don't track in the other, and useContext comes back undefined. Force a single copy:

// vite.config.ts
export default defineConfig({
  // link-only — drop it on the published dependency.
  resolve: { dedupe: ['solid-js'] },
});

Your test runner needs the same dedupe for the same reason — see Testing a consumer.

4. If you use the icon preset, cast stageIcons() #

stageIcons() returns a Vite Plugin. Under a link there are two vite copies (your app's, plus the one solid-stage uses to build itself), so the preset's Plugin type and your config's are distinct — their union in plugins[] overflows TypeScript's comparison depth (TS2321: Excessive stack depth comparing types). Cast it to your local Plugin:

import type { Plugin } from 'vite';

export default defineConfig({
  plugins: [solid(), stageIcons() as Plugin], // link-only cast
});

A published consumer has a single vite copy and writes plain stageIcons().

Cheat sheet #

Workaround Why it's needed under a link Remove when
link: (or workspace:*) dependency point the app at the local build back on the published dependency
rebuild dist after every change the linked package serves dist/, not src/ always (inherent to linking)
resolve.dedupe: ['solid-js'] one Solid runtime, not two published dependency (single copy)
stageIcons() as Plugin two vite copies → clashing Plugin types published dependency (single copy)

When you publish or switch back to the registry dependency, delete the dedupe and the cast — on a single install they're no-ops at best and misleading at worst.