UNPKG

@tanstack/router-plugin

Version:

Modern and scalable routing for React applications

74 lines (64 loc) 2.29 kB
import * as template from '@babel/template' import * as t from '@babel/types' import { createHmrHotExpressionAst } from '../../hmr-hot-expression' import { getUniqueProgramIdentifier } from '../../utils' import type { ReferenceRouteCompilerPlugin } from '../plugins' const buildReactRefreshIgnoredRouteExportsStatements = template.statements( ` const hot = %%hotExpression%% if (hot && typeof window !== 'undefined') { ;(hot.data ??= {}) const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => { const ignoredExportsById = new Map() const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports window.__getReactRefreshIgnoredExports = (ctx) => { const ignoredExports = previousGetIgnoredExports?.(ctx) ?? [] const moduleIgnored = ignoredExportsById.get(ctx.id) ?? [] return [...ignoredExports, ...moduleIgnored] } return { ignoredExportsById, } })() tsrReactRefresh.ignoredExportsById.set(%%moduleId%%, ['Route']) } `, { syntacticPlaceholders: true }, ) /** * A trivial component-shaped export that gives `@vitejs/plugin-react` a valid * Fast Refresh boundary. Without at least one non-ignored component export, * the module would be invalidated (full page reload) on every update even * though our custom route HMR handler already manages the update. */ const buildRefreshAnchorStatement = template.statement( `export function %%anchorName%%() { return null }`, { syntacticPlaceholders: true }, ) export function createReactRefreshIgnoredRouteExportsPlugin(opts?: { hotExpression?: string }): ReferenceRouteCompilerPlugin { return { name: 'react-refresh-ignored-route-exports', onAddHmr(ctx) { const anchorName = getUniqueProgramIdentifier( ctx.programPath, 'TSRFastRefreshAnchor', ) ctx.programPath.pushContainer( 'body', buildReactRefreshIgnoredRouteExportsStatements({ hotExpression: createHmrHotExpressionAst( opts?.hotExpression ?? ctx.opts.hmrHotExpression, ), moduleId: t.stringLiteral(ctx.opts.id), }), ) ctx.programPath.pushContainer( 'body', buildRefreshAnchorStatement({ anchorName }), ) return { modified: true } }, } }