-
-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(plugin-react): change how babel.include/exclude
options behave
#6202
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
import type { ParserOptions, TransformOptions, types as t } from '@babel/core' | ||
import * as babel from '@babel/core' | ||
import { createFilter } from '@rollup/pluginutils' | ||
import resolve from 'resolve' | ||
import type { Plugin, PluginOption } from 'vite' | ||
import { | ||
|
@@ -12,15 +11,22 @@ import { | |
} from './fast-refresh' | ||
import { babelImportToRequire } from './jsx-runtime/babel-import-to-require' | ||
import { restoreJSX } from './jsx-runtime/restore-jsx' | ||
import { | ||
createFileFilter, | ||
FileFilter, | ||
FilterOptions, | ||
loadPlugin | ||
} from './utils' | ||
|
||
export type BabelOptions = Omit<TransformOptions, keyof FilterOptions> & | ||
FilterOptions | ||
|
||
export interface Options { | ||
include?: string | RegExp | Array<string | RegExp> | ||
exclude?: string | RegExp | Array<string | RegExp> | ||
/** | ||
* Enable `react-refresh` integration. Vite disables this in prod env or build mode. | ||
* @default true | ||
*/ | ||
fastRefresh?: boolean | ||
fastRefresh?: boolean | FilterOptions | ||
/** | ||
* Set this to `"automatic"` to use [vite-react-jsx](https://github.com/alloc/vite-react-jsx). | ||
* @default "automatic" | ||
|
@@ -36,7 +42,7 @@ export interface Options { | |
/** | ||
* Babel configuration applied in both dev and prod. | ||
*/ | ||
babel?: TransformOptions | ||
babel?: BabelOptions | ||
/** | ||
* @deprecated Use `babel.parserOpts.plugins` instead | ||
*/ | ||
|
@@ -46,19 +52,39 @@ export interface Options { | |
export default function viteReact(opts: Options = {}): PluginOption[] { | ||
// Provide default values for Rollup compat. | ||
let base = '/' | ||
let filter = createFilter(opts.include, opts.exclude) | ||
let isProduction = true | ||
let projectRoot = process.cwd() | ||
let skipFastRefresh = opts.fastRefresh === false | ||
let skipReactImport = false | ||
let shouldProjectInclude: FileFilter | ||
let shouldProjectExclude: FileFilter | ||
let shouldUseFastRefresh: FileFilter | ||
initializeFilters() | ||
|
||
function initializeFilters(command?: string) { | ||
shouldProjectInclude = createFileFilter( | ||
{ include: opts.babel?.include }, | ||
false, | ||
projectRoot | ||
) | ||
shouldProjectExclude = createFileFilter( | ||
{ include: opts.babel?.exclude }, | ||
false, | ||
projectRoot | ||
) | ||
shouldUseFastRefresh = createFileFilter( | ||
!(isProduction || command === 'build') && opts.fastRefresh, | ||
true, | ||
projectRoot | ||
) | ||
} | ||
|
||
const useAutomaticRuntime = opts.jsxRuntime !== 'classic' | ||
|
||
const userPlugins = opts.babel?.plugins || [] | ||
const userParserPlugins = | ||
opts.parserPlugins || opts.babel?.parserOpts?.plugins || [] | ||
|
||
// Support pattens like: | ||
// Support patterns like: | ||
// - import * as React from 'react'; | ||
// - import React from 'react'; | ||
// - import React, {useEffect} from 'react'; | ||
|
@@ -73,11 +99,8 @@ export default function viteReact(opts: Options = {}): PluginOption[] { | |
configResolved(config) { | ||
base = config.base | ||
projectRoot = config.root | ||
filter = createFilter(opts.include, opts.exclude, { | ||
resolve: projectRoot | ||
}) | ||
isProduction = config.isProduction | ||
skipFastRefresh ||= isProduction || config.command === 'build' | ||
initializeFilters(config.command) | ||
|
||
const jsxInject = config.esbuild && config.esbuild.jsxInject | ||
if (jsxInject && importReactRE.test(jsxInject)) { | ||
|
@@ -112,20 +135,23 @@ export default function viteReact(opts: Options = {}): PluginOption[] { | |
const isNodeModules = id.includes('/node_modules/') | ||
const isProjectFile = | ||
!isNodeModules && (id[0] === '\0' || id.startsWith(projectRoot + '/')) | ||
? !shouldProjectExclude(id) | ||
: shouldProjectInclude(id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would any "exclude" settings be ignored in this case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good observation! With how this is currently written, one cannot Should be a simple fix, just add |
||
|
||
const plugins = isProjectFile ? [...userPlugins] : [] | ||
|
||
let useFastRefresh = false | ||
if (!skipFastRefresh && !ssr && !isNodeModules) { | ||
const usingFastRefresh = | ||
!ssr && | ||
!isNodeModules && | ||
shouldUseFastRefresh(id) && | ||
// Modules with .js or .ts extension must import React. | ||
const isReactModule = isJSX || code.includes('react') | ||
if (isReactModule && filter(id)) { | ||
useFastRefresh = true | ||
plugins.push([ | ||
await loadPlugin('react-refresh/babel.js'), | ||
{ skipEnvCheck: true } | ||
]) | ||
} | ||
(isJSX || code.includes('react')) | ||
|
||
if (usingFastRefresh) { | ||
plugins.push([ | ||
await loadPlugin('react-refresh/babel.js'), | ||
{ skipEnvCheck: true } | ||
]) | ||
} | ||
|
||
let ast: t.File | null | undefined | ||
|
@@ -238,7 +264,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] { | |
|
||
if (result) { | ||
let code = result.code! | ||
if (useFastRefresh && /\$RefreshReg\$\(/.test(code)) { | ||
if (usingFastRefresh && /\$RefreshReg\$\(/.test(code)) { | ||
const accept = isReasonReact || isRefreshBoundary(result.ast!) | ||
code = addRefreshWrapper(code, id, accept) | ||
} | ||
|
@@ -318,10 +344,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] { | |
|
||
viteReact.preambleCode = preambleCode | ||
|
||
function loadPlugin(path: string): Promise<any> { | ||
return import(path).then((module) => module.default || module) | ||
} | ||
|
||
// overwrite for cjs require('...')() usage | ||
module.exports = viteReact | ||
viteReact['default'] = viteReact |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { createFilter } from '@rollup/pluginutils' | ||
|
||
export function loadPlugin(path: string): Promise<any> { | ||
return import(path).then((module) => module.default || module) | ||
} | ||
|
||
export interface FilterOptions { | ||
include?: string | RegExp | Array<string | RegExp> | ||
exclude?: string | RegExp | Array<string | RegExp> | ||
} | ||
|
||
const returnTrue = () => true | ||
const returnFalse = () => false | ||
|
||
export type FileFilter = (id: string) => boolean | ||
|
||
export function createFileFilter( | ||
arg: boolean | FilterOptions | undefined, | ||
defaultArg: boolean, | ||
resolve?: string | ||
): FileFilter { | ||
return arg === true | ||
? returnTrue | ||
: arg === false | ||
? returnFalse | ||
: arg && (arg.include || arg.exclude) | ||
? createFilter(arg.include, arg.exclude, { resolve }) | ||
: defaultArg | ||
? returnTrue | ||
: returnFalse | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be "exclude" instead of "include"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No but it does need a comment to clarify that :)
It's creating a function that returns true if a
babel.exclude
pattern is matched.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, got it, thanks!