Welcome to the Vitefu documentation! If you are building tools for Vite, you might have realized that handling dependencies isn't always straightforward. Some packages are standard JavaScript, while others contain "raw" framework code (like .svelte, .vue, or specific JSX patterns) that Vite needs to handle differently.
Imagine you are a building inspector tasked with checking a massive skyscraper (your project).
lodash). The construction crew (Vite) can handle these quickly and automatically.If the construction crew rushes into a "Hazardous Room" treating it like a normal one, accidents happen (Build Errors!).
The Framework Dependency Crawler is that inspector. It walks through every room (dependency), marks the hazardous ones, and gives Vite a precise list of instructions on which rooms are safe to speed through and which ones need special safety gear.
The core function of this library is crawlFrameworkPkgs. It scans your project and generates configuration options for Vite.
Here is the most basic way to use it:
import { crawlFrameworkPkgs } from 'vitefu';
const config = await crawlFrameworkPkgs({
root: process.cwd(),
isBuild: false, // Are we in 'vite build' or 'vite dev'?
isFrameworkPkgByName: (pkgName) => {
return pkgName.startsWith('my-framework-');
}
});
To perform the inspection, the crawler needs to know what to look for. In the example above, we told it: "If a package name starts with my-framework-, treat it as hazardous/special."
The crawler returns an object with two main sections: optimizeDeps and ssr.
console.log(config);
/* Output:
{
optimizeDeps: {
include: [...], // Deep dependencies that need bundling
exclude: ['my-framework-ui'] // Don't pre-bundle this! It has raw code.
},
ssr: {
noExternal: ['my-framework-ui'], // Process this with Vite plugins!
external: [...]
}
}
*/
Under the hood, the crawler performs a recursive search. It starts at your project's root package.json and looks at your dependencies.
Let's look at the simplified logic inside src/index.js. The engine relies on a recursive function called crawl.
First, the crawler looks at the current package.json. If we are at the root, we check devDependencies too.
// src/index.js (simplified)
async function crawl(pkgJsonPath, pkgJson, parentDepNames = []) {
const isRoot = parentDepNames.length === 0;
// If root, check devDeps. Otherwise, only regular deps.
let deps = [
...Object.keys(pkgJson.dependencies || {}),
...(isRoot ? Object.keys(pkgJson.devDependencies || {}) : [])
];
// ... filtering logic follows
}
This is the brain of the inspector. It decides if a dependency is "special".
// src/index.js (simplified)
deps = deps.filter((dep) => {
const isFramework = options.isFrameworkPkgByName?.(dep);
if (isFramework) {
// It's raw code! Exclude from optimization.
optimizeDepsExclude.push(dep);
// Ensure SSR processes it.
ssrNoExternal.push(dep);
return true; // Keep crawling deeper!
}
return false; // Stop crawling this branch
});
Note: Determining exactly how to identify a framework package is complex. We cover custom logic for this in Package Classification Strategies.
Sometimes, a Framework Library (Hazardous) imports a Standard Library (Safe).
my-framework-ui imports lodash.
Since we excluded my-framework-ui from optimization, Vite might miss lodash. The crawler fixes this by explicitly adding deep dependencies to include.
// src/index.js (simplified)
if (!isRoot && !isFrameworkPkg) {
// If we are deep inside a framework package,
// but found a standard JS package (CJS):
if (await pkgNeedsOptimization(depPkgJson, path)) {
// Tell Vite to bundle this specific nested path
optimizeDepsInclude.push(parentDepNames.concat(dep).join(' > '));
}
}
This ensures that even though the parent is raw code, the standard children are still optimized for performance.
How does the crawler know a standard package needs optimization? It checks if the package is CommonJS (CJS) or has specific entry points.
// src/index.js
export async function pkgNeedsOptimization(pkgJson, pkgJsonPath) {
// If it's modern ESM, usually no need to force optimize
if (pkgJson.module || pkgJson.exports) return false;
// If it has a main file pointing to .js or .cjs
if (pkgJson.main) {
const ext = path.extname(pkgJson.main);
return !ext || ext === '.js' || ext === '.cjs';
}
return false;
}
This heuristic is discussed further in Optimization Heuristics.
In this chapter, we learned:
package.json files.optimizeDeps.exclude (for raw code) and optimizeDeps.include (for standard libs nested inside raw code).
But how exactly do we tell the crawler which packages are "Framework" packages? By name? By a field in package.json?
Next Chapter: Package Classification Strategies
Generated by Code IQ