{"record":{"id":"ac3802469466eb0d","repo":"koala73/worldmonitor","slug":"no-initial-js-assets-referenced-by-dashboardpath-run-build","errorCode":null,"errorMessage":"no initial JS assets referenced by ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}","messagePattern":"no initial JS assets referenced by (.+?) — run: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/bundle-budgets.mjs","lineNumber":179,"sourceCode":"\nfunction readDashboardHtml(distDir) {\n  const dashboardPath = join(distDir, 'dashboard.html');\n  try {\n    return { dashboardPath, html: readFileSync(dashboardPath, 'utf8') };\n  } catch (error) {\n    throw new Error(`cannot read ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}: ${error.message}`);\n  }\n}\n\nexport function initialDashboardAssetNames(distDir) {\n  const { dashboardPath, html } = readDashboardHtml(distDir);\n  const assets = new Set();\n  for (const match of html.matchAll(/(?:src|href)=[\"']([^\"']+\\.js(?:[?#][^\"']*)?)[\"']/gi)) {\n    const fileName = assetFileNameFromUrl(match[1]);\n    if (fileName) assets.add(fileName);\n  }\n  if (assets.size === 0) {\n    throw new Error(`no initial JS assets referenced by ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}`);\n  }\n  return [...assets].sort();\n}\n\n/**\n * The asset files Vite preloads for the dashboard entry's deferred\n * `import('./App-<hash>.js')`, in preload-list order and including CSS, or\n * null when the entry has no such import (App is then in the initial payload).\n *\n * Vite emits the loader as `P(() => import('./App-x.js')…, __vite__mapDeps([…]))`,\n * where the indices point into one `m.f=[…]` table and the list starts with\n * the imported chunk itself. Anything that breaks that shape throws: a parser\n * that silently measured the wrong list would let the application graph grow\n * unseen.\n */\nexport function deferredDashboardAppDependencies(distDir) {\n  const { dashboardPath, html } = readDashboardHtml(distDir);\n  const entryUrl = /<script\\b[^>]*\\btype=[\"']module[\"'][^>]*\\bsrc=[\"']([^\"']+\\.js(?:[?#][^\"']*)?)[\"']/i","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/bundle-budgets.mjs#L161-L197","documentation":"initialDashboardAssetNames scans dashboard.html for src/href references to .js assets under assets/ to compute initial bundle budgets. If the regex collects zero asset names, it throws, assuming the HTML is not a real Vite production build (which always references at least one JS asset). This prevents measuring an empty/stub HTML and reporting bogus zero-byte budgets.","triggerScenarios":"Calling initialDashboardAssetNames against a dashboard.html that contains no `<script src>`/`<link href>` pointing at assets/*.js — e.g. a dev-mode HTML (scripts served from /src as type=module without hashed asset URLs), a manually authored placeholder HTML, or a Vite config change that stops emitting hashed asset references.","commonSituations":"Budget script accidentally pointed at the dev server HTML or a source template instead of dist; Vite `build` produced only CSS (no JS chunks due to config error); build.config change renamed the assets subdirectory so assetFileNameFromUrl returns null for every match.","solutions":["Run BUILD_COMMANDS.dashboard to produce a real production build in distDir and retry","Inspect dist/dashboard.html — confirm it references hashed assets under assets/","If assets live under a different path, fix assetFileNameFromUrl in scripts/bundle-budgets.mjs or the Vite base/assetsDir config so URLs resolve to asset file names","Point the script at the correct distDir if it was aimed at the source template or dev output"],"exampleFix":"// before: dev HTML referenced by budgets\nvite build --mode development  // emits /src/main.ts references\n// after\nvite build  // emits <script type=\"module\" src=\"/assets/index-abc123.js\">","handlingStrategy":"validation","validationCode":"const html = readFileSync(join(distDir, 'dashboard.html'), 'utf8');\nif (!/(?:src|href)=[\"'][^\"']+.js(?:[?#][^\"']*)?[\"']/i.test(html)) throw new Error('dashboard.html references no JS assets — run the production build');","typeGuard":"const referencesJsAssets = (html) => /(?:src|href)=[\"'][^\"']+\\.js(?:[?#][^\"']*)?[\"']/i.test(html);","tryCatchPattern":"try {\n  const assets = initialDashboardAssetNames(distDir);\n} catch (e) {\n  if (e.message.includes('no initial JS assets')) {\n    console.error('Rebuild with the production Vite build before measuring budgets');\n    process.exitCode = 1;\n  } else throw e;\n}","preventionTips":["Run the production (not dev/development-mode) build before budget checks","Keep asset references under assets/ so hashed URLs are extractable","Don't hand-edit dashboard.html; treat it as build output","CI: generate the build in the same job that runs budget checks"],"tags":["build","vite","regex","empty-result"],"backgroundTag":"empty-result-set","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}