Skip to content

nordbeam/vitex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vitex

Hex.pm Hex Docs License Elixir Version Phoenix Version

Phoenix integration for Vite - a fast frontend build tool

FeaturesInstallationUsageConfigurationDocumentation

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?

  • ⚡ Lightning Fast HMR: See your changes instantly without page reloads
  • 🔧 Zero Configuration: Works out of the box with sensible defaults
  • 🎯 Framework Agnostic: Support for React, Vue, Svelte, and vanilla JavaScript
  • 📦 Optimized Builds: Automatic code splitting and tree shaking
  • 🔥 Modern Development: ES modules, TypeScript, JSX, and CSS modules support
  • 🚀 Production Ready: Efficient bundling with rollup under the hood

Features

  • Hot Module Replacement (HMR) - Instant updates without losing state
  • React Fast Refresh - Preserve component state during development
  • TypeScript Support - First-class TypeScript support with zero config
  • Inertia.js Integration - Build SPAs with server-side routing
  • SSR Support - Server-side rendering for better SEO and performance
  • Asset Optimization - Automatic minification, tree-shaking, and code splitting
  • CSS Processing - PostCSS, CSS modules, and preprocessor support
  • Static Asset Handling - Import images, fonts, and other assets
  • Manifest Generation - Production-ready asset manifests with hashing
  • Multiple Entry Points - Support for multiple JavaScript/CSS entry files
  • Phoenix LiveView Compatible - Works seamlessly with LiveView
  • Automatic TLS Detection - Detects and uses local certificates for HTTPS

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

  • --react - Enable React with Fast Refresh support
  • --typescript - Enable TypeScript support
  • --inertia - Enable Inertia.js for building SPAs (automatically includes React)
  • --shadcn - Enable shadcn/ui component library (requires TypeScript and React/Inertia)
  • --base-color - Set shadcn/ui theme color: neutral (default), gray, zinc, stone, or slate
  • --bun - Use Bun as the package manager via the Elixir bun package
  • --tls - Enable automatic TLS certificate detection for HTTPS development
  • --ssr - Enable Server-Side Rendering support

The installer will:

  • Create vite.config.js with appropriate settings
  • Update package.json with necessary dependencies
  • Configure Phoenix watchers for development
  • Update your root layout to use Vite helpers
  • Set up asset files for your chosen configuration

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 -->
<%= Vitex.vite_client() %> <!-- 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 -->
<%= Vitex.react_refresh() %> <!-- Add before your app scripts -->
<%= Vitex.vite_assets("js/app.jsx") %>

Configure Vite for React:

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

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

TypeScript Support

Vitex supports TypeScript out of the box:

// vite.config.js
export default defineConfig({
  plugins: [
    phoenix({
      input: ['js/app.ts', 'css/app.css'],
      // ... 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:

  • TypeScript must be enabled (--typescript)
  • Either React (--react) or Inertia.js (--inertia) must be enabled
# 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:

  • Configure path aliases for component imports
  • Initialize shadcn/ui with your chosen theme
  • Set up CSS variables for theming
  • Create the components directory structure

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:

  • @ - Root JavaScript directory (assets/js)
  • @/components - Component directory
  • @/lib - Utility functions
  • @/hooks - Custom React hooks

Server-Side Rendering (SSR)

Enable SSR in your Vite config:

// vite.config.js
export default defineConfig({
  plugins: [
    phoenix({
      input: ['js/app.js', 'css/app.css'],
      ssr: 'js/ssr.js',
      // ... 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: ['js/app.js', 'css/app.css'],

  // Output directories
  publicDirectory: '../priv/static',
  buildDirectory: 'assets',

  // Development server
  hotFile: '../priv/hot',
  detectTls: true, // Auto-detect local certificates

  // Build options
  manifestPath: '../priv/static/assets/manifest.json',

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

  // SSR
  ssr: 'js/ssr.js', // 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:

  • NODE_ENV - Set to "production" for production builds
  • VITE_PORT - Custom Vite dev server port
  • VITE_DEV_SERVER_KEY - Path to TLS key file
  • VITE_DEV_SERVER_CERT - Path to TLS certificate file

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:

  • Detect your system package manager automatically
  • Configure watchers to use node_modules/.bin/vite
  • Run npm install (or equivalent) during setup

Elixir-Managed Bun (--bun flag)

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

  • Adds {:bun, "~> 1.5", runtime: Mix.env() == :dev} to your dependencies
  • Downloads and manages the bun executable at _build/bun
  • Uses Bun workspaces for Phoenix JS dependencies
  • Configures watchers to use {Bun, :install_and_run, [:dev, []]}
  • Mix tasks handle the bun installation lifecycle

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>
# In prod: <!-- 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: ['js/app.jsx'],
      // ... other options
    })
  ],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom', 'react-router-dom']
        }
      }
    }
  }
})

Tailwind CSS

Vitex works great with Tailwind CSS v4:

// vite.config.js
import tailwindcss from '@tailwindcss/vite'

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

Multiple Entry Points

Support multiple sections of your app:

phoenix({
  input: [
    'js/app.js',
    'js/admin.js',
    'css/app.css',
    'css/admin.css'
  ],
  // ... other options
})

Code Splitting

Vite automatically handles code splitting for dynamic imports:

// Lazy load a component
const AdminPanel = lazy(() => import('./components/AdminPanel'))

// Dynamic import based on route
if (route === '/admin') {
  const { initAdmin } = await import('./admin')
  initAdmin()
}

Troubleshooting

Common Issues

Vite dev server not starting

  • Check that Node.js is installed (v18+ recommended)
  • Ensure assets/package.json exists
  • Run npm install in the assets directory

Assets not loading in production

  • Run mix vitex.build before deploying
  • Check that manifest.json is generated in priv/static/assets/
  • Ensure priv/static is included in your release

HMR not working

  • Verify Vite dev server is running (check priv/hot file)
  • Check browser console for connection errors
  • Ensure Vitex.vite_client() is included in your layout

TypeScript errors

  • Vite doesn't type-check by default (for speed)
  • Use your editor's TypeScript integration
  • Run tsc --noEmit for full type checking

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

About

Vitex brings the power of Vite to Phoenix applications, replacing the traditional esbuild setup with a modern, fast, and feature-rich development experience.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors