Chapter 2 Β· CORE

Package Classification Strategies

πŸ“„ 02_package_classification_strategies.md 🏷 Core

Chapter 2: Package Classification Strategies

In the previous chapter, we introduced the "Building Inspector"β€”the crawler that scans your project to find dangerous dependencies.

But here is the catch: The Inspector doesn't know what "dangerous" looks like unless you tell it.

By default, Vite assumes every package in node_modules is a standard, pre-compiled JavaScript library. It tries to bundle them immediately to make your dev server fast. If it tries to bundle a "raw" Framework package (like one containing .svelte or .jsx files), the build will fail.

This chapter explains how to teach vitefu to classify packages correctly.

The Analogy: The Recycling Center

Think of your dependency tree as a conveyor belt at a recycling center. Items come down the line, and we need to sort them into three bins:

  1. Raw Materials (Framework Packages):
  1. Sensitive Items (Semi-Framework Packages):
  1. Finished Goods (Standard Libraries):

How to Configure the Strategies

You provide "Strategy Functions" to crawlFrameworkPkgs. These functions inspect a package and return true or false.

There are two ways to inspect a package:

  1. By Name: Fast check (e.g., does it start with plugin-?).
  2. By JSON: Deep check (e.g., does package.json have a svelte field?).

Strategy 1: The "Framework" Package

These are packages that contain raw source code.

By Name (Fast Path): Use this if you have a naming convention.

// crawlFrameworkPkgs options
isFrameworkPkgByName: (pkgName) => {
  // If it starts with 'my-ui-', it's definitely a framework package
  if (pkgName.startsWith('my-ui-')) return true;
  
  // Return undefined to say "I don't know, check the JSON instead"
  return undefined; 
}

By JSON (Deep Path): Use this to check for specific fields in package.json.

// crawlFrameworkPkgs options
isFrameworkPkgByJson: (pkgJson) => {
  // Check if it has a specific keyword
  if (pkgJson.keywords?.includes('my-framework')) return true;

  // Or check if it exports a specific file type
  return !!pkgJson.svelte; 
}

Strategy 2: The "Semi-Framework" Package

These packages are tricky. They look like standard JS, but if you let Node.js load them externally during Server Side Rendering (SSR), they might break because they need Vite's plugin transformation.

Example: A library that imports a framework utility but doesn't have raw components itself.

// crawlFrameworkPkgs options
isSemiFrameworkPkgByJson: (pkgJson) => {
  // If this package depends on our framework, treat it as "Semi"
  const deps = pkgJson.dependencies || {};
  return Object.keys(deps).includes('my-framework-core');
}

Internal Implementation

How does vitefu use your strategies? It acts like a filter pipeline. It tries the "Name" strategy first (because it's fastβ€”no file reading required). If that returns undefined, it reads the package.json and tries the "JSON" strategy.

The Decision Flow

sequenceDiagram participant C as Crawler participant S as Strategy Logic participant V as Vite Config C->>S: Check Package Name alt isFrameworkPkgByName is TRUE S->>V: Mark optimizeDeps.exclude S->>V: Mark ssr.noExternal else isSemiFrameworkPkgByName is TRUE S->>V: Mark ssr.noExternal ONLY else Return UNDEFINED C->>S: Read package.json & Check JSON alt isFrameworkPkgByJson is TRUE S->>V: Mark exclude + noExternal else isSemiFrameworkPkgByJson is TRUE S->>V: Mark noExternal ONLY end end

Code Walkthrough

Let's look at the implementation in src/index.js. This runs for every dependency found.

Step 1: Check by Name

The crawler checks the name first to save file system reads.

// src/index.js (Simplified)
// Inside the loop checking dependencies
const isFrameworkPkg = options.isFrameworkPkgByName?.(dep);
const isSemiFrameworkPkg = options.isSemiFrameworkPkgByName?.(dep);

if (isFrameworkPkg) {
  optimizeDepsExclude.push(dep); // Don't Bundle
  ssrNoExternal.push(dep);       // Process in SSR
} else if (isSemiFrameworkPkg) {
  ssrNoExternal.push(dep);       // Just process in SSR
}

Step 2: Check by JSON

If the name check didn't give a definitive true or false, the crawler reads the file and checks the JSON.

// src/index.js (Simplified)
// If we didn't decide based on name, we read the file:
const depPkgJson = await readJson(depPkgJsonPath);

const isFrameworkPkg = options.isFrameworkPkgByJson?.(depPkgJson);
const isSemiFrameworkPkg = options.isSemiFrameworkPkgByJson?.(depPkgJson);

if (isFrameworkPkg) {
  optimizeDepsExclude.push(dep);
  ssrNoExternal.push(dep);
} else if (isSemiFrameworkPkg) {
  ssrNoExternal.push(dep);
}

What about Standard Libraries?

If a package returns false for both Framework and Semi-Framework checks, it is treated as a Standard Library.

Standard libraries usually don't need any special configuration. However, if a Standard Library is nested inside a Framework Package (e.g., your UI kit uses lodash), Vite needs to know about it.

This specific detection logic determines if that standard library is CommonJS or ESM. We cover that logic in the next chapter.

Summary

In this chapter, we learned:

  1. Framework Packages are raw code. We must exclude them from bundling and keep them noExternal for SSR.
  2. Semi-Framework Packages are intermediate. We keep them noExternal for SSR but don't need to exclude them from bundling.
  3. Strategies allow you to classify packages by Name (fast) or JSON content (accurate).

Now that we have sorted the hazardous materials, how does the crawler decide if a Standard Library needs help? Not all standard libraries are created equal; some are old CommonJS packages that break Vite.

Next Chapter: Optimization Heuristics


Generated by Code IQ