Skip to content

Releases: elixir-volt/volt

v0.6.2

15 Apr 18:18

Choose a tag to compare

Bug Fixes

  • Fix infinite label dedup loop when multiple modules import the same
    dependency (e.g. @vue/shared imported by both @vue/runtime-core
    and @vue/reactivity) — the second import no longer triggers label
    disambiguation, preventing mangled paths like dist/dist/@vue/shared_2

v0.6.1

15 Apr 16:42

Choose a tag to compare

Bug Fixes

  • Fix plugin content_type being ignored — when a plugin returned
    {:ok, code, "application/javascript"} for a .vue file, Pipeline
    still ran Vue SFC compilation on the already-compiled JS
  • Fix virtual modules (resolve"virtual:...") failing with
    :enoent — Collector now calls plugin load before File.read
  • Fix duplicate label crash when multiple files share the same basename
    (e.g. a/index.js and b/index.js) — labels are disambiguated with
    parent directory prefix and recursive _2 suffix fallback
  • Thread plugin content_type through Collector so import extraction
    dispatches consistently with Pipeline

v0.6.0

15 Apr 13:40

Choose a tag to compare

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 .map files and append //# sourceMappingURL (default)
  • sourcemap: :hidden — write .map files 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

15 Apr 07:52

Choose a tag to compare

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/2 now 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

Full changelog →

Release 0.4.3

25 Mar 05:38

Choose a tag to compare

Bump quickbeam to 0.8.1, remove stale package.json and vendoring tasks.

Release 0.4.2

24 Mar 20:53

Choose a tag to compare

  • Fix fresh installs for Tailwind support by removing the generated priv/tailwind.js workflow
  • Assemble the Tailwind runtime on first use from the tailwindcss package in the npm_ex cache
  • Bump QuickBEAM to 0.8.0 and npm_ex to 0.5.1

Release 0.4.1

24 Mar 06:54

Choose a tag to compare

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 npx
  • mix volt.js.fmt — format TypeScript assets via npx
  • mix volt.npm — install JS tooling deps via npm_ex
  • mix volt.vendor.tailwind — regenerate priv/tailwind.js from 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, and css fields
  • Standalone CSS entries in the manifest
  • Worker entry groundwork
  • Hardened package resolution with browser/import/default/require and CJS support
  • Dev console forwarding from browser to terminal

v0.4.0

17 Mar 19:00

Choose a tag to compare

Highlights

  • External globalsexternal: ["vue"] generates const { ref, h } = Vue; in IIFE output instead of silently stripping imports
  • CSS @import inlining — LightningCSS Bundler resolves imports recursively with @media/@supports/@layer wrapping
  • HTML entry points<script src="..."> tags extracted via Floki
  • import.meta.glob() — glob patterns expanded at build time via OXC AST
  • Module preloadVolt.Preload.tags/2 generates <link rel="modulepreload"> from manifest
  • Gzip reporting — build output shows 128.4 KB (gzip: 38.6 KB)

Bug Fixes

  • HMR: granular Vue SFC change detection (style-only updates) now works — cache lookup was using mtime 0
  • Vendor URLs: scoped packages (@vue/shared) no longer break on round-trip encoding
  • CSS Pipeline: errors no longer crash, properly returned as {:error, reason}
  • .env parsing: replaced hand-rolled parser with Dotenvy

Internal

  • Tailwind GenServer lazily initializes QuickBEAM runtime on first call
  • Deduplicated content_hash, file_mtime, derive_global_name, extract_vue_imports
  • IIFE injection uses OXC AST instead of string splitting
  • HTML parsing uses Floki instead of regex
  • Dependencies: oxc ~> 0.5.2, vize ~> 0.8.0, floki ~> 0.38, dotenvy ~> 1.1

See CHANGELOG.md for full details.

https://hex.pm/packages/volt/0.4.0

v0.3.0

17 Mar 19:02

Choose a tag to compare

First feature release — code splitting, plugin system, CSS Modules, static assets, JSON imports, env variables, import aliases, external modules, centralized config, multi-entry builds.

See CHANGELOG.md for details.

https://hex.pm/packages/volt/0.3.0