@vitejs/plugin-react 2.2.0-beta.0 → 2.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.
@@ -135,4 +135,4 @@ function babelRestoreJsx({ types: t }, { reactAlias = "React" }) {
135
135
  };
136
136
  }
137
137
 
138
- exports["default"] = babelRestoreJsx;
138
+ exports.default = babelRestoreJsx;
package/dist/index.cjs CHANGED
@@ -7,37 +7,31 @@ const MagicString = require('magic-string');
7
7
  const fs = require('node:fs');
8
8
  const node_module = require('node:module');
9
9
 
10
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
11
-
12
- function _interopNamespace(e) {
13
- if (e && e.__esModule) return e;
10
+ function _interopNamespaceDefault(e) {
14
11
  const n = Object.create(null);
15
12
  if (e) {
16
13
  for (const k in e) {
17
14
  n[k] = e[k];
18
15
  }
19
16
  }
20
- n["default"] = e;
17
+ n.default = e;
21
18
  return n;
22
19
  }
23
20
 
24
- const path__default = /*#__PURE__*/_interopDefaultLegacy(path);
25
- const babel__namespace = /*#__PURE__*/_interopNamespace(babel);
26
- const MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString);
27
- const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
21
+ const babel__namespace = /*#__PURE__*/_interopNamespaceDefault(babel);
28
22
 
29
23
  const runtimePublicPath = "/@react-refresh";
30
24
  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)));
31
- const reactRefreshDir = path__default.dirname(
25
+ const reactRefreshDir = path.dirname(
32
26
  _require.resolve("react-refresh/package.json")
33
27
  );
34
- const runtimeFilePath = path__default.join(
28
+ const runtimeFilePath = path.join(
35
29
  reactRefreshDir,
36
30
  "cjs/react-refresh-runtime.development.js"
37
31
  );
38
32
  const runtimeCode = `
39
33
  const exports = {}
40
- ${fs__default.readFileSync(runtimeFilePath, "utf-8")}
34
+ ${fs.readFileSync(runtimeFilePath, "utf-8")}
41
35
  function debounce(fn, delay) {
42
36
  let handle
43
37
  return () => {
@@ -262,7 +256,7 @@ function viteReact(opts = {}) {
262
256
  configResolved(config) {
263
257
  devBase = config.base;
264
258
  projectRoot = config.root;
265
- resolvedCacheDir = vite.normalizePath(path__default.resolve(config.cacheDir));
259
+ resolvedCacheDir = vite.normalizePath(path.resolve(config.cacheDir));
266
260
  filter = vite.createFilter(opts.include, opts.exclude, {
267
261
  resolve: projectRoot
268
262
  });
@@ -363,7 +357,7 @@ function viteReact(opts = {}) {
363
357
  let inputMap;
364
358
  if (prependReactImport) {
365
359
  if (needHiresSourcemap) {
366
- const s = new MagicString__default(code);
360
+ const s = new MagicString(code);
367
361
  s.prepend(prependReactImportCode);
368
362
  code = s.toString();
369
363
  inputMap = s.generateMap({ hires: true, source: id });
@@ -519,4 +513,4 @@ function createBabelOptions(rawOptions) {
519
513
  }
520
514
 
521
515
  module.exports = viteReact;
522
- module.exports["default"] = viteReact;
516
+ module.exports.default = viteReact;
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-react",
3
- "version": "2.2.0-beta.0",
3
+ "version": "2.2.0",
4
4
  "license": "MIT",
5
5
  "author": "Evan You",
6
6
  "contributors": [
7
7
  "Alec Larson"
8
8
  ],
9
9
  "files": [
10
- "dist",
11
- "src"
10
+ "dist"
12
11
  ],
13
12
  "main": "./dist/index.cjs",
14
13
  "module": "./dist/index.mjs",
@@ -39,12 +38,12 @@
39
38
  },
40
39
  "homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-react#readme",
41
40
  "dependencies": {
42
- "@babel/core": "^7.19.3",
41
+ "@babel/core": "^7.19.6",
43
42
  "@babel/plugin-transform-react-jsx": "^7.19.0",
44
43
  "@babel/plugin-transform-react-jsx-development": "^7.18.6",
45
44
  "@babel/plugin-transform-react-jsx-self": "^7.18.6",
46
- "@babel/plugin-transform-react-jsx-source": "^7.18.6",
47
- "magic-string": "^0.26.5",
45
+ "@babel/plugin-transform-react-jsx-source": "^7.19.6",
46
+ "magic-string": "^0.26.7",
48
47
  "react-refresh": "^0.14.0"
49
48
  },
50
49
  "peerDependencies": {
package/src/babel.d.ts DELETED
@@ -1,4 +0,0 @@
1
- declare module '@babel/plugin-transform-react-jsx'
2
- declare module '@babel/plugin-transform-react-jsx-self'
3
- declare module '@babel/plugin-transform-react-jsx-source'
4
- declare module 'react-refresh/babel.js'
@@ -1,155 +0,0 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { createRequire } from 'node:module'
4
- import type { types as t } from '@babel/core'
5
-
6
- export const runtimePublicPath = '/@react-refresh'
7
-
8
- const _require = createRequire(import.meta.url)
9
- const reactRefreshDir = path.dirname(
10
- _require.resolve('react-refresh/package.json')
11
- )
12
- const runtimeFilePath = path.join(
13
- reactRefreshDir,
14
- 'cjs/react-refresh-runtime.development.js'
15
- )
16
-
17
- export const runtimeCode = `
18
- const exports = {}
19
- ${fs.readFileSync(runtimeFilePath, 'utf-8')}
20
- function debounce(fn, delay) {
21
- let handle
22
- return () => {
23
- clearTimeout(handle)
24
- handle = setTimeout(fn, delay)
25
- }
26
- }
27
- exports.performReactRefresh = debounce(exports.performReactRefresh, 16)
28
- export default exports
29
- `
30
-
31
- export const preambleCode = `
32
- import RefreshRuntime from "__BASE__${runtimePublicPath.slice(1)}"
33
- RefreshRuntime.injectIntoGlobalHook(window)
34
- window.$RefreshReg$ = () => {}
35
- window.$RefreshSig$ = () => (type) => type
36
- window.__vite_plugin_react_preamble_installed__ = true
37
- `
38
-
39
- const header = `
40
- import RefreshRuntime from "${runtimePublicPath}";
41
-
42
- let prevRefreshReg;
43
- let prevRefreshSig;
44
-
45
- if (import.meta.hot) {
46
- if (!window.__vite_plugin_react_preamble_installed__) {
47
- 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"
50
- );
51
- }
52
-
53
- prevRefreshReg = window.$RefreshReg$;
54
- prevRefreshSig = window.$RefreshSig$;
55
- window.$RefreshReg$ = (type, id) => {
56
- RefreshRuntime.register(type, __SOURCE__ + " " + id)
57
- };
58
- window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
59
- }`.replace(/[\n]+/gm, '')
60
-
61
- const timeout = `
62
- if (!window.__vite_plugin_react_timeout) {
63
- window.__vite_plugin_react_timeout = setTimeout(() => {
64
- window.__vite_plugin_react_timeout = 0;
65
- RefreshRuntime.performReactRefresh();
66
- }, 30);
67
- }
68
- `
69
-
70
- const footer = `
71
- if (import.meta.hot) {
72
- window.$RefreshReg$ = prevRefreshReg;
73
- window.$RefreshSig$ = prevRefreshSig;
74
-
75
- __ACCEPT__
76
- }`
77
-
78
- const checkAndAccept = `
79
- function isReactRefreshBoundary(mod) {
80
- if (mod == null || typeof mod !== 'object') {
81
- return false;
82
- }
83
- let hasExports = false;
84
- let areAllExportsComponents = true;
85
- for (const exportName in mod) {
86
- hasExports = true;
87
- if (exportName === '__esModule') {
88
- continue;
89
- }
90
- const desc = Object.getOwnPropertyDescriptor(mod, exportName);
91
- if (desc && desc.get) {
92
- // Don't invoke getters as they may have side effects.
93
- return false;
94
- }
95
- const exportValue = mod[exportName];
96
- if (!RefreshRuntime.isLikelyComponentType(exportValue)) {
97
- areAllExportsComponents = false;
98
- }
99
- }
100
- return hasExports && areAllExportsComponents;
101
- }
102
-
103
- import.meta.hot.accept(mod => {
104
- if (isReactRefreshBoundary(mod)) {
105
- ${timeout}
106
- } else {
107
- import.meta.hot.invalidate();
108
- }
109
- });
110
- `
111
-
112
- export function addRefreshWrapper(
113
- code: string,
114
- id: string,
115
- accept: boolean
116
- ): string {
117
- return (
118
- header.replace('__SOURCE__', JSON.stringify(id)) +
119
- code +
120
- footer.replace('__ACCEPT__', accept ? checkAndAccept : timeout)
121
- )
122
- }
123
-
124
- export function isRefreshBoundary(ast: t.File): boolean {
125
- // Every export must be a potential React component.
126
- // We'll also perform a runtime check that's more robust as well (isLikelyComponentType).
127
- return ast.program.body.every((node) => {
128
- if (node.type !== 'ExportNamedDeclaration') {
129
- return true
130
- }
131
- const { declaration, specifiers } = node
132
- if (declaration) {
133
- if (declaration.type === 'ClassDeclaration') return false
134
- if (declaration.type === 'VariableDeclaration') {
135
- return declaration.declarations.every((variable) =>
136
- isComponentLikeIdentifier(variable.id)
137
- )
138
- }
139
- if (declaration.type === 'FunctionDeclaration') {
140
- return !!declaration.id && isComponentLikeIdentifier(declaration.id)
141
- }
142
- }
143
- return specifiers.every((spec) => {
144
- return isComponentLikeIdentifier(spec.exported)
145
- })
146
- })
147
- }
148
-
149
- function isComponentLikeIdentifier(node: t.Node): boolean {
150
- return node.type === 'Identifier' && isComponentLikeName(node.name)
151
- }
152
-
153
- function isComponentLikeName(name: string): boolean {
154
- return typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z'
155
- }
package/src/index.ts DELETED
@@ -1,479 +0,0 @@
1
- import path from 'node:path'
2
- import type { ParserOptions, TransformOptions, types as t } from '@babel/core'
3
- import * as babel from '@babel/core'
4
- import { createFilter, normalizePath } from 'vite'
5
- import type { Plugin, PluginOption, ResolvedConfig } from 'vite'
6
- import MagicString from 'magic-string'
7
- import type { SourceMap } from 'magic-string'
8
- import {
9
- addRefreshWrapper,
10
- isRefreshBoundary,
11
- preambleCode,
12
- runtimeCode,
13
- runtimePublicPath
14
- } from './fast-refresh'
15
- import { babelImportToRequire } from './jsx-runtime/babel-import-to-require'
16
- import { restoreJSX } from './jsx-runtime/restore-jsx'
17
-
18
- export interface Options {
19
- include?: string | RegExp | Array<string | RegExp>
20
- exclude?: string | RegExp | Array<string | RegExp>
21
- /**
22
- * Enable `react-refresh` integration. Vite disables this in prod env or build mode.
23
- * @default true
24
- */
25
- fastRefresh?: boolean
26
- /**
27
- * Set this to `"automatic"` to use [vite-react-jsx](https://github.com/alloc/vite-react-jsx).
28
- * @default "automatic"
29
- */
30
- jsxRuntime?: 'classic' | 'automatic'
31
- /**
32
- * Control where the JSX factory is imported from.
33
- * This option is ignored when `jsxRuntime` is not `"automatic"`.
34
- * @default "react"
35
- */
36
- jsxImportSource?: string
37
- /**
38
- * Set this to `true` to annotate the JSX factory with `\/* @__PURE__ *\/`.
39
- * This option is ignored when `jsxRuntime` is not `"automatic"`.
40
- * @default true
41
- */
42
- jsxPure?: boolean
43
- /**
44
- * Toggles whether or not to throw an error if an XML namespaced tag name is used.
45
- * @default true
46
- */
47
- jsxThrowIfNamespace?: boolean
48
- /**
49
- * Babel configuration applied in both dev and prod.
50
- */
51
- babel?:
52
- | BabelOptions
53
- | ((id: string, options: { ssr?: boolean }) => BabelOptions)
54
- }
55
-
56
- export type BabelOptions = Omit<
57
- TransformOptions,
58
- | 'ast'
59
- | 'filename'
60
- | 'root'
61
- | 'sourceFileName'
62
- | 'sourceMaps'
63
- | 'inputSourceMap'
64
- >
65
-
66
- /**
67
- * The object type used by the `options` passed to plugins with
68
- * an `api.reactBabel` method.
69
- */
70
- export interface ReactBabelOptions extends BabelOptions {
71
- plugins: Extract<BabelOptions['plugins'], any[]>
72
- presets: Extract<BabelOptions['presets'], any[]>
73
- overrides: Extract<BabelOptions['overrides'], any[]>
74
- parserOpts: ParserOptions & {
75
- plugins: Extract<ParserOptions['plugins'], any[]>
76
- }
77
- }
78
-
79
- type ReactBabelHook = (
80
- babelConfig: ReactBabelOptions,
81
- context: ReactBabelHookContext,
82
- config: ResolvedConfig
83
- ) => void
84
-
85
- type ReactBabelHookContext = { ssr: boolean; id: string }
86
-
87
- declare module 'vite' {
88
- export interface Plugin {
89
- api?: {
90
- /**
91
- * Manipulate the Babel options of `@vitejs/plugin-react`
92
- */
93
- reactBabel?: ReactBabelHook
94
- }
95
- }
96
- }
97
-
98
- const prependReactImportCode = "import React from 'react'; "
99
-
100
- export default function viteReact(opts: Options = {}): PluginOption[] {
101
- // Provide default values for Rollup compat.
102
- let devBase = '/'
103
- let resolvedCacheDir: string
104
- let filter = createFilter(opts.include, opts.exclude)
105
- let needHiresSourcemap = false
106
- let isProduction = true
107
- let projectRoot = process.cwd()
108
- let skipFastRefresh = opts.fastRefresh === false
109
- let skipReactImport = false
110
- let runPluginOverrides = (
111
- options: ReactBabelOptions,
112
- context: ReactBabelHookContext
113
- ) => false
114
- let staticBabelOptions: ReactBabelOptions | undefined
115
-
116
- const useAutomaticRuntime = opts.jsxRuntime !== 'classic'
117
-
118
- // Support patterns like:
119
- // - import * as React from 'react';
120
- // - import React from 'react';
121
- // - import React, {useEffect} from 'react';
122
- const importReactRE = /(^|\n)import\s+(\*\s+as\s+)?React(,|\s+)/
123
-
124
- // Any extension, including compound ones like '.bs.js'
125
- const fileExtensionRE = /\.[^\/\s\?]+$/
126
-
127
- const viteBabel: Plugin = {
128
- name: 'vite:react-babel',
129
- enforce: 'pre',
130
- config() {
131
- if (opts.jsxRuntime === 'classic') {
132
- return {
133
- esbuild: {
134
- logOverride: {
135
- 'this-is-undefined-in-esm': 'silent'
136
- }
137
- }
138
- }
139
- }
140
- },
141
- configResolved(config) {
142
- devBase = config.base
143
- projectRoot = config.root
144
- resolvedCacheDir = normalizePath(path.resolve(config.cacheDir))
145
- filter = createFilter(opts.include, opts.exclude, {
146
- resolve: projectRoot
147
- })
148
- needHiresSourcemap =
149
- config.command === 'build' && !!config.build.sourcemap
150
- isProduction = config.isProduction
151
- skipFastRefresh ||= isProduction || config.command === 'build'
152
-
153
- const jsxInject = config.esbuild && config.esbuild.jsxInject
154
- if (jsxInject && importReactRE.test(jsxInject)) {
155
- skipReactImport = true
156
- config.logger.warn(
157
- '[@vitejs/plugin-react] This plugin imports React for you automatically,' +
158
- ' so you can stop using `esbuild.jsxInject` for that purpose.'
159
- )
160
- }
161
-
162
- config.plugins.forEach((plugin) => {
163
- const hasConflict =
164
- plugin.name === 'react-refresh' ||
165
- (plugin !== viteReactJsx && plugin.name === 'vite:react-jsx')
166
-
167
- if (hasConflict)
168
- return config.logger.warn(
169
- `[@vitejs/plugin-react] You should stop using "${plugin.name}" ` +
170
- `since this plugin conflicts with it.`
171
- )
172
- })
173
-
174
- runPluginOverrides = (babelOptions, context) => {
175
- const hooks = config.plugins
176
- .map((plugin) => plugin.api?.reactBabel)
177
- .filter(Boolean) as ReactBabelHook[]
178
-
179
- if (hooks.length > 0) {
180
- return (runPluginOverrides = (babelOptions, context) => {
181
- hooks.forEach((hook) => hook(babelOptions, context, config))
182
- return true
183
- })(babelOptions, context)
184
- }
185
- runPluginOverrides = () => false
186
- return false
187
- }
188
- },
189
- async transform(code, id, options) {
190
- const ssr = options?.ssr === true
191
- // File extension could be mocked/overridden in querystring.
192
- const [filepath, querystring = ''] = id.split('?')
193
- const [extension = ''] =
194
- querystring.match(fileExtensionRE) ||
195
- filepath.match(fileExtensionRE) ||
196
- []
197
-
198
- if (/\.(mjs|[tj]sx?)$/.test(extension)) {
199
- const isJSX = extension.endsWith('x')
200
- const isNodeModules = id.includes('/node_modules/')
201
- const isProjectFile =
202
- !isNodeModules && (id[0] === '\0' || id.startsWith(projectRoot + '/'))
203
-
204
- let babelOptions = staticBabelOptions
205
- if (typeof opts.babel === 'function') {
206
- const rawOptions = opts.babel(id, { ssr })
207
- babelOptions = createBabelOptions(rawOptions)
208
- runPluginOverrides(babelOptions, { ssr, id: id })
209
- } else if (!babelOptions) {
210
- babelOptions = createBabelOptions(opts.babel)
211
- if (!runPluginOverrides(babelOptions, { ssr, id: id })) {
212
- staticBabelOptions = babelOptions
213
- }
214
- }
215
-
216
- const plugins = isProjectFile ? [...babelOptions.plugins] : []
217
-
218
- let useFastRefresh = false
219
- if (!skipFastRefresh && !ssr && !isNodeModules) {
220
- // Modules with .js or .ts extension must import React.
221
- const isReactModule = isJSX || importReactRE.test(code)
222
- if (isReactModule && filter(id)) {
223
- useFastRefresh = true
224
- plugins.push([
225
- await loadPlugin('react-refresh/babel'),
226
- { skipEnvCheck: true }
227
- ])
228
- }
229
- }
230
-
231
- let ast: t.File | null | undefined
232
- let prependReactImport = false
233
- if (!isProjectFile || isJSX) {
234
- if (useAutomaticRuntime) {
235
- // By reverse-compiling "React.createElement" calls into JSX,
236
- // React elements provided by dependencies will also use the
237
- // automatic runtime!
238
- // Avoid parsing the optimized react-dom since it will never
239
- // contain compiled JSX and it's a pretty big file (800kb).
240
- const isOptimizedReactDom =
241
- id.startsWith(resolvedCacheDir) && id.includes('/react-dom.js')
242
- const [restoredAst, isCommonJS] =
243
- !isProjectFile && !isJSX && !isOptimizedReactDom
244
- ? await restoreJSX(babel, code, id)
245
- : [null, false]
246
-
247
- if (isJSX || (ast = restoredAst)) {
248
- plugins.push([
249
- await loadPlugin(
250
- '@babel/plugin-transform-react-jsx' +
251
- (isProduction ? '' : '-development')
252
- ),
253
- {
254
- runtime: 'automatic',
255
- importSource: opts.jsxImportSource,
256
- pure: opts.jsxPure !== false,
257
- throwIfNamespace: opts.jsxThrowIfNamespace
258
- }
259
- ])
260
-
261
- // Avoid inserting `import` statements into CJS modules.
262
- if (isCommonJS) {
263
- plugins.push(babelImportToRequire)
264
- }
265
- }
266
- } else if (isProjectFile) {
267
- // These plugins are only needed for the classic runtime.
268
- if (!isProduction) {
269
- plugins.push(
270
- await loadPlugin('@babel/plugin-transform-react-jsx-self'),
271
- await loadPlugin('@babel/plugin-transform-react-jsx-source')
272
- )
273
- }
274
-
275
- // Even if the automatic JSX runtime is not used, we can still
276
- // inject the React import for .jsx and .tsx modules.
277
- if (!skipReactImport && !importReactRE.test(code)) {
278
- prependReactImport = true
279
- }
280
- }
281
- }
282
-
283
- let inputMap: SourceMap | undefined
284
- if (prependReactImport) {
285
- if (needHiresSourcemap) {
286
- const s = new MagicString(code)
287
- s.prepend(prependReactImportCode)
288
- code = s.toString()
289
- inputMap = s.generateMap({ hires: true, source: id })
290
- } else {
291
- code = prependReactImportCode + code
292
- }
293
- }
294
-
295
- // Plugins defined through this Vite plugin are only applied
296
- // to modules within the project root, but "babel.config.js"
297
- // files can define plugins that need to be applied to every
298
- // module, including node_modules and linked packages.
299
- const shouldSkip =
300
- !plugins.length &&
301
- !babelOptions.configFile &&
302
- !(isProjectFile && babelOptions.babelrc)
303
-
304
- // Avoid parsing if no plugins exist.
305
- if (shouldSkip) {
306
- return {
307
- code,
308
- map: inputMap ?? null
309
- }
310
- }
311
-
312
- const parserPlugins: typeof babelOptions.parserOpts.plugins = [
313
- ...babelOptions.parserOpts.plugins,
314
- 'importMeta',
315
- // This plugin is applied before esbuild transforms the code,
316
- // so we need to enable some stage 3 syntax that is supported in
317
- // TypeScript and some environments already.
318
- 'topLevelAwait',
319
- 'classProperties',
320
- 'classPrivateProperties',
321
- 'classPrivateMethods'
322
- ]
323
-
324
- if (!extension.endsWith('.ts')) {
325
- parserPlugins.push('jsx')
326
- }
327
-
328
- if (/\.tsx?$/.test(extension)) {
329
- parserPlugins.push('typescript')
330
- }
331
-
332
- const transformAsync = ast
333
- ? babel.transformFromAstAsync.bind(babel, ast, code)
334
- : babel.transformAsync.bind(babel, code)
335
-
336
- const isReasonReact = extension.endsWith('.bs.js')
337
- const result = await transformAsync({
338
- ...babelOptions,
339
- ast: !isReasonReact,
340
- root: projectRoot,
341
- filename: id,
342
- sourceFileName: filepath,
343
- parserOpts: {
344
- ...babelOptions.parserOpts,
345
- sourceType: 'module',
346
- allowAwaitOutsideFunction: true,
347
- plugins: parserPlugins
348
- },
349
- generatorOpts: {
350
- ...babelOptions.generatorOpts,
351
- decoratorsBeforeExport: true
352
- },
353
- plugins,
354
- sourceMaps: true,
355
- // Vite handles sourcemap flattening
356
- inputSourceMap: inputMap ?? (false as any)
357
- })
358
-
359
- if (result) {
360
- let code = result.code!
361
- if (useFastRefresh && /\$RefreshReg\$\(/.test(code)) {
362
- const accept = isReasonReact || isRefreshBoundary(result.ast!)
363
- code = addRefreshWrapper(code, id, accept)
364
- }
365
- return {
366
- code,
367
- map: result.map
368
- }
369
- }
370
- }
371
- }
372
- }
373
-
374
- const viteReactRefresh: Plugin = {
375
- name: 'vite:react-refresh',
376
- enforce: 'pre',
377
- config: () => ({
378
- resolve: {
379
- dedupe: ['react', 'react-dom']
380
- }
381
- }),
382
- resolveId(id) {
383
- if (id === runtimePublicPath) {
384
- return id
385
- }
386
- },
387
- load(id) {
388
- if (id === runtimePublicPath) {
389
- return runtimeCode
390
- }
391
- },
392
- transformIndexHtml() {
393
- if (!skipFastRefresh)
394
- return [
395
- {
396
- tag: 'script',
397
- attrs: { type: 'module' },
398
- children: preambleCode.replace(`__BASE__`, devBase)
399
- }
400
- ]
401
- }
402
- }
403
-
404
- const reactJsxRuntimeId = 'react/jsx-runtime'
405
- const reactJsxDevRuntimeId = 'react/jsx-dev-runtime'
406
- const virtualReactJsxRuntimeId = '\0' + reactJsxRuntimeId
407
- const virtualReactJsxDevRuntimeId = '\0' + reactJsxDevRuntimeId
408
- // Adapted from https://github.com/alloc/vite-react-jsx
409
- const viteReactJsx: Plugin = {
410
- name: 'vite:react-jsx',
411
- enforce: 'pre',
412
- config() {
413
- return {
414
- optimizeDeps: {
415
- // We can't add `react-dom` because the dependency is `react-dom/client`
416
- // for React 18 while it's `react-dom` for React 17. We'd need to detect
417
- // what React version the user has installed.
418
- include: [reactJsxRuntimeId, reactJsxDevRuntimeId, 'react']
419
- }
420
- }
421
- },
422
- resolveId(id, importer) {
423
- // Resolve runtime to a virtual path to be interoped.
424
- // Since the interop code re-imports `id`, we need to prevent re-resolving
425
- // to the virtual id if the importer is already the virtual id.
426
- if (id === reactJsxRuntimeId && importer !== virtualReactJsxRuntimeId) {
427
- return virtualReactJsxRuntimeId
428
- }
429
- if (
430
- id === reactJsxDevRuntimeId &&
431
- importer !== virtualReactJsxDevRuntimeId
432
- ) {
433
- return virtualReactJsxDevRuntimeId
434
- }
435
- },
436
- load(id) {
437
- // Apply manual interop
438
- if (id === virtualReactJsxRuntimeId) {
439
- return [
440
- `import * as jsxRuntime from ${JSON.stringify(reactJsxRuntimeId)}`,
441
- `export const Fragment = jsxRuntime.Fragment`,
442
- `export const jsx = jsxRuntime.jsx`,
443
- `export const jsxs = jsxRuntime.jsxs`
444
- ].join('\n')
445
- }
446
- if (id === virtualReactJsxDevRuntimeId) {
447
- return [
448
- `import * as jsxRuntime from ${JSON.stringify(reactJsxDevRuntimeId)}`,
449
- `export const Fragment = jsxRuntime.Fragment`,
450
- `export const jsxDEV = jsxRuntime.jsxDEV`
451
- ].join('\n')
452
- }
453
- }
454
- }
455
-
456
- return [viteBabel, viteReactRefresh, useAutomaticRuntime && viteReactJsx]
457
- }
458
-
459
- viteReact.preambleCode = preambleCode
460
-
461
- function loadPlugin(path: string): Promise<any> {
462
- return import(path).then((module) => module.default || module)
463
- }
464
-
465
- function createBabelOptions(rawOptions?: BabelOptions) {
466
- const babelOptions = {
467
- babelrc: false,
468
- configFile: false,
469
- ...rawOptions
470
- } as ReactBabelOptions
471
-
472
- babelOptions.plugins ||= []
473
- babelOptions.presets ||= []
474
- babelOptions.overrides ||= []
475
- babelOptions.parserOpts ||= {} as any
476
- babelOptions.parserOpts.plugins ||= []
477
-
478
- return babelOptions
479
- }
@@ -1,35 +0,0 @@
1
- import type * as babelCore from '@babel/core'
2
-
3
- /**
4
- * Replace this:
5
- *
6
- * import { jsx as _jsx } from "react/jsx-runtime"
7
- *
8
- * with this:
9
- *
10
- * var _jsx = require("react/jsx-runtime").jsx
11
- */
12
- export function babelImportToRequire({ types: t }: typeof babelCore): {
13
- visitor: babelCore.Visitor
14
- } {
15
- return {
16
- visitor: {
17
- ImportDeclaration(path) {
18
- const decl = path.node
19
- const spec = decl.specifiers[0] as babelCore.types.ImportSpecifier
20
-
21
- path.replaceWith(
22
- t.variableDeclaration('var', [
23
- t.variableDeclarator(
24
- spec.local,
25
- t.memberExpression(
26
- t.callExpression(t.identifier('require'), [decl.source]),
27
- spec.imported
28
- )
29
- )
30
- ])
31
- )
32
- }
33
- }
34
- }
35
- }
@@ -1,132 +0,0 @@
1
- import * as babel from '@babel/core'
2
- import { describe, expect, it } from 'vitest'
3
- import babelRestoreJSX from './babel-restore-jsx'
4
-
5
- function jsx(code: string) {
6
- return babel.transform(code, {
7
- parserOpts: { plugins: ['jsx'] },
8
- plugins: [babelRestoreJSX]
9
- })?.code
10
- }
11
-
12
- // Tests adapted from: https://github.com/flying-sheep/babel-plugin-transform-react-createelement-to-jsx/blob/63137b6/test/index.js
13
- describe('babel-restore-jsx', () => {
14
- it('should convert 1-argument calls', () => {
15
- expect(jsx('React.createElement("h1")')).toMatchInlineSnapshot(`"<h1 />;"`)
16
- expect(jsx('React.createElement(Foo)')).toMatchInlineSnapshot(`"<Foo />;"`)
17
- expect(jsx('React.createElement(Foo.Bar)')).toMatchInlineSnapshot(
18
- `"<Foo.Bar />;"`
19
- )
20
- expect(jsx('React.createElement(Foo.Bar.Baz)')).toMatchInlineSnapshot(
21
- `"<Foo.Bar.Baz />;"`
22
- )
23
- })
24
-
25
- it('should convert effective 1-argument calls (with null or undefined)', () => {
26
- expect(jsx('React.createElement("h1", null)')).toMatchInlineSnapshot(
27
- `"<h1 />;"`
28
- )
29
- expect(jsx('React.createElement("h2", null, null)')).toMatchInlineSnapshot(
30
- `"<h2 />;"`
31
- )
32
- expect(jsx('React.createElement("h3", undefined)')).toMatchInlineSnapshot(
33
- `"<h3 />;"`
34
- )
35
- })
36
-
37
- it('should handle props without children', () => {
38
- expect(jsx('React.createElement("h1", {hi: there})')).toMatchInlineSnapshot(
39
- `"<h1 hi={there} />;"`
40
- )
41
- expect(
42
- jsx('React.createElement("h2", {"hi": there})')
43
- ).toMatchInlineSnapshot(`"<h2 hi={there} />;"`)
44
- expect(
45
- jsx('React.createElement("h3", {hi: "there"})')
46
- ).toMatchInlineSnapshot(`"<h3 hi=\\"there\\" />;"`)
47
- })
48
-
49
- it('should handle spread props', () => {
50
- expect(jsx('React.createElement("h1", props)')).toMatchInlineSnapshot(
51
- `"<h1 {...props} />;"`
52
- )
53
- expect(jsx('React.createElement("h1", getProps())')).toMatchInlineSnapshot(
54
- `"<h1 {...getProps()} />;"`
55
- )
56
- })
57
-
58
- it('should handle mixed props', () => {
59
- expect(
60
- jsx('React.createElement("h1", _extends({ hi: "there" }, props))')
61
- ).toMatchInlineSnapshot(`"<h1 hi=\\"there\\" {...props} />;"`)
62
- expect(
63
- jsx('React.createElement("h1", _extends({}, props, { hi: "there" }))')
64
- ).toMatchInlineSnapshot(`"<h1 {...props} hi=\\"there\\" />;"`)
65
- expect(
66
- jsx('React.createElement("h1", { ...props, hi: "there" })')
67
- ).toMatchInlineSnapshot(`"<h1 {...props} hi=\\"there\\" />;"`)
68
- })
69
-
70
- it('should handle props and ignore “null”/“undefined” children', () => {
71
- expect(
72
- jsx('React.createElement("h1", {hi: there}, null, undefined)')
73
- ).toMatchInlineSnapshot(`"<h1 hi={there} />;"`)
74
- })
75
-
76
- it('should ignore “null”/“undefined” props and handle children', () => {
77
- expect(
78
- jsx('React.createElement("h1", null, "Header")')
79
- ).toMatchInlineSnapshot(`"<h1>Header</h1>;"`)
80
- //this can be created from e.g. '<h2>Header{"harhar"}</h2>', but i think there’s no downside to merging it
81
- expect(
82
- jsx('React.createElement("h2", null, "Header", "harhar")')
83
- ).toMatchInlineSnapshot(`"<h2>Headerharhar</h2>;"`)
84
- expect(
85
- jsx('React.createElement("h3", null, React.createElement("i"))')
86
- ).toMatchInlineSnapshot(`"<h3><i /></h3>;"`)
87
- expect(
88
- jsx('React.createElement("h4", null, "a", React.createElement("b"), "c")')
89
- ).toMatchInlineSnapshot(`"<h4>a<b />c</h4>;"`)
90
- })
91
-
92
- it('should handle props and children', () => {
93
- //we extensively tested props and children separately, so only sth. basic
94
- expect(
95
- jsx('React.createElement("h1", {hi: there}, "Header")')
96
- ).toMatchInlineSnapshot(`"<h1 hi={there}>Header</h1>;"`)
97
- })
98
-
99
- it('should ignore intermingled “null”/“undefined” children', () => {
100
- expect(
101
- jsx('React.createElement("h1", null, null, "Header", undefined)')
102
- ).toMatchInlineSnapshot(`"<h1>Header</h1>;"`)
103
- })
104
-
105
- it('should handle children in nested expressions', () => {
106
- expect(
107
- jsx(
108
- 'React.createElement("h1", null, foo ? React.createElement("p") : null)'
109
- )
110
- ).toMatchInlineSnapshot(`"<h1>{foo ? <p /> : null}</h1>;"`)
111
- })
112
-
113
- it('should handle lowercase component names', () => {
114
- expect(jsx('React.createElement(aaa)')).toMatchInlineSnapshot(
115
- `"React.createElement(aaa);"`
116
- )
117
- })
118
-
119
- it('should not handle contains __self prop', () => {
120
- expect(
121
- jsx('React.createElement(Provider, { __self: this })')
122
- ).toMatchInlineSnapshot('"<Provider />;"')
123
- })
124
-
125
- it('should not handle contains __source prop', () => {
126
- expect(
127
- jsx(
128
- 'React.createElement(Provider, { __source: { fileName: _jsxFileName, lineNumber: 133 }})'
129
- )
130
- ).toMatchInlineSnapshot('"<Provider />;"')
131
- })
132
- })
@@ -1,232 +0,0 @@
1
- /**
2
- * https://github.com/flying-sheep/babel-plugin-transform-react-createelement-to-jsx
3
- * @license GNU General Public License v3.0
4
- */
5
- import type * as babel from '@babel/core'
6
-
7
- interface PluginOptions {
8
- reactAlias: string
9
- }
10
-
11
- /**
12
- * Visitor factory for babel, converting React.createElement(...) to <jsx ...>...</jsx>
13
- *
14
- * What we want to handle here is this CallExpression:
15
- *
16
- * React.createElement(
17
- * type: StringLiteral|Identifier|MemberExpression,
18
- * [props: ObjectExpression|Expression],
19
- * [...children: StringLiteral|Expression]
20
- * )
21
- *
22
- * Any of those arguments might also be missing (undefined) and/or invalid.
23
- */
24
- export default function (
25
- { types: t }: typeof babel,
26
- { reactAlias = 'React' }: PluginOptions
27
- ): babel.PluginObj {
28
- /**
29
- * Get a `JSXElement` from a `CallExpression`.
30
- * Returns `null` if this impossible.
31
- */
32
- function getJSXNode(node: any): any {
33
- if (!isReactCreateElement(node)) {
34
- return null
35
- }
36
-
37
- //nameNode and propsNode may be undefined, getJSX* need to handle that
38
- const [nameNode, propsNode, ...childNodes] = node.arguments
39
-
40
- const name = getJSXName(nameNode)
41
- if (name == null) {
42
- return null //name is required
43
- }
44
-
45
- const props = getJSXProps(propsNode)
46
- if (props == null) {
47
- return null //no props → [], invalid → null
48
- }
49
-
50
- const children = getJSXChildren(childNodes)
51
- if (children == null) {
52
- return null //no children → [], invalid → null
53
- }
54
-
55
- if (
56
- t.isJSXMemberExpression(name) &&
57
- t.isJSXIdentifier(name.object) &&
58
- name.object.name === reactAlias &&
59
- name.property.name === 'Fragment'
60
- ) {
61
- return t.jsxFragment(
62
- t.jsxOpeningFragment(),
63
- t.jsxClosingFragment(),
64
- children
65
- )
66
- }
67
-
68
- // self-closing tag if no children
69
- const selfClosing = children.length === 0
70
- const startTag = t.jsxOpeningElement(name, props, selfClosing)
71
- startTag.loc = node.loc
72
- const endTag = selfClosing ? null : t.jsxClosingElement(name)
73
-
74
- return t.jsxElement(startTag, endTag, children, selfClosing)
75
- }
76
-
77
- /**
78
- * Get a JSXIdentifier or JSXMemberExpression from a Node of known type.
79
- * Returns null if an unknown node type, null or undefined is passed.
80
- */
81
- function getJSXName(node: any): any {
82
- if (node == null) {
83
- return null
84
- }
85
-
86
- const name = getJSXIdentifier(node, true)
87
- if (name != null) {
88
- return name
89
- }
90
-
91
- if (!t.isMemberExpression(node)) {
92
- return null
93
- }
94
- const object = getJSXName(node.object)
95
- const property = getJSXName(node.property)
96
- if (object == null || property == null) {
97
- return null
98
- }
99
- return t.jsxMemberExpression(object, property)
100
- }
101
-
102
- /**
103
- * Get an array of JSX(Spread)Attribute from a props ObjectExpression.
104
- * Handles the _extends Expression babel creates from SpreadElement nodes.
105
- * Returns null if a validation error occurs.
106
- */
107
- function getJSXProps(node: any): any[] | null {
108
- if (node == null || isNullLikeNode(node)) {
109
- return []
110
- }
111
-
112
- if (
113
- t.isCallExpression(node) &&
114
- t.isIdentifier(node.callee, { name: '_extends' })
115
- ) {
116
- const props: any[] = node.arguments.map(getJSXProps)
117
- //if calling this recursively works, flatten.
118
- if (props.every((prop) => prop != null)) {
119
- return [].concat(...props)
120
- }
121
- }
122
-
123
- if (!t.isObjectExpression(node) && t.isExpression(node))
124
- return [t.jsxSpreadAttribute(node)]
125
-
126
- if (!isPlainObjectExpression(node)) {
127
- return null
128
- }
129
- return node.properties
130
- .map((prop: any) =>
131
- t.isObjectProperty(prop)
132
- ? t.jsxAttribute(
133
- getJSXIdentifier(prop.key)!,
134
- getJSXAttributeValue(prop.value)
135
- )
136
- : t.jsxSpreadAttribute(prop.argument)
137
- )
138
- .filter((prop: any) =>
139
- t.isJSXIdentifier(prop.name)
140
- ? prop.name.name !== '__self' && prop.name.name !== '__source'
141
- : true
142
- )
143
- }
144
-
145
- function getJSXChild(node: any) {
146
- if (t.isStringLiteral(node)) {
147
- return t.jsxText(node.value)
148
- }
149
- if (isReactCreateElement(node)) {
150
- return getJSXNode(node)
151
- }
152
- if (t.isExpression(node)) {
153
- return t.jsxExpressionContainer(node)
154
- }
155
- return null
156
- }
157
-
158
- function getJSXChildren(nodes: any[]) {
159
- const children = nodes
160
- .filter((node) => !isNullLikeNode(node))
161
- .map(getJSXChild)
162
- if (children.some((child) => child == null)) {
163
- return null
164
- }
165
- return children
166
- }
167
-
168
- function getJSXIdentifier(node: any, tag = false) {
169
- //TODO: JSXNamespacedName
170
- if (t.isIdentifier(node) && (!tag || node.name.match(/^[A-Z]/))) {
171
- return t.jsxIdentifier(node.name)
172
- }
173
- if (t.isStringLiteral(node)) {
174
- return t.jsxIdentifier(node.value)
175
- }
176
- return null
177
- }
178
-
179
- function getJSXAttributeValue(node: any) {
180
- if (t.isStringLiteral(node)) {
181
- return node
182
- }
183
- if (t.isJSXElement(node)) {
184
- return node
185
- }
186
- if (t.isExpression(node)) {
187
- return t.jsxExpressionContainer(node)
188
- }
189
- return null
190
- }
191
-
192
- /**
193
- * Tests if a node is a CallExpression with callee `React.createElement`
194
- */
195
- const isReactCreateElement = (node: any) =>
196
- t.isCallExpression(node) &&
197
- t.isMemberExpression(node.callee) &&
198
- t.isIdentifier(node.callee.object, { name: reactAlias }) &&
199
- t.isIdentifier(node.callee.property, { name: 'createElement' }) &&
200
- !node.callee.computed
201
-
202
- /**
203
- * Tests if a node is `null` or `undefined`
204
- */
205
- const isNullLikeNode = (node: any) =>
206
- t.isNullLiteral(node) || t.isIdentifier(node, { name: 'undefined' })
207
-
208
- /**
209
- * Tests if a node is an object expression with noncomputed, nonmethod attrs
210
- */
211
- const isPlainObjectExpression = (node: any) =>
212
- t.isObjectExpression(node) &&
213
- node.properties.every(
214
- (property) =>
215
- t.isSpreadElement(property) ||
216
- (t.isObjectProperty(property, { computed: false }) &&
217
- getJSXIdentifier(property.key) != null &&
218
- getJSXAttributeValue(property.value) != null)
219
- )
220
-
221
- return {
222
- visitor: {
223
- CallExpression(path) {
224
- const node = getJSXNode(path.node)
225
- if (node == null) {
226
- return null
227
- }
228
- path.replaceWith(node)
229
- }
230
- }
231
- }
232
- }
@@ -1,147 +0,0 @@
1
- import * as babel from '@babel/core'
2
- import { describe, expect, it } from 'vitest'
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
- })
65
-
66
- async function jsx(sourceCode: string) {
67
- const [ast] = await restoreJSX(babel, sourceCode, 'test.js')
68
- if (ast == null) {
69
- return ast
70
- }
71
- const { code } = await babel.transformFromAstAsync(ast, null, {
72
- configFile: false
73
- })
74
- return code
75
- }
76
- // jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
77
- // React__default.createElement(Foo)`)
78
- // Tests adapted from: https://github.com/flying-sheep/babel-plugin-transform-react-createelement-to-jsx/blob/63137b6/test/index.js
79
- describe('restore-jsx', () => {
80
- it('should trans to ', async () => {
81
- expect(
82
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
83
- React__default.createElement(foo)`)
84
- ).toMatchInlineSnapshot(`
85
- "import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
86
- React__default.createElement(foo);"
87
- `)
88
- expect(
89
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
90
- React__default.createElement("h1")`)
91
- ).toMatch(`<h1 />;`)
92
- expect(
93
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
94
- React__default.createElement(Foo)`)
95
- ).toMatch(`<Foo />;`)
96
- expect(
97
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
98
- React__default.createElement(Foo.Bar)`)
99
- ).toMatch(`<Foo.Bar />;`)
100
- expect(
101
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
102
- React__default.createElement(Foo.Bar.Baz)`)
103
- ).toMatch(`<Foo.Bar.Baz />;`)
104
- })
105
-
106
- it('should handle props', async () => {
107
- expect(
108
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
109
- React__default.createElement(foo, {hi: there})`)
110
- ).toMatchInlineSnapshot(`
111
- "import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
112
- React__default.createElement(foo, {
113
- hi: there
114
- });"
115
- `)
116
- expect(
117
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
118
- React__default.createElement("h1", {hi: there})`)
119
- ).toMatch(`<h1 hi={there} />;`)
120
- expect(
121
- await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
122
- React__default.createElement(Foo, {hi: there})`)
123
- ).toMatch(`<Foo hi={there} />;`)
124
- })
125
-
126
- it('should handle Fragment', async () => {
127
- expect(
128
- await jsx(`import R, { Fragment } from 'react';
129
- R.createElement(Fragment)
130
- `)
131
- ).toMatchInlineSnapshot(`
132
- "import R, { Fragment } from 'react';
133
- <Fragment />;"
134
- `)
135
- })
136
-
137
- it('should handle Fragment alias', async () => {
138
- expect(
139
- await jsx(`import RA, { Fragment as F } from 'react';
140
- RA.createElement(F, null, RA.createElement(RA.Fragment))
141
- `)
142
- ).toMatchInlineSnapshot(`
143
- "import RA, { Fragment as F } from 'react';
144
- <F><></></F>;"
145
- `)
146
- })
147
- })
@@ -1,74 +0,0 @@
1
- import type * as babelCore from '@babel/core'
2
-
3
- type RestoredJSX = [
4
- result: babelCore.types.File | null | undefined,
5
- isCommonJS: boolean
6
- ]
7
-
8
- let babelRestoreJSX: Promise<babelCore.PluginItem> | undefined
9
-
10
- const jsxNotFound: RestoredJSX = [null, false]
11
-
12
- async function getBabelRestoreJSX() {
13
- if (!babelRestoreJSX)
14
- babelRestoreJSX = import('./babel-restore-jsx').then((r) => {
15
- const fn = r.default
16
- if ('default' in fn)
17
- // @ts-expect-error
18
- return fn.default
19
- return fn
20
- })
21
- return babelRestoreJSX
22
- }
23
-
24
- /** Restore JSX from `React.createElement` calls */
25
- export async function restoreJSX(
26
- babel: typeof babelCore,
27
- code: string,
28
- filename: string
29
- ): Promise<RestoredJSX> {
30
- const [reactAlias, isCommonJS] = parseReactAlias(code)
31
-
32
- if (!reactAlias) {
33
- return jsxNotFound
34
- }
35
-
36
- const reactJsxRE = new RegExp(
37
- `\\b${reactAlias}\\.(createElement|Fragment)\\b`,
38
- 'g'
39
- )
40
-
41
- if (!reactJsxRE.test(code)) {
42
- return jsxNotFound
43
- }
44
-
45
- const result = await babel.transformAsync(code, {
46
- babelrc: false,
47
- configFile: false,
48
- ast: true,
49
- code: false,
50
- filename,
51
- parserOpts: {
52
- plugins: ['jsx']
53
- },
54
- plugins: [[await getBabelRestoreJSX(), { reactAlias }]]
55
- })
56
-
57
- return [result?.ast, isCommonJS]
58
- }
59
-
60
- export function parseReactAlias(
61
- code: string
62
- ): [alias: string | undefined, isCommonJS: boolean] {
63
- let match = code.match(
64
- /\b(var|let|const)\s+([^=\{\s]+)\s*=\s*require\(["']react["']\)/
65
- )
66
- if (match) {
67
- return [match[2], true]
68
- }
69
- match = code.match(/^import\s+(?:\*\s+as\s+)?(\w+).+?\bfrom\s*["']react["']/m)
70
- if (match) {
71
- return [match[1], false]
72
- }
73
- return [undefined, false]
74
- }