UNPKG

rsbuild-plugin-react-router

Version:
885 lines (879 loc) 72.7 kB
import { basename, dirname, normalize, relative, resolve } from "pathe"; import { existsSync, readFileSync, statSync } from "node:fs"; import { langFromPath, parse, walk as external_yuku_parser_walk } from "yuku-parser"; import { Analyzer } from "yuku-analyzer"; import { print } from "yuku-codegen"; import { readFile, stat } from "node:fs/promises"; import { rspack } from "@rsbuild/core"; import { createRequire } from "node:module"; let PLUGIN_NAME = 'rsbuild:react-router', JS_EXTENSIONS = [ '.tsx', '.ts', '.jsx', '.js', '.mjs', '.mts' ], BUILD_CLIENT_ROUTE_QUERY_STRING = '?__react-router-build-client-route', SERVER_ONLY_ROUTE_EXPORTS = [ 'loader', 'action', 'middleware', 'headers' ], SERVER_ONLY_ROUTE_EXPORTS_SET = new Set(SERVER_ONLY_ROUTE_EXPORTS), CLIENT_ROUTE_EXPORTS_SET = new Set([ 'clientAction', 'clientLoader', 'clientMiddleware', 'handle', 'meta', 'links', 'shouldRevalidate', 'default', 'ErrorBoundary', 'HydrateFallback', 'Layout' ]), NAMED_COMPONENT_EXPORTS_SET = new Set([ 'HydrateFallback', 'ErrorBoundary' ]), SERVER_EXPORTS = { loader: 'loader', action: 'action', middleware: 'middleware', headers: 'headers' }, CLIENT_EXPORTS = { clientAction: 'clientAction', clientLoader: 'clientLoader', clientMiddleware: 'clientMiddleware', default: 'default', ErrorBoundary: 'ErrorBoundary', handle: 'handle', HydrateFallback: 'HydrateFallback', Layout: 'Layout', links: 'links', meta: 'meta', shouldRevalidate: 'shouldRevalidate' }, getPatternIdentifierNames = (pattern, names = new Set())=>{ if (!pattern) return names; if ('Identifier' === pattern.type) return names.add(pattern.name), names; if ('RestElement' === pattern.type) return getPatternIdentifierNames(pattern.argument, names); if ('AssignmentPattern' === pattern.type) return getPatternIdentifierNames(pattern.left, names); if ('ArrayPattern' === pattern.type) { for (let element of pattern.elements ?? [])getPatternIdentifierNames(element, names); return names; } if ('ObjectPattern' === pattern.type) for (let property of pattern.properties ?? [])'RestElement' === property.type ? getPatternIdentifierNames(property.argument, names) : getPatternIdentifierNames(property.value, names); return names; }, getIdentifierNamesFromPattern = (pattern)=>Array.from(getPatternIdentifierNames(pattern)), getExportedName = (node)=>{ let exported = node?.exported ?? node; return exported ? 'Identifier' === exported.type ? exported.name : 'Literal' === exported.type || 'StringLiteral' === exported.type ? String(exported.value) : null : null; }, identifier = (name)=>({ type: 'Identifier', start: 0, end: 0, name, decorators: [], optional: !1, typeAnnotation: null }), callExpression = (callee, args)=>({ type: 'CallExpression', start: 0, end: 0, callee, arguments: args, optional: !1 }), importDeclaration = (specifiers, source)=>({ type: 'ImportDeclaration', start: 0, end: 0, specifiers: specifiers.map((specifier)=>({ type: 'ImportSpecifier', start: 0, end: 0, imported: identifier(specifier.imported), local: identifier(specifier.local), importKind: 'value' })), source: { type: 'Literal', start: 0, end: 0, value: source, raw: JSON.stringify(source) }, attributes: [], phase: null, importKind: 'value' }), exportSpecifier = (local, exported)=>({ type: 'ExportSpecifier', start: 0, end: 0, local: identifier(local), exported: identifier(exported), exportKind: 'value' }), exportNamedDeclaration = (specifiers)=>({ type: 'ExportNamedDeclaration', start: 0, end: 0, declaration: null, specifiers, source: null, attributes: [], exportKind: 'value' }), variableDeclaration = (name, init)=>({ type: 'VariableDeclaration', start: 0, end: 0, kind: 'const', declare: !1, declarations: [ { type: 'VariableDeclarator', start: 0, end: 0, id: identifier(name), init, definite: !1 } ] }), removeFromArray = (array, value)=>{ let index = array.indexOf(value); index >= 0 && array.splice(index, 1); }, assertAllowedBindingName = (name, exportsToRemove)=>{ if (exportsToRemove.has(name)) throw Error(`Cannot remove destructured export "${name}"`); }, validateRestElement = (element, exportsToRemove)=>{ element.argument?.type === 'Identifier' && element.argument.name && assertAllowedBindingName(element.argument.name, exportsToRemove); }, validateObjectProperty = (property, exportsToRemove)=>{ 'RestElement' === property.type ? validateRestElement(property, exportsToRemove) : 'Property' === property.type && validateBindingTarget(property.value, exportsToRemove); }, validateBindingTarget = (node, exportsToRemove)=>{ if (node) switch(node.type){ case 'Identifier': node.name && assertAllowedBindingName(node.name, exportsToRemove); return; case 'AssignmentPattern': validateBindingTarget(node.left, exportsToRemove); return; case 'ArrayPattern': for (let element of node.elements ?? [])element?.type === 'RestElement' ? validateRestElement(element, exportsToRemove) : validateBindingTarget(element, exportsToRemove); return; case 'ObjectPattern': for (let property of node.properties ?? [])validateObjectProperty(property, exportsToRemove); } }, getDeclaredNames = (node)=>{ let names = new Set(); if ('VariableDeclaration' === node.type) for (let declarator of node.declarations ?? [])getPatternIdentifierNames(declarator.id, names); else if (('FunctionDeclaration' === node.type || 'ClassDeclaration' === node.type) && node.id?.name) names.add(node.id.name); else if ('ImportDeclaration' === node.type) for (let specifier of node.specifiers ?? [])specifier.local?.name && names.add(specifier.local.name); return names; }, collectReferencedNames = (node)=>{ let referenced = new Set(); return external_yuku_parser_walk(node, { Identifier (node, ctx) { let parent = ctx.parent; !(parent && 'Identifier' === node.type && (((node, parent)=>{ if (!parent || 'Identifier' !== node.type) return !1; if (('FunctionDeclaration' === parent.type || 'FunctionExpression' === parent.type || 'ClassDeclaration' === parent.type || 'ClassExpression' === parent.type) && parent.id === node) return !0; if ('VariableDeclarator' === parent.type) return !!(node.name && getPatternIdentifierNames(parent.id).has(node.name)); if (('ImportSpecifier' === parent.type || 'ImportDefaultSpecifier' === parent.type || 'ImportNamespaceSpecifier' === parent.type) && parent.local === node) return !0; if (('FunctionDeclaration' === parent.type || 'FunctionExpression' === parent.type || 'ArrowFunctionExpression' === parent.type) && node.name) { let name = node.name; return (parent.params ?? []).some((param)=>getPatternIdentifierNames(param).has(name)); } return !1; })(node, parent) || 'MemberExpression' === parent.type && parent.property === node && !parent.computed || 'Property' === parent.type && parent.key === node && !parent.computed && !parent.shorthand || 'MethodDefinition' === parent.type && parent.key === node && !parent.computed || 'ExportSpecifier' === parent.type || 'ExportDefaultSpecifier' === parent.type || 'ExportNamespaceSpecifier' === parent.type || 'ImportSpecifier' === parent.type && parent.imported === node || 'LabeledStatement' === parent.type || 'BreakStatement' === parent.type || 'ContinueStatement' === parent.type)) && node.name && referenced.add(node.name); }, JSXIdentifier (node, ctx) { let name, parent = ctx.parent; if (parent) { if ('JSXMemberExpression' === parent.type && parent.object === node) { node.name && referenced.add(node.name); return; } if (node.name && (name = node.name, /^[A-Z]/.test(name)) && ('JSXOpeningElement' === parent.type || 'JSXClosingElement' === parent.type) && parent.name === node) return void referenced.add(node.name); } }, ExportSpecifier (node, ctx) { let declaration = ctx.parent; !declaration?.source && declaration?.exportKind !== 'type' && node.local?.name && 'type' !== node.exportKind && referenced.add(node.local.name); } }), referenced; }, collectLiveTopLevelDeclarations = (program, graph)=>{ let pendingNames = []; for (let statement of program.body ?? [])if ('VariableDeclaration' !== statement.type && !graph.declarationsByNode.has(statement)) for (let name of collectReferencedNames(statement))pendingNames.push(name); let visitedNames = new Set(), liveDeclarations = new Set(); for(; pendingNames.length > 0;){ let name = pendingNames.pop(); if (!(!name || visitedNames.has(name))) { for (let declaration of (visitedNames.add(name), graph.declarationsByName.get(name) ?? []))if (!liveDeclarations.has(declaration)) for (let referencedName of (liveDeclarations.add(declaration), declaration.referencedNames))pendingNames.push(referencedName); } } return liveDeclarations; }, declarationReferencesName = (declaration, names, graph, cache, visitedNames = new Set())=>{ let cached = cache.get(declaration); if (void 0 !== cached) return cached; for (let referencedName of declaration.referencedNames){ if (names.has(referencedName)) return cache.set(declaration, !0), !0; if (!visitedNames.has(referencedName)) { for (let referencedDeclaration of (visitedNames.add(referencedName), graph.declarationsByName.get(referencedName) ?? []))if (declarationReferencesName(referencedDeclaration, names, graph, cache, visitedNames)) return cache.set(declaration, !0), !0; } } return cache.set(declaration, !1), !1; }; function toFunctionExpression(decl) { return { ...decl, type: 'FunctionExpression', declare: void 0 }; } function toClassExpression(decl) { return { ...decl, type: 'ClassExpression', declare: void 0 }; } let getComponentExportName = (exportedName)=>{ var name; return 'default' === exportedName ? 'Component' : (name = exportedName, NAMED_COMPONENT_EXPORTS_SET.has(name)) ? exportedName : null; }, declarationIncludesName = (declaration, name)=>'VariableDeclaration' === declaration.type ? (declaration.declarations ?? []).some((declarator)=>{ let pattern; return pattern = declarator.id, getPatternIdentifierNames(pattern).has(name); }) : ('FunctionDeclaration' === declaration.type || 'ClassDeclaration' === declaration.type || 'TSEnumDeclaration' === declaration.type) && declaration.id?.name ? declaration.id.name === name : 'ImportDeclaration' === declaration.type && (declaration.specifiers ?? []).some((specifier)=>specifier.local?.name === name), hasTopLevelBindingName = (program, name)=>{ for (let statement of program.body ?? []){ if ('ImportDeclaration' === statement.type) { if (declarationIncludesName(statement, name)) return !0; continue; } if ('ExportDefaultDeclaration' === statement.type) { if (statement.declaration?.id?.name === name) return !0; continue; } let declaration = 'ExportNamedDeclaration' === statement.type ? statement.declaration : statement; if (declaration && declarationIncludesName(declaration, name)) return !0; } return !1; }; function combineURLs(baseURL, relativeURL) { return relativeURL ? `${baseURL.replace(/\/+$/, '')}/${relativeURL.replace(/^\/+/, '')}` : baseURL; } function normalizeAssetPrefix(assetPrefix) { return assetPrefix && 'auto' !== assetPrefix ? assetPrefix.endsWith('/') ? assetPrefix : `${assetPrefix}/` : '/'; } function createRouteId(file) { return normalize(file.replace(/\.[^/.]+$/, '')); } function findEntryFile(basePath) { for (let ext of JS_EXTENSIONS){ let filePath = `${basePath}${ext}`; if (existsSync(filePath)) return filePath; } return `${basePath}.tsx`; } function generateWithProps() { return ` import { createElement as h } from "react"; import { useActionData, useLoaderData, useMatches, useParams, useRouteError } from "react-router"; export function withComponentProps(Component) { return function Wrapped() { const props = { params: useParams(), loaderData: useLoaderData(), actionData: useActionData(), matches: useMatches(), }; return h(Component, props); }; } export function withHydrateFallbackProps(HydrateFallback) { return function Wrapped() { const props = { params: useParams(), }; return h(HydrateFallback, props); }; } export function withErrorBoundaryProps(ErrorBoundary) { return function Wrapped() { const props = { params: useParams(), loaderData: useLoaderData(), actionData: useActionData(), error: useRouteError(), }; return h(ErrorBoundary, props); }; } `; } let routeChunkExportNames = [ 'clientAction', 'clientLoader', 'clientMiddleware', 'HydrateFallback' ]; [ ...routeChunkExportNames ]; let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exportName)=>source.includes(exportName)), createRouteChunkExportMap = (getValue)=>Object.fromEntries(routeChunkExportNames.map((exportName)=>[ exportName, getValue(exportName) ])), routeChunkQueryStringPrefix = '?route-chunk=', routeChunkQueryStrings = { main: `${routeChunkQueryStringPrefix}main`, clientAction: `${routeChunkQueryStringPrefix}clientAction`, clientLoader: `${routeChunkQueryStringPrefix}clientLoader`, clientMiddleware: `${routeChunkQueryStringPrefix}clientMiddleware`, HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback` }, routeChunkEntrySuffix = { clientAction: 'client-action', clientLoader: 'client-loader', clientMiddleware: 'client-middleware', HydrateFallback: 'hydrate-fallback' }, invariant = (value, message)=>{ if (!value) throw Error(message); }, getOrSetFromCache = (cache, key, version, getValue)=>{ let entry = cache.get(key); if (entry?.version === version) return entry.value; let value = getValue(); return cache.set(key, { value, version }), value; }, analyzeCode = (code, cache, cacheKey)=>getOrSetFromCache(cache, `${cacheKey}::analyzeCode`, code, ()=>{ let module = new Analyzer().addFile(cacheKey, code, { lang: 'tsx', sourceType: 'module', attachComments: !0 }), errors = module.diagnostics.filter((diagnostic)=>'error' === diagnostic.severity); if (errors.length > 0) throw Error(errors.map((error)=>error.message).join('\n')); return { module, program: module.ast }; }), route_chunks_getExportedName = (exported)=>'Identifier' === exported.type ? exported.name : String(exported.value), setsIntersect = (set1, set2)=>{ let smallerSet = set1, largerSet = set2; for (let element of (set1.size > set2.size && (smallerSet = set2, largerSet = set1), smallerSet))if (largerSet.has(element)) return !0; return !1; }, getExportDependencies = (code, cache, cacheKey)=>getOrSetFromCache(cache, `${cacheKey}::getExportDependencies`, code, ()=>{ let { module } = analyzeCode(code, cache, cacheKey), exportDependencies = new Map(), topLevelStatementCache = new Map(), variableDeclaratorCache = new Map(), getCachedTopLevelStatementForNode = (node)=>{ let cached = topLevelStatementCache.get(node); if (cached) return cached; let statement = ((module, node)=>{ let current = node, parent = module.parentOf(current); for(; parent && 'Program' !== parent.type;)current = parent, parent = module.parentOf(current); return invariant(parent?.type === 'Program', 'Expected node to be within Program'), current; })(module, node); return topLevelStatementCache.set(node, statement), statement; }, getCachedVariableDeclaratorForNode = (node)=>{ if (variableDeclaratorCache.has(node)) return variableDeclaratorCache.get(node) ?? null; let declarator = ((module, node)=>{ let current = node; for(; current;){ if ('VariableDeclarator' === current.type) return current; current = module.parentOf(current); } return null; })(module, node); return variableDeclaratorCache.set(node, declarator), declarator; }, addCachedTopLevelStatement = (dependencies, node)=>{ let statement = getCachedTopLevelStatementForNode(node); return dependencies.topLevelStatements.add(statement), 'ImportDeclaration' === statement.type || statement.type.startsWith('Export') || dependencies.topLevelNonModuleStatements.add(statement), statement; }, handleExport = (exportName, exportNode, localSymbol)=>{ let dependencies = { topLevelStatements: new Set(), topLevelNonModuleStatements: new Set(), importedIdentifierNames: new Set(), exportedVariableDeclarators: new Set() }, visitedSymbols = new Set(), scannedNodes = new Set(), scanNode = (node)=>{ scannedNodes.has(node) || (scannedNodes.add(node), external_yuku_parser_walk(node, { Identifier (node) { let reference = module.referenceOf(node); reference?.symbol && visitSymbol(reference.symbol); } })); }, visitSymbol = (symbol)=>{ if (!visitedSymbols.has(symbol)) { for (let declaration of (visitedSymbols.add(symbol), symbol.declarations)){ let statement = addCachedTopLevelStatement(dependencies, declaration); 'ImportDeclaration' === statement.type && dependencies.importedIdentifierNames.add(symbol.name); let declarator = getCachedVariableDeclaratorForNode(declaration); declarator && 'ExportNamedDeclaration' === getCachedTopLevelStatementForNode(declarator).type && dependencies.exportedVariableDeclarators.add(declarator), scanNode(declarator ?? statement); } for (let reference of symbol.references){ let statement = addCachedTopLevelStatement(dependencies, reference.node); scanNode(getCachedVariableDeclaratorForNode(reference.node) ?? statement); } } }; addCachedTopLevelStatement(dependencies, exportNode), localSymbol ? visitSymbol(localSymbol) : scanNode(getCachedTopLevelStatementForNode(exportNode)), exportDependencies.set(exportName, dependencies); }; for (let exp of module.exports)exp.typeOnly || exp.isStar || exp.isExportEquals || handleExport(exp.name, exp.node, exp.local ?? null); return exportDependencies; }), getChunkableExportMap = (code, cache, cacheKey)=>getOrSetFromCache(cache, `${cacheKey}::getChunkableExportMap`, code, ()=>{ let exportDependencies = getExportDependencies(code, cache, cacheKey); return createRouteChunkExportMap((exportName)=>((exportName, exportDependencies)=>{ let dependencies = exportDependencies.get(exportName); if (!dependencies) return !1; for (let [currentExportName, currentDependencies] of exportDependencies)if (currentExportName !== exportName && setsIntersect(currentDependencies.topLevelNonModuleStatements, dependencies.topLevelNonModuleStatements)) return !1; if (dependencies.exportedVariableDeclarators.size > 1) return !1; if (dependencies.exportedVariableDeclarators.size > 0) { for (let [currentExportName, currentDependencies] of exportDependencies)if (currentExportName !== exportName && setsIntersect(currentDependencies.exportedVariableDeclarators, dependencies.exportedVariableDeclarators)) return !1; } return !0; })(exportName, exportDependencies)); }), generateCode = (program)=>{ if (0 === program.body.length) return; let result = print(program, { comments: !0 }); if (result.errors.length > 0) throw Error(result.errors.map((error)=>error.message).join('\n')); return result.code; }, filterImportSpecifiers = (node, shouldKeep)=>{ if (0 === node.specifiers.length) return node; let specifiers = node.specifiers.filter((specifier)=>shouldKeep(specifier.local.name)); return specifiers.length > 0 ? { ...node, specifiers } : null; }, getChunkedExport = (code, exportName, cache, cacheKey)=>getOrSetFromCache(cache, `${cacheKey}::getChunkedExport::${exportName}`, code, ()=>{ if (!routeChunkExportNames.includes(exportName) || !getChunkableExportMap(code, cache, cacheKey)[exportName]) return; let dependencies = getExportDependencies(code, cache, cacheKey).get(exportName); invariant(dependencies, 'Expected export to have dependencies'); let program = analyzeCode(code, cache, cacheKey).program, body = program.body.filter((node)=>dependencies.topLevelStatements.has(node)).map((node)=>'ImportDeclaration' !== node.type ? node : 0 === dependencies.importedIdentifierNames.size ? null : filterImportSpecifiers(node, (importedName)=>dependencies.importedIdentifierNames.has(importedName))).map((node)=>{ if (!node || !node.type.startsWith('Export')) return node; if ('ExportAllDeclaration' === node.type) return null; if ('ExportDefaultDeclaration' === node.type) return 'default' === exportName ? node : null; let { declaration } = node; if (declaration?.type === 'VariableDeclaration') { let declarations = declaration.declarations.filter((declarationNode)=>dependencies.exportedVariableDeclarators.has(declarationNode)); return declarations.length > 0 ? { ...node, declaration: { ...declaration, declarations } } : null; } if (declaration?.type === 'FunctionDeclaration' || declaration?.type === 'ClassDeclaration') return declaration.id?.name === exportName ? node : null; if ('ExportNamedDeclaration' === node.type) { let specifiers = node.specifiers.filter((specifier)=>route_chunks_getExportedName(specifier.exported) === exportName); return specifiers.length > 0 ? { ...node, specifiers } : null; } throw Error('Unknown export node type'); }).filter(Boolean); return generateCode({ ...program, body }); }), hasCachedChunkedExport = (code, exportName, cache, cacheKey)=>{ let key; return key = `${cacheKey}::getChunkedExport::${exportName}`, cache.get(key)?.version === code; }, getRouteChunkModuleId = (filePath, chunkName)=>`${filePath}${routeChunkQueryStrings[chunkName]}`, normalizeRelativeFilePath = (file, appDirectory)=>{ let fullPath = resolve(appDirectory, file); return normalize(relative(appDirectory, fullPath)).split('?')[0]; }, isRootRouteModuleId = (config, id)=>normalizeRelativeFilePath(id, config.appDirectory) === config.rootRouteFile, shouldAnalyzeRouteChunks = (config, id, code)=>!!config.splitRouteModules && mightContainRouteChunkExportName(code) && !isRootRouteModuleId(config, id), createEmptyRouteChunkByExportName = ()=>createRouteChunkExportMap(()=>!1), buildManifestChunkValidity = (exportNames, hasRouteChunkByExportName)=>createRouteChunkExportMap((exportName)=>!exportNames.has(exportName) || hasRouteChunkByExportName[exportName]), detectRouteChunksIfEnabled = async (cache, config, id, code)=>{ let analysisCache, exportDependencies, hasRouteChunkByExportName, chunkedExports, hasRouteChunks; if (!shouldAnalyzeRouteChunks(config, id, code)) return { exportNames: [], chunkedExports: [], hasRouteChunks: !1, hasRouteChunkByExportName: createEmptyRouteChunkByExportName() }; let cacheKey = normalizeRelativeFilePath(id, config.appDirectory); return exportDependencies = getExportDependencies(code, analysisCache = cache ?? new Map(), cacheKey), hasRouteChunks = (chunkedExports = Object.entries(hasRouteChunkByExportName = getChunkableExportMap(code, analysisCache, cacheKey)).filter(([, isChunked])=>isChunked).map(([exportName])=>exportName)).length > 0, { exportNames: Array.from(exportDependencies.keys()), hasRouteChunks, hasRouteChunkByExportName, chunkedExports }; }, getRouteChunkIfEnabled = async (cache, config, id, chunkName, code)=>{ if (!config.splitRouteModules) return null; if ('main' === chunkName) { if (!mightContainRouteChunkExportName(code)) return code; } else if (!code.includes(chunkName)) return null; return ((code, chunkName, cache, cacheKey)=>{ let analysisCache = cache ?? new Map(); if ('main' === chunkName) return getOrSetFromCache(analysisCache, `${cacheKey}::omitChunkedExports::${routeChunkExportNames.join(',')}`, code, ()=>{ let chunkableExportMap = getChunkableExportMap(code, analysisCache, cacheKey), exportNameSet = new Set(routeChunkExportNames), isOmitted = (exportName)=>exportNameSet.has(exportName) && !!chunkableExportMap[exportName], exportDependencies = getExportDependencies(code, analysisCache, cacheKey), allExportNames = Array.from(exportDependencies.keys()), omittedExportNames = allExportNames.filter(isOmitted), retainedExportNames = allExportNames.filter((exportName)=>!isOmitted(exportName)), omittedStatements = new Set(), omittedExportedVariableDeclarators = new Set(), retainedImportedIdentifierNames = new Set(), omittedImportedIdentifierNames = new Set(); for (let omittedExportName of omittedExportNames){ let dependencies = exportDependencies.get(omittedExportName); for (let statement of (invariant(dependencies, `Expected dependencies for ${omittedExportName}`), dependencies.topLevelNonModuleStatements))omittedStatements.add(statement); for (let declarator of dependencies.exportedVariableDeclarators)omittedExportedVariableDeclarators.add(declarator); for (let importedName of dependencies.importedIdentifierNames)omittedImportedIdentifierNames.add(importedName); } for (let retainedExportName of retainedExportNames){ let dependencies = exportDependencies.get(retainedExportName); if (dependencies) for (let importedName of dependencies.importedIdentifierNames)retainedImportedIdentifierNames.add(importedName); } let program = analyzeCode(code, analysisCache, cacheKey).program, body = program.body.filter((node)=>!omittedStatements.has(node)).map((node)=>'ImportDeclaration' !== node.type ? node : filterImportSpecifiers(node, (importedName)=>!!retainedImportedIdentifierNames.has(importedName) || !omittedImportedIdentifierNames.has(importedName))).map((node)=>{ if (!node || !node.type.startsWith('Export') || 'ExportAllDeclaration' === node.type) return node; if ('ExportDefaultDeclaration' === node.type) return isOmitted('default') ? null : node; if (node.declaration?.type === 'VariableDeclaration') { let declarations = node.declaration.declarations.filter((declarationNode)=>!omittedExportedVariableDeclarators.has(declarationNode)); return declarations.length > 0 ? { ...node, declaration: { ...node.declaration, declarations } } : null; } if (node.declaration?.type === 'FunctionDeclaration' || node.declaration?.type === 'ClassDeclaration') return isOmitted(node.declaration.id.name) ? null : node; if ('ExportNamedDeclaration' === node.type) { let specifiers = node.specifiers.filter((specifier)=>!isOmitted(route_chunks_getExportedName(specifier.exported))); return specifiers.length > 0 || node.declaration ? { ...node, specifiers } : null; } throw Error('Unknown node type'); }).filter(Boolean); return generateCode({ ...program, body }); }); return hasCachedChunkedExport(code, chunkName, analysisCache, cacheKey) || ((code, cache, cacheKey)=>{ let chunkableExportMap = getChunkableExportMap(code, cache, cacheKey); for (let exportName of routeChunkExportNames)chunkableExportMap[exportName] && (hasCachedChunkedExport(code, exportName, cache, cacheKey) || getChunkedExport(code, exportName, cache, cacheKey)); })(code, analysisCache, cacheKey), getChunkedExport(code, chunkName, analysisCache, cacheKey); })(code, chunkName, cache, normalizeRelativeFilePath(id, config.appDirectory)) ?? null; }, validateRouteChunks = ({ config, id, valid })=>{ if (isRootRouteModuleId(config, id)) return; let invalidChunks = Object.entries(valid).filter(([, isValid])=>!isValid).map(([chunkName])=>chunkName); if (0 === invalidChunks.length) return; let plural = invalidChunks.length > 1; throw Error([ `Error splitting route module: ${normalizeRelativeFilePath(id, config.appDirectory)}`, invalidChunks.map((name)=>`- ${name}`).join('\n'), `${plural ? 'These exports' : 'This export'} could not be split into ${plural ? 'their own chunks' : 'its own chunk'} because ${plural ? 'they share' : 'it shares'} code with other exports. You should extract any shared code into its own module and then import it within the route module.` ].join('\n\n')); }, getRouteChunkEntryName = (routeId, chunkName)=>`${routeId}-${routeChunkEntrySuffix[chunkName]}`, setBoundedCacheEntry = (cache, key, value, maxEntries)=>{ if (maxEntries <= 0) return void cache.clear(); if (!cache.has(key) && cache.size >= maxEntries) { let oldestEntry = cache.keys().next(); oldestEntry.done || cache.delete(oldestEntry.value); } cache.set(key, value); }, exportInfoCache = new Map(), routeModuleAnalysisCache = new Map(), getParseErrors = (result)=>result.diagnostics.filter((diagnostic)=>'error' === diagnostic.severity), getParseErrorMessage = (errors)=>errors.map((error)=>error.message).join('\n'), parseProgram = (code, resourcePath)=>{ let sourcePath = resourcePath ? resourcePath.replace(/[?#].*$/, '') : void 0, lang = sourcePath ? langFromPath(sourcePath) : 'tsx', result = parse(code, { sourceType: 'module', lang }), errors = getParseErrors(result); if (0 === errors.length) return result.program ?? result; if (!sourcePath || 'ts' !== lang && 'tsx' !== lang) throw Error(getParseErrorMessage(errors)); let normalizedResult = parse(rspack.experiments.swc.transformSync(code, { filename: sourcePath, jsc: { parser: { syntax: "typescript", tsx: 'tsx' === lang } } }).code, { sourceType: 'module', lang: 'js' }), normalizedErrors = getParseErrors(normalizedResult); if (normalizedErrors.length > 0) throw Error(getParseErrorMessage(normalizedErrors)); return normalizedResult.program ?? normalizedResult; }, cachePromiseOnReject = (promise, invalidate)=>promise.catch((error)=>{ throw invalidate(), error; }), isTypeOnlyExport = (node)=>'type' === node.exportKind || 'TSExportAssignment' === node.type || node.declaration?.declare === !0 || 'ExportDefaultDeclaration' === node.type && node.declaration?.type === 'TSInterfaceDeclaration', collectProgramExportNames = (program)=>{ let exportNames = new Set(); for (let statement of program.body ?? []){ if (isTypeOnlyExport(statement)) continue; if ('ExportAllDeclaration' === statement.type) { let exported = getExportedName(statement.exported); exported && exportNames.add(exported); continue; } if ('ExportDefaultDeclaration' === statement.type) { exportNames.add('default'); continue; } if ('ExportNamedDeclaration' !== statement.type) continue; let declaration = statement.declaration; if (declaration) { if ('VariableDeclaration' === declaration.type) for (let declarator of declaration.declarations ?? [])for (let name of getIdentifierNamesFromPattern(declarator.id))exportNames.add(name); else ('FunctionDeclaration' === declaration.type || 'ClassDeclaration' === declaration.type || 'TSEnumDeclaration' === declaration.type) && declaration.id?.name && exportNames.add(declaration.id.name); continue; } for (let specifier of statement.specifiers ?? []){ if ('type' === specifier.exportKind) continue; let exported = getExportedName(specifier.exported); exported && exportNames.add(exported); } } return Array.from(exportNames); }, collectExportAllModules = (program)=>{ let modules = []; for (let statement of program.body ?? []){ if ('ExportAllDeclaration' !== statement.type || isTypeOnlyExport(statement) || statement.exported) continue; let source = statement.source?.value; 'string' == typeof source && modules.push(source); } return modules; }, getExportNames = async (code, resourcePath)=>(await getExportNamesAndExportAll(code, resourcePath)).exportNames, getExportNamesAndExportAll = async (code, resourcePath)=>{ var code1, resourcePath1; let lang, trackedExportInfo, cacheKey = (code1 = code, lang = (resourcePath1 = resourcePath) ? langFromPath(resourcePath1.replace(/[?#].*$/, '')) : 'inline', `${lang}\0${code1}`), cached = exportInfoCache.get(cacheKey); return cached || (trackedExportInfo = cachePromiseOnReject((async ()=>{ let program = parseProgram(code, resourcePath); return { exportNames: collectProgramExportNames(program), exportAllModules: collectExportAllModules(program) }; })(), ()=>{ exportInfoCache.get(cacheKey) === trackedExportInfo && exportInfoCache.delete(cacheKey); }), setBoundedCacheEntry(exportInfoCache, cacheKey, trackedExportInfo, 2048), trackedExportInfo); }, getRouteModuleAnalysis = async (resourcePath)=>{ let trackedAnalysis, stats = await stat(resourcePath), cached = routeModuleAnalysisCache.get(resourcePath); return cached?.mtimeMs === stats.mtimeMs && cached.size === stats.size ? cached.analysis : (trackedAnalysis = cachePromiseOnReject((async ()=>{ let source = await readFile(resourcePath, 'utf8'), program = parseProgram(source, resourcePath); return { code: source, exports: collectProgramExportNames(program), exportAllModules: collectExportAllModules(program) }; })(), ()=>{ routeModuleAnalysisCache.get(resourcePath)?.analysis === trackedAnalysis && routeModuleAnalysisCache.delete(resourcePath); }), setBoundedCacheEntry(routeModuleAnalysisCache, resourcePath, { mtimeMs: stats.mtimeMs, size: stats.size, analysis: trackedAnalysis }, 2048), trackedAnalysis); }, tryStat = (path)=>statSync(path, { throwIfNoEntry: !1 }) ?? null, PACKAGE_IMPORT_CONDITIONS = new Set([ 'import', 'node' ]), PACKAGE_RESOLUTION_NOT_APPLICABLE = Symbol('package resolution not applicable'), resolveIndexFile = (dirPath)=>{ for (let ext of JS_EXTENSIONS){ let candidate = resolve(dirPath, `index${ext}`), stats = tryStat(candidate); if (stats?.isFile()) return candidate; } return null; }, resolvePathWithExtensions = (basePath)=>{ let stats = tryStat(basePath); if (stats?.isFile()) return basePath; if (stats?.isDirectory()) return resolveIndexFile(basePath); for (let ext of JS_EXTENSIONS){ let candidate = `${basePath}${ext}`, candidateStats = tryStat(candidate); if (candidateStats?.isFile()) return candidate; } return resolveIndexFile(basePath); }, resolvePackageExportTarget = (target)=>{ if (!target) return null; if ('string' == typeof target) return target; if (Array.isArray(target)) { for (let nestedTarget of target){ let resolvedTarget = resolvePackageExportTarget(nestedTarget); if (resolvedTarget) return resolvedTarget; } return null; } for (let [condition, nestedTarget] of Object.entries(target))if ('default' === condition || PACKAGE_IMPORT_CONDITIONS.has(condition)) { let resolvedTarget = resolvePackageExportTarget(nestedTarget); if (resolvedTarget) return resolvedTarget; } return null; }, resolveExportAllModule = (specifier, importerPath)=>{ if (specifier.startsWith('.') || specifier.startsWith('/')) { let resolvedPath = resolvePathWithExtensions(specifier.startsWith('/') ? specifier : resolve(dirname(importerPath), specifier)); if (resolvedPath) return resolvedPath; } let importResolvedPath = ((specifier, importerPath)=>{ let parsedSpecifier = ((specifier)=>{ if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#')) return null; let parts = specifier.split('/'), packageName = specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0], packagePathParts = specifier.startsWith('@') ? parts.slice(2) : parts.slice(1); return { packageName, packageSubpath: packagePathParts.length > 0 ? `./${packagePathParts.join('/')}` : '.' }; })(specifier); if (!parsedSpecifier) return PACKAGE_RESOLUTION_NOT_APPLICABLE; let packageDirectory = ((importerPath, packageName)=>{ let currentDirectory = dirname(importerPath); for(;;){ let packageDirectory = resolve(currentDirectory, 'node_modules', packageName), packageJsonPath = resolve(packageDirectory, 'package.json'); if (tryStat(packageJsonPath)?.isFile()) return packageDirectory; let parentDirectory = dirname(currentDirectory); if (parentDirectory === currentDirectory) return null; currentDirectory = parentDirectory; } })(importerPath, parsedSpecifier.packageName); if (!packageDirectory) return PACKAGE_RESOLUTION_NOT_APPLICABLE; let packageJson = ((packageDirectory)=>{ try { return JSON.parse(readFileSync(resolve(packageDirectory, 'package.json'), 'utf8')); } catch { return null; } })(packageDirectory); return packageJson && (void 0 !== packageJson.exports || packageJson.module || packageJson.main) ? ((packageDirectory, packageSubpath, packageJson)=>{ let exports = packageJson.exports; if (!exports) { let entry = packageJson.module ?? packageJson.main; return entry ? resolvePathWithExtensions(resolve(packageDirectory, entry)) : null; } let resolvedTarget = resolvePackageExportTarget('object' == typeof exports && !Array.isArray(exports) && Object.keys(exports).some((key)=>key.startsWith('.')) ? exports[packageSubpath] : '.' === packageSubpath ? exports : void 0); return resolvedTarget && resolvedTarget.startsWith('./') ? resolvePathWithExtensions(resolve(packageDirectory, resolvedTarget)) : null; })(packageDirectory, parsedSpecifier.packageSubpath, packageJson) : PACKAGE_RESOLUTION_NOT_APPLICABLE; })(specifier, importerPath); if (importResolvedPath !== PACKAGE_RESOLUTION_NOT_APPLICABLE) return importResolvedPath; try { return createRequire(importerPath).resolve(specifier); } catch { return null; } }, createBundlerRouteExportResolver = (resolveModule)=>(specifier, importerPath)=>new Promise((resolvePromise)=>{ resolveModule(dirname(importerPath), specifier, (error, resolved)=>{ resolvePromise(error || !resolved ? null : resolved); }); }), collectClientOnlyStubExportNames = async (code, resourcePath, resolveModule = resolveExportAllModule)=>{ let { exportNames: directExportNames, exportAllModules } = await getExportNamesAndExportAll(code, resourcePath), exportNames = new Set(directExportNames), unresolvedExportAll = new Set(), visitedModules = new Set(), collectExportNamesFromModule = async (modulePath)=>{ if (visitedModules.has(modulePath)) return; visitedModules.add(modulePath); let { exports: moduleExportNames, exportAllModules: moduleExportAll } = await getRouteModuleAnalysis(modulePath); for (let name of moduleExportNames)'default' !== name && exportNames.add(name); for (let nestedSpecifier of moduleExportAll){ let nestedPath = await resolveModule(nestedSpecifier, modulePath); if (!nestedPath) { unresolvedExportAll.add(nestedSpecifier); continue; } await collectExportNamesFromModule(nestedPath); } }; for (let specifier of exportAllModules){ let resolvedPath = await resolveModule(specifier, resourcePath); if (!resolvedPath) { unresolvedExportAll.add(specifier); continue; } await collectExportNamesFromModule(resolvedPath); } if (unresolvedExportAll.size > 0) throw Error(`[${PLUGIN_NAME}] Client-only module uses \`export * from\` with unresolvable specifier(s): ${Array.from(unresolvedExportAll).map((spec)=>`\`${spec}\``).join(', ')}. Please explicitly re-export named bindings in \`${relative(process.cwd(), resourcePath)}\`.`); return exportNames; }, HMR_PATCHABLE_ROUTE_FLAGS = [ 'hasAction', 'hasClientAction', 'hasClientLoader', 'hasClientMiddleware', 'hasErrorBoundary', 'hasLoader' ], HMR_FLAG_EXPORT_NAME = { hasAction: SERVER_EXPORTS.action, hasClientAction: CLIENT_EXPORTS.clientAction, hasClientLoader: CLIENT_EXPORTS.clientLoader, hasClientMiddleware: CLIENT_EXPORTS.clientMiddleware, hasErrorBoundary: CLIENT_EXPORTS.ErrorBoundary, hasLoader: SERVER_EXPORTS.loader }, createRouteClientEntryArtifact = async ({ code, resourcePath, environmentName, isBuild, routeChunkCache, routeChunkConfig, routeId, devHmr })=>{ let isServer = 'node' === environmentName, routeChunkInfo = !isServer && isBuild && shouldAnalyzeRouteChunks(routeChunkConfig, resourcePath, code) ? await detectRouteChunksIfEnabled(routeChunkCache, routeChunkConfig, resourcePath, code) : null; return { code: (({ exportNames, chunkedExports, isServer, resourcePath, routeId, devHmr })=>{ let exports, flags, chunkedExportSet = chunkedExports.length > 0 ? new Set(chunkedExports) : void 0, reexports = exportNames.filter((exp)=>!chunkedExportSet?.has(exp) && (CLIENT_ROUTE_EXPORTS_SET.has(exp) || isServer && SERVER_ONLY_ROUTE_EXPORTS_SET.has(exp))).sort(), target = `${resourcePath}?react-router-route`, reexportCode = `export { ${reexports.join(', ')} } from ${JSON.stringify(target)};`; return !devHmr || isServer || void 0 === routeId ? reexportCode : reexportCode + (({ routeId, target, acceptTarget, flags })=>{ let targetJson = JSON.stringify(target), acceptTargetJson = JSON.stringify(acceptTarget); return ` import * as __rrm from ${targetJson}; import { registerReactRouterRouteExports as __rrr, scheduleReactRouterRouteUpdate as __rru, } from "virtual/react-router/hmr-runtime"; const __rrid = ${JSON.stringify(routeId)}; const __rrf = ${flags}; const __rrg = () => __rrm; const __rru0 = () => { __rrr(__rrid, __rrm); __rru(__rrid, __rrf, __rrg); }; __rrr(__rrid, __rrm); if (import.meta.webpackHot) { const __rrh = import.meta.webpackHot; __rrh.accept(${acceptTargetJson}, __rru0); __rrh.accept(); __rrh.dispose(data => { data.__rr = true; }); if (__rrh.data && __rrh.data.__rr) __rru0(); } `; })({ routeId, target, acceptTarget: `./${basename(resourcePath)}?react-router-route`, flags: (exports = new Set(exportNames), flags = 0, HMR_PATCHABLE_ROUTE_FLAGS.forEach((flag, index)=>{ exports.has(HMR_FLAG_EXPORT_NAME[flag]) && (flags |= 1 << index); }), flags) }); })({ exportNames: routeChunkInfo?.exportNames ?? await getExportNames(code, resourcePath), chunkedExports: routeChunkInfo?.chunkedExports ?? [], isServer, resourcePath, routeId, devHmr: devHmr && !isBuild }) }; }, createRouteChunkArtifact = async ({ code, resource, resourcePath, isBuild, routeChunkCache, routeChunkConfig })=>{ let splitRouteModules = routeChunkConfig.splitRouteModules; if (!isBuild || !splitRouteModules) return { code: 'export {};', map: null }; let chunkName = ((id)=>{ let queryIndex = id.indexOf(routeChunkQueryStringPrefix); if (-1 === queryIndex) return null; let chunkNameStart = queryIndex + routeChunkQueryStringPrefix.length, chunkNameEnd = id.indexOf('&', chunkNameStart), chunkName = id.slice(chunkNameStart, -1 === chunkNameEnd ? void 0 : chunkNameEnd); return 'main' === chunkName || routeChunkExportNames.includes(chunkName) ? chunkName : null; })(resource); if (!chunkName) throw Error(`Invalid route chunk name in "${resource}"`); if ('main' !== chunkName && !code.includes(chunkName)) return { code: 'export {};', map: null }; let chunk = await getRouteChunkIfEnabled(routeChunkCache, routeChunkConfig, resourcePath, chunkName, code); if ('enforce' === splitRouteModules && 'main' === chunkName && chunk) { let exportNameSet, exportNames = await getExportNames(chunk, resourcePath); validateRouteChunks({ config: routeChunkConfig, id: resourcePath, valid: (exportNameSet = new Set(exportNames), createRouteChunkExportMap((exportName)=>!exportNameSet.has(exportName))) }); } return { code: chunk ?? 'export {};', map: null }; }, defaultRouteChunkCache = new Map(), getRouteChunkCache = (options)=>options?.routeChunkCache ?? defaultRouteChunkCache, splitRouteExports = async (task, options)=>{ let { exportNames, hasRouteChunks, chunkedExports } = await detectRouteChunksIfEnabled(getRouteChunkCache(options), task.routeChunkConfig, task.resourcePath, task.code); if (!hasRouteChunks) return { code: task.code, map: null }; let chunkedExportSet = new Set(chunkedExports), mainChunkReexports = exportNames.filter((name)=>!chunkedExportSet.has(name)).join(', '), chunkBasePath = `./${basename(task.resourcePath)}`; return { code: [ mainChunkReexports ? `export { ${mainChunkReexports} } from "${getRouteChunkModuleId(chunkBasePath, 'main')}";` : null, ...chunkedExports.map((exportName)=>`export { ${exportName} } from "${getRouteChunkModuleId(chunkBasePath, exportName)}";`) ].filter(Boolean).join('\n'), map: null }; }, createClientOnlyStub = async (task)=>({ code: Array.from(await collectClientOnlyStubExportNames(task.code, task.resourcePath, task.resolveExportAllModule)).map((name)=>'default' === name ? 'export default undefined;' : `export const ${name} = undefined;`).join('\n'), map: null }), callResolvesToComponent = (node)=>{ let args = node.arguments ?? []; if (0 === args.length) return !1; let callee = node.callee; if (!callee || 'Import' === callee.type) return !1; if ('Identifier' === callee.type) { let calleeName = callee.name ?? ''; if (calleeName.startsWith('require') || calleeName.startsWith('import')) return !1; } else if ('MemberExpression' !== callee.type) return !1; var node1 = args[0]; switch(node1?.type){ case 'FunctionExpression': return !0; case 'ArrowFunctionExpression': return node1.body?.type !== 'ArrowFunctionExpression'; case '