{"id":47197520,"url":"https://github.com/elixir-volt/volt","last_synced_at":"2026-04-01T17:21:03.873Z","repository":{"id":344038093,"uuid":"1179507189","full_name":"elixir-volt/volt","owner":"elixir-volt","description":"Elixir-native frontend build tool — dev server, HMR, and production builds for JavaScript, TypeScript, Vue SFCs, and CSS. No Node.js required.","archived":false,"fork":false,"pushed_at":"2026-03-25T05:38:13.000Z","size":472,"stargazers_count":61,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-25T08:31:17.058Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/volt/readme.html","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elixir-volt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-12T05:05:06.000Z","updated_at":"2026-03-25T05:38:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/elixir-volt/volt","commit_stats":null,"previous_names":["elixir-volt/volt"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/elixir-volt/volt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-volt%2Fvolt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-volt%2Fvolt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-volt%2Fvolt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-volt%2Fvolt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elixir-volt","download_url":"https://codeload.github.com/elixir-volt/volt/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-volt%2Fvolt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31018542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-27T03:51:26.850Z","status":"ssl_error","status_checked_at":"2026-03-27T03:51:09.693Z","response_time":164,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-13T12:08:03.532Z","updated_at":"2026-03-27T04:01:45.158Z","avatar_url":"https://github.com/elixir-volt.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Volt ⚡\n\nElixir-native frontend build tool. Dev server with HMR, Tailwind CSS compilation, and production bundling — no Node.js, no esbuild, no Vite.\n\nBuilt on Rust NIFs: [OXC](https://hex.pm/packages/oxc) for JS/TS, [Vize](https://hex.pm/packages/vize) for Vue SFCs + LightningCSS, [Oxide](https://hex.pm/packages/oxide_ex) for Tailwind scanning, and [QuickBEAM](https://hex.pm/packages/quickbeam) for the Tailwind compiler.\n\n## Features\n\n- **No JavaScript app bundler** — Volt builds app assets natively without esbuild or Vite\n- **JS/TS bundling** — parse, transform, minify via OXC (Rust)\n- **Vue SFC support** — single-file components with scoped CSS and Vapor IR\n- **Tailwind CSS v4** — parallel content scanning + full compiler, ~40ms builds\n- **Dev server** — on-demand compilation with mtime caching and error overlays\n- **HMR** — file watcher, WebSocket push, CSS hot-swap without page reload\n- **Production builds** — tree-shaken bundles with content-hashed filenames and manifests\n- **Code splitting** — dynamic `import()` creates async chunks, shared code extracted automatically\n- **CSS Modules** — `.module.css` with LightningCSS-powered scoping\n- **Static assets** — images, fonts, SVGs inlined or hashed\n- **JSON imports** — `import data from './data.json'`\n- **Environment variables** — `.env` files with `import.meta.env.VOLT_*`\n- **Import aliases** — `@/components/Button` → `assets/src/components/Button`\n- **Plugin system** — resolve, load, transform, and render_chunk hooks\n- **External modules** — exclude packages from the bundle (e.g. Phoenix JS deps)\n\n## Installation\n\n```elixir\ndef deps do\n  [{:volt, \"~\u003e 0.4.2\"}]\nend\n```\n\n## Configuration\n\nAll config lives in your standard `config/*.exs` files:\n\n```elixir\n# config/config.exs\nconfig :volt,\n  entry: \"assets/js/app.ts\",\n  target: :es2020,\n  external: ~w(phoenix phoenix_html phoenix_live_view),\n  aliases: %{\n    \"@\" =\u003e \"assets/src\",\n    \"@components\" =\u003e \"assets/src/components\"\n  },\n  plugins: [],\n  tailwind: [\n    css: \"assets/css/app.css\",\n    sources: [\n      %{base: \"lib/\", pattern: \"**/*.{ex,heex}\"},\n      %{base: \"assets/\", pattern: \"**/*.{vue,ts,tsx}\"}\n    ]\n  ]\n\n# config/dev.exs\nconfig :volt, :server,\n  prefix: \"/assets\",\n  watch_dirs: [\"lib/\"]\n```\n\nCLI flags override config values for one-off use.\n\n## Quick Start\n\n### Dev Server\n\nAdd the Plug to your Phoenix endpoint:\n\n```elixir\n# lib/my_app_web/endpoint.ex\nif code_reloading? do\n  plug Volt.DevServer, root: \"assets\"\nend\n```\n\nStart the watcher in `config/dev.exs`:\n\n```elixir\nconfig :my_app, MyAppWeb.Endpoint,\n  watchers: [\n    volt: {Mix.Tasks.Volt.Dev, :run, [~w(--tailwind)]}\n  ]\n```\n\n### Production Build\n\n```bash\nmix volt.build\n```\n\n```\nBuilding Tailwind CSS...\n  app-1a2b3c4d.css  23.9 KB\nBuilt Tailwind in 43ms\nBuilding \"assets/js/app.ts\"...\n  app-5e6f7a8b.js  128.4 KB\n  manifest.json  2 entries\nBuilt in 15ms\n```\n\n## Code Splitting\n\nDynamic imports are automatically split into separate chunks:\n\n```typescript\n// Loaded immediately\nimport { setup } from \"./core\";\n\n// Loaded on demand — becomes a separate chunk\nconst admin = await import(\"./admin\");\n```\n\nProduces:\n\n```\napp-5e6f7a8b.js        42 KB   (entry)\napp-admin-c3d4e5f6.js  86 KB   (async)\nmanifest.json           3 entries\n```\n\nShared modules between chunks are extracted into common chunks to avoid duplication.\n\nDisable with `code_splitting: false` in config or `--no-code-splitting` flag.\n\n## External Modules\n\nExclude packages that the host page already provides:\n\n```elixir\nconfig :volt, external: ~w(phoenix phoenix_html phoenix_live_view)\n```\n\nOr per-build: `mix volt.build --external phoenix --external phoenix_html`\n\n## CSS Modules\n\nFiles ending in `.module.css` get scoped class names via LightningCSS:\n\n```css\n/* button.module.css */\n.primary {\n  color: blue;\n}\n```\n\n```typescript\nimport styles from \"./button.module.css\";\nconsole.log(styles.primary); // \"ewq3O_primary\"\n```\n\n## Static Assets\n\nImages, fonts, and other files are handled automatically:\n\n```typescript\nimport logo from \"./logo.svg\"; // small → data:image/svg+xml;base64,...\nimport photo from \"./photo.jpg\"; // large → /assets/photo-a1b2c3d4.jpg\n```\n\n## JSON Imports\n\n```typescript\nimport config from \"./config.json\";\nconsole.log(config.apiUrl);\n```\n\n## Environment Variables\n\nCreate `.env` files in your project root:\n\n```\nVOLT_API_URL=https://api.example.com\nVOLT_DEBUG=true\n```\n\nAccess in your code:\n\n```typescript\nconsole.log(import.meta.env.VOLT_API_URL);\nconsole.log(import.meta.env.MODE); // \"development\" or \"production\"\nconsole.log(import.meta.env.DEV); // true/false\nconsole.log(import.meta.env.PROD); // true/false\n```\n\nFiles loaded: `.env`, `.env.local`, `.env.{mode}`, `.env.{mode}.local`\n\n## Import Aliases\n\n```elixir\nconfig :volt, aliases: %{\"@\" =\u003e \"assets/src\"}\n```\n\n```typescript\nimport { Button } from \"@/components/Button\";\n// resolves to assets/src/components/Button\n```\n\n## Plugins\n\nExtend the build pipeline with the `Volt.Plugin` behaviour:\n\n```elixir\ndefmodule MyApp.MarkdownPlugin do\n  @behaviour Volt.Plugin\n\n  @impl true\n  def name, do: \"markdown\"\n\n  @impl true\n  def resolve(spec, _importer) do\n    if String.ends_with?(spec, \".md\"), do: {:ok, spec}\n  end\n\n  @impl true\n  def load(path) do\n    if String.ends_with?(path, \".md\") do\n      html = path |\u003e File.read!() |\u003e Earmark.as_html!()\n      {:ok, \"export default #{Jason.encode!(html)};\\n\"}\n    end\n  end\n\n  def resolve(_, _), do: nil\n  def load(_), do: nil\nend\n```\n\n```elixir\nconfig :volt, plugins: [MyApp.MarkdownPlugin]\n```\n\nHooks: `resolve/2`, `load/1`, `transform/2`, `render_chunk/2` — all optional.\n\n## Tailwind CSS\n\nVolt compiles Tailwind CSS natively at runtime and installs the Tailwind compiler into the npm_ex cache on first use.\n\n[Oxide](https://hex.pm/packages/oxide_ex) scans your source files in parallel for candidate class names, then the Tailwind v4 compiler (running in [QuickBEAM](https://hex.pm/packages/quickbeam)) generates the CSS. [LightningCSS](https://hex.pm/packages/vize) handles minification.\n\n```elixir\n# Programmatic API\n{:ok, css} = Volt.Tailwind.build(\n  sources: [\n    %{base: \"lib/\", pattern: \"**/*.{ex,heex}\"},\n    %{base: \"assets/\", pattern: \"**/*.{vue,ts,tsx}\"}\n  ],\n  css: File.read!(\"assets/css/app.css\"),\n  minify: true\n)\n```\n\n### Incremental Rebuilds\n\nIn dev mode, only changed files are re-scanned. If a `.heex` template adds new Tailwind classes, only those new candidates trigger a CSS rebuild — the browser gets a style-only update without a page reload.\n\n## HMR\n\nThe file watcher monitors your asset and template directories:\n\n| File type                                    | Action                                             |\n| -------------------------------------------- | -------------------------------------------------- |\n| `.ts`, `.tsx`, `.js`, `.jsx`, `.vue`, `.css` | Recompile via Pipeline, push update over WebSocket |\n| `.ex`, `.heex`, `.eex`                       | Incremental Tailwind rebuild, CSS hot-swap         |\n| `.vue` (style-only change)                   | CSS hot-swap, no page reload                       |\n\nThe browser client auto-reconnects on disconnect and shows compilation errors as an overlay.\n\n## Mix Tasks\n\n### `mix volt.build`\n\nBuild production assets. Reads from `config :volt`, CLI flags override.\n\n```\n--entry          Entry file (repeatable for multi-page apps)\n--outdir         Output directory\n--target         JS target (e.g. es2020)\n--external       Exclude from bundle (repeatable)\n--no-minify      Skip minification\n--no-sourcemap   Skip source maps\n--no-hash        Stable filenames\n--no-code-splitting  Disable chunk splitting\n--mode           Build mode for env variables\n--resolve-dir    Additional resolution directory (repeatable)\n--tailwind       Build Tailwind CSS\n--tailwind-css   Custom Tailwind input CSS file\n--tailwind-source  Source directory for scanning (repeatable)\n```\n\n### `mix volt.dev`\n\nStart the file watcher for development.\n\n```\n--root           Asset source directory\n--watch-dir      Additional directory to watch (repeatable)\n--tailwind       Enable Tailwind CSS rebuilds\n--tailwind-css   Custom Tailwind input CSS file\n--target         JS target\n```\n\n## Pipeline\n\n`Volt.Pipeline` compiles individual files:\n\n```elixir\n# TypeScript\n{:ok, result} = Volt.Pipeline.compile(\"app.ts\", source)\nresult.code       #=\u003e \"const x = 42;\\n\"\nresult.sourcemap  #=\u003e \"{\\\"version\\\":3, ...}\"\n\n# Vue SFC\n{:ok, result} = Volt.Pipeline.compile(\"App.vue\", source)\nresult.code    #=\u003e compiled JavaScript\nresult.css     #=\u003e scoped CSS (or nil)\n\n# CSS Modules\n{:ok, result} = Volt.Pipeline.compile(\"btn.module.css\", source)\nresult.code    #=\u003e export default {\"btn\":\"ewq3O_btn\"}\nresult.css     #=\u003e .ewq3O_btn { color: red }\n\n# JSON\n{:ok, result} = Volt.Pipeline.compile(\"data.json\", source)\nresult.code    #=\u003e export default {\"key\":\"value\"}\n```\n\n## Stack\n\n```\nvolt\n├── oxc       — JS/TS parse, transform, bundle, minify (Rust NIF)\n├── vize      — Vue SFC compilation, CSS Modules, LightningCSS (Rust NIF)\n├── oxide_ex  — Tailwind content scanning, candidate extraction (Rust NIF)\n├── quickbeam — Tailwind compiler runtime (QuickJS on BEAM)\n└── plug      — HTTP dev server\n```\n\n## Demo\n\nSee the [demo app](https://github.com/elixir-volt/volt/tree/master/examples/demo) for a full Phoenix app using Volt + [PhoenixVapor](https://github.com/dannote/phoenix_vapor) — Vue templates rendered as native LiveView, Tailwind CSS, no JavaScript runtime for SSR.\n\n## License\n\nMIT © 2026 Danila Poyarkov\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-volt%2Fvolt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felixir-volt%2Fvolt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-volt%2Fvolt/lists"}