@vitejs/plugin-react 2.0.0-alpha.2 → 2.0.0-beta.1

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/dist/index.cjs CHANGED
@@ -1,11 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const path = require('path');
3
+ const path = require('node:path');
4
4
  const babel = require('@babel/core');
5
- const pluginutils = require('@rollup/pluginutils');
6
5
  const vite = require('vite');
7
- const fs = require('fs');
8
- const module$1 = require('module');
6
+ const fs = require('node:fs');
7
+ const node_module = require('node:module');
9
8
 
10
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
11
10
 
@@ -26,7 +25,7 @@ const babel__namespace = /*#__PURE__*/_interopNamespace(babel);
26
25
  const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
27
26
 
28
27
  const runtimePublicPath = "/@react-refresh";
29
- const _require = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
28
+ 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)));
30
29
  const reactRefreshDir = path__default.dirname(_require.resolve("react-refresh/package.json"));
31
30
  const runtimeFilePath = path__default.join(reactRefreshDir, "cjs/react-refresh-runtime.development.js");
32
31
  const runtimeCode = `
@@ -173,11 +172,11 @@ async function restoreJSX(babel, code, filename) {
173
172
  return [result?.ast, isCommonJS];
174
173
  }
175
174
  function parseReactAlias(code) {
176
- let match = code.match(/\b(var|let|const) +(\w+) *= *require\(["']react["']\)/);
175
+ let match = code.match(/\b(var|let|const)\s+([^=\{\s]+)\s*=\s*require\(["']react["']\)/);
177
176
  if (match) {
178
177
  return [match[2], true];
179
178
  }
180
- match = code.match(/^import (\w+).+? from ["']react["']/m);
179
+ match = code.match(/^import\s+(?:\*\s+as\s+)?(\w+).+?\bfrom\s*["']react["']/m);
181
180
  if (match) {
182
181
  return [match[1], false];
183
182
  }
@@ -185,9 +184,9 @@ function parseReactAlias(code) {
185
184
  }
186
185
 
187
186
  function viteReact(opts = {}) {
188
- let base = "/";
187
+ let devBase = "/";
189
188
  let resolvedCacheDir;
190
- let filter = pluginutils.createFilter(opts.include, opts.exclude);
189
+ let filter = vite.createFilter(opts.include, opts.exclude);
191
190
  let isProduction = true;
192
191
  let projectRoot = process.cwd();
193
192
  let skipFastRefresh = opts.fastRefresh === false;
@@ -200,11 +199,22 @@ function viteReact(opts = {}) {
200
199
  const viteBabel = {
201
200
  name: "vite:react-babel",
202
201
  enforce: "pre",
202
+ config() {
203
+ if (opts.jsxRuntime === "classic") {
204
+ return {
205
+ esbuild: {
206
+ logOverride: {
207
+ "this-is-undefined-in-esm": "silent"
208
+ }
209
+ }
210
+ };
211
+ }
212
+ },
203
213
  configResolved(config) {
204
- base = config.base;
214
+ devBase = config.base;
205
215
  projectRoot = config.root;
206
216
  resolvedCacheDir = vite.normalizePath(path__default.resolve(config.cacheDir));
207
- filter = pluginutils.createFilter(opts.include, opts.exclude, {
217
+ filter = vite.createFilter(opts.include, opts.exclude, {
208
218
  resolve: projectRoot
209
219
  });
210
220
  isProduction = config.isProduction;
@@ -222,17 +232,17 @@ function viteReact(opts = {}) {
222
232
  runPluginOverrides = (babelOptions, context) => {
223
233
  const hooks = config.plugins.map((plugin) => plugin.api?.reactBabel).filter(Boolean);
224
234
  if (hooks.length > 0) {
225
- return (runPluginOverrides = (babelOptions2) => {
226
- hooks.forEach((hook) => hook(babelOptions2, context, config));
235
+ return (runPluginOverrides = (babelOptions2, context2) => {
236
+ hooks.forEach((hook) => hook(babelOptions2, context2, config));
227
237
  return true;
228
- })(babelOptions);
238
+ })(babelOptions, context);
229
239
  }
230
240
  runPluginOverrides = () => false;
231
241
  return false;
232
242
  };
233
243
  },
234
244
  async transform(code, id, options) {
235
- const ssr = typeof options === "boolean" ? options : options?.ssr === true;
245
+ const ssr = options?.ssr === true;
236
246
  const [filepath, querystring = ""] = id.split("?");
237
247
  const [extension = ""] = querystring.match(fileExtensionRE) || filepath.match(fileExtensionRE) || [];
238
248
  if (/\.(mjs|[tj]sx?)$/.test(extension)) {
@@ -291,7 +301,9 @@ function viteReact(opts = {}) {
291
301
  }
292
302
  const shouldSkip = !plugins.length && !babelOptions.configFile && !(isProjectFile && babelOptions.babelrc);
293
303
  if (shouldSkip) {
294
- return;
304
+ return {
305
+ code
306
+ };
295
307
  }
296
308
  const parserPlugins = [
297
309
  ...babelOptions.parserOpts.plugins,
@@ -367,20 +379,49 @@ function viteReact(opts = {}) {
367
379
  {
368
380
  tag: "script",
369
381
  attrs: { type: "module" },
370
- children: preambleCode.replace(`__BASE__`, base)
382
+ children: preambleCode.replace(`__BASE__`, devBase)
371
383
  }
372
384
  ];
373
385
  }
374
386
  };
387
+ const reactJsxRuntimeId = "react/jsx-runtime";
388
+ const reactJsxDevRuntimeId = "react/jsx-dev-runtime";
389
+ const virtualReactJsxRuntimeId = "\0" + reactJsxRuntimeId;
390
+ const virtualReactJsxDevRuntimeId = "\0" + reactJsxDevRuntimeId;
375
391
  const viteReactJsx = {
376
392
  name: "vite:react-jsx",
377
393
  enforce: "pre",
378
394
  config() {
379
395
  return {
380
396
  optimizeDeps: {
381
- include: ["react/jsx-dev-runtime"]
397
+ include: [reactJsxRuntimeId, reactJsxDevRuntimeId]
382
398
  }
383
399
  };
400
+ },
401
+ resolveId(id, importer) {
402
+ if (id === reactJsxRuntimeId && importer !== virtualReactJsxRuntimeId) {
403
+ return virtualReactJsxRuntimeId;
404
+ }
405
+ if (id === reactJsxDevRuntimeId && importer !== virtualReactJsxDevRuntimeId) {
406
+ return virtualReactJsxDevRuntimeId;
407
+ }
408
+ },
409
+ load(id) {
410
+ if (id === virtualReactJsxRuntimeId) {
411
+ return [
412
+ `import * as jsxRuntime from ${JSON.stringify(reactJsxRuntimeId)}`,
413
+ `export const Fragment = jsxRuntime.Fragment`,
414
+ `export const jsx = jsxRuntime.jsx`,
415
+ `export const jsxs = jsxRuntime.jsxs`
416
+ ].join("\n");
417
+ }
418
+ if (id === virtualReactJsxDevRuntimeId) {
419
+ return [
420
+ `import * as jsxRuntime from ${JSON.stringify(reactJsxDevRuntimeId)}`,
421
+ `export const Fragment = jsxRuntime.Fragment`,
422
+ `export const jsxDEV = jsxRuntime.jsxDEV`
423
+ ].join("\n");
424
+ }
384
425
  }
385
426
  };
386
427
  return [viteBabel, viteReactRefresh, useAutomaticRuntime && viteReactJsx];
package/dist/index.mjs CHANGED
@@ -1,9 +1,8 @@
1
- import path from 'path';
1
+ import path from 'node:path';
2
2
  import * as babel from '@babel/core';
3
- import { createFilter } from '@rollup/pluginutils';
4
- import { normalizePath } from 'vite';
5
- import fs from 'fs';
6
- import { createRequire } from 'module';
3
+ import { createFilter, normalizePath } from 'vite';
4
+ import fs from 'node:fs';
5
+ import { createRequire } from 'node:module';
7
6
 
8
7
  const runtimePublicPath = "/@react-refresh";
9
8
  const _require = createRequire(import.meta.url);
@@ -153,11 +152,11 @@ async function restoreJSX(babel, code, filename) {
153
152
  return [result?.ast, isCommonJS];
154
153
  }
155
154
  function parseReactAlias(code) {
156
- let match = code.match(/\b(var|let|const) +(\w+) *= *require\(["']react["']\)/);
155
+ let match = code.match(/\b(var|let|const)\s+([^=\{\s]+)\s*=\s*require\(["']react["']\)/);
157
156
  if (match) {
158
157
  return [match[2], true];
159
158
  }
160
- match = code.match(/^import (\w+).+? from ["']react["']/m);
159
+ match = code.match(/^import\s+(?:\*\s+as\s+)?(\w+).+?\bfrom\s*["']react["']/m);
161
160
  if (match) {
162
161
  return [match[1], false];
163
162
  }
@@ -165,7 +164,7 @@ function parseReactAlias(code) {
165
164
  }
166
165
 
167
166
  function viteReact(opts = {}) {
168
- let base = "/";
167
+ let devBase = "/";
169
168
  let resolvedCacheDir;
170
169
  let filter = createFilter(opts.include, opts.exclude);
171
170
  let isProduction = true;
@@ -180,8 +179,19 @@ function viteReact(opts = {}) {
180
179
  const viteBabel = {
181
180
  name: "vite:react-babel",
182
181
  enforce: "pre",
182
+ config() {
183
+ if (opts.jsxRuntime === "classic") {
184
+ return {
185
+ esbuild: {
186
+ logOverride: {
187
+ "this-is-undefined-in-esm": "silent"
188
+ }
189
+ }
190
+ };
191
+ }
192
+ },
183
193
  configResolved(config) {
184
- base = config.base;
194
+ devBase = config.base;
185
195
  projectRoot = config.root;
186
196
  resolvedCacheDir = normalizePath(path.resolve(config.cacheDir));
187
197
  filter = createFilter(opts.include, opts.exclude, {
@@ -202,17 +212,17 @@ function viteReact(opts = {}) {
202
212
  runPluginOverrides = (babelOptions, context) => {
203
213
  const hooks = config.plugins.map((plugin) => plugin.api?.reactBabel).filter(Boolean);
204
214
  if (hooks.length > 0) {
205
- return (runPluginOverrides = (babelOptions2) => {
206
- hooks.forEach((hook) => hook(babelOptions2, context, config));
215
+ return (runPluginOverrides = (babelOptions2, context2) => {
216
+ hooks.forEach((hook) => hook(babelOptions2, context2, config));
207
217
  return true;
208
- })(babelOptions);
218
+ })(babelOptions, context);
209
219
  }
210
220
  runPluginOverrides = () => false;
211
221
  return false;
212
222
  };
213
223
  },
214
224
  async transform(code, id, options) {
215
- const ssr = typeof options === "boolean" ? options : options?.ssr === true;
225
+ const ssr = options?.ssr === true;
216
226
  const [filepath, querystring = ""] = id.split("?");
217
227
  const [extension = ""] = querystring.match(fileExtensionRE) || filepath.match(fileExtensionRE) || [];
218
228
  if (/\.(mjs|[tj]sx?)$/.test(extension)) {
@@ -271,7 +281,9 @@ function viteReact(opts = {}) {
271
281
  }
272
282
  const shouldSkip = !plugins.length && !babelOptions.configFile && !(isProjectFile && babelOptions.babelrc);
273
283
  if (shouldSkip) {
274
- return;
284
+ return {
285
+ code
286
+ };
275
287
  }
276
288
  const parserPlugins = [
277
289
  ...babelOptions.parserOpts.plugins,
@@ -347,20 +359,49 @@ function viteReact(opts = {}) {
347
359
  {
348
360
  tag: "script",
349
361
  attrs: { type: "module" },
350
- children: preambleCode.replace(`__BASE__`, base)
362
+ children: preambleCode.replace(`__BASE__`, devBase)
351
363
  }
352
364
  ];
353
365
  }
354
366
  };
367
+ const reactJsxRuntimeId = "react/jsx-runtime";
368
+ const reactJsxDevRuntimeId = "react/jsx-dev-runtime";
369
+ const virtualReactJsxRuntimeId = "\0" + reactJsxRuntimeId;
370
+ const virtualReactJsxDevRuntimeId = "\0" + reactJsxDevRuntimeId;
355
371
  const viteReactJsx = {
356
372
  name: "vite:react-jsx",
357
373
  enforce: "pre",
358
374
  config() {
359
375
  return {
360
376
  optimizeDeps: {
361
- include: ["react/jsx-dev-runtime"]
377
+ include: [reactJsxRuntimeId, reactJsxDevRuntimeId]
362
378
  }
363
379
  };
380
+ },
381
+ resolveId(id, importer) {
382
+ if (id === reactJsxRuntimeId && importer !== virtualReactJsxRuntimeId) {
383
+ return virtualReactJsxRuntimeId;
384
+ }
385
+ if (id === reactJsxDevRuntimeId && importer !== virtualReactJsxDevRuntimeId) {
386
+ return virtualReactJsxDevRuntimeId;
387
+ }
388
+ },
389
+ load(id) {
390
+ if (id === virtualReactJsxRuntimeId) {
391
+ return [
392
+ `import * as jsxRuntime from ${JSON.stringify(reactJsxRuntimeId)}`,
393
+ `export const Fragment = jsxRuntime.Fragment`,
394
+ `export const jsx = jsxRuntime.jsx`,
395
+ `export const jsxs = jsxRuntime.jsxs`
396
+ ].join("\n");
397
+ }
398
+ if (id === virtualReactJsxDevRuntimeId) {
399
+ return [
400
+ `import * as jsxRuntime from ${JSON.stringify(reactJsxDevRuntimeId)}`,
401
+ `export const Fragment = jsxRuntime.Fragment`,
402
+ `export const jsxDEV = jsxRuntime.jsxDEV`
403
+ ].join("\n");
404
+ }
364
405
  }
365
406
  };
366
407
  return [viteBabel, viteReactRefresh, useAutomaticRuntime && viteReactJsx];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "2.0.0-alpha.2",
3
+ "version": "2.0.0-beta.1",
4
4
  "license": "MIT",
5
5
  "author": "Evan You",
6
6
  "contributors": [
@@ -23,11 +23,11 @@
23
23
  "scripts": {
24
24
  "dev": "unbuild --stub",
25
25
  "build": "unbuild && pnpm run patch-cjs",
26
- "patch-cjs": "esno ../../scripts/patchCJS.ts",
26
+ "patch-cjs": "tsx ../../scripts/patchCJS.ts",
27
27
  "prepublishOnly": "npm run build"
28
28
  },
29
29
  "engines": {
30
- "node": ">=14.6.0"
30
+ "node": ">=14.18.0"
31
31
  },
32
32
  "repository": {
33
33
  "type": "git",
@@ -39,17 +39,15 @@
39
39
  },
40
40
  "homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-react#readme",
41
41
  "dependencies": {
42
- "@babel/core": "^7.18.0",
43
- "@babel/plugin-transform-react-jsx": "^7.17.12",
44
- "@babel/plugin-transform-react-jsx-development": "^7.16.7",
45
- "@babel/plugin-transform-react-jsx-self": "^7.17.12",
46
- "@babel/plugin-transform-react-jsx-source": "^7.16.7",
47
- "@rollup/pluginutils": "^4.2.1",
48
- "react-refresh": "^0.13.0",
49
- "resolve": "^1.22.0"
42
+ "@babel/core": "^7.18.6",
43
+ "@babel/plugin-transform-react-jsx": "^7.18.6",
44
+ "@babel/plugin-transform-react-jsx-development": "^7.18.6",
45
+ "@babel/plugin-transform-react-jsx-self": "^7.18.6",
46
+ "@babel/plugin-transform-react-jsx-source": "^7.18.6",
47
+ "react-refresh": "^0.14.0"
50
48
  },
51
49
  "peerDependencies": {
52
- "vite": "^3.0.0-alpha"
50
+ "vite": "^3.0.0-alpha.11"
53
51
  },
54
52
  "devDependencies": {
55
53
  "vite": "workspace:*"
@@ -1,6 +1,6 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import { createRequire } from 'module'
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import { createRequire } from 'node:module'
4
4
  import type { types as t } from '@babel/core'
5
5
 
6
6
  export const runtimePublicPath = '/@react-refresh'
package/src/index.ts CHANGED
@@ -1,8 +1,7 @@
1
- import path from 'path'
1
+ import path from 'node:path'
2
2
  import type { ParserOptions, TransformOptions, types as t } from '@babel/core'
3
3
  import * as babel from '@babel/core'
4
- import { createFilter } from '@rollup/pluginutils'
5
- import { normalizePath } from 'vite'
4
+ import { createFilter, normalizePath } from 'vite'
6
5
  import type { Plugin, PluginOption, ResolvedConfig } from 'vite'
7
6
  import {
8
7
  addRefreshWrapper,
@@ -91,7 +90,7 @@ declare module 'vite' {
91
90
 
92
91
  export default function viteReact(opts: Options = {}): PluginOption[] {
93
92
  // Provide default values for Rollup compat.
94
- let base = '/'
93
+ let devBase = '/'
95
94
  let resolvedCacheDir: string
96
95
  let filter = createFilter(opts.include, opts.exclude)
97
96
  let isProduction = true
@@ -118,8 +117,19 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
118
117
  const viteBabel: Plugin = {
119
118
  name: 'vite:react-babel',
120
119
  enforce: 'pre',
120
+ config() {
121
+ if (opts.jsxRuntime === 'classic') {
122
+ return {
123
+ esbuild: {
124
+ logOverride: {
125
+ 'this-is-undefined-in-esm': 'silent'
126
+ }
127
+ }
128
+ }
129
+ }
130
+ },
121
131
  configResolved(config) {
122
- base = config.base
132
+ devBase = config.base
123
133
  projectRoot = config.root
124
134
  resolvedCacheDir = normalizePath(path.resolve(config.cacheDir))
125
135
  filter = createFilter(opts.include, opts.exclude, {
@@ -155,17 +165,17 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
155
165
  .filter(Boolean) as ReactBabelHook[]
156
166
 
157
167
  if (hooks.length > 0) {
158
- return (runPluginOverrides = (babelOptions) => {
168
+ return (runPluginOverrides = (babelOptions, context) => {
159
169
  hooks.forEach((hook) => hook(babelOptions, context, config))
160
170
  return true
161
- })(babelOptions)
171
+ })(babelOptions, context)
162
172
  }
163
173
  runPluginOverrides = () => false
164
174
  return false
165
175
  }
166
176
  },
167
177
  async transform(code, id, options) {
168
- const ssr = typeof options === 'boolean' ? options : options?.ssr === true
178
+ const ssr = options?.ssr === true
169
179
  // File extension could be mocked/overridden in querystring.
170
180
  const [filepath, querystring = ''] = id.split('?')
171
181
  const [extension = ''] =
@@ -266,7 +276,10 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
266
276
  !(isProjectFile && babelOptions.babelrc)
267
277
 
268
278
  if (shouldSkip) {
269
- return // Avoid parsing if no plugins exist.
279
+ // Avoid parsing if no plugins exist.
280
+ return {
281
+ code
282
+ }
270
283
  }
271
284
 
272
285
  const parserPlugins: typeof babelOptions.parserOpts.plugins = [
@@ -355,13 +368,16 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
355
368
  {
356
369
  tag: 'script',
357
370
  attrs: { type: 'module' },
358
- children: preambleCode.replace(`__BASE__`, base)
371
+ children: preambleCode.replace(`__BASE__`, devBase)
359
372
  }
360
373
  ]
361
374
  }
362
375
  }
363
376
 
364
- // const runtimeId = 'react/jsx-runtime'
377
+ const reactJsxRuntimeId = 'react/jsx-runtime'
378
+ const reactJsxDevRuntimeId = 'react/jsx-dev-runtime'
379
+ const virtualReactJsxRuntimeId = '\0' + reactJsxRuntimeId
380
+ const virtualReactJsxDevRuntimeId = '\0' + reactJsxDevRuntimeId
365
381
  // Adapted from https://github.com/alloc/vite-react-jsx
366
382
  const viteReactJsx: Plugin = {
367
383
  name: 'vite:react-jsx',
@@ -369,32 +385,42 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
369
385
  config() {
370
386
  return {
371
387
  optimizeDeps: {
372
- include: ['react/jsx-dev-runtime']
388
+ include: [reactJsxRuntimeId, reactJsxDevRuntimeId]
373
389
  }
374
390
  }
375
- }
376
- // TODO: this optimization may not be necesary and it is breacking esbuild+rollup compat,
377
- // see https://github.com/vitejs/vite/pull/7246#discussion_r861552185
378
- // We could still do the same trick and resolve to the optimized dependency here
379
- /*
380
- resolveId(id: string) {
381
- return id === runtimeId ? id : null
382
- },
383
- load(id: string) {
384
- if (id === runtimeId) {
385
- const runtimePath = resolve.sync(runtimeId, {
386
- basedir: projectRoot
387
- })
388
- const exports = ['jsx', 'jsxs', 'Fragment']
391
+ },
392
+ resolveId(id, importer) {
393
+ // Resolve runtime to a virtual path to be interoped.
394
+ // Since the interop code re-imports `id`, we need to prevent re-resolving
395
+ // to the virtual id if the importer is already the virtual id.
396
+ if (id === reactJsxRuntimeId && importer !== virtualReactJsxRuntimeId) {
397
+ return virtualReactJsxRuntimeId
398
+ }
399
+ if (
400
+ id === reactJsxDevRuntimeId &&
401
+ importer !== virtualReactJsxDevRuntimeId
402
+ ) {
403
+ return virtualReactJsxDevRuntimeId
404
+ }
405
+ },
406
+ load(id) {
407
+ // Apply manual interop
408
+ if (id === virtualReactJsxRuntimeId) {
389
409
  return [
390
- `import * as jsxRuntime from ${JSON.stringify(runtimePath)}`,
391
- // We can't use `export * from` or else any callsite that uses
392
- // this module will be compiled to `jsxRuntime.exports.jsx`
393
- // instead of the more concise `jsx` alias.
394
- ...exports.map((name) => `export const ${name} = jsxRuntime.${name}`)
410
+ `import * as jsxRuntime from ${JSON.stringify(reactJsxRuntimeId)}`,
411
+ `export const Fragment = jsxRuntime.Fragment`,
412
+ `export const jsx = jsxRuntime.jsx`,
413
+ `export const jsxs = jsxRuntime.jsxs`
395
414
  ].join('\n')
396
415
  }
397
- } */
416
+ if (id === virtualReactJsxDevRuntimeId) {
417
+ return [
418
+ `import * as jsxRuntime from ${JSON.stringify(reactJsxDevRuntimeId)}`,
419
+ `export const Fragment = jsxRuntime.Fragment`,
420
+ `export const jsxDEV = jsxRuntime.jsxDEV`
421
+ ].join('\n')
422
+ }
423
+ }
398
424
  }
399
425
 
400
426
  return [viteBabel, viteReactRefresh, useAutomaticRuntime && viteReactJsx]
@@ -1,6 +1,67 @@
1
1
  import * as babel from '@babel/core'
2
2
  import { describe, expect, it } from 'vitest'
3
- import { restoreJSX } from './restore-jsx'
3
+ import { parseReactAlias, restoreJSX } from './restore-jsx'
4
+
5
+ describe('parseReactAlias', () => {
6
+ it('handles cjs require', () => {
7
+ expect(parseReactAlias(`const React = require("react")`))
8
+ .toMatchInlineSnapshot(`
9
+ [
10
+ "React",
11
+ true,
12
+ ]
13
+ `)
14
+ })
15
+
16
+ it('handles cjs require (minified)', () => {
17
+ expect(parseReactAlias(`var F=require('foo');var R=require('react')`))
18
+ .toMatchInlineSnapshot(`
19
+ [
20
+ "R",
21
+ true,
22
+ ]
23
+ `)
24
+ })
25
+
26
+ it('does not handle destructured cjs require', () => {
27
+ expect(parseReactAlias(`var {createElement} = require("react")`))
28
+ .toMatchInlineSnapshot(`
29
+ [
30
+ undefined,
31
+ false,
32
+ ]
33
+ `)
34
+ })
35
+
36
+ it('handles esm import', () => {
37
+ expect(parseReactAlias(`import React from 'react'`)).toMatchInlineSnapshot(`
38
+ [
39
+ "React",
40
+ false,
41
+ ]
42
+ `)
43
+ })
44
+
45
+ it('handles esm import namespace', () => {
46
+ expect(parseReactAlias(`import * as React from "react"`))
47
+ .toMatchInlineSnapshot(`
48
+ [
49
+ "React",
50
+ false,
51
+ ]
52
+ `)
53
+ })
54
+
55
+ it('does not handle destructured esm import', () => {
56
+ expect(parseReactAlias(`import {createElement} from "react"`))
57
+ .toMatchInlineSnapshot(`
58
+ [
59
+ undefined,
60
+ false,
61
+ ]
62
+ `)
63
+ })
64
+ })
4
65
 
5
66
  async function jsx(sourceCode: string) {
6
67
  const [ast] = await restoreJSX(babel, sourceCode, 'test.js')
@@ -79,16 +79,16 @@ export async function restoreJSX(
79
79
  return [result?.ast, isCommonJS]
80
80
  }
81
81
 
82
- function parseReactAlias(
82
+ export function parseReactAlias(
83
83
  code: string
84
84
  ): [alias: string | undefined, isCommonJS: boolean] {
85
85
  let match = code.match(
86
- /\b(var|let|const) +(\w+) *= *require\(["']react["']\)/
86
+ /\b(var|let|const)\s+([^=\{\s]+)\s*=\s*require\(["']react["']\)/
87
87
  )
88
88
  if (match) {
89
89
  return [match[2], true]
90
90
  }
91
- match = code.match(/^import (\w+).+? from ["']react["']/m)
91
+ match = code.match(/^import\s+(?:\*\s+as\s+)?(\w+).+?\bfrom\s*["']react["']/m)
92
92
  if (match) {
93
93
  return [match[1], false]
94
94
  }