Frontend Development 18 min read

Understanding Vite's Dependency Scanning and Pre‑Bundling Process

Vite improves dev‑server startup and runtime speed by scanning every project HTML file (excluding node_modules) with an esbuild plugin that traverses the module graph, classifies JavaScript, assets, bare imports and framework files, creates virtual modules, and records each bare import’s actual path for pre‑bundling.

Tencent Cloud Developer
Tencent Cloud Developer
Tencent Cloud Developer
Understanding Vite's Dependency Scanning and Pre‑Bundling Process

Vite performs a dependency pre‑bundling step to improve compatibility and performance. The core of this step is a dependency scan that collects all bare imports from the project.

The scan starts by treating every HTML file (excluding node_modules ) as an entry point. Vite uses esbuild with a custom plugin ( esbuildScanPlugin ) to traverse the module graph.

Key parts of the plugin:

import { build } from 'esbuild';
export async function scanImports(config) {
  let entries = await globEntries('**/*.html', config);
  const deps = {};
  const missing = {};
  const plugin = esbuildScanPlugin(config, container, deps, missing, entries);
  await Promise.all(entries.map(entry =>
    build({
      absWorkingDir: process.cwd(),
      write: false,
      entryPoints: [entry],
      bundle: true,
      format: 'esm',
      plugins: [...plugins, plugin],
    })
  ));
  return { deps, missing };
}

During resolution, the plugin distinguishes several module types:

JS modules – handled directly by esbuild.

Non‑JS assets (CSS, images, etc.) – marked as external.

Bare imports – modules whose IDs are not paths. If they resolve to a file inside node_modules , they are recorded in deps and treated as external.

HTML/Vue/Svelte/… files – resolved to a virtual html namespace, then loaded by extracting <script> tags.

HTML loading example:

build.onResolve({ filter: /\.(html|vue|svelte|astro)$/ }, async ({ path, importer }) => {
  const resolved = await resolve(path, importer);
  if (!resolved || resolved.includes('node_modules')) return;
  return { path: resolved, namespace: 'html' };
});

build.onLoad({ filter: /\.(html|vue|svelte|astro)$/, namespace: 'html' }, async ({ path }) => {
  let raw = fs.readFileSync(path, 'utf-8');
  raw = raw.replace(commentRE, '
');
  const scriptRE = isHtml ? scriptModuleRE : scriptRE;
  let js = '';
  let scriptId = 0;
  let match;
  while ((match = scriptRE.exec(raw))) {
    const [, openTag, content] = match;
    const srcMatch = openTag.match(srcRE);
    if (srcMatch) {
      const src = srcMatch[1] || srcMatch[2] || srcMatch[3];
      js += `import ${JSON.stringify(src)}\n`;
    } else if (content.trim()) {
      const key = `${path}?id=${scriptId++}`;
      scripts[key] = { loader, content };
      const virtualModulePath = virtualModulePrefix + key;
      js += `export * from ${virtualModulePath}\n`;
    }
  }
  return { loader: 'js', contents: js };
});

Virtual modules are resolved later:

build.onResolve({ filter: /^virtual-module:.*/ }, ({ path }) => ({
  path: path.replace(virtualModulePrefix, ''),
  namespace: 'script',
}));

build.onLoad({ filter: /.*/, namespace: 'script' }, ({ path }) => scripts[path]);

The final deps object maps each bare import name to its real file path, e.g.:

{
  "vue": "D:/app/vite/node_modules/.pnpm/[email protected]/node_modules/vue/dist/vue.runtime.esm-bundler.js",
  "lodash-es": "D:/app/vite/node_modules/.pnpm/[email protected]/node_modules/lodash-es/lodash.js"
}

This scan determines which dependencies Vite will pre‑bundle, improving dev‑server start‑up time and runtime performance.

JavaScriptHTMLvitedependency scanningesbuildPre‑bundlingvirtual modules
Tencent Cloud Developer
Written by

Tencent Cloud Developer

Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.