@vitejs/plugin-react
Advanced tools
| /* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
| // @ts-ignore --- `@rolldown/plugin-babel` is an optional peer dependency, so this may cause an error | ||
| import type * as pluginBabel from '@rolldown/plugin-babel' | ||
| // @ts-ignore --- `babel-plugin-react-compiler` is an optional peer dependency, so this may cause an error | ||
| import type * as babelPluginReactCompiler from 'babel-plugin-react-compiler' | ||
| // @ts-ignore --- `@rolldown/plugin-babel` is an optional peer dependency, so this may cause an error | ||
| export type RolldownBabelPreset = pluginBabel.RolldownBabelPreset | ||
| // @ts-ignore --- `babel-plugin-react-compiler` is an optional peer dependency, so this may cause an error | ||
| export type ReactCompilerBabelPluginOptions = | ||
| babelPluginReactCompiler.PluginOptions |
+7
-34
@@ -1,4 +0,7 @@ | ||
| import { Plugin, ResolvedConfig } from "vite"; | ||
| import { ParserOptions, TransformOptions } from "@babel/core"; | ||
| import { Plugin } from "vite"; | ||
| import { ReactCompilerBabelPluginOptions, RolldownBabelPreset } from "#optionalTypes"; | ||
| //#region src/reactCompilerPreset.d.ts | ||
| declare const reactCompilerPreset: (options?: Pick<ReactCompilerBabelPluginOptions, "compilationMode" | "target">) => RolldownBabelPreset; | ||
| //#endregion | ||
| //#region src/index.d.ts | ||
@@ -21,3 +24,3 @@ interface Options { | ||
| * Control where the JSX factory is imported from. | ||
| * https://esbuild.github.io/api/#jsx-import-source | ||
| * https://oxc.rs/docs/guide/usage/transformer/jsx.html#import-source | ||
| * @default 'react' | ||
@@ -32,8 +35,2 @@ */ | ||
| /** | ||
| * Babel configuration applied in both dev and prod. | ||
| */ | ||
| babel?: BabelOptions | ((id: string, options: { | ||
| ssr?: boolean; | ||
| }) => BabelOptions); | ||
| /** | ||
| * React Fast Refresh runtime URL prefix. | ||
@@ -47,26 +44,2 @@ * Useful in a module federation context to enable HMR by specifying | ||
| } | ||
| type BabelOptions = Omit<TransformOptions, 'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'>; | ||
| /** | ||
| * The object type used by the `options` passed to plugins with | ||
| * an `api.reactBabel` method. | ||
| */ | ||
| interface ReactBabelOptions extends BabelOptions { | ||
| plugins: Extract<BabelOptions['plugins'], any[]>; | ||
| presets: Extract<BabelOptions['presets'], any[]>; | ||
| overrides: Extract<BabelOptions['overrides'], any[]>; | ||
| parserOpts: ParserOptions & { | ||
| plugins: Extract<ParserOptions['plugins'], any[]>; | ||
| }; | ||
| } | ||
| type ReactBabelHook = (babelConfig: ReactBabelOptions, context: ReactBabelHookContext, config: ResolvedConfig) => void; | ||
| type ReactBabelHookContext = { | ||
| ssr: boolean; | ||
| id: string; | ||
| }; | ||
| type ViteReactPluginApi = { | ||
| /** | ||
| * Manipulate the Babel options of `@vitejs/plugin-react` | ||
| */ | ||
| reactBabel?: ReactBabelHook; | ||
| }; | ||
| declare function viteReact(opts?: Options): Plugin[]; | ||
@@ -78,2 +51,2 @@ declare namespace viteReact { | ||
| //#endregion | ||
| export { BabelOptions, Options, ReactBabelOptions, ViteReactPluginApi, viteReact as default, viteReactForCjs as "module.exports" }; | ||
| export { Options, viteReact as default, viteReactForCjs as "module.exports", reactCompilerPreset }; |
+50
-247
@@ -5,9 +5,6 @@ import { readFileSync } from "node:fs"; | ||
| import { exactRegex, makeIdFiltersToMatchWithQuery } from "@rolldown/pluginutils"; | ||
| import * as vite from "vite"; | ||
| import { createFilter } from "vite"; | ||
| import { reactRefreshWrapperPlugin } from "vite/internal"; | ||
| //#region ../common/refresh-utils.ts | ||
| const runtimePublicPath = "/@react-refresh"; | ||
| const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/; | ||
| const refreshContentRE = /\$RefreshReg\$\(/; | ||
| const preambleCode = `import { injectIntoGlobalHook } from "__BASE__${runtimePublicPath.slice(1)}"; | ||
@@ -18,33 +15,2 @@ injectIntoGlobalHook(window); | ||
| const getPreambleCode = (base) => preambleCode.replace("__BASE__", base); | ||
| function addRefreshWrapper(code, pluginName, id, reactRefreshHost = "") { | ||
| const hasRefresh = refreshContentRE.test(code); | ||
| const onlyReactComp = !hasRefresh && reactCompRE.test(code); | ||
| if (!hasRefresh && !onlyReactComp) return void 0; | ||
| let newCode = code; | ||
| newCode += ` | ||
| import * as RefreshRuntime from "${reactRefreshHost}${runtimePublicPath}"; | ||
| const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; | ||
| if (import.meta.hot && !inWebWorker) { | ||
| if (!window.$RefreshReg$) { | ||
| throw new Error( | ||
| "${pluginName} can't detect preamble. Something is wrong." | ||
| ); | ||
| } | ||
| RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => { | ||
| RefreshRuntime.registerExportsForReactRefresh(${JSON.stringify(id)}, currentExports); | ||
| import.meta.hot.accept((nextExports) => { | ||
| if (!nextExports) return; | ||
| const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(${JSON.stringify(id)}, currentExports, nextExports); | ||
| if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage); | ||
| }); | ||
| }); | ||
| } | ||
| `; | ||
| if (hasRefresh) newCode += `function $RefreshReg$(type, id) { return RefreshRuntime.register(type, ${JSON.stringify(id)} + ' ' + id) } | ||
| function $RefreshSig$() { return RefreshRuntime.createSignatureFunctionForTransform(); } | ||
| `; | ||
| return newCode; | ||
| } | ||
| function virtualPreamblePlugin({ name, isEnabled }) { | ||
@@ -82,30 +48,28 @@ return { | ||
| //#endregion | ||
| //#region src/reactCompilerPreset.ts | ||
| const reactCompilerPreset = (options = {}) => ({ | ||
| preset: () => ({ plugins: [["babel-plugin-react-compiler", options]] }), | ||
| rolldown: { | ||
| filter: { code: options.compilationMode === "annotation" ? /['"]use memo['"]/ : /\b[A-Z]|\buse/ }, | ||
| applyToEnvironmentHook: (env) => env.config.consumer === "client", | ||
| optimizeDeps: { include: options.target === "17" || options.target === "18" ? ["react-compiler-runtime"] : ["react/compiler-runtime"] } | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/index.ts | ||
| const refreshRuntimePath = join(dirname(fileURLToPath(import.meta.url)), "refresh-runtime.js"); | ||
| let babel; | ||
| async function loadBabel() { | ||
| if (!babel) babel = await import("@babel/core"); | ||
| return babel; | ||
| } | ||
| const defaultIncludeRE = /\.[tj]sx?$/; | ||
| const defaultExcludeRE = /\/node_modules\//; | ||
| const tsRE = /\.tsx?$/; | ||
| const compilerAnnotationRE = /['"]use memo['"]/; | ||
| function viteReact(opts = {}) { | ||
| const include = opts.include ?? defaultIncludeRE; | ||
| const exclude = opts.exclude ?? defaultExcludeRE; | ||
| const filter = createFilter(include, exclude); | ||
| const jsxImportSource = opts.jsxImportSource ?? "react"; | ||
| const jsxImportRuntime = `${jsxImportSource}/jsx-runtime`; | ||
| const jsxImportDevRuntime = `${jsxImportSource}/jsx-dev-runtime`; | ||
| const isRolldownVite = "rolldownVersion" in vite; | ||
| let runningInVite = false; | ||
| let isProduction = true; | ||
| let projectRoot = process.cwd(); | ||
| let skipFastRefresh = true; | ||
| let base; | ||
| let isBundledDev = false; | ||
| let runPluginOverrides; | ||
| let staticBabelOptions; | ||
| const importReactRE = /\bimport\s+(?:\*\s+as\s+)?React\b/; | ||
| const viteBabel = { | ||
@@ -115,7 +79,6 @@ name: "vite:react-babel", | ||
| config(_userConfig, { command }) { | ||
| if ("rolldownVersion" in vite) if (opts.jsxRuntime === "classic") return { oxc: { | ||
| if (opts.jsxRuntime === "classic") return { oxc: { | ||
| jsx: { | ||
| runtime: "classic", | ||
| refresh: command === "serve", | ||
| development: false | ||
| refresh: command === "serve" | ||
| }, | ||
@@ -137,10 +100,2 @@ jsxRefreshInclude: makeIdFiltersToMatchWithQuery(include), | ||
| }; | ||
| if (opts.jsxRuntime === "classic") return { esbuild: { jsx: "transform" } }; | ||
| else return { | ||
| esbuild: { | ||
| jsx: "automatic", | ||
| jsxImportSource: opts.jsxImportSource | ||
| }, | ||
| optimizeDeps: { esbuildOptions: { jsx: "automatic" } } | ||
| }; | ||
| }, | ||
@@ -151,13 +106,4 @@ configResolved(config) { | ||
| if (config.experimental.bundledDev) isBundledDev = true; | ||
| projectRoot = config.root; | ||
| isProduction = config.isProduction; | ||
| skipFastRefresh = isProduction || config.command === "build" || config.server.hmr === false; | ||
| const hooks = config.plugins.map((plugin) => plugin.api?.reactBabel).filter(defined); | ||
| if (hooks.length > 0) runPluginOverrides = (babelOptions, context) => { | ||
| hooks.forEach((hook) => hook(babelOptions, context, config)); | ||
| }; | ||
| else if (typeof opts.babel !== "function") { | ||
| staticBabelOptions = createBabelOptions(opts.babel); | ||
| if ((isRolldownVite || skipFastRefresh) && canSkipBabel(staticBabelOptions.plugins, staticBabelOptions) && (opts.jsxRuntime === "classic" ? isProduction : true)) delete viteBabel.transform; | ||
| } | ||
| }, | ||
@@ -173,72 +119,2 @@ options(options) { | ||
| } | ||
| }, | ||
| transform: { | ||
| filter: { id: { | ||
| include: makeIdFiltersToMatchWithQuery(include), | ||
| exclude: makeIdFiltersToMatchWithQuery(exclude) | ||
| } }, | ||
| async handler(code, id, options) { | ||
| const [filepath] = id.split("?"); | ||
| if (!filter(filepath)) return; | ||
| const ssr = options?.ssr === true; | ||
| const babelOptions = (() => { | ||
| if (staticBabelOptions) return staticBabelOptions; | ||
| const newBabelOptions = createBabelOptions(typeof opts.babel === "function" ? opts.babel(id, { ssr }) : opts.babel); | ||
| runPluginOverrides?.(newBabelOptions, { | ||
| id, | ||
| ssr | ||
| }); | ||
| return newBabelOptions; | ||
| })(); | ||
| const plugins = [...babelOptions.plugins]; | ||
| let reactCompilerPlugin = getReactCompilerPlugin(plugins); | ||
| if (reactCompilerPlugin && ssr) { | ||
| plugins.splice(plugins.indexOf(reactCompilerPlugin), 1); | ||
| reactCompilerPlugin = void 0; | ||
| } | ||
| if (Array.isArray(reactCompilerPlugin) && reactCompilerPlugin[1]?.compilationMode === "annotation" && !compilerAnnotationRE.test(code)) { | ||
| plugins.splice(plugins.indexOf(reactCompilerPlugin), 1); | ||
| reactCompilerPlugin = void 0; | ||
| } | ||
| const isJSX = filepath.endsWith("x"); | ||
| const useFastRefresh = !(isRolldownVite || skipFastRefresh) && !ssr && (isJSX || (opts.jsxRuntime === "classic" ? importReactRE.test(code) : code.includes(jsxImportDevRuntime) || code.includes(jsxImportRuntime))); | ||
| if (useFastRefresh) plugins.push([await loadPlugin("react-refresh/babel"), { skipEnvCheck: true }]); | ||
| if (opts.jsxRuntime === "classic" && isJSX) { | ||
| if (!isProduction) plugins.push(await loadPlugin("@babel/plugin-transform-react-jsx-self"), await loadPlugin("@babel/plugin-transform-react-jsx-source")); | ||
| } | ||
| if (canSkipBabel(plugins, babelOptions)) return; | ||
| const parserPlugins = [...babelOptions.parserOpts.plugins]; | ||
| if (!filepath.endsWith(".ts")) parserPlugins.push("jsx"); | ||
| if (tsRE.test(filepath)) parserPlugins.push("typescript"); | ||
| const result = await (await loadBabel()).transformAsync(code, { | ||
| ...babelOptions, | ||
| root: projectRoot, | ||
| filename: id, | ||
| sourceFileName: filepath, | ||
| retainLines: reactCompilerPlugin ? false : !isProduction && isJSX && opts.jsxRuntime !== "classic", | ||
| parserOpts: { | ||
| ...babelOptions.parserOpts, | ||
| sourceType: "module", | ||
| allowAwaitOutsideFunction: true, | ||
| plugins: parserPlugins | ||
| }, | ||
| generatorOpts: { | ||
| ...babelOptions.generatorOpts, | ||
| importAttributesKeyword: "with", | ||
| decoratorsBeforeExport: true | ||
| }, | ||
| plugins, | ||
| sourceMaps: true | ||
| }); | ||
| if (result) { | ||
| if (!useFastRefresh) return { | ||
| code: result.code, | ||
| map: result.map | ||
| }; | ||
| return { | ||
| code: addRefreshWrapper(result.code, "@vitejs/plugin-react", id, opts.reactRefreshHost) ?? result.code, | ||
| map: result.map | ||
| }; | ||
| } | ||
| } | ||
| } | ||
@@ -251,13 +127,3 @@ }; | ||
| if (env.config.consumer !== "client" || skipFastRefresh) return false; | ||
| let nativePlugin; | ||
| try { | ||
| nativePlugin = (await import("vite/internal")).reactRefreshWrapperPlugin; | ||
| } catch {} | ||
| if (!nativePlugin || [ | ||
| "7.1.10", | ||
| "7.1.11", | ||
| "7.1.12" | ||
| ].includes(vite.version)) return true; | ||
| delete viteRefreshWrapper.transform; | ||
| return nativePlugin({ | ||
| return reactRefreshWrapperPlugin({ | ||
| cwd: process.cwd(), | ||
@@ -269,19 +135,2 @@ include: makeIdFiltersToMatchWithQuery(include), | ||
| }); | ||
| }, | ||
| transform: { | ||
| filter: { id: { | ||
| include: makeIdFiltersToMatchWithQuery(include), | ||
| exclude: makeIdFiltersToMatchWithQuery(exclude) | ||
| } }, | ||
| handler(code, id, options) { | ||
| const ssr = options?.ssr === true; | ||
| const [filepath] = id.split("?"); | ||
| const isJSX = filepath.endsWith("x"); | ||
| if (!(!skipFastRefresh && !ssr && (isJSX || code.includes(jsxImportDevRuntime) || code.includes(jsxImportRuntime)))) return; | ||
| const newCode = addRefreshWrapper(code, "@vitejs/plugin-react", id, opts.reactRefreshHost); | ||
| return newCode ? { | ||
| code: newCode, | ||
| map: null | ||
| } : void 0; | ||
| } | ||
| } | ||
@@ -316,42 +165,34 @@ }; | ||
| ]; | ||
| const reactCompilerPlugin = getReactCompilerPlugin(typeof opts.babel === "object" ? opts.babel?.plugins ?? [] : []); | ||
| if (reactCompilerPlugin != null) { | ||
| const reactCompilerRuntimeModule = getReactCompilerRuntimeModule(reactCompilerPlugin); | ||
| dependencies.push(reactCompilerRuntimeModule); | ||
| } | ||
| const viteReactRefresh = { | ||
| name: "vite:react-refresh", | ||
| enforce: "pre", | ||
| config: (userConfig) => ({ | ||
| build: silenceUseClientWarning(userConfig), | ||
| optimizeDeps: { include: dependencies } | ||
| }), | ||
| resolveId: { | ||
| filter: { id: exactRegex(runtimePublicPath) }, | ||
| handler(id) { | ||
| if (id === runtimePublicPath) return id; | ||
| return [ | ||
| viteBabel, | ||
| viteRefreshWrapper, | ||
| viteConfigPost, | ||
| viteReactRefreshBundledDevMode, | ||
| { | ||
| name: "vite:react-refresh", | ||
| enforce: "pre", | ||
| config: (userConfig) => ({ | ||
| build: silenceUseClientWarning(userConfig), | ||
| optimizeDeps: { include: dependencies } | ||
| }), | ||
| resolveId: { | ||
| filter: { id: exactRegex(runtimePublicPath) }, | ||
| handler(id) { | ||
| if (id === runtimePublicPath) return id; | ||
| } | ||
| }, | ||
| load: { | ||
| filter: { id: exactRegex(runtimePublicPath) }, | ||
| handler(id) { | ||
| if (id === runtimePublicPath) return readFileSync(refreshRuntimePath, "utf-8").replace(/__README_URL__/g, "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react"); | ||
| } | ||
| }, | ||
| transformIndexHtml() { | ||
| if (!skipFastRefresh && !isBundledDev) return [{ | ||
| tag: "script", | ||
| attrs: { type: "module" }, | ||
| children: getPreambleCode(base) | ||
| }]; | ||
| } | ||
| }, | ||
| load: { | ||
| filter: { id: exactRegex(runtimePublicPath) }, | ||
| handler(id) { | ||
| if (id === runtimePublicPath) return readFileSync(refreshRuntimePath, "utf-8").replace(/__README_URL__/g, "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react"); | ||
| } | ||
| }, | ||
| transformIndexHtml() { | ||
| if (!skipFastRefresh && !isBundledDev) return [{ | ||
| tag: "script", | ||
| attrs: { type: "module" }, | ||
| children: getPreambleCode(base) | ||
| }]; | ||
| } | ||
| }; | ||
| return [ | ||
| viteBabel, | ||
| ...isRolldownVite ? [ | ||
| viteRefreshWrapper, | ||
| viteConfigPost, | ||
| viteReactRefreshBundledDevMode | ||
| ] : [], | ||
| viteReactRefresh, | ||
| virtualPreamblePlugin({ | ||
@@ -367,46 +208,8 @@ name: "@vitejs/plugin-react/preamble", | ||
| } | ||
| Object.assign(viteReactForCjs, { default: viteReactForCjs }); | ||
| function canSkipBabel(plugins, babelOptions) { | ||
| return !(plugins.length || babelOptions.presets.length || babelOptions.overrides.length || babelOptions.configFile || babelOptions.babelrc); | ||
| } | ||
| const loadedPlugin = /* @__PURE__ */ new Map(); | ||
| function loadPlugin(path) { | ||
| const cached = loadedPlugin.get(path); | ||
| if (cached) return cached; | ||
| const promise = import(path).then((module) => { | ||
| const value = module.default || module; | ||
| loadedPlugin.set(path, value); | ||
| return value; | ||
| }); | ||
| loadedPlugin.set(path, promise); | ||
| return promise; | ||
| } | ||
| function createBabelOptions(rawOptions) { | ||
| const babelOptions = { | ||
| babelrc: false, | ||
| configFile: false, | ||
| ...rawOptions | ||
| }; | ||
| babelOptions.plugins ||= []; | ||
| babelOptions.presets ||= []; | ||
| babelOptions.overrides ||= []; | ||
| babelOptions.parserOpts ||= {}; | ||
| babelOptions.parserOpts.plugins ||= []; | ||
| return babelOptions; | ||
| } | ||
| function defined(value) { | ||
| return value !== void 0; | ||
| } | ||
| function getReactCompilerPlugin(plugins) { | ||
| return plugins.find((p) => p === "babel-plugin-react-compiler" || Array.isArray(p) && p[0] === "babel-plugin-react-compiler"); | ||
| } | ||
| function getReactCompilerRuntimeModule(plugin) { | ||
| let moduleName = "react/compiler-runtime"; | ||
| if (Array.isArray(plugin)) { | ||
| if (plugin[1]?.target === "17" || plugin[1]?.target === "18") moduleName = "react-compiler-runtime"; | ||
| } | ||
| return moduleName; | ||
| } | ||
| Object.assign(viteReactForCjs, { | ||
| default: viteReactForCjs, | ||
| reactCompilerPreset | ||
| }); | ||
| //#endregion | ||
| export { viteReact as default, viteReactForCjs as "module.exports" }; | ||
| export { viteReact as default, viteReactForCjs as "module.exports", reactCompilerPreset }; |
+22
-12
| { | ||
| "name": "@vitejs/plugin-react", | ||
| "version": "5.1.4", | ||
| "version": "6.0.0-beta.0", | ||
| "description": "The default Vite plugin for React projects", | ||
| "keywords": [ | ||
| "babel", | ||
| "fast refresh", | ||
@@ -33,2 +32,5 @@ "react", | ||
| "type": "module", | ||
| "imports": { | ||
| "#optionalTypes": "./types/optionalTypes.d.ts" | ||
| }, | ||
| "exports": { | ||
@@ -45,20 +47,28 @@ ".": "./dist/index.js", | ||
| "dependencies": { | ||
| "@babel/core": "^7.29.0", | ||
| "@babel/plugin-transform-react-jsx-self": "^7.27.1", | ||
| "@babel/plugin-transform-react-jsx-source": "^7.27.1", | ||
| "@rolldown/pluginutils": "1.0.0-rc.3", | ||
| "@types/babel__core": "^7.20.5", | ||
| "react-refresh": "^0.18.0" | ||
| "@rolldown/pluginutils": "1.0.0-rc.6" | ||
| }, | ||
| "devDependencies": { | ||
| "@babel/core": "8.0.0-rc.2", | ||
| "@rolldown/plugin-babel": "^0.1.7", | ||
| "@vitejs/react-common": "workspace:*", | ||
| "babel-plugin-react-compiler": "19.1.0-rc.3", | ||
| "babel-plugin-react-compiler": "^1.0.0", | ||
| "react": "^19.2.4", | ||
| "react-dom": "^19.2.4", | ||
| "rolldown": "1.0.0-rc.3", | ||
| "tsdown": "^0.20.3" | ||
| "rolldown": "1.0.0-rc.6", | ||
| "tsdown": "^0.20.3", | ||
| "vite": "^8.0.0-beta.16" | ||
| }, | ||
| "peerDependencies": { | ||
| "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" | ||
| "@rolldown/plugin-babel": "^0.1.7", | ||
| "babel-plugin-react-compiler": "^1.0.0", | ||
| "vite": "^8.0.0" | ||
| }, | ||
| "peerDependenciesMeta": { | ||
| "@rolldown/plugin-babel": { | ||
| "optional": true | ||
| }, | ||
| "babel-plugin-react-compiler": { | ||
| "optional": true | ||
| } | ||
| }, | ||
| "engines": { | ||
@@ -65,0 +75,0 @@ "node": "^20.19.0 || >=22.12.0" |
+23
-34
@@ -7,3 +7,2 @@ # @vitejs/plugin-react [](https://npmjs.com/package/@vitejs/plugin-react) | ||
| - use the [automatic JSX runtime](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) | ||
| - use custom Babel plugins/presets | ||
| - small installation size | ||
@@ -72,52 +71,42 @@ | ||
| ### babel | ||
| ### reactRefreshHost | ||
| The `babel` option lets you add plugins, presets, and [other configuration](https://babeljs.io/docs/en/options) to the Babel transformation performed on each included file. | ||
| The `reactRefreshHost` option is only necessary in a module federation context. It enables HMR to work between a remote & host application. In your remote Vite config, you would add your host origin: | ||
| ```js | ||
| react({ | ||
| babel: { | ||
| presets: [...], | ||
| // Your plugins run before any built-in transform (eg: Fast Refresh) | ||
| plugins: [...], | ||
| // Use .babelrc files | ||
| babelrc: true, | ||
| // Use babel.config.js files | ||
| configFile: true, | ||
| } | ||
| }) | ||
| react({ reactRefreshHost: 'http://localhost:3000' }) | ||
| ``` | ||
| Note: When not using plugins, only esbuild is used for production builds, resulting in faster builds. | ||
| Under the hood, this simply updates the React Fash Refresh runtime URL from `/@react-refresh` to `http://localhost:3000/@react-refresh` to ensure there is only one Refresh runtime across the whole application. Note that if you define `base` option in the host application, you need to include it in the option, like: `http://localhost:3000/{base}`. | ||
| #### Proposed syntax | ||
| ## React Compiler | ||
| If you are using ES syntax that are still in proposal status (e.g. class properties), you can selectively enable them with the `babel.parserOpts.plugins` option: | ||
| [React Compiler](https://react.dev/learn/react-compiler) support is available via the exported `reactCompilerPreset` helper, which requires [`@rolldown/plugin-babel`](https://npmx.dev/package/@rolldown/plugin-babel) and [`babel-plugin-react-compiler`](https://npmx.dev/package/babel-plugin-react-compiler) as peer dependencies: | ||
| ```sh | ||
| npm install -D @rolldown/plugin-babel babel-plugin-react-compiler | ||
| ``` | ||
| ```js | ||
| react({ | ||
| babel: { | ||
| parserOpts: { | ||
| plugins: ['decorators-legacy'], | ||
| }, | ||
| }, | ||
| // vite.config.js | ||
| import { defineConfig } from 'vite' | ||
| import react, { reactCompilerPreset } from '@vitejs/plugin-react' | ||
| import babel from '@rolldown/plugin-babel' | ||
| export default defineConfig({ | ||
| plugins: [react(), babel({ presets: [reactCompilerPreset()] })], | ||
| }) | ||
| ``` | ||
| This option does not enable _code transformation_. That is handled by esbuild. | ||
| The `reactCompilerPreset` accepts an optional options object with the following properties: | ||
| **Note:** TypeScript syntax is handled automatically. | ||
| - `compilationMode` — Set to `'annotation'` to only compile components annotated with `"use memo"`. | ||
| - `target` — Set to `'17'` or `'18'` to target older React versions (uses `react-compiler-runtime` instead of `react/compiler-runtime`). | ||
| Here's the [complete list of Babel parser plugins](https://babeljs.io/docs/en/babel-parser#ecmascript-proposalshttpsgithubcombabelproposals). | ||
| ### reactRefreshHost | ||
| The `reactRefreshHost` option is only necessary in a module federation context. It enables HMR to work between a remote & host application. In your remote Vite config, you would add your host origin: | ||
| ```js | ||
| react({ reactRefreshHost: 'http://localhost:3000' }) | ||
| babel({ | ||
| presets: [reactCompilerPreset({ compilationMode: 'annotation' })], | ||
| }) | ||
| ``` | ||
| Under the hood, this simply updates the React Fash Refresh runtime URL from `/@react-refresh` to `http://localhost:3000/@react-refresh` to ensure there is only one Refresh runtime across the whole application. Note that if you define `base` option in the host application, you need to include it in the option, like: `http://localhost:3000/{base}`. | ||
| ## `@vitejs/plugin-react/preamble` | ||
@@ -124,0 +113,0 @@ |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
4
-42.86%8
14.29%2
-33.33%38752
-16.19%9
50%858
-19.89%1
Infinity%149
-6.88%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed