Releases: elixir-volt/volt
v0.6.5
Added
- Strip TypeScript types from Vue SFCs with
<script lang="ts">after Vize compilation - Resolve
import './types.js'to./types.tswhen the.jsfile doesn't exist (standard TS convention) - Resolve bare specifiers in directories without
package.json(e.g. Phoenix colocated hooks viaresolve_dirs: [Mix.Project.build_path()])
Fixed
- Fix Vue SFC compiler-injected
vueimports being externalized in SSR bundles — bare specifiers introduced by Vize are now resolved via a global fallback map - Fix JSON module imports crashing OXC.bundle —
.jsonlabels are renamed to.json.jsso Rolldown treats theexport defaultwrapper as JavaScript - Skip JSON files in import extraction (they have no imports)
v0.6.4
Added
loadersoption for overriding file type parsing (e.g.loaders: %{".js" => "jsx"}for React projects that use JSX in.jsfiles)- CJS
require()calls are now collected as imports during dependency walking
Fixed
- Fix bare specifier subpath resolution when package has no
exportsfield (e.g.iframe-resizer/js/iframeResizer) — falls back to direct file path instead of returning the package main entry - Skip
.d.tstype declaration imports instead of raising not-found errors - Skip CSS imports (
import './app.css',@fontsource/inter, etc.) during JS bundling — CSS files are no longer collected, resolved, or passed to OXC.bundle - Fix files from
resolve_dirsgetting absolute path labels that break import rewriting
Performance
- Use
OXC.collect_imports(Rust NIF) for 98% of modules instead ofparse+postwalkJSON round-trip — 2.5x faster collection - Use
OXC.transform_many(rayon thread pool) for parallel module compilation — 3x faster on large projects - Livebook (2045 modules): 9s → 1.8s; Plausible Analytics dashboard: 5s → 1.2s
v0.6.3
Bug Fixes
- Fix bundling packages with internal relative imports (reka-ui, @internationalized/date, etc.) — labels now preserve directory structure relative to node_modules, and import rewriting uses per-file specifier maps instead of a global map that conflated identical relative specifiers from different importers
- Fix
CaseClauseErrorwhen an alias resolves to a missing file —NPM.PackageResolver.try_resolvereturning bare:erroris now wrapped into{:error, {:not_found, path}} - Bump
oxcto 0.7.1 (fixesparse/2hitting serde_json recursion limit on large ASTs)
v0.6.2
Bug Fixes
- Fix infinite label dedup loop when multiple modules import the same
dependency (e.g.@vue/sharedimported by both@vue/runtime-core
and@vue/reactivity) — the second import no longer triggers label
disambiguation, preventing mangled paths likedist/dist/@vue/shared_2
v0.6.1
Bug Fixes
- Fix plugin
content_typebeing ignored — when a plugin returned
{:ok, code, "application/javascript"}for a.vuefile, Pipeline
still ran Vue SFC compilation on the already-compiled JS - Fix virtual modules (
resolve→"virtual:...") failing with
:enoent— Collector now calls pluginloadbeforeFile.read - Fix duplicate label crash when multiple files share the same basename
(e.g.a/index.jsandb/index.js) — labels are disambiguated with
parent directory prefix and recursive_2suffix fallback - Thread plugin
content_typethrough Collector so import extraction
dispatches consistently with Pipeline
v0.6.0
Per-Module ESM Dev Server with HMR
The dev server now serves individual ESM modules instead of opaque compiled
files. Each .ts, .vue, .jsx file gets its own URL, and import specifiers
are rewritten so the browser resolves the full module graph natively:
- Relative imports (
./utils) →/assets/utils.ts - Bare imports (
vue) →/@vendor/vue.js(pre-bundled) - Alias imports (
@/utils) → resolved via tsconfig paths or config aliases
Each JS module is injected with an import.meta.hot preamble for granular HMR:
if (import.meta.hot) {
import.meta.hot.dispose(() => clearInterval(timer));
import.meta.hot.accept();
}On file change, the watcher walks the dependency graph upward to find the
nearest import.meta.hot.accept() boundary. Only that module is re-imported
via import("/@assets/Button.tsx?t=123") — no full page reload. Accept
callbacks receive the new module exports. Falls back to location.reload()
when no boundary is found.
TypeScript assets (HMR client, console forwarder, error overlay) are now
compiled to JS via OXC before serving to the browser.
Production Source Maps
Source maps are now fully usable in production builds:
sourcemap: true— write.mapfiles and append//# sourceMappingURL(default)sourcemap: :hidden— write.mapfiles without the URL comment (for Sentry, Datadog)sourcemap: false— no source maps- Chunked builds now generate source maps (previously discarded)
- CLI:
--sourcemap hidden
tsconfig.json Paths
Volt automatically reads compilerOptions.paths from tsconfig.json in the
project root and merges them into aliases. Explicit aliases take precedence.
Supports baseUrl for path resolution.
Manual Chunk Splitting
Control chunk boundaries via config:
config :volt,
chunks: %{
"vendor" => ["vue", "vue-router", "pinia"],
"ui" => ["assets/src/components"]
}Bare specifiers match package names in node_modules. Path patterns match by
directory prefix. Manual chunks work alongside automatic dynamic-import splitting.
Bug Fixes
- Fix alias-imported Vue SFCs silently dropping bare npm imports from the bundle
Internal
- Reorganize internal modules into
Volt.JS.*,Volt.CSS.*,Volt.Dev.*namespaces - Add Playwright browser integration tests (
mix test --include integration)
v0.5.0
Tailwind Plugin & Config Support
Volt now resolves and bundles any Tailwind plugin or config on the fly — no vendored JS needed.
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "./my-plugin.js";
@config "./tailwind.config.js";Local plugins with require() dependency graphs are prebundled automatically via OXC.
Bundling Fix
Fixed a bug where bundling multiple npm packages (e.g. vue + @vue-flow/core) could produce SyntaxError: Identifier has already been declared due to scope collisions in the output.
Other Fixes
Preload.tags/2now correctly generates modulepreload tags from manifests- File watcher detects create/close events, not just modifications
- ETS cache tables are properly supervised (no more startup race)
Dependency Upgrades
oxc ~> 0.7.0,quickbeam ~> 0.10.0,npm ~> 0.5.3
Release 0.4.3
Bump quickbeam to 0.8.1, remove stale package.json and vendoring tasks.
Release 0.4.2
- Fix fresh installs for Tailwind support by removing the generated
priv/tailwind.jsworkflow - Assemble the Tailwind runtime on first use from the
tailwindcsspackage in thenpm_excache - Bump QuickBEAM to 0.8.0 and npm_ex to 0.5.1
Release 0.4.1
TypeScript Assets
Browser JavaScript (HMR client, error overlay, dev console forwarder) moved from inline Elixir heredocs to separate TypeScript files in priv/ts/.
Maintainer Tooling
mix volt.js.check— oxfmt format check and oxlint via npxmix volt.js.fmt— format TypeScript assets via npxmix volt.npm— install JS tooling deps via npm_exmix volt.vendor.tailwind— regeneratepriv/tailwind.jsfrom installed tailwindcss
Tailwind Vendoring
priv/tailwind.js is now generated from the tailwindcss npm package by mix volt.vendor.tailwind instead of being maintained by hand.
Build Improvements
- Structured manifest entries with
file,src,assets, andcssfields - Standalone CSS entries in the manifest
- Worker entry groundwork
- Hardened package resolution with
browser/import/default/requireand CJS support - Dev console forwarding from browser to terminal