@vitejs/plugin-react 1.3.1 → 2.0.0-alpha.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/src/index.ts CHANGED
@@ -2,7 +2,7 @@ import type { ParserOptions, TransformOptions, types as t } from '@babel/core'
2
2
  import * as babel from '@babel/core'
3
3
  import { createFilter } from '@rollup/pluginutils'
4
4
  import resolve from 'resolve'
5
- import type { Plugin, PluginOption } from 'vite'
5
+ import type { Plugin, PluginOption, ResolvedConfig } from 'vite'
6
6
  import {
7
7
  addRefreshWrapper,
8
8
  isRefreshBoundary,
@@ -38,15 +38,10 @@ export interface Options {
38
38
  * @default true
39
39
  */
40
40
  jsxPure?: boolean
41
-
42
41
  /**
43
42
  * Babel configuration applied in both dev and prod.
44
43
  */
45
44
  babel?: BabelOptions
46
- /**
47
- * @deprecated Use `babel.parserOpts.plugins` instead
48
- */
49
- parserPlugins?: ParserOptions['plugins']
50
45
  }
51
46
 
52
47
  export type BabelOptions = Omit<
@@ -104,7 +99,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
104
99
  babelOptions.presets ||= []
105
100
  babelOptions.overrides ||= []
106
101
  babelOptions.parserOpts ||= {} as any
107
- babelOptions.parserOpts.plugins ||= opts.parserPlugins || []
102
+ babelOptions.parserOpts.plugins ||= []
108
103
 
109
104
  // Support patterns like:
110
105
  // - import * as React from 'react';
@@ -154,7 +149,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
154
149
  },
155
150
  async transform(code, id, options) {
156
151
  const ssr = typeof options === 'boolean' ? options : options?.ssr === true
157
- // File extension could be mocked/overriden in querystring.
152
+ // File extension could be mocked/overridden in querystring.
158
153
  const [filepath, querystring = ''] = id.split('?')
159
154
  const [extension = ''] =
160
155
  querystring.match(fileExtensionRE) ||
@@ -373,10 +368,3 @@ viteReact.preambleCode = preambleCode
373
368
  function loadPlugin(path: string): Promise<any> {
374
369
  return import(path).then((module) => module.default || module)
375
370
  }
376
-
377
- // overwrite for cjs require('...')() usage
378
- // The following lines are inserted by scripts/patchEsbuildDist.ts,
379
- // this doesn't bundle correctly after esbuild 0.14.4
380
- //
381
- // module.exports = viteReact
382
- // viteReact['default'] = viteReact
@@ -1,5 +1,4 @@
1
1
  import type * as babelCore from '@babel/core'
2
- import type { types as t, Visitor } from '@babel/core'
3
2
 
4
3
  /**
5
4
  * Replace this:
@@ -11,13 +10,13 @@ import type { types as t, Visitor } from '@babel/core'
11
10
  * var _jsx = require("react/jsx-runtime").jsx
12
11
  */
13
12
  export function babelImportToRequire({ types: t }: typeof babelCore): {
14
- visitor: Visitor
13
+ visitor: babelCore.Visitor
15
14
  } {
16
15
  return {
17
16
  visitor: {
18
17
  ImportDeclaration(path) {
19
18
  const decl = path.node
20
- const spec = decl.specifiers[0] as t.ImportSpecifier
19
+ const spec = decl.specifiers[0] as babelCore.types.ImportSpecifier
21
20
 
22
21
  path.replaceWith(
23
22
  t.variableDeclaration('var', [
@@ -1,5 +1,6 @@
1
- import babelRestoreJSX from './babel-restore-jsx'
2
1
  import * as babel from '@babel/core'
2
+ import { describe, expect, it } from 'vitest'
3
+ import babelRestoreJSX from './babel-restore-jsx'
3
4
 
4
5
  function jsx(code: string) {
5
6
  return babel.transform(code, {
@@ -0,0 +1,56 @@
1
+ import * as babel from '@babel/core'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { restoreJSX } from './restore-jsx'
4
+
5
+ async function jsx(sourceCode: string) {
6
+ const [ast] = await restoreJSX(babel, sourceCode, 'test.js')
7
+ if (ast == null) {
8
+ return ast
9
+ }
10
+ const { code } = await babel.transformFromAstAsync(ast, null, {
11
+ configFile: false
12
+ })
13
+ return code
14
+ }
15
+ // jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
16
+ // React__default.createElement(Foo)`)
17
+ // Tests adapted from: https://github.com/flying-sheep/babel-plugin-transform-react-createelement-to-jsx/blob/63137b6/test/index.js
18
+ describe('restore-jsx', () => {
19
+ it('should trans to ', async () => {
20
+ expect(
21
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
22
+ React__default.createElement(foo)`)
23
+ ).toBeNull()
24
+ expect(
25
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
26
+ React__default.createElement("h1")`)
27
+ ).toMatch(`<h1 />;`)
28
+ expect(
29
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
30
+ React__default.createElement(Foo)`)
31
+ ).toMatch(`<Foo />;`)
32
+ expect(
33
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
34
+ React__default.createElement(Foo.Bar)`)
35
+ ).toMatch(`<Foo.Bar />;`)
36
+ expect(
37
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
38
+ React__default.createElement(Foo.Bar.Baz)`)
39
+ ).toMatch(`<Foo.Bar.Baz />;`)
40
+ })
41
+
42
+ it('should handle props', async () => {
43
+ expect(
44
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
45
+ React__default.createElement(foo, {hi: there})`)
46
+ ).toBeNull()
47
+ expect(
48
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
49
+ React__default.createElement("h1", {hi: there})`)
50
+ ).toMatch(`<h1 hi={there} />;`)
51
+ expect(
52
+ await jsx(`import React__default, { PureComponent, Component, forwardRef, memo, createElement } from 'react';
53
+ React__default.createElement(Foo, {hi: there})`)
54
+ ).toMatch(`<Foo hi={there} />;`)
55
+ })
56
+ })
@@ -1,12 +1,26 @@
1
1
  import type * as babelCore from '@babel/core'
2
- import type { PluginItem, types as t } from '@babel/core'
3
2
 
4
- type RestoredJSX = [result: t.File | null | undefined, isCommonJS: boolean]
3
+ type RestoredJSX = [
4
+ result: babelCore.types.File | null | undefined,
5
+ isCommonJS: boolean
6
+ ]
5
7
 
6
- let babelRestoreJSX: Promise<PluginItem> | undefined
8
+ let babelRestoreJSX: Promise<babelCore.PluginItem> | undefined
7
9
 
8
10
  const jsxNotFound: RestoredJSX = [null, false]
9
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
+
10
24
  /** Restore JSX from `React.createElement` calls */
11
25
  export async function restoreJSX(
12
26
  babel: typeof babelCore,
@@ -20,34 +34,42 @@ export async function restoreJSX(
20
34
  }
21
35
 
22
36
  const [reactAlias, isCommonJS] = parseReactAlias(code)
37
+
23
38
  if (!reactAlias) {
24
39
  return jsxNotFound
25
40
  }
26
41
 
27
- const reactJsxRE = new RegExp(
28
- '\\b' + reactAlias + '\\.(createElement|Fragment)\\b',
29
- 'g'
30
- )
31
-
32
42
  let hasCompiledJsx = false
33
- code = code.replace(reactJsxRE, (_, prop) => {
34
- hasCompiledJsx = true
35
- // Replace with "React" so JSX can be reverse compiled.
36
- return 'React.' + prop
37
- })
43
+
44
+ const fragmentPattern = `\\b${reactAlias}\\.Fragment\\b`
45
+ const createElementPattern = `\\b${reactAlias}\\.createElement\\(\\s*([A-Z"'][\\w$.]*["']?)`
46
+
47
+ // Replace the alias with "React" so JSX can be reverse compiled.
48
+ code = code
49
+ .replace(new RegExp(fragmentPattern, 'g'), () => {
50
+ hasCompiledJsx = true
51
+ return 'React.Fragment'
52
+ })
53
+ .replace(new RegExp(createElementPattern, 'g'), (original, component) => {
54
+ if (/^[a-z][\w$]*$/.test(component)) {
55
+ // Take care not to replace the alias for `createElement` calls whose
56
+ // component is a lowercased variable, since the `restoreJSX` Babel
57
+ // plugin leaves them untouched.
58
+ return original
59
+ }
60
+ hasCompiledJsx = true
61
+ return (
62
+ 'React.createElement(' +
63
+ // Assume `Fragment` is equivalent to `React.Fragment` so modules
64
+ // that use `import {Fragment} from 'react'` are reverse compiled.
65
+ (component === 'Fragment' ? 'React.Fragment' : component)
66
+ )
67
+ })
38
68
 
39
69
  if (!hasCompiledJsx) {
40
70
  return jsxNotFound
41
71
  }
42
72
 
43
- // Support modules that use `import {Fragment} from 'react'`
44
- code = code.replace(
45
- /createElement\(Fragment,/g,
46
- 'createElement(React.Fragment,'
47
- )
48
-
49
- babelRestoreJSX ||= import('./babel-restore-jsx')
50
-
51
73
  const result = await babel.transformAsync(code, {
52
74
  babelrc: false,
53
75
  configFile: false,
@@ -57,8 +79,7 @@ export async function restoreJSX(
57
79
  parserOpts: {
58
80
  plugins: ['jsx']
59
81
  },
60
- // @ts-ignore
61
- plugins: [(await babelRestoreJSX).default]
82
+ plugins: [await getBabelRestoreJSX()]
62
83
  })
63
84
 
64
85
  return [result?.ast, isCommonJS]