{"version":3,"sources":["../../../src/server/dev/hot-reloader-rspack.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs/promises'\nimport { createHash } from 'crypto'\nimport HotReloaderWebpack from './hot-reloader-webpack'\nimport { BUILT, EntryTypes, getEntries } from './on-demand-entry-handler'\nimport type { __ApiPreviewProps } from '../api-utils'\nimport type { RouteDefinition } from '../route-definitions/route-definition'\nimport type { MultiCompiler } from 'webpack'\nimport { COMPILER_NAMES } from '../../shared/lib/constants'\n\n/**\n * Rspack Persistent Cache Strategy for Next.js Development\n *\n * Rspack's persistent caching differs from Webpack in how it manages module graphs.\n * While Webpack incrementally updates modules, Rspack operates on complete module\n * graph snapshots for cache restoration.\n *\n * Problem:\n * - Next.js dev server starts with no page modules in the initial entry points\n * - When Rspack restores from persistent cache, it finds no modules and purges\n *   the entire module graph\n * - Later page requests find no cached module information, preventing cache reuse\n *\n * Solution:\n * - Track successfully built page entries after each compilation\n * - Restore these entries on dev server restart to maintain module graph continuity\n * - This ensures previously compiled pages can leverage persistent cache for faster builds\n */\nexport default class HotReloaderRspack extends HotReloaderWebpack {\n  private builtEntriesCachePath?: string\n\n  private isClientCacheEnabled = false\n  private isServerCacheEnabled = false\n  private isEdgeServerCacheEnabled = false\n\n  public async afterCompile(multiCompiler: MultiCompiler): Promise<void> {\n    // Always initialize the fallback error watcher for Rspack.\n    // Rspack may restore/retain the previous build's error state, so without this\n    // a page that previously failed to build might not be rebuilt on the next request.\n    await super.buildFallbackError()\n\n    const rspackStartSpan = this.hotReloaderSpan.traceChild(\n      'rspack-after-compile'\n    )\n    await rspackStartSpan.traceAsyncFn(async () => {\n      const hash = createHash('sha1')\n      multiCompiler.compilers.forEach((compiler) => {\n        const cache = compiler.options.cache\n        if (typeof cache === 'object' && 'version' in cache && cache.version) {\n          hash.update(cache.version)\n          if (compiler.name === COMPILER_NAMES.client) {\n            this.isClientCacheEnabled = true\n          } else if (compiler.name === COMPILER_NAMES.server) {\n            this.isServerCacheEnabled = true\n          } else if (compiler.name === COMPILER_NAMES.edgeServer) {\n            this.isEdgeServerCacheEnabled = true\n          }\n        } else {\n          hash.update('-')\n        }\n        return undefined\n      })\n      this.builtEntriesCachePath = path.join(\n        this.distDir,\n        'cache',\n        'rspack',\n        hash.digest('hex').substring(0, 16),\n        'built-entries.json'\n      )\n\n      const hasBuiltEntriesCache = await fs\n        .access(this.builtEntriesCachePath)\n        .then(\n          () => true,\n          () => false\n        )\n      if (hasBuiltEntriesCache) {\n        try {\n          const builtEntries: ReturnType<typeof getEntries> = JSON.parse(\n            (await fs.readFile(this.builtEntriesCachePath, 'utf-8')) || '{}'\n          )\n\n          await Promise.all(\n            Object.keys(builtEntries).map(async (entryKey) => {\n              const entryData = builtEntries[entryKey]\n\n              const isEntry = entryData.type === EntryTypes.ENTRY\n              const isChildEntry = entryData.type === EntryTypes.CHILD_ENTRY\n\n              // Check if the page was removed or disposed and remove it\n              if (isEntry) {\n                const pageExists =\n                  !entryData.dispose &&\n                  (await fs.access(entryData.absolutePagePath).then(\n                    () => true,\n                    () => false\n                  ))\n                if (!pageExists) {\n                  delete builtEntries[entryKey]\n                  return\n                } else if (\n                  !('hash' in builtEntries[entryKey]) ||\n                  builtEntries[entryKey].hash !==\n                    (await calculateFileHash(entryData.absolutePagePath))\n                ) {\n                  delete builtEntries[entryKey]\n                  return\n                }\n              }\n\n              // For child entries, if it has an entry file and it's gone, remove it\n              if (isChildEntry) {\n                if (entryData.absoluteEntryFilePath) {\n                  const pageExists =\n                    !entryData.dispose &&\n                    (await fs.access(entryData.absoluteEntryFilePath).then(\n                      () => true,\n                      () => false\n                    ))\n                  if (!pageExists) {\n                    delete builtEntries[entryKey]\n                    return\n                  } else {\n                    if (\n                      !('hash' in builtEntries[entryKey]) ||\n                      builtEntries[entryKey].hash !==\n                        (await calculateFileHash(\n                          entryData.absoluteEntryFilePath\n                        ))\n                    ) {\n                      delete builtEntries[entryKey]\n                      return\n                    }\n                  }\n                }\n              }\n            })\n          )\n          Object.assign(getEntries(multiCompiler.outputPath), builtEntries)\n        } catch (error) {\n          console.error('Rspack failed to read built entries cache: ', error)\n        }\n      }\n    })\n  }\n\n  public async ensurePage({\n    page,\n    clientOnly,\n    appPaths,\n    definition,\n    isApp,\n    url,\n  }: {\n    page: string\n    clientOnly: boolean\n    appPaths?: ReadonlyArray<string> | null\n    isApp?: boolean\n    definition?: RouteDefinition\n    url?: string\n  }): Promise<void> {\n    await super.ensurePage({\n      page,\n      clientOnly,\n      appPaths,\n      definition,\n      isApp,\n      url,\n    })\n    const entries = getEntries(this.multiCompiler!.outputPath)\n    const builtEntries: { [entryName: string]: any } = {}\n    await Promise.all(\n      Object.keys(entries).map(async (entryName) => {\n        const entry = entries[entryName]\n        if (entry.status !== BUILT) return\n        const result =\n          /^(client|server|edge-server)@(app|pages|root)@(.*)/g.exec(entryName)\n        const [, key /* pageType */, ,] = result! // this match should always happen\n        if (key === 'client' && !this.isClientCacheEnabled) return\n        if (key === 'server' && !this.isServerCacheEnabled) return\n        if (key === 'edge-server' && !this.isEdgeServerCacheEnabled) return\n\n        // TODO: Rspack does not store middleware entries in persistent cache, causing\n        // test/integration/middleware-src/test/index.test.ts to fail. This is a temporary\n        // workaround to skip middleware entry caching until Rspack properly supports it.\n        if (page === '/middleware') {\n          return\n        }\n\n        let hash: string | undefined\n        if (entry.type === EntryTypes.ENTRY) {\n          hash = await calculateFileHash(entry.absolutePagePath)\n        } else if (entry.absoluteEntryFilePath) {\n          hash = await calculateFileHash(entry.absoluteEntryFilePath)\n        }\n        if (!hash) {\n          return\n        }\n\n        builtEntries[entryName] = entry\n        builtEntries[entryName].hash = hash\n      })\n    )\n\n    const hasBuitEntriesCache = await fs\n      .access(this.builtEntriesCachePath!)\n      .then(\n        () => true,\n        () => false\n      )\n    try {\n      if (!hasBuitEntriesCache) {\n        await fs.mkdir(path.dirname(this.builtEntriesCachePath!), {\n          recursive: true,\n        })\n      }\n      await fs.writeFile(\n        this.builtEntriesCachePath!,\n        JSON.stringify(builtEntries, null, 2)\n      )\n    } catch (error) {\n      console.error('Rspack failed to write built entries cache: ', error)\n    }\n  }\n}\n\nasync function calculateFileHash(\n  filePath: string,\n  algorithm: string = 'sha256'\n): Promise<string | undefined> {\n  if (\n    !(await fs.access(filePath).then(\n      () => true,\n      () => false\n    ))\n  ) {\n    return\n  }\n  const fileBuffer = await fs.readFile(filePath)\n  const hash = createHash(algorithm)\n  hash.update(fileBuffer)\n  return hash.digest('hex')\n}\n"],"names":["HotReloaderRspack","HotReloaderWebpack","afterCompile","multiCompiler","buildFallbackError","rspackStartSpan","hotReloaderSpan","traceChild","traceAsyncFn","hash","createHash","compilers","forEach","compiler","cache","options","version","update","name","COMPILER_NAMES","client","isClientCacheEnabled","server","isServerCacheEnabled","edgeServer","isEdgeServerCacheEnabled","undefined","builtEntriesCachePath","path","join","distDir","digest","substring","hasBuiltEntriesCache","fs","access","then","builtEntries","JSON","parse","readFile","Promise","all","Object","keys","map","entryKey","entryData","isEntry","type","EntryTypes","ENTRY","isChildEntry","CHILD_ENTRY","pageExists","dispose","absolutePagePath","calculateFileHash","absoluteEntryFilePath","assign","getEntries","outputPath","error","console","ensurePage","page","clientOnly","appPaths","definition","isApp","url","entries","entryName","entry","status","BUILT","result","exec","key","hasBuitEntriesCache","mkdir","dirname","recursive","writeFile","stringify","filePath","algorithm","fileBuffer"],"mappings":"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","ignoreList":[0]}