[]previous and next page

Vite plugin

shadow(options) returns a Vite plugin named shadowjs with enforce: "pre", so it runs before Vite's own TypeScript and JSX handling and Vite never sees JSX.

For agentsUpdated

shadow(options) returns a Vite plugin named shadowjs with enforce: "pre", so it runs before Vite's own TypeScript and JSX handling and Vite never sees JSX. The default export and the named export shadow are the same function. See shadow and ShadowPluginOptions.

vite.config.tsts
import shadow from "@shadow-js/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    shadow({
      include: /\.[cm]?[jt]sx$/,
      exclude: /[\\/]node_modules[\\/]/,
      autoReactive: true,
      hmr: true,
      domTests: false,
    }),
  ],
});
Option Type Default Effect
include RegExp /\.[cm]?[jt]sx$/ Files to compile, matched against the module id without its ?query. The default is every .jsx and .tsx file (and the .cjsx, .mjsx, .ctsx, .mtsx spellings).
exclude RegExp /[\\/]node_modules[\\/]/ Files to skip. A file is compiled when it matches include and does not match exclude.
moduleName string the compiler's default Passed to the compiler as moduleName when set.
autoReactive boolean true Passed as autoReactive; only false disables it.
hmr boolean true Allows component-level hot updates during vite dev. See below for when it applies.
dev boolean true under vite dev (command === "serve"), false otherwise Passed as dev. Set it to force development output (component names) in a build, or to disable it in dev.
domTests boolean true when running under Vitest with environment: "happy-dom" or "jsdom", otherwise false Runs the browser build of ShadowJS under Vitest. See Vitest.

How the plugin calls the compiler#

For every module that passes include/exclude, the plugin calls compile with:

Compiler option Value
filename the module id without ?query
generate "ssr" when Vite is transforming for the server (an SSR build, ssrLoadModule), otherwise "dom"
dev the dev option, or true under vite dev
autoReactive options.autoReactive !== false
hmr dev && hmr option !== false && not a test run && not an SSR transform
moduleName the moduleName option, when given

A module without JSX is returned as is (the plugin returns null). A CompileError becomes a Vite error with the file, line and column. Test runs never get HMR: Vite's mode is test or the VITEST environment variable is set.

What the plugin adds to Vite's configuration#

The plugin's config hook contributes these settings:

Setting Value Why
oxc.jsx { runtime: "automatic", importSource: "@shadow-js/web" } Dependency scanning and any file the plugin skips are parsed with the ShadowJS JSX types, never React's.
resolve.dedupe ["@shadow-js/core", "@shadow-js/web"] One copy of each package, so state and context are shared.
optimizeDeps.exclude ["@shadow-js/core", "@shadow-js/web"] The packages are not pre-bundled, so the export conditions below apply.
resolve.conditions ["browser"] Only when domTests is on (Vitest with a DOM).
test.server.deps.inline [/@shadow-js\//] Only when domTests is on: packages Node would load natively go through Vite, so they also see the browser condition.