Skip to content

Commit

Permalink
chore!: drop ast check for refresh boundary (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnaudBarre committed Dec 5, 2022
1 parent dab77ea commit e43bd76
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 62 deletions.
58 changes: 8 additions & 50 deletions packages/plugin-react/src/fast-refresh.ts
@@ -1,7 +1,6 @@
import fs from 'node:fs'
import path from 'node:path'
import { createRequire } from 'node:module'
import type { types as t } from '@babel/core'

export const runtimePublicPath = '/@react-refresh'

Expand Down Expand Up @@ -67,14 +66,6 @@ const timeout = `
}
`

const footer = `
if (import.meta.hot) {
window.$RefreshReg$ = prevRefreshReg;
window.$RefreshSig$ = prevRefreshSig;
__ACCEPT__
}`

const checkAndAccept = `
function isReactRefreshBoundary(mod) {
if (mod == null || typeof mod !== 'object') {
Expand Down Expand Up @@ -109,47 +100,14 @@ import.meta.hot.accept(mod => {
});
`

export function addRefreshWrapper(
code: string,
id: string,
accept: boolean,
): string {
return (
header.replace('__SOURCE__', JSON.stringify(id)) +
code +
footer.replace('__ACCEPT__', accept ? checkAndAccept : timeout)
)
}

export function isRefreshBoundary(ast: t.File): boolean {
// Every export must be a potential React component.
// We'll also perform a runtime check that's more robust as well (isLikelyComponentType).
return ast.program.body.every((node) => {
if (node.type !== 'ExportNamedDeclaration') {
return true
}
const { declaration, specifiers } = node
if (declaration) {
if (declaration.type === 'ClassDeclaration') return false
if (declaration.type === 'VariableDeclaration') {
return declaration.declarations.every((variable) =>
isComponentLikeIdentifier(variable.id),
)
}
if (declaration.type === 'FunctionDeclaration') {
return !!declaration.id && isComponentLikeIdentifier(declaration.id)
}
}
return specifiers.every((spec) => {
return isComponentLikeIdentifier(spec.exported)
})
})
}
const footer = `
if (import.meta.hot) {
window.$RefreshReg$ = prevRefreshReg;
window.$RefreshSig$ = prevRefreshSig;
function isComponentLikeIdentifier(node: t.Node): boolean {
return node.type === 'Identifier' && isComponentLikeName(node.name)
}
${checkAndAccept}
}`

function isComponentLikeName(name: string): boolean {
return typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z'
export function addRefreshWrapper(code: string, id: string): string {
return header.replace('__SOURCE__', JSON.stringify(id)) + code + footer
}
15 changes: 3 additions & 12 deletions packages/plugin-react/src/index.ts
@@ -1,13 +1,12 @@
import path from 'node:path'
import type { ParserOptions, TransformOptions, types as t } from '@babel/core'
import type { ParserOptions, TransformOptions } from '@babel/core'
import * as babel from '@babel/core'
import { createFilter, loadEnv, normalizePath, resolveEnvPrefix } from 'vite'
import type { Plugin, PluginOption, ResolvedConfig } from 'vite'
import MagicString from 'magic-string'
import type { SourceMap } from 'magic-string'
import {
addRefreshWrapper,
isRefreshBoundary,
preambleCode,
runtimeCode,
runtimePublicPath,
Expand Down Expand Up @@ -245,7 +244,6 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
}
}

let ast: t.File | null | undefined
let prependReactImport = false
if (!isProjectFile || isJSX) {
if (!useAutomaticRuntime && isProjectFile) {
Expand Down Expand Up @@ -314,14 +312,8 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
parserPlugins.push('typescript')
}

const transformAsync = ast
? babel.transformFromAstAsync.bind(babel, ast, code)
: babel.transformAsync.bind(babel, code)

const isReasonReact = extension.endsWith('.bs.js')
const result = await transformAsync({
const result = await babel.transformAsync(code, {
...babelOptions,
ast: !isReasonReact,
root: projectRoot,
filename: id,
sourceFileName: filepath,
Expand All @@ -344,8 +336,7 @@ export default function viteReact(opts: Options = {}): PluginOption[] {
if (result) {
let code = result.code!
if (useFastRefresh && /\$RefreshReg\$\(/.test(code)) {
const accept = isReasonReact || isRefreshBoundary(result.ast!)
code = addRefreshWrapper(code, id, accept)
code = addRefreshWrapper(code, id)
}
return {
code,
Expand Down

0 comments on commit e43bd76

Please sign in to comment.