Vitex

[![Hex.pm](https://img.shields.io/hexpm/v/vitex.svg)](https://hex.pm/packages/vitex) [![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/vitex/) [![License](https://img.shields.io/hexpm/l/vitex.svg)](https://github.com/nordbeam/vitex/blob/main/LICENSE) [![Elixir Version](https://img.shields.io/badge/elixir-~%3E%201.14-purple)](https://elixir-lang.org/) [![Phoenix Version](https://img.shields.io/badge/phoenix-~%3E%201.8-orange)](https://www.phoenixframework.org/) **Phoenix integration for Vite - a fast frontend build tool** [Features](#features) • [Installation](#installation) • [Usage](#usage) • [Configuration](#configuration) • [Documentation](#documentation)

Table of Contents

Introduction

Vitex brings the power of Vite to Phoenix applications, replacing the traditional esbuild setup with a modern, fast, and feature-rich development experience. With Vitex, you get instant hot module replacement (HMR), optimized production builds, and seamless integration with modern frontend frameworks.

Why Vitex?

Features

Installation

Automatic Installation (Recommended)

The easiest way to add Vitex to your Phoenix application is using the automatic installer with Igniter:

  1. Use the Igniter installer.
mix archive.install hex igniter_new
  1. Run the installer:
# Basic installation
mix igniter.install vitex

# With React support
mix igniter.install vitex --react

# With TypeScript
mix igniter.install vitex --typescript

# With Inertia.js (includes React)
mix igniter.install vitex --inertia

# With shadcn/ui components (requires TypeScript and React/Inertia)
mix igniter.install vitex --typescript --react --shadcn

# With custom shadcn theme color
mix igniter.install vitex --typescript --react --shadcn --base-color slate

# With Bun as package manager (Elixir-managed)
mix igniter.install vitex --bun

# With all features
mix igniter.install vitex --react --typescript --tls --bun

Installation Options

The installer will:

Manual Installation

If you prefer manual setup or don't want to use Igniter:

  1. Add Vitex to your dependencies:
# mix.exs
def deps do
  [
    {:vitex, "~> 0.2"}
  ]
end
  1. Create assets/vite.config.js:
import { defineConfig } from 'vite'
import phoenix from '../deps/vitex/priv/static/vitex'

export default defineConfig({
  plugins: [
    phoenix({
      input: ['js/app.js', 'css/app.css'],
      publicDirectory: '../priv/static',
      buildDirectory: 'assets',
      hotFile: '../priv/hot',
      manifestPath: '../priv/static/assets/manifest.json',
      refresh: true
    })
  ],
})
  1. Update assets/package.json:
{
  "name": "your_app",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "vite": "^7.0.0"
  }
}
  1. Update your Phoenix configuration:
# config/dev.exs
config :your_app, YourAppWeb.Endpoint,
  watchers: [
    node: ["node_modules/.bin/vite", cd: "assets"]
  ]
  1. Update your root layout:
# lib/your_app_web/components/layouts/root.html.heex
<!DOCTYPE html>
<html>
  <head>
<!-- ... -->

    <%= Vitex.vite_client() %>
    <%= Vitex.vite_assets("css/app.css") %>
    <%= Vitex.vite_assets("js/app.js") %>
  </head>
<!-- ... -->

</html>

Usage

Basic Usage

After installation, Vitex provides helper functions for your templates:

<!-- In your root layout -->

<!-- Enables HMR in development -->

<%= Vitex.vite_assets("js/app.js") %>
<%= Vitex.vite_assets("css/app.css") %>

Start your Phoenix server:

mix phx.server

Vite will automatically start in development mode with HMR enabled.

React Support

To use React with Fast Refresh:

<!-- In your layout -->

<!-- Add before your app scripts -->

<%= Vitex.vite_assets("js/app.jsx") %>

Configure Vite for React:

// vite.config.js
import { defineConfig } from &#39;vite&#39;
import phoenix from &#39;../deps/vitex/priv/static/vitex&#39;
import react from &#39;@vitejs/plugin-react&#39;

export default defineConfig({
  plugins: [
    react(),
    phoenix({
      input: [&#39;js/app.jsx&#39;, &#39;css/app.css&#39;],
      reactRefresh: true,
      // ... other options
    })
  ],
})

TypeScript Support

Vitex supports TypeScript out of the box:

// vite.config.js
export default defineConfig({
  plugins: [
    phoenix({
      input: [&#39;js/app.ts&#39;, &#39;css/app.css&#39;],
      // ... other options
    })
  ],
})

Create assets/tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    "jsx": "react-jsx",
    "strict": true,
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": ["js/**/*"]
}

Inertia.js Integration

For building SPAs with Inertia.js:

# In your controller
def index(conn, _params) do
  conn
  |> assign_prop(:users, Users.list_users())
  |> render_inertia("Users/Index")
end
// assets/js/pages/Users/Index.jsx
import React from 'react'

export default function UsersIndex({ users }) {
  return (
    <div>
      <h1>Users</h1>
      {users.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  )
}

shadcn/ui Integration

Vitex supports shadcn/ui, a collection of reusable components built with Radix UI and Tailwind CSS.

Requirements:

# Install with shadcn/ui
mix igniter.install vitex --typescript --react --shadcn

# With custom theme color (neutral, gray, zinc, stone, slate)
mix igniter.install vitex --typescript --react --shadcn --base-color slate

The installer will:

Adding Components:

cd assets && npx shadcn@latest add button
cd assets && npx shadcn@latest add card dialog

Usage in your React components:

import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"

export default function MyComponent() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Welcome</CardTitle>
      </CardHeader>
      <CardContent>
        <Button variant="outline">Click me</Button>
      </CardContent>
    </Card>
  )
}

Path Aliases:

Server-Side Rendering (SSR)

Enable SSR in your Vite config:

// vite.config.js
export default defineConfig({
  plugins: [
    phoenix({
      input: [&#39;js/app.js&#39;, &#39;css/app.css&#39;],
      ssr: &#39;js/ssr.js&#39;,
      // ... other options
    })
  ],
})

Build your SSR bundle:

mix vitex.ssr.build

Configuration

Vite Configuration

The Phoenix Vite plugin accepts the following options:

phoenix({
  // Entry files (required)
  input: [&#39;js/app.js&#39;, &#39;css/app.css&#39;],

  // Output directories
  publicDirectory: &#39;../priv/static&#39;,
  buildDirectory: &#39;assets&#39;,

  // Development server
  hotFile: &#39;../priv/hot&#39;,
  detectTls: true, // Auto-detect local certificates

  // Build options
  manifestPath: &#39;../priv/static/assets/manifest.json&#39;,

  // Features
  refresh: true, // Enable full page reload on blade/heex changes
  reactRefresh: true, // Enable React Fast Refresh

  // SSR
  ssr: &#39;js/ssr.js&#39;, // SSR entry point
})

TLS/HTTPS Setup

Vitex can automatically detect local TLS certificates. Enable with:

phoenix({
  detectTls: true,
  // ... other options
})

For manual TLS configuration, see the TLS setup guide.

Environment Variables

Vitex respects the following environment variables:

Package Manager Support

Vitex supports two approaches for package management:

System Package Managers (Default)

By default, Vitex detects and uses whatever package manager is installed on your system (npm, pnpm, yarn, or bun). The installer will:

Elixir-Managed Bun (--bun flag)

When you use the --bun flag, Vitex integrates with the Elixir bun package:

Example with Bun:

# Install with Bun support
mix igniter.install vitex --bun

# After installation, these commands are available:
mix bun.install          # Install bun executable
mix bun assets           # Install npm dependencies
mix bun build            # Build assets for production

Mix Tasks

Vitex provides several Mix tasks:

mix vitex

Run Vite commands directly:

mix vitex build         # Build for production
mix vitex dev          # Start dev server
mix vitex preview      # Preview production build

mix vitex.install

Install and configure Vitex (requires Igniter):

mix vitex.install [options]

Options:
  --react        Enable React support
  --typescript   Enable TypeScript
  --inertia      Enable Inertia.js (includes React)
  --shadcn       Enable shadcn/ui components (requires TypeScript + React/Inertia)
  --base-color   Base color for shadcn/ui theme (neutral, gray, zinc, stone, slate)
  --tls          Enable TLS auto-detection
  --ssr          Enable SSR support

mix vitex.build

Build assets for production:

mix vitex.build

mix vitex.ssr.build

Build SSR bundle:

mix vitex.ssr.build

Helper Functions

Vitex provides the following helper functions:

Vitex.vite_assets/1

Generate script/link tags for entries:

Vitex.vite_assets("js/app.js")
# In dev: <script type="module" src="http://localhost:5173/js/app.js"></script>
# In prod: <script type="module" src="/assets/app.123abc.js"></script>

Vitex.vite_assets(["js/app.js", "js/admin.js"])
# Generates tags for multiple entries

Vitex.vite_client/0

Enable HMR in development:

Vitex.vite_client()
# In dev: <script type="module" src="http://localhost:5173/@vite/client"></script>
<!-- nothing -->

Vitex.react_refresh/0

Enable React Fast Refresh:

Vitex.react_refresh()
# Injects React Refresh runtime in development

Vitex.asset_path/1

Get the URL for an asset:

Vitex.asset_path("images/logo.png")
# In dev: "http://localhost:5173/images/logo.png"
# In prod: "/assets/logo.123abc.png"

Vitex.hmr_enabled?/0

Check if HMR is active:

if Vitex.hmr_enabled?() do
  # Development-specific code
end

Common Use Cases

Single Page Applications

Build SPAs with client-side routing:

// vite.config.js
export default defineConfig({
  plugins: [
    phoenix({
      input: [&#39;js/app.jsx&#39;],
      // ... other options
    })
  ],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: [&#39;react&#39;, &#39;react-dom&#39;, &#39;react-router-dom&#39;]
        }
      }
    }
  }
})

Tailwind CSS

Vitex works great with Tailwind CSS v4:

// vite.config.js
import tailwindcss from &#39;@tailwindcss/vite&#39;

export default defineConfig({
  plugins: [
    tailwindcss(),
    phoenix({
      // ... options
    })
  ],
})

Multiple Entry Points

Support multiple sections of your app:

phoenix({
  input: [
    &#39;js/app.js&#39;,
    &#39;js/admin.js&#39;,
    &#39;css/app.css&#39;,
    &#39;css/admin.css&#39;
  ],
  // ... other options
})

Code Splitting

Vite automatically handles code splitting for dynamic imports:

// Lazy load a component
const AdminPanel = lazy(() => import(&#39;./components/AdminPanel&#39;))

// Dynamic import based on route
if (route === &#39;/admin&#39;) {
  const { initAdmin } = await import(&#39;./admin&#39;)
  initAdmin()
}

Troubleshooting

Common Issues

Vite dev server not starting

Assets not loading in production

HMR not working

TypeScript errors

Getting Help

Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone the repo
git clone https://github.com/nordbeam/vitex.git
cd vitex

# Install dependencies
mix deps.get
cd priv/vitex && npm install

# Run tests
mix test

# Build the Vite plugin
cd priv/vitex && npm run build

License

This project is licensed under the MIT License - see the LICENSE file for details.

Copyright (c) 2025 Nordbeam Team


Made with ❤️ by the Nordbeam Team