koala73/worldmonitor · error · Error

no initial JS assets referenced by ${dashboardPath} — run: $

Error message

no initial JS assets referenced by ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}

What it means

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.

Solutions

  1. Run BUILD_COMMANDS.dashboard to produce a real production build in distDir and retry
  2. Inspect dist/dashboard.html — confirm it references hashed assets under assets/
  3. 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
  4. Point the script at the correct distDir if it was aimed at the source template or dev output

Example fix

// before: dev HTML referenced by budgets
vite build --mode development  // emits /src/main.ts references
// after
vite build  // emits <script type="module" src="/assets/index-abc123.js">
Defensive patterns

Strategy: validation

Validate before calling

const html = readFileSync(join(distDir, 'dashboard.html'), 'utf8');
if (!/(?:src|href)=["'][^"']+.js(?:[?#][^"']*)?["']/i.test(html)) throw new Error('dashboard.html references no JS assets — run the production build');

Type guard

const referencesJsAssets = (html) => /(?:src|href)=["'][^"']+\.js(?:[?#][^"']*)?["']/i.test(html);

Try / catch

try {
  const assets = initialDashboardAssetNames(distDir);
} catch (e) {
  if (e.message.includes('no initial JS assets')) {
    console.error('Rebuild with the production Vite build before measuring budgets');
    process.exitCode = 1;
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/ac3802469466eb0d. Report an issue: GitHub.

Appendix: source

Thrown at scripts/bundle-budgets.mjs:179

function readDashboardHtml(distDir) {
  const dashboardPath = join(distDir, 'dashboard.html');
  try {
    return { dashboardPath, html: readFileSync(dashboardPath, 'utf8') };
  } catch (error) {
    throw new Error(`cannot read ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}: ${error.message}`);
  }
}

export function initialDashboardAssetNames(distDir) {
  const { dashboardPath, html } = readDashboardHtml(distDir);
  const assets = new Set();
  for (const match of html.matchAll(/(?:src|href)=["']([^"']+\.js(?:[?#][^"']*)?)["']/gi)) {
    const fileName = assetFileNameFromUrl(match[1]);
    if (fileName) assets.add(fileName);
  }
  if (assets.size === 0) {
    throw new Error(`no initial JS assets referenced by ${dashboardPath} — run: ${BUILD_COMMANDS.dashboard}`);
  }
  return [...assets].sort();
}

/**
 * The asset files Vite preloads for the dashboard entry's deferred
 * `import('./App-<hash>.js')`, in preload-list order and including CSS, or
 * null when the entry has no such import (App is then in the initial payload).
 *
 * Vite emits the loader as `P(() => import('./App-x.js')…, __vite__mapDeps([…]))`,
 * where the indices point into one `m.f=[…]` table and the list starts with
 * the imported chunk itself. Anything that breaks that shape throws: a parser
 * that silently measured the wrong list would let the application graph grow
 * unseen.
 */
export function deferredDashboardAppDependencies(distDir) {
  const { dashboardPath, html } = readDashboardHtml(distDir);
  const entryUrl = /<script\b[^>]*\btype=["']module["'][^>]*\bsrc=["']([^"']+\.js(?:[?#][^"']*)?)["']/i

View on GitHub (pinned to 7d06c8633d)