@vitejs/plugin-react 1.1.1 → 1.2.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,45 @@
1
+ # [1.2.0](https://github.com/vitejs/vite/compare/plugin-react@1.1.4...plugin-react@1.2.0) (2022-02-09)
2
+
3
+
4
+ ### Features
5
+
6
+ * **plugin-react:** ensure `overrides` array exists before `api.reactBabel` hooks are called ([#6750](https://github.com/vitejs/vite/issues/6750)) ([104bdb5](https://github.com/vitejs/vite/commit/104bdb5b5e44e79bf3456cabe15f3753f7c1ef28))
7
+
8
+
9
+
10
+ ## [1.1.4](https://github.com/vitejs/vite/compare/plugin-react@1.1.3...plugin-react@1.1.4) (2022-01-04)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **plugin-react:** check for import React statement in .js files ([#6320](https://github.com/vitejs/vite/issues/6320)) ([bd9e97b](https://github.com/vitejs/vite/commit/bd9e97bd1b9156059b78b531871a12f6f47c04b1)), closes [#6148](https://github.com/vitejs/vite/issues/6148) [#6148](https://github.com/vitejs/vite/issues/6148)
16
+ * **plugin-react:** restore-jsx bug when component name is lowercase ([#6110](https://github.com/vitejs/vite/issues/6110)) ([ce65c56](https://github.com/vitejs/vite/commit/ce65c567a64fad3be4209cbd1132e62e905fe349))
17
+
18
+
19
+ ### Features
20
+
21
+ * **plugin-react:** check for `api.reactBabel` on other plugins ([#5454](https://github.com/vitejs/vite/issues/5454)) ([2ab41b3](https://github.com/vitejs/vite/commit/2ab41b3184d2452be4fa0b427f05c791311644aa))
22
+
23
+
24
+
25
+ ## [1.1.3](https://github.com/vitejs/vite/compare/plugin-react@1.1.2...plugin-react@1.1.3) (2021-12-13)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * **plugin-react:** only detect preamble in hmr context ([#6096](https://github.com/vitejs/vite/issues/6096)) ([8735294](https://github.com/vitejs/vite/commit/8735294055ce16308a6b8302eba4538f4a2931d0))
31
+
32
+
33
+
34
+ ## [1.1.2](https://github.com/vitejs/vite/compare/plugin-react@1.1.1...plugin-react@1.1.2) (2021-12-13)
35
+
36
+
37
+ ### Bug Fixes
38
+
39
+ * ignore babel config when running restore-jsx ([#6047](https://github.com/vitejs/vite/issues/6047)) ([9c2843c](https://github.com/vitejs/vite/commit/9c2843cf0506844ee32f042a04c22c440434df2a))
40
+
41
+
42
+
1
43
  ## [1.1.1](https://github.com/vitejs/vite/compare/plugin-react@1.1.0...plugin-react@1.1.1) (2021-12-07)
2
44
 
3
45
 
package/README.md CHANGED
@@ -33,6 +33,16 @@ react({
33
33
  })
34
34
  ```
35
35
 
36
+ ## Opting out of the automatic JSX runtime
37
+
38
+ By default, the plugin uses the [automatic JSX runtime](https://github.com/alloc/vite-react-jsx#faq). However, if you encounter any issues, you may opt out using the `jsxRuntime` option.
39
+
40
+ ```js
41
+ react({
42
+ jsxRuntime: 'classic'
43
+ })
44
+ ```
45
+
36
46
  ## Babel configuration
37
47
 
38
48
  The `babel` option lets you add plugins, presets, and [other configuration](https://babeljs.io/docs/en/options) to the Babel transformation performed on each JSX/TSX file.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ import type { ParserOptions } from '@babel/core';
2
2
  import type { PluginOption } from 'vite';
3
3
  import type { TransformOptions } from '@babel/core';
4
4
 
5
+ export declare type BabelOptions = Omit<TransformOptions, 'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'>;
6
+
5
7
  export declare interface Options {
6
8
  include?: string | RegExp | Array<string | RegExp>;
7
9
  exclude?: string | RegExp | Array<string | RegExp>;
@@ -24,13 +26,26 @@ export declare interface Options {
24
26
  /**
25
27
  * Babel configuration applied in both dev and prod.
26
28
  */
27
- babel?: TransformOptions;
29
+ babel?: BabelOptions;
28
30
  /**
29
31
  * @deprecated Use `babel.parserOpts.plugins` instead
30
32
  */
31
33
  parserPlugins?: ParserOptions['plugins'];
32
34
  }
33
35
 
36
+ /**
37
+ * The object type used by the `options` passed to plugins with
38
+ * an `api.reactBabel` method.
39
+ */
40
+ export declare interface ReactBabelOptions extends BabelOptions {
41
+ plugins: Extract<BabelOptions['plugins'], any[]>;
42
+ presets: Extract<BabelOptions['presets'], any[]>;
43
+ overrides: Extract<BabelOptions['overrides'], any[]>;
44
+ parserOpts: ParserOptions & {
45
+ plugins: Extract<ParserOptions['plugins'], any[]>;
46
+ };
47
+ }
48
+
34
49
  declare function viteReact(opts?: Options): PluginOption[];
35
50
 
36
51
  declare namespace viteReact {
package/dist/index.js CHANGED
@@ -23,24 +23,28 @@ var __spreadValues = (a, b) => {
23
23
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
24
  var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
25
25
  var __esm = (fn, res) => function __init() {
26
- return fn && (res = (0, fn[Object.keys(fn)[0]])(fn = 0)), res;
26
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
27
27
  };
28
28
  var __export = (target, all) => {
29
- __markAsModule(target);
30
29
  for (var name in all)
31
30
  __defProp(target, name, { get: all[name], enumerable: true });
32
31
  };
33
- var __reExport = (target, module2, desc) => {
32
+ var __reExport = (target, module2, copyDefault, desc) => {
34
33
  if (module2 && typeof module2 === "object" || typeof module2 === "function") {
35
34
  for (let key of __getOwnPropNames(module2))
36
- if (!__hasOwnProp.call(target, key) && key !== "default")
35
+ if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
37
36
  __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
38
37
  }
39
38
  return target;
40
39
  };
41
- var __toModule = (module2) => {
42
- return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
40
+ var __toESM = (module2, isNodeMode) => {
41
+ return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", !isNodeMode && module2 && module2.__esModule ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
43
42
  };
43
+ var __toCommonJS = /* @__PURE__ */ ((cache) => {
44
+ return (module2, temp) => {
45
+ return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp);
46
+ };
47
+ })(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
44
48
 
45
49
  // src/jsx-runtime/babel-restore-jsx.ts
46
50
  var babel_restore_jsx_exports = {};
@@ -78,7 +82,7 @@ function babel_restore_jsx_default({ types: t }) {
78
82
  if (node == null) {
79
83
  return null;
80
84
  }
81
- const name = getJSXIdentifier(node);
85
+ const name = getJSXIdentifier(node, true);
82
86
  if (name != null) {
83
87
  return name;
84
88
  }
@@ -128,8 +132,8 @@ function babel_restore_jsx_default({ types: t }) {
128
132
  }
129
133
  return children;
130
134
  }
131
- function getJSXIdentifier(node) {
132
- if (t.isIdentifier(node)) {
135
+ function getJSXIdentifier(node, tag = false) {
136
+ if (t.isIdentifier(node) && (!tag || node.name.match(/^[A-Z]/))) {
133
137
  return t.jsxIdentifier(node.name);
134
138
  }
135
139
  if (t.isStringLiteral(node)) {
@@ -170,15 +174,16 @@ var init_babel_restore_jsx = __esm({
170
174
  });
171
175
 
172
176
  // src/index.ts
173
- __export(exports, {
177
+ var src_exports = {};
178
+ __export(src_exports, {
174
179
  default: () => viteReact
175
180
  });
176
- var babel = __toModule(require("@babel/core"));
177
- var import_pluginutils = __toModule(require("@rollup/pluginutils"));
178
- var import_resolve = __toModule(require("resolve"));
181
+ var babel = __toESM(require("@babel/core"));
182
+ var import_pluginutils = require("@rollup/pluginutils");
183
+ var import_resolve = __toESM(require("resolve"));
179
184
 
180
185
  // src/fast-refresh.ts
181
- var import_fs = __toModule(require("fs"));
186
+ var import_fs = __toESM(require("fs"));
182
187
  var runtimePublicPath = "/@react-refresh";
183
188
  var runtimeFilePath = require.resolve("react-refresh/cjs/react-refresh-runtime.development.js");
184
189
  var runtimeCode = `
@@ -207,14 +212,14 @@ import RefreshRuntime from "${runtimePublicPath}";
207
212
  let prevRefreshReg;
208
213
  let prevRefreshSig;
209
214
 
210
- if (!window.__vite_plugin_react_preamble_installed__) {
211
- throw new Error(
212
- "@vitejs/plugin-react can't detect preamble. Something is wrong. " +
213
- "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
214
- );
215
- }
216
-
217
215
  if (import.meta.hot) {
216
+ if (!window.__vite_plugin_react_preamble_installed__) {
217
+ throw new Error(
218
+ "@vitejs/plugin-react can't detect preamble. Something is wrong. " +
219
+ "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
220
+ );
221
+ }
222
+
218
223
  prevRefreshReg = window.$RefreshReg$;
219
224
  prevRefreshSig = window.$RefreshSig$;
220
225
  window.$RefreshReg$ = (type, id) => {
@@ -265,9 +270,7 @@ function isComponentLikeName(name) {
265
270
  }
266
271
 
267
272
  // src/jsx-runtime/babel-import-to-require.ts
268
- function babelImportToRequire({
269
- types: t
270
- }) {
273
+ function babelImportToRequire({ types: t }) {
271
274
  return {
272
275
  visitor: {
273
276
  ImportDeclaration(path) {
@@ -304,13 +307,15 @@ async function restoreJSX(babel2, code, filename) {
304
307
  code = code.replace(/createElement\(Fragment,/g, "createElement(React.Fragment,");
305
308
  babelRestoreJSX || (babelRestoreJSX = Promise.resolve().then(() => (init_babel_restore_jsx(), babel_restore_jsx_exports)));
306
309
  const result = await babel2.transformAsync(code, {
310
+ babelrc: false,
311
+ configFile: false,
307
312
  ast: true,
308
313
  code: false,
309
314
  filename,
310
315
  parserOpts: {
311
316
  plugins: ["jsx"]
312
317
  },
313
- plugins: [await babelRestoreJSX]
318
+ plugins: [(await babelRestoreJSX).default]
314
319
  });
315
320
  return [result == null ? void 0 : result.ast, isCommonJS];
316
321
  }
@@ -328,7 +333,7 @@ function parseReactAlias(code) {
328
333
 
329
334
  // src/index.ts
330
335
  function viteReact(opts = {}) {
331
- var _a, _b, _c;
336
+ var _a;
332
337
  let base = "/";
333
338
  let filter = (0, import_pluginutils.createFilter)(opts.include, opts.exclude);
334
339
  let isProduction = true;
@@ -336,8 +341,15 @@ function viteReact(opts = {}) {
336
341
  let skipFastRefresh = opts.fastRefresh === false;
337
342
  let skipReactImport = false;
338
343
  const useAutomaticRuntime = opts.jsxRuntime !== "classic";
339
- const userPlugins = ((_a = opts.babel) == null ? void 0 : _a.plugins) || [];
340
- const userParserPlugins = opts.parserPlugins || ((_c = (_b = opts.babel) == null ? void 0 : _b.parserOpts) == null ? void 0 : _c.plugins) || [];
344
+ const babelOptions = __spreadValues({
345
+ babelrc: false,
346
+ configFile: false
347
+ }, opts.babel);
348
+ babelOptions.plugins || (babelOptions.plugins = []);
349
+ babelOptions.presets || (babelOptions.presets = []);
350
+ babelOptions.overrides || (babelOptions.overrides = []);
351
+ babelOptions.parserOpts || (babelOptions.parserOpts = {});
352
+ (_a = babelOptions.parserOpts).plugins || (_a.plugins = opts.parserPlugins || []);
341
353
  const importReactRE = /(^|\n)import\s+(\*\s+as\s+)?React(,|\s+)/;
342
354
  const fileExtensionRE = /\.[^\/\s\?]+$/;
343
355
  const viteBabel = {
@@ -356,10 +368,17 @@ function viteReact(opts = {}) {
356
368
  skipReactImport = true;
357
369
  config.logger.warn("[@vitejs/plugin-react] This plugin imports React for you automatically, so you can stop using `esbuild.jsxInject` for that purpose.");
358
370
  }
359
- config.plugins.forEach((plugin) => (plugin.name === "react-refresh" || plugin !== viteReactJsx && plugin.name === "vite:react-jsx") && config.logger.warn(`[@vitejs/plugin-react] You should stop using "${plugin.name}" since this plugin conflicts with it.`));
371
+ config.plugins.forEach((plugin) => {
372
+ var _a2;
373
+ const hasConflict = plugin.name === "react-refresh" || plugin !== viteReactJsx && plugin.name === "vite:react-jsx";
374
+ if (hasConflict)
375
+ return config.logger.warn(`[@vitejs/plugin-react] You should stop using "${plugin.name}" since this plugin conflicts with it.`);
376
+ if ((_a2 = plugin.api) == null ? void 0 : _a2.reactBabel) {
377
+ plugin.api.reactBabel(babelOptions, config);
378
+ }
379
+ });
360
380
  },
361
381
  async transform(code, id, options) {
362
- var _a2, _b2, _c2, _d;
363
382
  const ssr = typeof options === "boolean" ? options : (options == null ? void 0 : options.ssr) === true;
364
383
  const [filepath, querystring = ""] = id.split("?");
365
384
  const [extension = ""] = querystring.match(fileExtensionRE) || filepath.match(fileExtensionRE) || [];
@@ -367,10 +386,10 @@ function viteReact(opts = {}) {
367
386
  const isJSX = extension.endsWith("x");
368
387
  const isNodeModules = id.includes("/node_modules/");
369
388
  const isProjectFile = !isNodeModules && (id[0] === "\0" || id.startsWith(projectRoot + "/"));
370
- const plugins = isProjectFile ? [...userPlugins] : [];
389
+ const plugins = isProjectFile ? [...babelOptions.plugins] : [];
371
390
  let useFastRefresh = false;
372
391
  if (!skipFastRefresh && !ssr && !isNodeModules) {
373
- const isReactModule = isJSX || code.includes("react");
392
+ const isReactModule = isJSX || importReactRE.test(code);
374
393
  if (isReactModule && filter(id)) {
375
394
  useFastRefresh = true;
376
395
  plugins.push([
@@ -404,12 +423,12 @@ function viteReact(opts = {}) {
404
423
  }
405
424
  }
406
425
  }
407
- const shouldSkip = !plugins.length && !((_a2 = opts.babel) == null ? void 0 : _a2.configFile) && !(isProjectFile && ((_b2 = opts.babel) == null ? void 0 : _b2.babelrc));
426
+ const shouldSkip = !plugins.length && !babelOptions.configFile && !(isProjectFile && babelOptions.babelrc);
408
427
  if (shouldSkip) {
409
428
  return;
410
429
  }
411
430
  const parserPlugins = [
412
- ...userParserPlugins,
431
+ ...babelOptions.parserOpts.plugins,
413
432
  "importMeta",
414
433
  "topLevelAwait",
415
434
  "classProperties",
@@ -422,28 +441,25 @@ function viteReact(opts = {}) {
422
441
  if (/\.tsx?$/.test(extension)) {
423
442
  parserPlugins.push("typescript");
424
443
  }
444
+ const transformAsync2 = ast ? babel.transformFromAstAsync.bind(babel, ast, code) : babel.transformAsync.bind(babel, code);
425
445
  const isReasonReact = extension.endsWith(".bs.js");
426
- const babelOpts = __spreadProps(__spreadValues({
427
- babelrc: false,
428
- configFile: false
429
- }, opts.babel), {
446
+ const result = await transformAsync2(__spreadProps(__spreadValues({}, babelOptions), {
430
447
  ast: !isReasonReact,
431
448
  root: projectRoot,
432
449
  filename: id,
433
450
  sourceFileName: filepath,
434
- parserOpts: __spreadProps(__spreadValues({}, (_c2 = opts.babel) == null ? void 0 : _c2.parserOpts), {
451
+ parserOpts: __spreadProps(__spreadValues({}, babelOptions.parserOpts), {
435
452
  sourceType: "module",
436
453
  allowAwaitOutsideFunction: true,
437
454
  plugins: parserPlugins
438
455
  }),
439
- generatorOpts: __spreadProps(__spreadValues({}, (_d = opts.babel) == null ? void 0 : _d.generatorOpts), {
456
+ generatorOpts: __spreadProps(__spreadValues({}, babelOptions.generatorOpts), {
440
457
  decoratorsBeforeExport: true
441
458
  }),
442
459
  plugins,
443
460
  sourceMaps: true,
444
461
  inputSourceMap: false
445
- });
446
- const result = ast ? await babel.transformFromAstAsync(ast, code, babelOpts) : await babel.transformAsync(code, babelOpts);
462
+ }));
447
463
  if (result) {
448
464
  let code2 = result.code;
449
465
  if (useFastRefresh && /\$RefreshReg\$\(/.test(code2)) {
@@ -518,10 +534,10 @@ function viteReact(opts = {}) {
518
534
  }
519
535
  viteReact.preambleCode = preambleCode;
520
536
  function loadPlugin(path) {
521
- return Promise.resolve().then(() => __toModule(require(path))).then((module2) => module2.default || module2);
537
+ return Promise.resolve().then(() => __toESM(require(path))).then((module2) => module2.default || module2);
522
538
  }
523
539
  module.exports = viteReact;
524
- viteReact["default"] = viteReact;
540
+ viteReact['default'] = viteReact;
525
541
  // Annotate the CommonJS export names for ESM import in node:
526
542
  0 && (module.exports = {});
527
543
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "license": "MIT",
5
5
  "author": "Evan You",
6
6
  "contributors": [
@@ -15,10 +15,11 @@
15
15
  "scripts": {
16
16
  "dev": "tsc -p . -w --incremental",
17
17
  "build": "rimraf dist && run-s build-bundle build-types",
18
- "build-bundle": "esbuild src/index.ts --bundle --platform=node --target=node12 --external:@babel/* --external:@rollup/* --external:resolve --external:react-refresh/* --outfile=dist/index.js",
18
+ "build-bundle": "esbuild src/index.ts --bundle --platform=node --target=node12 --external:@babel/* --external:@rollup/* --external:resolve --external:react-refresh/* --outfile=dist/index.js && npm run patch-dist",
19
+ "patch-dist": "ts-node ../../scripts/patchEsbuildDist.ts dist/index.js viteReact",
19
20
  "build-types": "tsc -p . --emitDeclarationOnly --outDir temp && api-extractor run && rimraf temp",
20
21
  "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s --commit-path . --lerna-package plugin-react",
21
- "release": "node ../../scripts/release.cjs"
22
+ "release": "ts-node ../../scripts/release.ts"
22
23
  },
23
24
  "engines": {
24
25
  "node": ">=12.0.0"
@@ -33,13 +34,13 @@
33
34
  },
34
35
  "homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-react#readme",
35
36
  "dependencies": {
36
- "@babel/core": "^7.16.0",
37
- "@babel/plugin-transform-react-jsx": "^7.16.0",
38
- "@babel/plugin-transform-react-jsx-development": "^7.16.0",
39
- "@babel/plugin-transform-react-jsx-self": "^7.16.0",
40
- "@babel/plugin-transform-react-jsx-source": "^7.16.0",
41
- "@rollup/pluginutils": "^4.1.1",
37
+ "@babel/core": "^7.16.12",
38
+ "@babel/plugin-transform-react-jsx": "^7.16.7",
39
+ "@babel/plugin-transform-react-jsx-development": "^7.16.7",
40
+ "@babel/plugin-transform-react-jsx-self": "^7.16.7",
41
+ "@babel/plugin-transform-react-jsx-source": "^7.16.7",
42
+ "@rollup/pluginutils": "^4.1.2",
42
43
  "react-refresh": "^0.11.0",
43
- "resolve": "^1.20.0"
44
+ "resolve": "^1.22.0"
44
45
  }
45
46
  }
@@ -35,14 +35,14 @@ import RefreshRuntime from "${runtimePublicPath}";
35
35
  let prevRefreshReg;
36
36
  let prevRefreshSig;
37
37
 
38
- if (!window.__vite_plugin_react_preamble_installed__) {
39
- throw new Error(
40
- "@vitejs/plugin-react can't detect preamble. Something is wrong. " +
41
- "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
42
- );
43
- }
44
-
45
38
  if (import.meta.hot) {
39
+ if (!window.__vite_plugin_react_preamble_installed__) {
40
+ throw new Error(
41
+ "@vitejs/plugin-react can't detect preamble. Something is wrong. " +
42
+ "See https://github.com/vitejs/vite-plugin-react/pull/11#discussion_r430879201"
43
+ );
44
+ }
45
+
46
46
  prevRefreshReg = window.$RefreshReg$;
47
47
  prevRefreshSig = window.$RefreshSig$;
48
48
  window.$RefreshReg$ = (type, id) => {
package/src/index.ts CHANGED
@@ -36,13 +36,47 @@ export interface Options {
36
36
  /**
37
37
  * Babel configuration applied in both dev and prod.
38
38
  */
39
- babel?: TransformOptions
39
+ babel?: BabelOptions
40
40
  /**
41
41
  * @deprecated Use `babel.parserOpts.plugins` instead
42
42
  */
43
43
  parserPlugins?: ParserOptions['plugins']
44
44
  }
45
45
 
46
+ export type BabelOptions = Omit<
47
+ TransformOptions,
48
+ | 'ast'
49
+ | 'filename'
50
+ | 'root'
51
+ | 'sourceFileName'
52
+ | 'sourceMaps'
53
+ | 'inputSourceMap'
54
+ >
55
+
56
+ /**
57
+ * The object type used by the `options` passed to plugins with
58
+ * an `api.reactBabel` method.
59
+ */
60
+ export interface ReactBabelOptions extends BabelOptions {
61
+ plugins: Extract<BabelOptions['plugins'], any[]>
62
+ presets: Extract<BabelOptions['presets'], any[]>
63
+ overrides: Extract<BabelOptions['overrides'], any[]>
64
+ parserOpts: ParserOptions & {
65
+ plugins: Extract<ParserOptions['plugins'], any[]>
66
+ }
67
+ }
68
+
69
+ declare module 'vite' {
70
+ export interface Plugin {
71
+ api?: {
72
+ /**
73
+ * Manipulate the Babel options of `@vitejs/plugin-react`
74
+ */
75
+ reactBabel?: (options: ReactBabelOptions, config: ResolvedConfig) => void
76
+ }
77
+ }
78
+ }
79
+
46
80
  export default function viteReact(opts: Options = {}): PluginOption[] {
47
81
  // Provide default values for Rollup compat.
48
82
  let base = '/'
@@ -54,11 +88,19 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
54
88
 
55
89
  const useAutomaticRuntime = opts.jsxRuntime !== 'classic'
56
90
 
57
- const userPlugins = opts.babel?.plugins || []
58
- const userParserPlugins =
59
- opts.parserPlugins || opts.babel?.parserOpts?.plugins || []
91
+ const babelOptions = {
92
+ babelrc: false,
93
+ configFile: false,
94
+ ...opts.babel
95
+ } as ReactBabelOptions
60
96
 
61
- // Support pattens like:
97
+ babelOptions.plugins ||= []
98
+ babelOptions.presets ||= []
99
+ babelOptions.overrides ||= []
100
+ babelOptions.parserOpts ||= {} as any
101
+ babelOptions.parserOpts.plugins ||= opts.parserPlugins || []
102
+
103
+ // Support patterns like:
62
104
  // - import * as React from 'react';
63
105
  // - import React from 'react';
64
106
  // - import React, {useEffect} from 'react';
@@ -88,15 +130,21 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
88
130
  )
89
131
  }
90
132
 
91
- config.plugins.forEach(
92
- (plugin) =>
93
- (plugin.name === 'react-refresh' ||
94
- (plugin !== viteReactJsx && plugin.name === 'vite:react-jsx')) &&
95
- config.logger.warn(
133
+ config.plugins.forEach((plugin) => {
134
+ const hasConflict =
135
+ plugin.name === 'react-refresh' ||
136
+ (plugin !== viteReactJsx && plugin.name === 'vite:react-jsx')
137
+
138
+ if (hasConflict)
139
+ return config.logger.warn(
96
140
  `[@vitejs/plugin-react] You should stop using "${plugin.name}" ` +
97
141
  `since this plugin conflicts with it.`
98
142
  )
99
- )
143
+
144
+ if (plugin.api?.reactBabel) {
145
+ plugin.api.reactBabel(babelOptions, config)
146
+ }
147
+ })
100
148
  },
101
149
  async transform(code, id, options) {
102
150
  const ssr = typeof options === 'boolean' ? options : options?.ssr === true
@@ -113,12 +161,12 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
113
161
  const isProjectFile =
114
162
  !isNodeModules && (id[0] === '\0' || id.startsWith(projectRoot + '/'))
115
163
 
116
- const plugins = isProjectFile ? [...userPlugins] : []
164
+ const plugins = isProjectFile ? [...babelOptions.plugins] : []
117
165
 
118
166
  let useFastRefresh = false
119
167
  if (!skipFastRefresh && !ssr && !isNodeModules) {
120
168
  // Modules with .js or .ts extension must import React.
121
- const isReactModule = isJSX || code.includes('react')
169
+ const isReactModule = isJSX || importReactRE.test(code)
122
170
  if (isReactModule && filter(id)) {
123
171
  useFastRefresh = true
124
172
  plugins.push([
@@ -179,15 +227,15 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
179
227
  // module, including node_modules and linked packages.
180
228
  const shouldSkip =
181
229
  !plugins.length &&
182
- !opts.babel?.configFile &&
183
- !(isProjectFile && opts.babel?.babelrc)
230
+ !babelOptions.configFile &&
231
+ !(isProjectFile && babelOptions.babelrc)
184
232
 
185
233
  if (shouldSkip) {
186
234
  return // Avoid parsing if no plugins exist.
187
235
  }
188
236
 
189
- const parserPlugins: typeof userParserPlugins = [
190
- ...userParserPlugins,
237
+ const parserPlugins: typeof babelOptions.parserOpts.plugins = [
238
+ ...babelOptions.parserOpts.plugins,
191
239
  'importMeta',
192
240
  // This plugin is applied before esbuild transforms the code,
193
241
  // so we need to enable some stage 3 syntax that is supported in
@@ -206,35 +254,32 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
206
254
  parserPlugins.push('typescript')
207
255
  }
208
256
 
209
- const isReasonReact = extension.endsWith('.bs.js')
257
+ const transformAsync = ast
258
+ ? babel.transformFromAstAsync.bind(babel, ast, code)
259
+ : babel.transformAsync.bind(babel, code)
210
260
 
211
- const babelOpts: TransformOptions = {
212
- babelrc: false,
213
- configFile: false,
214
- ...opts.babel,
261
+ const isReasonReact = extension.endsWith('.bs.js')
262
+ const result = await transformAsync({
263
+ ...babelOptions,
215
264
  ast: !isReasonReact,
216
265
  root: projectRoot,
217
266
  filename: id,
218
267
  sourceFileName: filepath,
219
268
  parserOpts: {
220
- ...opts.babel?.parserOpts,
269
+ ...babelOptions.parserOpts,
221
270
  sourceType: 'module',
222
271
  allowAwaitOutsideFunction: true,
223
272
  plugins: parserPlugins
224
273
  },
225
274
  generatorOpts: {
226
- ...opts.babel?.generatorOpts,
275
+ ...babelOptions.generatorOpts,
227
276
  decoratorsBeforeExport: true
228
277
  },
229
278
  plugins,
230
279
  sourceMaps: true,
231
280
  // Vite handles sourcemap flattening
232
281
  inputSourceMap: false as any
233
- }
234
-
235
- const result = ast
236
- ? await babel.transformFromAstAsync(ast, code, babelOpts)
237
- : await babel.transformAsync(code, babelOpts)
282
+ })
238
283
 
239
284
  if (result) {
240
285
  let code = result.code!
@@ -323,5 +368,8 @@ function loadPlugin(path: string): Promise<any> {
323
368
  }
324
369
 
325
370
  // overwrite for cjs require('...')() usage
326
- module.exports = viteReact
327
- viteReact['default'] = viteReact
371
+ // The following lines are inserted by scripts/patchEsbuildDist.ts,
372
+ // this doesn't bundle correctly after esbuild 0.14.4
373
+ //
374
+ // module.exports = viteReact
375
+ // viteReact['default'] = viteReact
@@ -1,3 +1,4 @@
1
+ import type * as babelCore from '@babel/core'
1
2
  import type { types as t, Visitor } from '@babel/core'
2
3
 
3
4
  /**
@@ -9,9 +10,7 @@ import type { types as t, Visitor } from '@babel/core'
9
10
  *
10
11
  * var _jsx = require("react/jsx-runtime").jsx
11
12
  */
12
- export function babelImportToRequire({
13
- types: t
14
- }: typeof import('@babel/core')): {
13
+ export function babelImportToRequire({ types: t }: typeof babelCore): {
15
14
  visitor: Visitor
16
15
  } {
17
16
  return {
@@ -108,4 +108,10 @@ describe('babel-restore-jsx', () => {
108
108
  )
109
109
  ).toMatchInlineSnapshot(`"<h1>{foo ? <p /> : null}</h1>;"`)
110
110
  })
111
+
112
+ it('should handle lowercase component names', () => {
113
+ expect(jsx('React.createElement(aaa)')).toMatchInlineSnapshot(
114
+ `"React.createElement(aaa);"`
115
+ )
116
+ })
111
117
  })
@@ -2,7 +2,7 @@
2
2
  * https://github.com/flying-sheep/babel-plugin-transform-react-createelement-to-jsx
3
3
  * @license GNU General Public License v3.0
4
4
  */
5
- import * as babel from '@babel/core'
5
+ import type * as babel from '@babel/core'
6
6
 
7
7
  /**
8
8
  * Visitor factory for babel, converting React.createElement(...) to <jsx ...>...</jsx>
@@ -76,7 +76,7 @@ export default function ({ types: t }: typeof babel): babel.PluginObj {
76
76
  return null
77
77
  }
78
78
 
79
- const name = getJSXIdentifier(node)
79
+ const name = getJSXIdentifier(node, true)
80
80
  if (name != null) {
81
81
  return name
82
82
  }
@@ -152,9 +152,9 @@ export default function ({ types: t }: typeof babel): babel.PluginObj {
152
152
  return children
153
153
  }
154
154
 
155
- function getJSXIdentifier(node: any) {
155
+ function getJSXIdentifier(node: any, tag = false) {
156
156
  //TODO: JSXNamespacedName
157
- if (t.isIdentifier(node)) {
157
+ if (t.isIdentifier(node) && (!tag || node.name.match(/^[A-Z]/))) {
158
158
  return t.jsxIdentifier(node.name)
159
159
  }
160
160
  if (t.isStringLiteral(node)) {
@@ -1,3 +1,4 @@
1
+ import type * as babelCore from '@babel/core'
1
2
  import type { PluginItem, types as t } from '@babel/core'
2
3
 
3
4
  type RestoredJSX = [result: t.File | null | undefined, isCommonJS: boolean]
@@ -8,7 +9,7 @@ const jsxNotFound: RestoredJSX = [null, false]
8
9
 
9
10
  /** Restore JSX from `React.createElement` calls */
10
11
  export async function restoreJSX(
11
- babel: typeof import('@babel/core'),
12
+ babel: typeof babelCore,
12
13
  code: string,
13
14
  filename: string
14
15
  ): Promise<RestoredJSX> {
@@ -48,13 +49,16 @@ export async function restoreJSX(
48
49
  babelRestoreJSX ||= import('./babel-restore-jsx')
49
50
 
50
51
  const result = await babel.transformAsync(code, {
52
+ babelrc: false,
53
+ configFile: false,
51
54
  ast: true,
52
55
  code: false,
53
56
  filename,
54
57
  parserOpts: {
55
58
  plugins: ['jsx']
56
59
  },
57
- plugins: [await babelRestoreJSX]
60
+ // @ts-ignore
61
+ plugins: [(await babelRestoreJSX).default]
58
62
  })
59
63
 
60
64
  return [result?.ast, isCommonJS]