Using Vite with Remix: Installation, Configuration, and Feature Guide

This guide explains how to add the experimental Vite bundler to a Remix project—installing Vite, creating a vite.config.ts with the Remix plugin, configuring TypeScript, path aliases, CSS imports, Tailwind, vanilla‑extract, MDX, and noting differences such as LiveReload placement, Fast Refresh constraints, and current feature support across environments.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Using Vite with Remix: Installation, Configuration, and Feature Guide

Vite is a powerful, high‑performance, and extensible JavaScript development environment. The Remix team is experimenting with Vite as a replacement for esbuild to improve and extend Remix's bundling capabilities. The current Vite support is experimental and not recommended for production.

Feature support matrix (✅ tested, ❓ untested, ⏳ not yet supported):

Feature

Node

Deno

Cloudflare

Built‑in dev server

Other servers (e.g., Express)

HMR

HDR

MDX routing

Getting Started

To add Vite to an existing Remix project (or a new project created with create‑remix), install Vite as a development dependency: npm install -D vite Create a vite.config.ts file at the project root and add the Remix plugin to the plugins array:

import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [remix()],
});

The Vite plugin accepts a subset of Remix configuration options (e.g., appDirectory, assetsBuildDirectory, ignoredRouteFiles, publicPath, routes, serverBuildPath, serverModuleFormat).

export default defineConfig({
  plugins: [
    remix({
      ignoredRouteFiles: ["**/.*"],
    }),
  ],
});

Run the development server with vite dev and build for production with vite build && vite build --ssr:

vite dev
vite build && vite build --ssr

Differences When Using Vite

Because Vite now handles bundling, some behaviours differ from the Remix compiler. For example, the <LiveReload /> component must appear before <Scripts /> to allow React Fast Refresh to work correctly.

// app/root.tsx
export default function App() {
  return (
    <html lang="en">
      <head>...</head>
      <body>
        <Outlet />
        <ScrollRestoration />
        <LiveReload />
        <Scripts />
      </body>
    </html>
  );
}

New Bundling Features

Vite provides many features and plugins not available in the Remix compiler. Using them may break backward compatibility and should only be done when Vite is the sole bundler.

TypeScript Support

Add vite/client types to a .d.ts file (or replace remix.env.d.ts with env.d.ts):

/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node" />
/// <reference types="vite/client" />

Path Aliases

Remix resolves aliases via tsconfig.json. Vite does not provide aliases by default, but you can install vite-tsconfig-paths to mirror Remix behaviour:

npm install -D vite-tsconfig-paths
import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [remix(), tsconfigPaths()],
});

Alternatively, define aliases directly with Vite's resolve.alias option:

import { fileURLToPath, URL } from "node:url";
import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";

export default defineConfig({
  resolve: {
    alias: {
      "~": fileURLToPath(new URL("./app", import.meta.url)),
    },
  },
  plugins: [remix()],
});

CSS Imports

When importing CSS with Vite, the default export is a string. To obtain a URL, append ?url to the import path.

// import styles from "./styles.css";          // ❌
import styles from "./styles.css?url"; // ✅

If both Vite and the Remix compiler are used, enable legacyCssImports in the Remix Vite plugin to automatically add ?url to CSS imports.

export default defineConfig({
  plugins: [
    remix({
      legacyCssImports: true,
    }),
  ],
});

Tailwind CSS

Install Tailwind and its dependencies, generate the config, and add the Tailwind directives to a CSS file (e.g., tailwind.css).

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init --ts -p
@tailwind base;
@tailwind components;
@tailwind utilities;

Vanilla Extract

Install the official Vite plugin and add it to the Vite config:

npm install -D @vanilla-extract/vite-plugin
import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [remix(), vanillaExtractPlugin()],
});

MDX Support

Use the official MDX Rollup plugin and, if needed, add frontmatter handling via remark-frontmatter and remark-mdx-frontmatter:

npm install -D @mdx-js/rollup remark-frontmatter remark-mdx-frontmatter
import mdx from "@mdx-js/rollup";
import remarkFrontmatter from "remark-frontmatter";
import remarkMdxFrontmatter from "remark-mdx-frontmatter";
import { unstable_vitePlugin as remix } from "@remix-run/dev";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    remix(),
    mdx({
      remarkPlugins: [
        remarkFrontmatter,
        [remarkMdxFrontmatter, { name: "attributes" }],
      ],
    }),
  ],
});

MDX files can export meta, headers, and handle routes via frontmatter, which can be mapped manually:

---
meta:
  - title: My First Post
  - name: description
    content: Isn't this awesome?
headers:
  Cache-Control: no-cache
---

export const meta = frontmatter.meta;
export const headers = frontmatter.headers;

# Hello World

React Fast Refresh Limitations

Fast Refresh does not preserve state for class components or higher‑order components that return classes. Function components must be named, and only component exports are hot‑reloaded; other exports cause a full reload.

// ❌ class component – state not preserved
export class ComponentA extends Component {}

// ✅ named function component
export function ComponentB() {}

Adding or removing hooks (e.g., useLoaderData) may trigger a full reload for the next render.

Acknowledgements

Thanks to the Vite team (Matias Capeletto, Arnaud Barré, Bjorn Lu) and the Remix community for their contributions, as well as inspiration from Astro, SolidStart, and SvelteKit.

References

For the full list of references, see the original document.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptConfigurationbuild toolsViteMDXRemix
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.