Skip to content

fix: clean up migration file packaging using Bun.embeddedFiles#155

Merged
mcowger merged 6 commits intomainfrom
claude/fix-file-packaging-vfs-S3I49
Apr 11, 2026
Merged

fix: clean up migration file packaging using Bun.embeddedFiles#155
mcowger merged 6 commits intomainfrom
claude/fix-file-packaging-vfs-S3I49

Conversation

@mcowgeratsigma
Copy link
Copy Markdown
Collaborator

Summary

PR #146 introduced a fragile approach to embedding drizzle migration files in the compiled binary: SQL files were listed individually as glob patterns in every compile script, --asset-naming="[name].[ext]" was required, and migrate.ts used complex path-regex filtering over Bun.embeddedFiles to find them at runtime. The journal JSON required a completely separate code path (migrations-bundle.ts) because Bun transpiles JSON to JS rather than treating it as a file asset.

This PR replaces all of that with a clean, minimal implementation.

What changed

migrate.ts — complete rewrite of the migration loading path:

  • Bun.embeddedFiles is loaded into a Map<name, blob> once at module load
  • readSql(tag, devDir) does a direct map lookup by ${tag}.sql; if the map is empty (dev/source mode), falls back to Bun.file() at the import.meta.dir-relative filesystem path — no binary-detection logic, just a map miss
  • Journal JSON is imported directly as a standard TS import (works in both modes; Bun bundles it as a JS module)
  • buildMigrations() assembles the MigrationMeta[] array that db.dialect.migrate() expects, bypassing drizzle's folder-based migrate() wrapper entirely — drizzle still owns all tracking-table logic
  • attemptPostgresDuplicateColumnRepair uses the already-loaded MigrationMeta[] instead of re-reading from disk
  • Logs the migration source (embedded vs filesystem) and count at startup so it's always clear which path ran

package.json:

  • Removed make-vfs devDependency (added mid-branch, removed again after finding a better approach)
  • Removed generate:migrations-vfs script
  • Compile scripts restored to clean form: TS entry + frontend assets + SQL globs + --asset-naming="[name].[ext]"
  • No longer need to run a prebuild generation step before compiling

Deleted: migrations-bundle.ts, migrations-vfs-sqlite.ts, migrations-vfs-pg.ts

.gitignore: added root-level .test-db.sqlite entries

Verified

  • 849/849 tests passing
  • Compiled plexus-linux binary started against a fresh SQLite DB and logged:
    Loaded 25 migrations from embedded source
    Migrations completed successfully
    
    confirming Bun.embeddedFiles is the source in compiled mode, not the filesystem fallback.

claude added 6 commits April 11, 2026 00:11
PR #146 embedded SQL migration files as bun binary assets and read them
back via Bun.embeddedFiles at runtime — a brittle approach that required
glob patterns and --asset-naming in every compile script.

This replaces that with make-vfs (seveibar/make-vfs):

- Add `generate:migrations-vfs` script that runs make-vfs on both
  drizzle/migrations (SQLite) and drizzle/migrations_pg (Postgres),
  emitting migrations-vfs-sqlite.ts and migrations-vfs-pg.ts as
  standard TypeScript modules with SQL content as decoded strings.

- migrate.ts now imports those VFS modules plus the _journal.json files
  directly.  getMigrationsDir() writes VFS content to a per-process
  tmpdir and returns the path for drizzle's migrator — no conditional
  Bun.embeddedFiles detection, no BunEmbeddedFile interface.

- Compile scripts (compile:linux/macos/windows, build:bin) revert to
  the pre-PR#146 form: only TS entry point + frontend HTML/JS/CSS.
  No SQL globs, no --asset-naming flag.  The VFS .ts files are bundled
  by Bun as ordinary TypeScript.

- Delete migrations-bundle.ts (no longer needed).

To regenerate the VFS after drizzle-kit generates new migrations, run:
  bun run generate:migrations-vfs

https://claude.ai/code/session_01J5ev59zvC8RqRifVxi2FRL
Previous commits only excluded .test-db.sqlite-shm; add the main DB
file and WAL file so running `bun test` no longer produces uncommitted
changes.

https://claude.ai/code/session_01J5ev59zvC8RqRifVxi2FRL
Instead of writing VFS content to a temp directory so drizzle-orm's
migrate() can read it back from disk, build the MigrationMeta[] array
that drizzle's internal dialect.migrate() expects and call it directly.

drizzle-orm's migrate() is a two-step wrapper:
  1. readMigrationFiles(config) — reads folder → MigrationMeta[]
  2. db.dialect.migrate(migrations, session, config) — applies to DB

migrationsFromVfs() replicates step 1 from VFS strings instead of fs,
then we call step 2 directly. drizzle still owns all migration tracking
logic (__drizzle_migrations table creation, hash recording, skip-if-applied).

Removes: os, fs, path imports; getMigrationsDir(); migrationsDirCache;
tmpdir writes; process exit cleanup handlers.
attemptPostgresDuplicateColumnRepair() now reads from pgVfs/pgJournal
directly instead of from the (now-gone) migrationsPath on disk.

https://claude.ai/code/session_01J5ev59zvC8RqRifVxi2FRL
Remove make-vfs entirely. SQL migration files are embedded in the
compiled binary via glob patterns in the compile scripts (same as
before PR #146), and accessed at runtime via Bun.embeddedFiles.

The key difference from PR #146's implementation:
- No path-matching regex to find files — we use the journal to know
  exactly which filenames to expect, then do a direct Map lookup
- Journal JSON is imported directly (not via embeddedFiles) since Bun
  transpiles JSON to a JS module rather than embedding it as a file asset
- In dev/source mode, embeddedFiles is empty so readSql() falls back to
  Bun.file() at the import.meta.dir-relative filesystem path — no
  conditional binary-detection logic needed, just a Map lookup miss

compile scripts: restore SQL globs + --asset-naming="[name].[ext]",
drop the generate:migrations-vfs prebuild step entirely.

migrate.ts still calls db.dialect.migrate() directly with a built
MigrationMeta[] (no folder-based migrate() wrapper).

845/845 tests passing.

https://claude.ai/code/session_01J5ev59zvC8RqRifVxi2FRL
Log the source of migrations (embedded or filesystem) and the count
so startup output confirms which path was taken.

https://claude.ai/code/session_01J5ev59zvC8RqRifVxi2FRL
@mcowger mcowger merged commit 71bd730 into main Apr 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants