@tanstack/router-plugin
Version:
Modern and scalable routing for React applications
1 lines • 4.08 kB
Source Map (JSON)
{"version":3,"file":"webpack-adapter.cjs","names":[],"sources":["../../../../src/core/hmr/webpack-adapter.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport { getHandleRouteUpdateCode } from './handle-route-update'\nimport type { Config } from '../config'\nimport type * as t from '@babel/types'\n\n/**\n * Emits HMR accept code for bundlers with webpack-compatible `module.hot`\n * semantics (classic webpack via `import.meta.webpackHot`, and Rspack).\n *\n * Unlike Vite's `hot.accept((newModule) => {...})` — where the callback receives\n * the freshly re-imported module — webpack re-executes the module factory on\n * accept, so our HMR logic must live at module top level and read the previous\n * `routeId` out of `hot.data`. `hot.dispose` stashes it for the next run, and\n * `hot.accept()` (no callback) enrolls us as a self-accepting boundary.\n *\n * Returns an array of statements that patches route definitions during HMR.\n */\nexport function createWebpackHmrStatement(\n stableRouteOptionKeys: Array<string>,\n opts: {\n targetFramework: Config['target']\n routeId?: string\n },\n): Array<t.Statement> {\n const handleRouteUpdateCode = getHandleRouteUpdateCode(stableRouteOptionKeys)\n const staticRouteIdLiteral =\n typeof opts.routeId === 'string'\n ? JSON.stringify(opts.routeId)\n : 'undefined'\n\n // React-only: route modules aren't React Refresh \"boundaries\" (they export\n // a non-component `Route`), so the bundler's react-refresh runtime won't\n // call `performReactRefresh` for us. We kick it manually after swapping\n // route options so newly-registered component bodies get patched into live\n // fibers.\n //\n // Webpack and Rspack refresh plugins inject `__react_refresh_utils__` via\n // ProvidePlugin. Use it when present instead of importing\n // `react-refresh/runtime`, because Rsbuild apps may use React without the\n // React plugin and therefore may not have that optional dependency installed.\n //\n // Use the same delayed refresh style as Rspack's React Refresh runtime.\n // Route modules and their split component chunks can arrive in separate HMR\n // steps under CI load; a microtask can run before the split chunk registers\n // its new component family, causing the refresh to no-op or remount.\n //\n // For non-React frameworks we skip this entirely.\n const reactRefreshCall =\n opts.targetFramework === 'react'\n ? `\n try {\n const tsrReactRefreshUtils =\n typeof __react_refresh_utils__ !== 'undefined'\n ? __react_refresh_utils__\n : undefined\n const tsrEnqueueUpdate =\n tsrReactRefreshUtils && typeof tsrReactRefreshUtils.enqueueUpdate === 'function'\n ? tsrReactRefreshUtils.enqueueUpdate\n : undefined\n if (tsrEnqueueUpdate) {\n tsrEnqueueUpdate(() => {})\n }\n } catch (_err) { /* noop */ }`\n : ''\n\n return [\n template.statement(\n `\nif (import.meta.webpackHot) {\n const hot = import.meta.webpackHot\n const hotData = hot.data ??= {}\n const routeId = hotData['tsr-route-id'] ?? Route.id ?? (Route.isRoot ? '__root__' : ${staticRouteIdLiteral})\n if (routeId) {\n hotData['tsr-route-id'] = routeId\n }\n const existingRoute =\n typeof window !== 'undefined' && routeId\n ? window.__TSR_ROUTER__?.routesById?.[routeId]\n : undefined\n if (routeId && existingRoute && existingRoute !== Route) {\n (${handleRouteUpdateCode})(routeId, Route)${reactRefreshCall}\n }\n hot.dispose((data) => {\n if (routeId) {\n data['tsr-route-id'] = routeId\n }\n })\n hot.accept()\n}\n`,\n {\n syntacticPlaceholders: true,\n },\n )(),\n ]\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,0BACd,uBACA,MAIoB;CACpB,MAAM,wBAAwB,4BAAA,yBAAyB,sBAAsB;CAC7E,MAAM,uBACJ,OAAO,KAAK,YAAY,WACpB,KAAK,UAAU,KAAK,QAAQ,GAC5B;CAmBN,MAAM,mBACJ,KAAK,oBAAoB,UACrB;;;;;;;;;;;;;qCAcA;AAEN,QAAO,CACL,gBAAS,UACP;;;;wFAIkF,qBAAqB;;;;;;;;;OAStG,sBAAsB,mBAAmB,iBAAiB;;;;;;;;;GAU3D,EACE,uBAAuB,MACxB,CACF,EAAE,CACJ"}