Skip to content

Instantly share code, notes, and snippets.

@davo
Last active August 30, 2025 16:11
Show Gist options
  • Save davo/881ad0ea3d651e878705ea67b7d7f958 to your computer and use it in GitHub Desktop.
Save davo/881ad0ea3d651e878705ea67b7d7f958 to your computer and use it in GitHub Desktop.
Local-first pain points

Local-first DX kinda sucks

These are not even all of my core pain points.

Is local-first development is really like this? Or can be attributed simply to a "skill-issue".

I haven't even touched other stuff like:

  • CommonJS vs. ESM is still a predominant issue.
  • ts-config is diabolical.
  • building with different alternative node runtimes like bun, deno or Cloudflare wrangler is challenging.
  • the most stable env. for me has been pnpm + vite.
  • for lib development, what has been more stable and fast for me was this combo bun + vite.
// vite.config.js
// Problem 2: Vite Aggressively Caches The Wrong Stuff
import { defineConfig } from "vite";
export default defineConfig({
cacheDir: "node_modules/.vite",
optimizeDeps: {
force: true, // Supposed to rebuild... doesn't
include: ["@my/local-lib"] // Gets stuck on old version
}
});
// The "fix" that shouldn't be necessary:
// rm -rf node_modules/.vite && vite --force
// Even worse with file: dependencies:
// package.json: "@my/local-lib": "file:../local-lib"
// Vite caches the symlink resolution, not the actual files
// vite.config.js
// Problem 1: Local Package Changes Will Not Hot Reload
import { defineConfig } from "vite";
import path from "path";
export default defineConfig({
resolve: {
alias: {
"@my/local-lib": path.resolve("../local-lib/src/index.js")
}
},
server: {
watch: {
// This SHOULD work but doesn't reliably
ignored: ["!**/node_modules/@my/local-lib/**"]
}
},
optimizeDeps: {
exclude: ["@my/local-lib"], // Prevents pre-bundling
// But also breaks hot reload
}
});
// Reality: Edit local-lib → Nothing happens
// Required: Kill server → Clear node_modules/.vite → Restart → Hope 4 the best.
@gavinmcfarland
Copy link

One of the issues you could be hitting is pnpm caching the module and not Vite.

I often experience a lot of issues when symlinking modules, i.e. pnpm link. What might work better is to set up a workspace in your Vite app. The workspace should then reference the other module using a relative or absolute URL. I can't remember exactly how I set it up but you could experiment. I'll share my workspace file in another comment.

@gavinmcfarland
Copy link

It's something like this. I can't remember why I have plugma listed in both packages and overrides. They might not both be needed.

# vite-app/pnpm-workspace.yml

packages:
  - .
  - /Users/gavinmcfarland/Developer/repos/plugma/packages/plugma

overrides:
  plugma: link:../../../Library/pnpm/global/5/node_modules/plugma

This is a pain though, because you have to work out the relative paths.

The other approach is to store your Vite app in the same folder as your other library.

Something like this:

local-lib/
    pnpm-workspace.yml
    vite-app/  # I usually call it sandbox if it's just for testing

@gavinmcfarland
Copy link

gavinmcfarland commented Aug 30, 2025

And just to comment in general about your post. Yeah, I agree. It's a mindfield and requires so much knowledge across so many different libraries to get things to work. Development is so fragmented. I think the bulk of the issues can be attributed to bundling and compiling. Introducing ESM and TypeScript introduces a lot of overhead, but both are offer nicer developer experiences once you're set up is working for you. These days when I create a project I use AI to do most of that stuff. I understand it a bit better but only through watching AI correct it, and investigating it. One technique I've found that works really well for me, is to tell Cursor to create a test file once it's finished and if the test doesn't pass I ask it to keep investigating the issue until it's fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment