@vitejs/plugin-react-oxc
Version:
The future default Vite plugin for React projects
164 lines (158 loc) • 5.85 kB
JavaScript
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { readFileSync } from "node:fs";
import { exactRegex } from "@rolldown/pluginutils";
//#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)}";
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;`;
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;
}
//#endregion
//#region ../common/warning.ts
const silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warning, defaultHandler) {
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && (warning.message.includes("use client") || warning.message.includes("use server"))) return;
if (warning.code === "SOURCEMAP_ERROR" && warning.message.includes("resolve original location") && warning.pos === 0) return;
if (userConfig.build?.rollupOptions?.onwarn) userConfig.build.rollupOptions.onwarn(warning, defaultHandler);
else defaultHandler(warning);
} } });
//#endregion
//#region src/index.ts
const _dirname = dirname(fileURLToPath(import.meta.url));
const refreshRuntimePath = join(_dirname, "refresh-runtime.js");
const defaultIncludeRE = /\.[tj]sx?(?:$|\?)/;
const defaultExcludeRE = /\/node_modules\//;
function viteReact(opts = {}) {
const include = opts.include ?? defaultIncludeRE;
const exclude = opts.exclude ?? defaultExcludeRE;
const jsxImportSource = opts.jsxImportSource ?? "react";
const jsxImportRuntime = `${jsxImportSource}/jsx-runtime`;
const jsxImportDevRuntime = `${jsxImportSource}/jsx-dev-runtime`;
const viteConfig = {
name: "vite:react-oxc:config",
config(userConfig, { command }) {
return {
build: silenceUseClientWarning(userConfig),
oxc: {
jsx: {
runtime: "automatic",
importSource: jsxImportSource,
refresh: command === "serve",
development: command === "serve"
},
jsxRefreshInclude: include,
jsxRefreshExclude: exclude
},
optimizeDeps: {
include: [
"react",
"react-dom",
jsxImportDevRuntime,
jsxImportRuntime
],
rollupOptions: { transform: { jsx: { runtime: "automatic" } } }
}
};
},
configResolved(config) {
config.logger.warn("@vitejs/plugin-react-oxc is deprecated. Please use @vitejs/plugin-react instead. The changes of this plugin is now included in @vitejs/plugin-react.");
},
options() {
if (!this.meta.rolldownVersion) throw new Error("@vitejs/plugin-react-oxc requires rolldown-vite to be used. See https://vitejs.dev/guide/rolldown for more details about rolldown-vite.");
}
};
const viteConfigPost = {
name: "vite:react-oxc:config-post",
enforce: "post",
config(userConfig) {
if (userConfig.server?.hmr === false) return { oxc: { jsx: { refresh: false } } };
}
};
const viteRefreshRuntime = {
name: "vite:react-oxc:refresh-runtime",
enforce: "pre",
resolveId: {
filter: { id: exactRegex(runtimePublicPath) },
handler(id) {
return id;
}
},
load: {
filter: { id: exactRegex(runtimePublicPath) },
handler(_id) {
return readFileSync(refreshRuntimePath, "utf-8").replace(/__README_URL__/g, "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react-oxc");
}
}
};
let skipFastRefresh = false;
return [
viteConfig,
viteConfigPost,
viteRefreshRuntime,
{
name: "vite:react-oxc:refresh-wrapper",
apply: "serve",
configResolved(config) {
skipFastRefresh = config.isProduction || config.server.hmr === false;
},
transform: {
filter: { id: {
include,
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-oxc", id);
return newCode ? {
code: newCode,
map: null
} : void 0;
}
},
transformIndexHtml(_, config) {
if (!skipFastRefresh) return [{
tag: "script",
attrs: { type: "module" },
children: getPreambleCode(config.server.config.base)
}];
}
}
];
}
//#endregion
export { viteReact as default };