Skip to content

Fix issues #63, #64, #65 and #67 - #66

Merged
dannote merged 5 commits into
masterfrom
issues-63-65
Oct 7, 2026
Merged

dannote merged 5 commits into
masterfrom
issues-63-65

Conversation

@dannote

@dannote dannote commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Three issues, one commit each:

  • Bundling fails on Node built-in subpaths (timers/promises), and the package browser field is not read #64 — Node built-in subpaths such as timers/promises are treated as built-ins, and the package browser field is read: false resolves to an empty module, a path to that path. The builder, dev server and Tailwind resolver share the check (Volt.JS.Specifier.node_builtin?/1).
  • Browser tests launch a browser and bundle their file for every single test, and run one at a time #65 — Browser tests share one browser per run. The Playwright driver supervisor was linked to each test process, so every test started a driver (~240 ms) and launched a browser (~360 ms). Volt.Test.Browser now keeps both under Volt.Supervisor for the run, each test gets a context, the test runtime is installed as a context init script, a file is bundled once for all of its tests (re-bundled when a source's mtime changes), and the generated ExUnit modules are async: true. Ten tests in one file: 1.4 s → 0.43 s in-process; in real mix test runs the saving is larger since the driver no longer restarts per test. A driver crash restarts the tree and the next test launches afresh.
  • Type .vue imports with their real declarations in mix volt.js.check #63 — .vue imports are typed by their generated declarations: new Volt.Plugin.declaration/3 callback, implemented by the Vue plugin with Vize.generate_dts/2; the check sends it to tsgolint as <file>.vue.d.ts, which TypeScript resolves the import to without allowArbitraryExtensions. Verified with the real tsgolint: h(Button, { variant: 'huge' }) is rejected, no *.vue shim needed. A project's own X.vue.d.ts is kept. defineModel still missing from the declaration is a vize matter (Expose vize_canon: virtual TypeScript for templates, and type_check_sfc vize_ex#10).
  • Dev server caches vendored packages as immutable under a URL that does not change when the package does #67 — Vendor URLs change when a package changes. The ?v= hash now covers the pre-bundle's generation (a hash over every package's cache signature, written after each pre-bundle), so a package bundled again gives every vendor module a new URL — one URL for all is deliberate, since the bundles share chunks. Two more things found on the way: after a lockfile change, unchanged app modules were served from the compile cache with the old v= and that URL answered 504 (now the compiled entry records the hash it was compiled with and is recompiled when it's stale); and npm.lock — the lockfile of mix npm.install — wasn't a lockfile to Volt at all. Packages linked from outside node_modules are watched: a change forgets the pre-bundle and reloads the page. Lockfiles are known by size + mtime (the hash runs per vendor import and per cached-module hit; ~0.1 ms).

Fixes #63, fixes #64, fixes #65, fixes #67.

Bundling a package that requires timers/promises failed with
{:not_found, "timers/promises"}: the built-in check only knew top-level
names, and the browser field that maps the specifier to false was not
read. Specifiers a browser field maps to false now resolve to an empty
module, those mapped to a path resolve to that path, and the builder,
dev server and Tailwind resolver share one built-in check that covers
subpaths.

Fixes #64
Every browser test started a Playwright driver and launched a browser for
itself: the driver supervisor was linked to the test process, so it went
away with each test, and starting both again cost more than the test.
Volt.Test.Browser now keeps the driver and the launched browsers for the
run under Volt.Supervisor, installs the test runtime in each context and
bundles a test file once for all of its tests, bundling again only when
one of its source files changes. The generated ExUnit modules for browser
tests are async: true, since contexts isolate the tests from each other.

Fixes #65
mix volt.js.check resolved an import of a .vue file only through a
hand-written declare module "*.vue" shim, so every component had the
same type. The Vue plugin now generates a declaration per checked .vue
file with Vize.generate_dts/2, through a new Volt.Plugin.declaration/3
callback, and the check sends it to tsgolint as <file>.vue.d.ts, which
TypeScript resolves the import to without any compiler option. A
declaration the project wrote under that name is kept.

Fixes #63
Volt.Test.Browser, Volt.Test.Browser.Run and Volt.Test.BrowserRunner were
three names for two things. The process that launches browsers and keeps
the bundled modules is Volt.Test.Browser, and the tree around it and the
Playwright driver is Volt.Test.Browser.Supervisor, as with Volt.Tailwind.
The guides describe what users see; how it is done stays in the changelog
and module docs.
…ackages

The dev server served a package under an immutable URL whose hash did
not cover the package, so one that changed in place kept its URL and
browsers kept their copy. The hash now covers the generation of the
pre-bundle, written after each one as a hash over every package's cache
signature; a compiled application module is compiled again when the hash
it was compiled with is no longer current, which also fixes unchanged
modules importing an outdated URL after a lockfile change; packages
linked from outside node_modules are watched; and npm.lock counts as a
lockfile. Lockfiles are known by size and modification time, since the
hash is computed on every vendor import and cached module.

Fixes #67
@dannote dannote changed the title Fix issues #63, #64 and #65 Fix issues #63, #64, #65 and #67 Oct 7, 2026
@dannote
dannote merged commit 7bc7d99 into master Oct 7, 2026
2 checks passed
@dannote
dannote deleted the issues-63-65 branch October 7, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment