vite build error: Failed to resolve import - Does the file exist after webpack to vite migration
Fixes Vite 'Failed to resolve import ... Does the file exist?' after migrating from webpack. Use when the dev server or build fails on imports webpack used to resolve. Key trigger: the failing specifier is a Node builtin, a webpack alias, or a path webpack resolved leniently.
TL;DR
Identify the failing specifier and give Vite what webpack gave it for free: map webpack aliases into resolve.alias, polyfill or replace Node builtins, and fix extensionless or misspelled paths. Vite resolves strictly, ESM-style, with no implicit Node polyfills. Once the specifier resolves, the build passes.
Failed to resolve import "crypto" from "src/util/hash.js". Does the file exist?Steps
Read the error. It names the exact specifier and the importing file. Classify it: Node builtin (crypto, path, stream, buffer), webpack alias (@/...), or relative path. Expected: you know which of the three buckets you are in.
Node builtin: replace it with a browser-safe alternative, or add a node-polyfills plugin for Vite and retry. Expected: the builtin resolves to the polyfill or is gone from the import graph.
Alias: port each webpack alias into the Vite config:
import { fileURLToPath } from 'node:url'; export default { resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } };Expected: every webpack alias has a Vite equivalent.
Relative path: check the file exists at that exact path with that exact casing. Vite is case-sensitive even where webpack on macOS was not. Expected: the path matches reality character for character.
Run the build again. Expected: build completes with no resolve errors.
Use this when
- Webpack to Vite migration with "Failed to resolve import / Does the file exist" errors
- Imports of Node builtins in browser code
- @ aliases stop working after the move
- The error names a specifier that worked fine under webpack
Not for this skill when
- The specifier is an npm package that is not installed (install it)
- TypeScript path aliases are involved (also check the tsconfig paths and mirror them in Vite)
- Assets 404 at runtime (public directory handling, a different topic)
- The import works in dev but fails in build (Rollup vs esbuild resolution difference; check both)
Variant phrasings
- vite "does the file exist" after webpack migration
- vite build failed to resolve import crypto
- vite resolve alias webpack migration
- vite failed to resolve import node builtin
Why it happens
Webpack 4 auto-polyfilled Node builtins, resolved extensions and aliases leniently, and tolerated case mismatches on case-insensitive filesystems. Vite does native ESM resolution in dev: exact specifiers, no builtin polyfills, case-sensitive, and it only knows the aliases you declare. Code that relied on webpack's leniency breaks at the first strict lookup.
Edge cases
- Leftover
require()calls from webpack-era code: Vite has no require in the browser bundle. Convert them to import. - JSON imports may need the explicit extension depending on setup.
- CSS
@importaliases need separate handling from JS aliases. - An import can pass dev (esbuild resolution) and fail build (Rollup resolution), or the reverse. Verify both.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_37oH4UAesaRCSg3qNwS8cA