index.cjs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. 'use strict';
  2. const path = require('node:path');
  3. const babel = require('@babel/core');
  4. const vite = require('vite');
  5. const MagicString = require('magic-string');
  6. const fs = require('node:fs');
  7. const node_module = require('node:module');
  8. function _interopNamespaceDefault(e) {
  9. const n = Object.create(null);
  10. if (e) {
  11. for (const k in e) {
  12. n[k] = e[k];
  13. }
  14. }
  15. n.default = e;
  16. return n;
  17. }
  18. const babel__namespace = /*#__PURE__*/_interopNamespaceDefault(babel);
  19. const runtimePublicPath = "/@react-refresh";
  20. const _require = node_module.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
  21. const reactRefreshDir = path.dirname(
  22. _require.resolve("react-refresh/package.json")
  23. );
  24. const runtimeFilePath = path.join(
  25. reactRefreshDir,
  26. "cjs/react-refresh-runtime.development.js"
  27. );
  28. const runtimeCode = `
  29. const exports = {}
  30. ${fs.readFileSync(runtimeFilePath, "utf-8")}
  31. function debounce(fn, delay) {
  32. let handle
  33. return () => {
  34. clearTimeout(handle)
  35. handle = setTimeout(fn, delay)
  36. }
  37. }
  38. exports.performReactRefresh = debounce(exports.performReactRefresh, 16)
  39. export default exports
  40. `;
  41. const preambleCode = `
  42. import RefreshRuntime from "__BASE__${runtimePublicPath.slice(1)}"
  43. RefreshRuntime.injectIntoGlobalHook(window)
  44. window.$RefreshReg$ = () => {}
  45. window.$RefreshSig$ = () => (type) => type
  46. window.__vite_plugin_react_preamble_installed__ = true
  47. `;
  48. const header = `
  49. import RefreshRuntime from "${runtimePublicPath}";
  50. let prevRefreshReg;
  51. let prevRefreshSig;
  52. if (import.meta.hot) {
  53. if (!window.__vite_plugin_react_preamble_installed__) {
  54. throw new Error(
  55. "@vitejs/plugin-react can't detect preamble. Something is wrong. " +
  56. "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
  57. );
  58. }
  59. prevRefreshReg = window.$RefreshReg$;
  60. prevRefreshSig = window.$RefreshSig$;
  61. window.$RefreshReg$ = (type, id) => {
  62. RefreshRuntime.register(type, __SOURCE__ + " " + id)
  63. };
  64. window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
  65. }`.replace(/[\n]+/gm, "");
  66. const timeout = `
  67. if (!window.__vite_plugin_react_timeout) {
  68. window.__vite_plugin_react_timeout = setTimeout(() => {
  69. window.__vite_plugin_react_timeout = 0;
  70. RefreshRuntime.performReactRefresh();
  71. }, 30);
  72. }
  73. `;
  74. const footer = `
  75. if (import.meta.hot) {
  76. window.$RefreshReg$ = prevRefreshReg;
  77. window.$RefreshSig$ = prevRefreshSig;
  78. __ACCEPT__
  79. }`;
  80. const checkAndAccept = `
  81. function isReactRefreshBoundary(mod) {
  82. if (mod == null || typeof mod !== 'object') {
  83. return false;
  84. }
  85. let hasExports = false;
  86. let areAllExportsComponents = true;
  87. for (const exportName in mod) {
  88. hasExports = true;
  89. if (exportName === '__esModule') {
  90. continue;
  91. }
  92. const desc = Object.getOwnPropertyDescriptor(mod, exportName);
  93. if (desc && desc.get) {
  94. // Don't invoke getters as they may have side effects.
  95. return false;
  96. }
  97. const exportValue = mod[exportName];
  98. if (!RefreshRuntime.isLikelyComponentType(exportValue)) {
  99. areAllExportsComponents = false;
  100. }
  101. }
  102. return hasExports && areAllExportsComponents;
  103. }
  104. import.meta.hot.accept(mod => {
  105. if (isReactRefreshBoundary(mod)) {
  106. ${timeout}
  107. } else {
  108. import.meta.hot.invalidate();
  109. }
  110. });
  111. `;
  112. function addRefreshWrapper(code, id, accept) {
  113. return header.replace("__SOURCE__", JSON.stringify(id)) + code + footer.replace("__ACCEPT__", accept ? checkAndAccept : timeout);
  114. }
  115. function isRefreshBoundary(ast) {
  116. return ast.program.body.every((node) => {
  117. if (node.type !== "ExportNamedDeclaration") {
  118. return true;
  119. }
  120. const { declaration, specifiers } = node;
  121. if (declaration) {
  122. if (declaration.type === "ClassDeclaration")
  123. return false;
  124. if (declaration.type === "VariableDeclaration") {
  125. return declaration.declarations.every(
  126. (variable) => isComponentLikeIdentifier(variable.id)
  127. );
  128. }
  129. if (declaration.type === "FunctionDeclaration") {
  130. return !!declaration.id && isComponentLikeIdentifier(declaration.id);
  131. }
  132. }
  133. return specifiers.every((spec) => {
  134. return isComponentLikeIdentifier(spec.exported);
  135. });
  136. });
  137. }
  138. function isComponentLikeIdentifier(node) {
  139. return node.type === "Identifier" && isComponentLikeName(node.name);
  140. }
  141. function isComponentLikeName(name) {
  142. return typeof name === "string" && name[0] >= "A" && name[0] <= "Z";
  143. }
  144. function babelImportToRequire({ types: t }) {
  145. return {
  146. visitor: {
  147. ImportDeclaration(path) {
  148. const decl = path.node;
  149. const spec = decl.specifiers[0];
  150. path.replaceWith(
  151. t.variableDeclaration("var", [
  152. t.variableDeclarator(
  153. spec.local,
  154. t.memberExpression(
  155. t.callExpression(t.identifier("require"), [decl.source]),
  156. spec.imported
  157. )
  158. )
  159. ])
  160. );
  161. }
  162. }
  163. };
  164. }
  165. let babelRestoreJSX;
  166. const jsxNotFound = [null, false];
  167. async function getBabelRestoreJSX() {
  168. if (!babelRestoreJSX)
  169. babelRestoreJSX = import('./chunks/babel-restore-jsx.cjs').then((r) => {
  170. const fn = r.default;
  171. if ("default" in fn)
  172. return fn.default;
  173. return fn;
  174. });
  175. return babelRestoreJSX;
  176. }
  177. async function restoreJSX(babel, code, filename) {
  178. const [reactAlias, isCommonJS] = parseReactAlias(code);
  179. if (!reactAlias) {
  180. return jsxNotFound;
  181. }
  182. const reactJsxRE = new RegExp(
  183. `\\b${reactAlias}\\.(createElement|Fragment)\\b`,
  184. "g"
  185. );
  186. if (!reactJsxRE.test(code)) {
  187. return jsxNotFound;
  188. }
  189. const result = await babel.transformAsync(code, {
  190. babelrc: false,
  191. configFile: false,
  192. ast: true,
  193. code: false,
  194. filename,
  195. parserOpts: {
  196. plugins: ["jsx"]
  197. },
  198. plugins: [[await getBabelRestoreJSX(), { reactAlias }]]
  199. });
  200. return [result?.ast, isCommonJS];
  201. }
  202. function parseReactAlias(code) {
  203. let match = code.match(
  204. /\b(var|let|const)\s+([^=\{\s]+)\s*=\s*require\(["']react["']\)/
  205. );
  206. if (match) {
  207. return [match[2], true];
  208. }
  209. match = code.match(/^import\s+(?:\*\s+as\s+)?(\w+).+?\bfrom\s*["']react["']/m);
  210. if (match) {
  211. return [match[1], false];
  212. }
  213. return [void 0, false];
  214. }
  215. const prependReactImportCode = "import React from 'react'; ";
  216. function viteReact(opts = {}) {
  217. let devBase = "/";
  218. let resolvedCacheDir;
  219. let filter = vite.createFilter(opts.include, opts.exclude);
  220. let needHiresSourcemap = false;
  221. let isProduction = true;
  222. let projectRoot = process.cwd();
  223. let skipFastRefresh = opts.fastRefresh === false;
  224. let skipReactImport = false;
  225. let runPluginOverrides = (options, context) => false;
  226. let staticBabelOptions;
  227. const useAutomaticRuntime = opts.jsxRuntime !== "classic";
  228. const importReactRE = /(^|\n)import\s+(\*\s+as\s+)?React(,|\s+)/;
  229. const fileExtensionRE = /\.[^\/\s\?]+$/;
  230. const viteBabel = {
  231. name: "vite:react-babel",
  232. enforce: "pre",
  233. config() {
  234. if (opts.jsxRuntime === "classic") {
  235. return {
  236. esbuild: {
  237. logOverride: {
  238. "this-is-undefined-in-esm": "silent"
  239. }
  240. }
  241. };
  242. }
  243. },
  244. configResolved(config) {
  245. devBase = config.base;
  246. projectRoot = config.root;
  247. resolvedCacheDir = vite.normalizePath(path.resolve(config.cacheDir));
  248. filter = vite.createFilter(opts.include, opts.exclude, {
  249. resolve: projectRoot
  250. });
  251. needHiresSourcemap = config.command === "build" && !!config.build.sourcemap;
  252. isProduction = config.isProduction;
  253. skipFastRefresh || (skipFastRefresh = isProduction || config.command === "build");
  254. const jsxInject = config.esbuild && config.esbuild.jsxInject;
  255. if (jsxInject && importReactRE.test(jsxInject)) {
  256. skipReactImport = true;
  257. config.logger.warn(
  258. "[@vitejs/plugin-react] This plugin imports React for you automatically, so you can stop using `esbuild.jsxInject` for that purpose."
  259. );
  260. }
  261. config.plugins.forEach((plugin) => {
  262. const hasConflict = plugin.name === "react-refresh" || plugin !== viteReactJsx && plugin.name === "vite:react-jsx";
  263. if (hasConflict)
  264. return config.logger.warn(
  265. `[@vitejs/plugin-react] You should stop using "${plugin.name}" since this plugin conflicts with it.`
  266. );
  267. });
  268. runPluginOverrides = (babelOptions, context) => {
  269. const hooks = config.plugins.map((plugin) => plugin.api?.reactBabel).filter(Boolean);
  270. if (hooks.length > 0) {
  271. return (runPluginOverrides = (babelOptions2, context2) => {
  272. hooks.forEach((hook) => hook(babelOptions2, context2, config));
  273. return true;
  274. })(babelOptions, context);
  275. }
  276. runPluginOverrides = () => false;
  277. return false;
  278. };
  279. },
  280. async transform(code, id, options) {
  281. const ssr = options?.ssr === true;
  282. const [filepath, querystring = ""] = id.split("?");
  283. const [extension = ""] = querystring.match(fileExtensionRE) || filepath.match(fileExtensionRE) || [];
  284. if (/\.(mjs|[tj]sx?)$/.test(extension)) {
  285. const isJSX = extension.endsWith("x");
  286. const isNodeModules = id.includes("/node_modules/");
  287. const isProjectFile = !isNodeModules && (id[0] === "\0" || id.startsWith(projectRoot + "/"));
  288. let babelOptions = staticBabelOptions;
  289. if (typeof opts.babel === "function") {
  290. const rawOptions = opts.babel(id, { ssr });
  291. babelOptions = createBabelOptions(rawOptions);
  292. runPluginOverrides(babelOptions, { ssr, id });
  293. } else if (!babelOptions) {
  294. babelOptions = createBabelOptions(opts.babel);
  295. if (!runPluginOverrides(babelOptions, { ssr, id })) {
  296. staticBabelOptions = babelOptions;
  297. }
  298. }
  299. const plugins = isProjectFile ? [...babelOptions.plugins] : [];
  300. let useFastRefresh = false;
  301. if (!skipFastRefresh && !ssr && !isNodeModules) {
  302. const isReactModule = isJSX || importReactRE.test(code);
  303. if (isReactModule && filter(id)) {
  304. useFastRefresh = true;
  305. plugins.push([
  306. await loadPlugin("react-refresh/babel"),
  307. { skipEnvCheck: true }
  308. ]);
  309. }
  310. }
  311. let ast;
  312. let prependReactImport = false;
  313. if (!isProjectFile || isJSX) {
  314. if (useAutomaticRuntime) {
  315. const isOptimizedReactDom = id.startsWith(resolvedCacheDir) && id.includes("/react-dom.js");
  316. const [restoredAst, isCommonJS] = !isProjectFile && !isJSX && !isOptimizedReactDom ? await restoreJSX(babel__namespace, code, id) : [null, false];
  317. if (isJSX || (ast = restoredAst)) {
  318. plugins.push([
  319. await loadPlugin(
  320. "@babel/plugin-transform-react-jsx" + (isProduction ? "" : "-development")
  321. ),
  322. {
  323. runtime: "automatic",
  324. importSource: opts.jsxImportSource,
  325. pure: opts.jsxPure !== false,
  326. throwIfNamespace: opts.jsxThrowIfNamespace
  327. }
  328. ]);
  329. if (isCommonJS) {
  330. plugins.push(babelImportToRequire);
  331. }
  332. }
  333. } else if (isProjectFile) {
  334. if (!isProduction) {
  335. plugins.push(
  336. await loadPlugin("@babel/plugin-transform-react-jsx-self"),
  337. await loadPlugin("@babel/plugin-transform-react-jsx-source")
  338. );
  339. }
  340. if (!skipReactImport && !importReactRE.test(code)) {
  341. prependReactImport = true;
  342. }
  343. }
  344. }
  345. let inputMap;
  346. if (prependReactImport) {
  347. if (needHiresSourcemap) {
  348. const s = new MagicString(code);
  349. s.prepend(prependReactImportCode);
  350. code = s.toString();
  351. inputMap = s.generateMap({ hires: true, source: id });
  352. } else {
  353. code = prependReactImportCode + code;
  354. }
  355. }
  356. const shouldSkip = !plugins.length && !babelOptions.configFile && !(isProjectFile && babelOptions.babelrc);
  357. if (shouldSkip) {
  358. return {
  359. code,
  360. map: inputMap ?? null
  361. };
  362. }
  363. const parserPlugins = [
  364. ...babelOptions.parserOpts.plugins,
  365. "importMeta",
  366. "topLevelAwait",
  367. "classProperties",
  368. "classPrivateProperties",
  369. "classPrivateMethods"
  370. ];
  371. if (!extension.endsWith(".ts")) {
  372. parserPlugins.push("jsx");
  373. }
  374. if (/\.tsx?$/.test(extension)) {
  375. parserPlugins.push("typescript");
  376. }
  377. const transformAsync = ast ? babel__namespace.transformFromAstAsync.bind(babel__namespace, ast, code) : babel__namespace.transformAsync.bind(babel__namespace, code);
  378. const isReasonReact = extension.endsWith(".bs.js");
  379. const result = await transformAsync({
  380. ...babelOptions,
  381. ast: !isReasonReact,
  382. root: projectRoot,
  383. filename: id,
  384. sourceFileName: filepath,
  385. parserOpts: {
  386. ...babelOptions.parserOpts,
  387. sourceType: "module",
  388. allowAwaitOutsideFunction: true,
  389. plugins: parserPlugins
  390. },
  391. generatorOpts: {
  392. ...babelOptions.generatorOpts,
  393. decoratorsBeforeExport: true
  394. },
  395. plugins,
  396. sourceMaps: true,
  397. inputSourceMap: inputMap ?? false
  398. });
  399. if (result) {
  400. let code2 = result.code;
  401. if (useFastRefresh && /\$RefreshReg\$\(/.test(code2)) {
  402. const accept = isReasonReact || isRefreshBoundary(result.ast);
  403. code2 = addRefreshWrapper(code2, id, accept);
  404. }
  405. return {
  406. code: code2,
  407. map: result.map
  408. };
  409. }
  410. }
  411. }
  412. };
  413. const viteReactRefresh = {
  414. name: "vite:react-refresh",
  415. enforce: "pre",
  416. config: () => ({
  417. resolve: {
  418. dedupe: ["react", "react-dom"]
  419. }
  420. }),
  421. resolveId(id) {
  422. if (id === runtimePublicPath) {
  423. return id;
  424. }
  425. },
  426. load(id) {
  427. if (id === runtimePublicPath) {
  428. return runtimeCode;
  429. }
  430. },
  431. transformIndexHtml() {
  432. if (!skipFastRefresh)
  433. return [
  434. {
  435. tag: "script",
  436. attrs: { type: "module" },
  437. children: preambleCode.replace(`__BASE__`, devBase)
  438. }
  439. ];
  440. }
  441. };
  442. const reactJsxRuntimeId = "react/jsx-runtime";
  443. const reactJsxDevRuntimeId = "react/jsx-dev-runtime";
  444. const virtualReactJsxRuntimeId = "\0" + reactJsxRuntimeId;
  445. const virtualReactJsxDevRuntimeId = "\0" + reactJsxDevRuntimeId;
  446. const viteReactJsx = {
  447. name: "vite:react-jsx",
  448. enforce: "pre",
  449. config() {
  450. return {
  451. optimizeDeps: {
  452. include: [reactJsxRuntimeId, reactJsxDevRuntimeId, "react"]
  453. }
  454. };
  455. },
  456. resolveId(id, importer) {
  457. if (id === reactJsxRuntimeId && importer !== virtualReactJsxRuntimeId) {
  458. return virtualReactJsxRuntimeId;
  459. }
  460. if (id === reactJsxDevRuntimeId && importer !== virtualReactJsxDevRuntimeId) {
  461. return virtualReactJsxDevRuntimeId;
  462. }
  463. },
  464. load(id) {
  465. if (id === virtualReactJsxRuntimeId) {
  466. return [
  467. `import * as jsxRuntime from ${JSON.stringify(reactJsxRuntimeId)}`,
  468. `export const Fragment = jsxRuntime.Fragment`,
  469. `export const jsx = jsxRuntime.jsx`,
  470. `export const jsxs = jsxRuntime.jsxs`
  471. ].join("\n");
  472. }
  473. if (id === virtualReactJsxDevRuntimeId) {
  474. return [
  475. `import * as jsxRuntime from ${JSON.stringify(reactJsxDevRuntimeId)}`,
  476. `export const Fragment = jsxRuntime.Fragment`,
  477. `export const jsxDEV = jsxRuntime.jsxDEV`
  478. ].join("\n");
  479. }
  480. }
  481. };
  482. return [viteBabel, viteReactRefresh, useAutomaticRuntime && viteReactJsx];
  483. }
  484. viteReact.preambleCode = preambleCode;
  485. function loadPlugin(path2) {
  486. return import(path2).then((module) => module.default || module);
  487. }
  488. function createBabelOptions(rawOptions) {
  489. var _a;
  490. const babelOptions = {
  491. babelrc: false,
  492. configFile: false,
  493. ...rawOptions
  494. };
  495. babelOptions.plugins || (babelOptions.plugins = []);
  496. babelOptions.presets || (babelOptions.presets = []);
  497. babelOptions.overrides || (babelOptions.overrides = []);
  498. babelOptions.parserOpts || (babelOptions.parserOpts = {});
  499. (_a = babelOptions.parserOpts).plugins || (_a.plugins = []);
  500. return babelOptions;
  501. }
  502. module.exports = viteReact;
  503. module.exports.default = viteReact;