@vitejs/plugin-react 4.3.4 → 4.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,9 +94,19 @@ This option does not enable _code transformation_. That is handled by esbuild.
94
94
 
95
95
  Here's the [complete list of Babel parser plugins](https://babeljs.io/docs/en/babel-parser#ecmascript-proposalshttpsgithubcombabelproposals).
96
96
 
97
+ ### reactRefreshHost
98
+
99
+ 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:
100
+
101
+ ```js
102
+ react({ reactRefreshHost: 'http://localhost:3000' })
103
+ ```
104
+
105
+ 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}`.
106
+
97
107
  ## Middleware mode
98
108
 
99
- In [middleware mode](https://vitejs.dev/config/server-options.html#server-middlewaremode), you should make sure your entry `index.html` file is transformed by Vite. Here's an example for an Express server:
109
+ In [middleware mode](https://vite.dev/config/server-options.html#server-middlewaremode), you should make sure your entry `index.html` file is transformed by Vite. Here's an example for an Express server:
100
110
 
101
111
  ```js
102
112
  app.get('/', async (req, res, next) => {
package/dist/index.cjs CHANGED
@@ -1,89 +1,115 @@
1
1
  'use strict';
2
2
 
3
+ const node_path = require('node:path');
4
+ const node_url = require('node:url');
5
+ const node_fs = require('node:fs');
3
6
  const vite = require('vite');
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
- const node_module = require('node:module');
7
7
 
8
8
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
9
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
10
-
11
- const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
12
- const path__default = /*#__PURE__*/_interopDefaultCompat(path);
13
-
14
9
  const runtimePublicPath = "/@react-refresh";
15
- const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
16
- const reactRefreshDir = path__default.dirname(
17
- _require.resolve("react-refresh/package.json")
18
- );
19
- const runtimeFilePath = path__default.join(
20
- reactRefreshDir,
21
- "cjs/react-refresh-runtime.development.js"
22
- );
23
- const runtimeCode = `
24
- const exports = {}
25
- ${fs__default.readFileSync(runtimeFilePath, "utf-8")}
26
- ${fs__default.readFileSync(_require.resolve("./refreshUtils.js"), "utf-8")}
27
- export default exports
28
- `;
29
- const preambleCode = `
30
- import RefreshRuntime from "__BASE__${runtimePublicPath.slice(1)}"
31
- RefreshRuntime.injectIntoGlobalHook(window)
32
- window.$RefreshReg$ = () => {}
33
- window.$RefreshSig$ = () => (type) => type
34
- window.__vite_plugin_react_preamble_installed__ = true
35
- `;
36
- const sharedHeader = `
37
- import RefreshRuntime from "${runtimePublicPath}";
38
-
39
- const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
40
- `.replace(/\n+/g, "");
41
- const functionHeader = `
42
- let prevRefreshReg;
10
+ const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/;
11
+ const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
12
+ const preambleCode = `import { injectIntoGlobalHook } from "__BASE__${runtimePublicPath.slice(
13
+ 1
14
+ )}"
15
+ injectIntoGlobalHook(window);
16
+ window.$RefreshReg$ = () => {};
17
+ window.$RefreshSig$ = () => (type) => type;`;
18
+ const getPreambleCode = (base) => preambleCode.replace("__BASE__", base);
19
+ const avoidSourceMapOption = Symbol();
20
+ function addRefreshWrapper(code, map, pluginName, id, reactRefreshHost = "") {
21
+ const hasRefresh = refreshContentRE.test(code);
22
+ const onlyReactComp = !hasRefresh && reactCompRE.test(code);
23
+ const normalizedMap = map === avoidSourceMapOption ? null : map;
24
+ if (!hasRefresh && !onlyReactComp) return { code, map: normalizedMap };
25
+ const avoidSourceMap = map === avoidSourceMapOption;
26
+ const newMap = typeof normalizedMap === "string" ? JSON.parse(normalizedMap) : normalizedMap;
27
+ let newCode = code;
28
+ if (hasRefresh) {
29
+ const refreshHead = removeLineBreaksIfNeeded(
30
+ `let prevRefreshReg;
43
31
  let prevRefreshSig;
44
32
 
45
33
  if (import.meta.hot && !inWebWorker) {
46
- if (!window.__vite_plugin_react_preamble_installed__) {
34
+ if (!window.$RefreshReg$) {
47
35
  throw new Error(
48
- "@vitejs/plugin-react can't detect preamble. Something is wrong. " +
49
- "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
36
+ "${pluginName} can't detect preamble. Something is wrong."
50
37
  );
51
38
  }
52
39
 
53
40
  prevRefreshReg = window.$RefreshReg$;
54
41
  prevRefreshSig = window.$RefreshSig$;
55
- window.$RefreshReg$ = (type, id) => {
56
- RefreshRuntime.register(type, __SOURCE__ + " " + id)
57
- };
42
+ window.$RefreshReg$ = RefreshRuntime.getRefreshReg(${JSON.stringify(id)});
58
43
  window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
59
- }`.replace(/\n+/g, "");
60
- const functionFooter = `
44
+ }
45
+
46
+ `,
47
+ avoidSourceMap
48
+ );
49
+ newCode = `${refreshHead}${newCode}
50
+
61
51
  if (import.meta.hot && !inWebWorker) {
62
52
  window.$RefreshReg$ = prevRefreshReg;
63
53
  window.$RefreshSig$ = prevRefreshSig;
64
- }`;
65
- const sharedFooter = (id) => `
54
+ }
55
+ `;
56
+ if (newMap) {
57
+ newMap.mappings = ";".repeat(16) + newMap.mappings;
58
+ }
59
+ }
60
+ const sharedHead = removeLineBreaksIfNeeded(
61
+ `import * as RefreshRuntime from "${reactRefreshHost}${runtimePublicPath}";
62
+ const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
63
+
64
+ `,
65
+ avoidSourceMap
66
+ );
67
+ newCode = `${sharedHead}${newCode}
68
+
66
69
  if (import.meta.hot && !inWebWorker) {
67
70
  RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
68
71
  RefreshRuntime.registerExportsForReactRefresh(${JSON.stringify(
69
- id
70
- )}, currentExports);
72
+ id
73
+ )}, currentExports);
71
74
  import.meta.hot.accept((nextExports) => {
72
75
  if (!nextExports) return;
73
76
  const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(${JSON.stringify(
74
- id
75
- )}, currentExports, nextExports);
77
+ id
78
+ )}, currentExports, nextExports);
76
79
  if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
77
80
  });
78
81
  });
79
- }`;
80
- function addRefreshWrapper(code, id) {
81
- return sharedHeader + functionHeader.replace("__SOURCE__", JSON.stringify(id)) + code + functionFooter + sharedFooter(id);
82
82
  }
83
- function addClassComponentRefreshWrapper(code, id) {
84
- return sharedHeader + code + sharedFooter(id);
83
+ `;
84
+ if (newMap) {
85
+ newMap.mappings = ";;;" + newMap.mappings;
86
+ }
87
+ return { code: newCode, map: newMap };
85
88
  }
89
+ function removeLineBreaksIfNeeded(code, enabled) {
90
+ return enabled ? code.replace(/\n/g, "") : code;
91
+ }
92
+
93
+ const silenceUseClientWarning = (userConfig) => ({
94
+ rollupOptions: {
95
+ onwarn(warning, defaultHandler) {
96
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
97
+ return;
98
+ }
99
+ if (warning.code === "SOURCEMAP_ERROR" && warning.message.includes("resolve original location") && warning.pos === 0) {
100
+ return;
101
+ }
102
+ if (userConfig.build?.rollupOptions?.onwarn) {
103
+ userConfig.build.rollupOptions.onwarn(warning, defaultHandler);
104
+ } else {
105
+ defaultHandler(warning);
106
+ }
107
+ }
108
+ }
109
+ });
86
110
 
111
+ const _dirname = node_path.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
112
+ const refreshRuntimePath = node_path.join(_dirname, "refresh-runtime.js") ;
87
113
  let babel;
88
114
  async function loadBabel() {
89
115
  if (!babel) {
@@ -91,12 +117,9 @@ async function loadBabel() {
91
117
  }
92
118
  return babel;
93
119
  }
94
- const reactCompRE = /extends\s+(?:React\.)?(?:Pure)?Component/;
95
- const refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
96
120
  const defaultIncludeRE = /\.[tj]sx?$/;
97
121
  const tsRE = /\.tsx?$/;
98
122
  function viteReact(opts = {}) {
99
- let devBase = "/";
100
123
  const filter = vite.createFilter(opts.include ?? defaultIncludeRE, opts.exclude);
101
124
  const jsxImportSource = opts.jsxImportSource ?? "react";
102
125
  const jsxImportRuntime = `${jsxImportSource}/jsx-runtime`;
@@ -128,7 +151,6 @@ function viteReact(opts = {}) {
128
151
  }
129
152
  },
130
153
  configResolved(config) {
131
- devBase = config.base;
132
154
  projectRoot = config.root;
133
155
  isProduction = config.isProduction;
134
156
  skipFastRefresh = isProduction || config.command === "build" || config.server.hmr === false;
@@ -147,15 +169,12 @@ function viteReact(opts = {}) {
147
169
  }
148
170
  },
149
171
  async transform(code, id, options) {
150
- if (id.includes("/node_modules/"))
151
- return;
172
+ if (id.includes("/node_modules/")) return;
152
173
  const [filepath] = id.split("?");
153
- if (!filter(filepath))
154
- return;
174
+ if (!filter(filepath)) return;
155
175
  const ssr = options?.ssr === true;
156
176
  const babelOptions = (() => {
157
- if (staticBabelOptions)
158
- return staticBabelOptions;
177
+ if (staticBabelOptions) return staticBabelOptions;
159
178
  const newBabelOptions = createBabelOptions(
160
179
  typeof opts.babel === "function" ? opts.babel(id, { ssr }) : opts.babel
161
180
  );
@@ -196,7 +215,7 @@ function viteReact(opts = {}) {
196
215
  filename: id,
197
216
  sourceFileName: filepath,
198
217
  // Required for esbuild.jsxDev to provide correct line numbers
199
- // This crates issues the react compiler because the re-order is too important
218
+ // This creates issues the react compiler because the re-order is too important
200
219
  // People should use @babel/plugin-transform-react-jsx-development to get back good line numbers
201
220
  retainLines: getReactCompilerPlugin(plugins) != null ? false : !isProduction && isJSX && opts.jsxRuntime !== "classic",
202
221
  parserOpts: {
@@ -215,15 +234,16 @@ function viteReact(opts = {}) {
215
234
  sourceMaps: true
216
235
  });
217
236
  if (result) {
218
- let code2 = result.code;
219
- if (useFastRefresh) {
220
- if (refreshContentRE.test(code2)) {
221
- code2 = addRefreshWrapper(code2, id);
222
- } else if (reactCompRE.test(code2)) {
223
- code2 = addClassComponentRefreshWrapper(code2, id);
224
- }
237
+ if (!useFastRefresh) {
238
+ return { code: result.code, map: result.map };
225
239
  }
226
- return { code: code2, map: result.map };
240
+ return addRefreshWrapper(
241
+ result.code,
242
+ result.map,
243
+ "@vitejs/plugin-react",
244
+ id,
245
+ opts.reactRefreshHost
246
+ );
227
247
  }
228
248
  }
229
249
  };
@@ -258,16 +278,19 @@ function viteReact(opts = {}) {
258
278
  },
259
279
  load(id) {
260
280
  if (id === runtimePublicPath) {
261
- return runtimeCode;
281
+ return node_fs.readFileSync(refreshRuntimePath, "utf-8").replace(
282
+ /__README_URL__/g,
283
+ "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react"
284
+ );
262
285
  }
263
286
  },
264
- transformIndexHtml() {
287
+ transformIndexHtml(_, config) {
265
288
  if (!skipFastRefresh)
266
289
  return [
267
290
  {
268
291
  tag: "script",
269
292
  attrs: { type: "module" },
270
- children: preambleCode.replace(`__BASE__`, devBase)
293
+ children: getPreambleCode(config.server.config.base)
271
294
  }
272
295
  ];
273
296
  }
@@ -275,28 +298,10 @@ function viteReact(opts = {}) {
275
298
  return [viteBabel, viteReactRefresh];
276
299
  }
277
300
  viteReact.preambleCode = preambleCode;
278
- const silenceUseClientWarning = (userConfig) => ({
279
- rollupOptions: {
280
- onwarn(warning, defaultHandler) {
281
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
282
- return;
283
- }
284
- if (warning.code === "SOURCEMAP_ERROR" && warning.message.includes("resolve original location") && warning.pos === 0) {
285
- return;
286
- }
287
- if (userConfig.build?.rollupOptions?.onwarn) {
288
- userConfig.build.rollupOptions.onwarn(warning, defaultHandler);
289
- } else {
290
- defaultHandler(warning);
291
- }
292
- }
293
- }
294
- });
295
301
  const loadedPlugin = /* @__PURE__ */ new Map();
296
302
  function loadPlugin(path) {
297
303
  const cached = loadedPlugin.get(path);
298
- if (cached)
299
- return cached;
304
+ if (cached) return cached;
300
305
  const promise = import(path).then((module) => {
301
306
  const value = module.default || module;
302
307
  loadedPlugin.set(path, value);
@@ -306,17 +311,16 @@ function loadPlugin(path) {
306
311
  return promise;
307
312
  }
308
313
  function createBabelOptions(rawOptions) {
309
- var _a;
310
314
  const babelOptions = {
311
315
  babelrc: false,
312
316
  configFile: false,
313
317
  ...rawOptions
314
318
  };
315
- babelOptions.plugins || (babelOptions.plugins = []);
316
- babelOptions.presets || (babelOptions.presets = []);
317
- babelOptions.overrides || (babelOptions.overrides = []);
318
- babelOptions.parserOpts || (babelOptions.parserOpts = {});
319
- (_a = babelOptions.parserOpts).plugins || (_a.plugins = []);
319
+ babelOptions.plugins ||= [];
320
+ babelOptions.presets ||= [];
321
+ babelOptions.overrides ||= [];
322
+ babelOptions.parserOpts ||= {};
323
+ babelOptions.parserOpts.plugins ||= [];
320
324
  return babelOptions;
321
325
  }
322
326
  function defined(value) {
package/dist/index.d.cts CHANGED
@@ -21,6 +21,14 @@ interface Options {
21
21
  babel?: BabelOptions | ((id: string, options: {
22
22
  ssr?: boolean;
23
23
  }) => BabelOptions);
24
+ /**
25
+ * React Fast Refresh runtime URL prefix.
26
+ * Useful in a module federation context to enable HMR by specifying
27
+ * the host application URL in the Vite config of a remote application.
28
+ * @example
29
+ * reactRefreshHost: 'http://localhost:3000'
30
+ */
31
+ reactRefreshHost?: string;
24
32
  }
25
33
  type BabelOptions = Omit<TransformOptions, 'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'>;
26
34
  /**
@@ -51,4 +59,5 @@ declare namespace viteReact {
51
59
  var preambleCode: string;
52
60
  }
53
61
 
54
- export { type BabelOptions, type Options, type ReactBabelOptions, type ViteReactPluginApi, viteReact as default };
62
+ export = viteReact;
63
+ export type { BabelOptions, Options, ReactBabelOptions, ViteReactPluginApi };
package/dist/index.d.mts CHANGED
@@ -21,6 +21,14 @@ interface Options {
21
21
  babel?: BabelOptions | ((id: string, options: {
22
22
  ssr?: boolean;
23
23
  }) => BabelOptions);
24
+ /**
25
+ * React Fast Refresh runtime URL prefix.
26
+ * Useful in a module federation context to enable HMR by specifying
27
+ * the host application URL in the Vite config of a remote application.
28
+ * @example
29
+ * reactRefreshHost: 'http://localhost:3000'
30
+ */
31
+ reactRefreshHost?: string;
24
32
  }
25
33
  type BabelOptions = Omit<TransformOptions, 'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'>;
26
34
  /**
@@ -51,4 +59,5 @@ declare namespace viteReact {
51
59
  var preambleCode: string;
52
60
  }
53
61
 
54
- export { type BabelOptions, type Options, type ReactBabelOptions, type ViteReactPluginApi, viteReact as default };
62
+ export { viteReact as default };
63
+ export type { BabelOptions, Options, ReactBabelOptions, ViteReactPluginApi };
package/dist/index.d.ts CHANGED
@@ -21,6 +21,14 @@ interface Options {
21
21
  babel?: BabelOptions | ((id: string, options: {
22
22
  ssr?: boolean;
23
23
  }) => BabelOptions);
24
+ /**
25
+ * React Fast Refresh runtime URL prefix.
26
+ * Useful in a module federation context to enable HMR by specifying
27
+ * the host application URL in the Vite config of a remote application.
28
+ * @example
29
+ * reactRefreshHost: 'http://localhost:3000'
30
+ */
31
+ reactRefreshHost?: string;
24
32
  }
25
33
  type BabelOptions = Omit<TransformOptions, 'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'>;
26
34
  /**
@@ -51,4 +59,5 @@ declare namespace viteReact {
51
59
  var preambleCode: string;
52
60
  }
53
61
 
54
- export { type BabelOptions, type Options, type ReactBabelOptions, type ViteReactPluginApi, viteReact as default };
62
+ export = viteReact;
63
+ export type { BabelOptions, Options, ReactBabelOptions, ViteReactPluginApi };