Token导航 LogoToken导航TokenDH.com
研究检索操作浏览器github未标认证来源可访问许可证需确认审计通过

build-pipelines-bundling构建管道捆绑

Agent Skill

build-pipelines-bundling 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

212

周安装

9

GitHub Stars

34

下载量

74
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:build-pipelines-bundling(构建管道捆绑)
来源仓库:https://github.com/farming-labs/fm-skills
仓库路径:skills/build-pipelines-bundling
安装命令:
npx skills add https://github.com/farming-labs/fm-skills --skill build-pipelines-bundling
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/farming-labs/fm-skills --skill build-pipelines-bundling

简介

用于理解和管理前端构建管道与打包流程,优化浏览器资产交付性能。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中诊断 HTTP 限制、依赖加载和树摇问题。
  • 通过 npx skills add 命令从 GitHub 安装,需结合具体构建工具(如 Webpack、Vite)使用。
  • 注意权限范围和维护状态,避免触发不必要的联网、命令执行或文件写入操作。
  • build-pipelines-bundling 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Build Pipelines and Bundling

Overview

Build pipelines transform your source code into optimized assets for browsers. Understanding this process is essential for performance optimization and debugging.

Why Bundling Exists

Browsers historically couldn't handle modern JavaScript development patterns:

// YOUR CODE: Many small files with imports
// src/
// ├── index.js (imports App)
// ├── App.js (imports Header, Main, Footer)
// ├── Header.js (imports Logo, Nav)
// ├── Nav.js (imports NavLink)
// └── ... 100+ files

// PROBLEM 1: HTTP/1.1 could only load 6 files in parallel
// 100 files = 17 round trips = SLOW

// PROBLEM 2: Browsers didn't support import/export (until ES modules)
import { Component } from './Component.js';  // Didn't work!

// PROBLEM 3: npm packages live in node_modules
import React from 'react';  // Browser can't resolve this path!

// SOLUTION: Bundle everything into fewer files
// dist/
// ├── index.html
// ├── main.js (all your code + dependencies)
// └── main.css

The Build Pipeline

SOURCE CODE                    BUILD PIPELINE                      OUTPUT
─────────────────────────────────────────────────────────────────────────────

src/                                                               dist/
├── index.tsx     ───┐                                        ┌─► index.html
├── App.tsx          │    ┌──────────────────────────────┐    │
├── components/      ├───►│  1. Resolve imports          │    ├─► main.[hash].js
│   ├── Header.tsx   │    │  2. Transform (TS, JSX, etc) │    │
│   └── Button.tsx   │    │  3. Bundle modules           │───►├─► vendor.[hash].js
├── styles/          │    │  4. Optimize (minify, etc)   │    │
│   └── main.css     │    │  5. Output files             │    ├─► main.[hash].css
└── assets/          │    └──────────────────────────────┘    │
    └── logo.png ────┘                                        └─► assets/logo.[hash].png

Bundler Comparison

BundlerSpeedConfigurationBest For
WebpackSlowerComplex, powerfulLarge apps, legacy
ViteFast (dev)MinimalModern apps, DX
esbuildFastestLimitedBuild step, library
RollupMediumPlugin-focusedLibraries
ParcelFastZero-configQuick prototypes
TurbopackFastWebpack-compatibleNext.js

Core Bundling Concepts

Module Resolution

How bundlers find your imports:

// Relative imports - resolved from current file
import { Button } from './components/Button';
// → src/components/Button.js

// Bare imports - resolved from node_modules
import React from 'react';
// → node_modules/react/index.js

// Alias imports - resolved via config
import { api } from '@/lib/api';
// → src/lib/api.js (@ mapped to src/)

// RESOLUTION ORDER (Node-style):
// 1. Exact path: ./Button.js
// 2. Add extensions: ./Button → ./Button.js, ./Button.ts, ./Button.tsx
// 3. Index files: ./Button → ./Button/index.js
// 4. Package.json "main" or "exports" field

Dependency Graph

Bundlers build a graph of all dependencies:

Entry: src/index.tsx
         │
         ▼
    ┌─────────┐
    │ index   │
    └────┬────┘
         │ imports
         ▼
    ┌─────────┐     ┌─────────┐
    │   App   │────►│  React  │
    └────┬────┘     └─────────┘
         │ imports
    ┌────┴────┐
    ▼         ▼
┌────────┐ ┌────────┐
│ Header │ │ Footer │
└───┬────┘ └────────┘
    │ imports
    ▼
┌─────────┐
│  Logo   │
└─────────┘

// Bundler walks this graph:
// 1. Start at entry point
// 2. Parse file, find imports
// 3. Recursively process each import
// 4. Build complete dependency graph
// 5. Output bundle in correct order

Code Splitting

Breaking your bundle into smaller pieces loaded on demand.

Why Code Split?

WITHOUT CODE SPLITTING:
┌─────────────────────────────────────────┐
│              main.js (2MB)              │
│  ┌─────┐ ┌─────┐ ┌─────┐ ┌───────────┐ │
│  │Home │ │About│ │Blog │ │ Dashboard │ │
│  └─────┘ └─────┘ └─────┘ └───────────┘ │
└─────────────────────────────────────────┘
User visits /home → Downloads 2MB (includes unused Dashboard code)

WITH CODE SPLITTING:
┌──────────────┐
│ main.js (50KB)│ ← Core app, router
└──────────────┘
     │
     ├─► home.js (30KB)      ← Loaded on /home
     ├─► about.js (20KB)     ← Loaded on /about
     ├─► blog.js (40KB)      ← Loaded on /blog
     └─► dashboard.js (500KB) ← Loaded only on /dashboard

User visits /home → Downloads 80KB (main + home)

Split Strategies

1. Route-Based Splitting

// React with lazy loading
import { lazy, Suspense } from 'react';

// Each route becomes a separate chunk
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/dashboard" element={<Dashboard />} />
      </Routes>
    </Suspense>
  );
}

// Build output:
// main.js - core app
// pages-Home-[hash].js - home chunk
// pages-About-[hash].js - about chunk
// pages-Dashboard-[hash].js - dashboard chunk

2. Component-Based Splitting

// Heavy components loaded on demand
const HeavyChart = lazy(() => import('./components/HeavyChart'));
const MarkdownEditor = lazy(() => import('./components/MarkdownEditor'));

function Dashboard() {
  const [showChart, setShowChart] = useState(false);

  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>

      {showChart && (
        <Suspense fallback={<ChartSkeleton />}>
          <HeavyChart />  {/* Loaded only when needed */}
        </Suspense>
      )}
    </div>
  );
}

3. Vendor Splitting

// Webpack config
optimization: {
  splitChunks: {
    cacheGroups: {
      // Separate node_modules into vendor chunk
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all',
      },
      // Separate large libraries
      react: {
        test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
        name: 'react',
        chunks: 'all',
      },
    },
  },
}

// Output:
// main.js - your code
// vendors.js - all node_modules
// react.js - react + react-dom (cached separately)

Chunking Strategies

Chunk Types

ENTRY CHUNKS:
- Starting points of your application
- Usually one per "page" or entry point

ASYNC CHUNKS:
- Created by dynamic imports: import('./module')
- Loaded on demand

COMMON/SHARED CHUNKS:
- Code used by multiple chunks
- Extracted to avoid duplication

VENDOR CHUNKS:
- Third-party code from node_modules
- Changes less frequently = better caching

Optimal Chunking

// Webpack splitChunks configuration
optimization: {
  splitChunks: {
    chunks: 'all',
    minSize: 20000,        // Minimum chunk size (20KB)
    maxSize: 244000,       // Try to keep under 244KB
    minChunks: 1,          // Minimum times a module is shared
    maxAsyncRequests: 30,  // Max parallel requests for async chunks

    cacheGroups: {
      defaultVendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10,
        reuseExistingChunk: true,
      },
      default: {
        minChunks: 2,      // Split if used 2+ times
        priority: -20,
        reuseExistingChunk: true,
      },
    },
  },
}

Tree Shaking

Removing unused code from the bundle.

How It Works

// utils.js - exports multiple functions
export function usedFunction() {
  return 'I am used';
}

export function unusedFunction() {
  return 'I am never imported anywhere';
}

export const USED_CONSTANT = 42;
export const UNUSED_CONSTANT = 999;

// app.js - only imports some exports
import { usedFunction, USED_CONSTANT } from './utils';

console.log(usedFunction(), USED_CONSTANT);

// AFTER TREE SHAKING:
// Bundle only contains usedFunction and USED_CONSTANT
// unusedFunction and UNUSED_CONSTANT are removed

Requirements for Tree Shaking

// ✓ WORKS: ES modules (static structure)
import { specific } from 'library';
export function myFunction() {}

// ✗ DOESN'T WORK: CommonJS (dynamic structure)
const library = require('library');
module.exports = myFunction;

// ✗ DOESN'T WORK: Dynamic imports of specific exports
const { specific } = await import('library');  // Can tree shake the import
// But the library must use ES modules internally

// SIDE EFFECTS: Code that runs on import
// package.json
{
  "sideEffects": false  // All files are pure, safe to tree shake
}

// Or specify which files have side effects:
{
  "sideEffects": [
    "*.css",           // CSS imports have side effects
    "./src/polyfills.js"  // This file runs code on import
  ]
}

Minification

Reducing code size without changing behavior.

Techniques

// ORIGINAL CODE:
function calculateTotalPrice(items) {
  let totalPrice = 0;
  for (let i = 0; i < items.length; i++) {
    totalPrice += items[i].price * items[i].quantity;
  }
  return totalPrice;
}

// AFTER MINIFICATION:
function calculateTotalPrice(e){let t=0;for(let l=0;l<e.length;l++)t+=e[l].price*e[l].quantity;return t}

// TECHNIQUES APPLIED:
// 1. Whitespace removal
// 2. Variable name shortening (mangling)
// 3. Dead code elimination
// 4. Constant folding: 1 + 2 → 3
// 5. Boolean simplification: !!x → x (in boolean context)

Minifiers

ToolSpeedCompressionUse Case
TerserSlowBestProduction builds
esbuildFastestGoodDevelopment, fast builds
SWCVery fastGoodNext.js, Rust-based
UglifyJSSlowGoodLegacy projects

Source Maps

Mapping minified code back to source for debugging.

// MINIFIED CODE (main.js):
function a(e){throw new Error("Invalid: "+e)}

// SOURCE MAP (main.js.map):
{
  "version": 3,
  "sources": ["src/validation.ts"],
  "names": ["throwValidationError", "message"],
  "mappings": "AAAA,SAASA,EAAoBC..."
}

// BROWSER DEVTOOLS:
// Shows original source with meaningful names:
function throwValidationError(message) {
  throw new Error("Invalid: " + message);
}
// With correct line numbers!

Source Map Types

// Webpack devtool options:

// Development:
devtool: 'eval-source-map'      // Fast rebuild, full source maps
devtool: 'eval-cheap-source-map' // Faster, line-only mapping

// Production:
devtool: 'source-map'           // Full source maps (separate file)
devtool: 'hidden-source-map'    // Source maps generated but not linked
devtool: false                  // No source maps

Asset Handling

Processing non-JavaScript assets.

Images

// Webpack (with asset modules)
{
  test: /\.(png|jpg|gif|svg)$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 8 * 1024  // Inline if < 8KB
    }
  }
}

// Vite (automatic)
import logo from './logo.png';  // Returns URL
import icon from './icon.svg?raw';  // Returns SVG content

// Output:
// Small images → Inlined as data URLs
// Large images → Copied to dist with hash

CSS

// CSS Processing Pipeline:
// 1. PostCSS (autoprefixer, future CSS)
// 2. CSS Modules (scoped class names)
// 3. Minification (cssnano)
// 4. Extraction (separate .css files)

// Vite handles this automatically
import styles from './Button.module.css';

function Button() {
  return <button className={styles.button}>Click</button>;
}

// Output:
// .button → .Button_button_x7h3j (scoped)

Content Hashing

Cache busting with content-based filenames.

// WITHOUT HASHING:
// main.js - browser caches indefinitely
// Update code → browser still uses old cached version!

// WITH CONTENT HASHING:
// main.a1b2c3d4.js - hash based on content
// Update code → new hash → new filename → browser fetches new version

// Webpack configuration:
output: {
  filename: '[name].[contenthash].js',
  chunkFilename: '[name].[contenthash].chunk.js',
}

// Benefits:
// - Unchanged files keep same hash = cached
// - Changed files get new hash = fresh download
// - Long cache headers possible (immutable)

Build Performance Optimization

Caching

// Webpack persistent caching
cache: {
  type: 'filesystem',
  buildDependencies: {
    config: [__filename],  // Invalidate on config change
  },
}

// First build: 30 seconds
// Subsequent builds: 5 seconds (cache hit)

Parallelization

// Webpack thread-loader for expensive loaders
{
  test: /\.tsx?$/,
  use: [
    'thread-loader',  // Run in worker pool
    'babel-loader',
  ],
}

// esbuild/SWC are parallel by default (Rust/Go)

Excluding node_modules

// Don't transform node_modules (already compiled)
{
  test: /\.js$/,
  exclude: /node_modules/,
  use: 'babel-loader',
}

Build Analysis

Understanding your bundle contents.

# Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer

# Add to webpack config:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

plugins: [
  new BundleAnalyzerPlugin()
]

# Generates interactive treemap of bundle contents
# source-map-explorer
npx source-map-explorer dist/main.js

# Vite
npx vite-bundle-visualizer

Deep Dive: Understanding Bundling From First Principles

What Bundlers Actually Do: Step by Step

Let's trace through exactly what happens when you run npm run build:

// YOUR SOURCE FILES:

// src/index.js
import { greet } from './utils.js';
import React from 'react';
console.log(greet('World'));

// src/utils.js
export function greet(name) {
  return `Hello, ${name}!`;
}
export function unused() {
  return 'Never called';
}

Step 1: Parse Entry Point

// Bundler parses index.js into AST (Abstract Syntax Tree)
{
  type: 'Program',
  body: [
    {
      type: 'ImportDeclaration',
      source: { value: './utils.js' },
      specifiers: [{ imported: { name: 'greet' } }]
    },
    {
      type: 'ImportDeclaration',
      source: { value: 'react' },
      specifiers: [{ imported: { name: 'default' }, local: { name: 'React' } }]
    },
    // ... rest of AST
  ]
}

Step 2: Resolve Dependencies

// For each import, resolve to actual file path

// './utils.js'
// → Current dir: /project/src/
// → Resolved: /project/src/utils.js ✓

// 'react'
// → Not relative, check node_modules
// → /project/node_modules/react/package.json
// → "main": "index.js"
// → Resolved: /project/node_modules/react/index.js ✓

Step 3: Build Dependency Graph

// Graph structure (simplified)
const graph = {
  '/project/src/index.js': {
    dependencies: [
      '/project/src/utils.js',
      '/project/node_modules/react/index.js'
    ],
    code: '...',
    exports: [],
    imports: ['greet', 'React']
  },
  '/project/src/utils.js': {
    dependencies: [],
    code: '...',
    exports: ['greet', 'unused'],
    imports: []
  },
  // ... react and its dependencies
};

Step 4: Transform Code

// Each file goes through loaders/plugins

// TypeScript → JavaScript
// TSX/JSX → React.createElement calls
// Modern JS → Compatible JS (Babel)

// Input (TSX):
const Button: React.FC = () => <button>Click</button>;

// Output (JS):
const Button = () => React.createElement("button", null, "Click");

Step 5: Tree Shake

// Analyze what's actually used

// utils.js exports: ['greet', 'unused']
// index.js imports from utils: ['greet']
//
// 'unused' is never imported anywhere
// Mark for removal

// After tree shaking, only 'greet' is included

Step 6: Concatenate Modules

// Combine all modules into bundle format

// IIFE wrapper (Immediately Invoked Function Expression)
(function(modules) {
  // Module cache
  var installedModules = {};

  // Module loader
  function __webpack_require__(moduleId) {
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    var module = installedModules[moduleId] = { exports: {} };
    modules[moduleId](module, module.exports, __webpack_require__);
    return module.exports;
  }

  // Start at entry point
  return __webpack_require__('./src/index.js');
})({
  './src/index.js': function(module, exports, __webpack_require__) {
    var utils = __webpack_require__('./src/utils.js');
    var React = __webpack_require__('react');
    console.log(utils.greet('World'));
  },
  './src/utils.js': function(module, exports) {
    exports.greet = function(name) {
      return 'Hello, ' + name + '!';
    };
    // Note: unused() is gone!
  },
  // ... react modules
});

Step 7: Minify

// Terser/esbuild minification

// Before:
function greet(name) {
  return 'Hello, ' + name + '!';
}

// After:
function greet(n){return"Hello, "+n+"!"}

// Or with further optimization:
const greet=n=>"Hello, "+n+"!";

Step 8: Output with Hashing

dist/
├── index.html
├── main.7f8a2b3c.js      ← Hash based on content
├── main.7f8a2b3c.js.map  ← Source map
└── index.html            ← References hashed files

Module Formats: A History Lesson

Understanding why we have multiple module systems:

// 1. NO MODULES (Pre-2009)
// Everything in global scope
// script.js
var myApp = {};
myApp.utils = {
  greet: function(name) { return 'Hello, ' + name; }
};

// Problem: Global namespace pollution, dependency order matters

// 2. COMMONJS (2009, Node.js)
// Synchronous, designed for servers
// utils.js
module.exports.greet = function(name) { return 'Hello, ' + name; };

// index.js
const { greet } = require('./utils');

// Problem: Synchronous require() doesn't work in browsers

// 3. AMD - Asynchronous Module Definition (2011, RequireJS)
// Async loading for browsers
define(['./utils'], function(utils) {
  console.log(utils.greet('World'));
});

// Problem: Verbose, non-standard

// 4. UMD - Universal Module Definition (2014)
// Works everywhere (browser global, CommonJS, AMD)
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['dep'], factory);  // AMD
  } else if (typeof module === 'object') {
    module.exports = factory(require('dep'));  // CommonJS
  } else {
    root.myLib = factory(root.dep);  // Browser global
  }
}(this, function(dep) {
  return { greet: function(name) { return 'Hello, ' + name; } };
}));

// Problem: Complex wrapper for every file

// 5. ES MODULES (2015, ES6)
// Official JavaScript standard
// Static structure enables tree shaking
export function greet(name) { return 'Hello, ' + name; }
import { greet } from './utils.js';

// Now supported natively in browsers and Node.js!

Why Vite is Fast: Native ES Modules

Traditional bundlers (Webpack) vs Vite approach:

WEBPACK DEVELOPMENT:

Your Code                   Webpack                    Browser
────────────────────────────────────────────────────────────────
  src/
  ├── index.js  ─┐
  ├── App.js     ├─► Bundle ALL ─► bundle.js ─────► Load bundle
  ├── Header.js  │    files
  └── 100+ more ─┘    together

Time: Parse + transform + bundle ALL files = 10-30 seconds
Change 1 file → Rebundle everything = 2-5 seconds

VITE DEVELOPMENT:

Your Code                     Vite                     Browser
────────────────────────────────────────────────────────────────
  src/
  ├── index.js  ──────────────────────────────────► Request each
  ├── App.js    ─► Transform ─► Serve directly ──► file when needed
  ├── Header.js   on demand                        via native ES
  └── 100+ more ─► (only if requested)             module imports

Time: Transform only requested files = 300-500ms
Change 1 file → Transform only that file = <100ms

WHY THIS WORKS:

<!-- Browser requests via native ES modules -->
<script type="module" src="/src/index.js"></script>

// index.js (served directly, not bundled)
import { App } from './App.js';  // Browser makes another request

// Browser's network tab:
// GET /src/index.js
// GET /src/App.js      (from import in index.js)
// GET /src/Header.js   (from import in App.js)
// ...

Dynamic Imports: How Code Splitting Works

The magic behind import():

// STATIC IMPORT (resolved at build time)
import { heavy } from './heavy.js';
// Always included in main bundle

// DYNAMIC IMPORT (resolved at runtime)
const heavy = await import('./heavy.js');
// Creates a separate chunk, loaded on demand

What the bundler does:

// Your code:
button.onclick = async () => {
  const { HeavyComponent } = await import('./HeavyComponent.js');
  render(HeavyComponent);
};

// Bundler output:

// main.js
button.onclick = async () => {
  const { HeavyComponent } = await __webpack_require__.e("HeavyComponent")
    .then(__webpack_require__.bind(__webpack_require__, "./HeavyComponent.js"));
  render(HeavyComponent);
};

// HeavyComponent.a1b2c3.chunk.js (separate file)
(self["webpackChunk"] = self["webpackChunk"] || []).push([
  ["HeavyComponent"],
  {
    "./HeavyComponent.js": (module, exports) => {
      exports.HeavyComponent = function() { /* ... */ };
    }
  }
]);

// At runtime:
// 1. User clicks button
// 2. __webpack_require__.e creates <script> tag
// 3. Browser fetches HeavyComponent.a1b2c3.chunk.js
// 4. Script executes and registers module
// 5. Promise resolves with exports
// 6. Component renders

Magic Comments: Controlling Chunk Behavior

// Name the chunk (for debugging/analysis)
const Admin = () => import(/* webpackChunkName: "admin" */ './Admin');
// Output: admin.a1b2c3.js

// Prefetch (load in background after main content)
const Settings = () => import(/* webpackPrefetch: true */ './Settings');
// Adds: <link rel="prefetch" href="settings.chunk.js">

// Preload (load immediately, needed soon)
const Critical = () => import(/* webpackPreload: true */ './Critical');
// Adds: <link rel="preload" href="critical.chunk.js">

// Control loading mode
const Lib = () => import(/* webpackMode: "lazy-once" */ `./lib/${name}`);
// Modes: lazy (default), lazy-once, eager, weak

Tree Shaking Deep Dive: Static Analysis

Why ES modules can be tree shaken but CommonJS cannot:

// ES MODULES - STATIC STRUCTURE
// Imports/exports are determined at parse time (before execution)

import { a, b } from './utils';  // ALWAYS imports a and b
export { x, y };                  // ALWAYS exports x and y

// The bundler can statically analyze:
// "This file exports x and y"
// "This file imports a and b"
// No code execution needed!

// COMMONJS - DYNAMIC STRUCTURE
// Imports/exports determined at runtime

const utils = require('./utils');    // What does this export? Depends on runtime
module.exports = something;          // What is 'something'? Depends on runtime

// Examples that break static analysis:
if (condition) {
  module.exports = optionA;
} else {
  module.exports = optionB;
}

const name = 'foo';
module.exports[name] = value;  // Dynamic property

require('./' + dynamicPath);   // Path not known until runtime

The side effects problem:

// utils.js
console.log('Utils loaded!');  // SIDE EFFECT - runs on import

export function used() { return 'used'; }
export function unused() { return 'unused'; }

// Even if 'unused' is never called, we import the file
// The console.log runs!
// Bundler can't remove the file entirely

// SOLUTION: Mark as side-effect free
// package.json
{
  "sideEffects": false
}
// Now bundler knows: if no exports are used, skip the entire file

Scope Hoisting: Module Concatenation

Modern bundlers can merge modules for smaller bundles:

// WITHOUT SCOPE HOISTING:
// Each module wrapped in function

(function(modules) {
  function __require__(id) { /* ... */ }

  // Module 0
  (function(module, exports, __require__) {
    var utils = __require__(1);
    console.log(utils.greet('World'));
  });

  // Module 1
  (function(module, exports) {
    exports.greet = function(name) { return 'Hello, ' + name; };
  });
})();

// WITH SCOPE HOISTING (Module Concatenation):
// Modules merged into one scope

(function() {
  // From utils.js (inlined)
  function greet(name) { return 'Hello, ' + name; }

  // From index.js
  console.log(greet('World'));
})();

// Benefits:
// - Smaller bundle (no module wrappers)
// - Faster execution (no function call overhead)
// - Better minification (variables can be renamed together)

Chunk Splitting Algorithms

How bundlers decide what goes in which chunk:

// WEBPACK'S SPLITCHUNKS ALGORITHM (Simplified)

// For each module, track:
// - Which chunks include it
// - Size of the module
// - Whether it's from node_modules

// Decision process:
for (module of allModules) {
  const chunks = module.usedInChunks;

  // Rule 1: Shared by multiple chunks?
  if (chunks.length >= minChunks) {
    // Candidate for extraction

    // Rule 2: Big enough to be worth a separate request?
    if (module.size >= minSize) {

      // Rule 3: Won't create too many parallel requests?
      if (currentAsyncRequests < maxAsyncRequests) {

        // Extract to common chunk!
        createCommonChunk(module);
      }
    }
  }
}

// RESULT:
// Shared code in common chunks
// Route-specific code in route chunks
// Vendor code in vendor chunks
// Balance between: cache efficiency vs request count

Long-Term Caching Strategy

Optimal caching requires careful chunk design:

// PROBLEM: Any change invalidates entire bundle
// main.js contains: app code + vendor code
// Change 1 line of app code → new hash → users re-download everything

// SOLUTION: Separate by change frequency

// 1. Runtime chunk (tiny, rarely changes)
output: {
  filename: '[name].[contenthash].js',
},
optimization: {
  runtimeChunk: 'single',  // Webpack runtime in separate file
}

// 2. Vendor chunk (medium, changes on npm update)
optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all',
      },
    },
  },
}

// 3. App chunks (changes frequently)
// Default behavior - your code

// RESULT:
// runtime.a1b1b1.js (1KB)   - Almost never changes
// vendors.c2c2c2.js (200KB) - Changes on npm update
// main.d3d3d3.js (50KB)     - Changes on each deploy
// page-home.e4e4e4.js (10KB) - Changes when home page changes

// User has cached vendors.js
// You deploy change to home page
// User only downloads: main.js + page-home.js (60KB vs 260KB)

Build Performance: What Makes Builds Slow?

SLOW OPERATIONS (in order of cost):

1. TYPESCRIPT COMPILATION
   - Type checking is expensive
   - Solution: Use transpileOnly, run tsc separately

2. BABEL TRANSFORMS
   - Parsing + transforming every file
   - Solution: Exclude node_modules, cache results

3. MINIFICATION
   - Complex AST analysis
   - Solution: Use esbuild/SWC instead of Terser

4. SOURCE MAP GENERATION
   - Creating mapping data
   - Solution: Use simpler source map types in dev

5. LARGE DEPENDENCIES
   - Parsing huge node_modules
   - Solution: Externalize, use pre-bundled versions

OPTIMIZATION CHECKLIST:

□ Enable persistent caching (cache: { type: 'filesystem' })
□ Exclude node_modules from babel/typescript
□ Use thread-loader for parallel processing
□ Use esbuild for minification
□ Use 'eval-source-map' in development
□ Analyze bundle to find unexpected large dependencies

The Future: VoidZero and the Unified Rust Toolchain

The Fragmentation Problem

Today's JavaScript tooling is fragmented across many tools:

CURRENT STATE (2024):

Parsing:      Babel, TypeScript, SWC, esbuild (each has own parser)
Transforming: Babel, SWC, esbuild, TypeScript (duplicated work)
Bundling:     Webpack, Rollup, esbuild, Parcel (different algorithms)
Minifying:    Terser, esbuild, SWC (yet more parsers)
Linting:      ESLint (slow, JavaScript-based)
Formatting:   Prettier (slow, JavaScript-based)
Type Check:   TypeScript (can't be parallelized easily)

PROBLEMS:
1. Each tool parses your code separately = redundant work
2. Different tools have different bugs/behaviors
3. JavaScript tools are inherently slow (single-threaded, interpreted)
4. Configuration complexity across many tools
5. Inconsistent error messages and source locations

VoidZero's Vision

VoidZero, founded by Evan You (creator of Vue.js and Vite), is building a unified JavaScript toolchain in Rust:

VOIDZERO UNIFIED TOOLCHAIN:

                    ┌─────────────────────────────────────────┐
                    │              OXC (Core)                  │
                    │  Rust-based JavaScript/TypeScript        │
                    │  Parser, Linter, Transformer, Resolver   │
                    └─────────────────┬───────────────────────┘
                                      │
              ┌───────────────────────┼───────────────────────┐
              │                       │                       │
              ▼                       ▼                       ▼
    ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
    │    Rolldown     │    │   oxc-linter    │    │  oxc-transform  │
    │  (Bundler)      │    │   (ESLint alt)  │    │  (Babel alt)    │
    └────────┬────────┘    └─────────────────┘    └─────────────────┘
             │
             ▼
    ┌─────────────────┐
    │      Vite       │
    │ (Dev + Build)   │
    └─────────────────┘

SHARED BENEFITS:
- Single parser for all operations
- Consistent AST representation
- Native speed (Rust, parallelized)
- Unified configuration
- Coherent error messages

Oxc (Oxidation Compiler)

Oxc is a collection of high-performance JavaScript/TypeScript tools written in Rust:

OXC COMPONENTS:

┌─────────────────────────────────────────────────────────────────┐
│                         oxc_parser                               │
│  - Parses JavaScript, TypeScript, JSX, TSX                      │
│  - 3x faster than SWC, 5x faster than Babel                     │
│  - Produces identical AST for all downstream tools              │
└─────────────────────────────────────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│  oxc_linter   │    │ oxc_transformer│   │  oxc_minifier │
│               │    │                │    │               │
│ 50-100x faster│    │ TypeScript →JS │    │ Compresses    │
│ than ESLint   │    │ JSX → JS       │    │ output code   │
│               │    │ Modern → Legacy│    │               │
└───────────────┘    └───────────────┘    └───────────────┘

┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│ oxc_resolver  │    │ oxc_sourcemap │    │ oxc_prettier  │
│               │    │               │    │  (planned)    │
│ Module        │    │ Source map    │    │               │
│ resolution    │    │ generation    │    │ Code          │
│               │    │               │    │ formatting    │
└───────────────┘    └───────────────┘    └───────────────┘

Performance comparison:

PARSING BENCHMARK (large codebase):

Tool          Time        Relative
────────────────────────────────────
oxc_parser    45ms        1.0x (baseline)
swc_parser    150ms       3.3x slower
esbuild       180ms       4.0x slower
babel         900ms       20x slower
typescript    1200ms      26x slower

LINTING BENCHMARK (ESLint rules):

Tool          Time
────────────────────────────────────
oxc_linter    0.5s
ESLint        50s         (100x slower)

WHY SO FAST?
1. Rust: No garbage collection pauses
2. Parallelization: Uses all CPU cores
3. Zero-copy parsing: Minimal memory allocation
4. SIMD: CPU vectorization for string operations
5. Single pass: Parse once, analyze everything

Rolldown: The Rollup Replacement

Rolldown is a Rust-based bundler designed as a drop-in Rollup replacement:

ROLLDOWN VS ROLLUP:

┌─────────────────────────────────────────────────────────────────┐
│                           ROLLUP                                 │
│                                                                  │
│  Language:     JavaScript                                        │
│  Speed:        Medium (single-threaded JS)                       │
│  Plugins:      Rich ecosystem (established)                      │
│  Output:       Excellent tree-shaking and code quality          │
│  Use case:     Libraries, ES module output                       │
│                                                                  │
│  LIMITATIONS:                                                    │
│  - Can't parallelize (JavaScript)                                │
│  - Large projects = slow builds                                  │
│  - Memory-intensive for big codebases                           │
└─────────────────────────────────────────────────────────────────┘

                              │
                              ▼

┌─────────────────────────────────────────────────────────────────┐
│                          ROLLDOWN                                │
│                                                                  │
│  Language:     Rust                                              │
│  Speed:        10-30x faster than Rollup                        │
│  Plugins:      Rollup-compatible (most plugins work)            │
│  Output:       Same quality as Rollup                           │
│  Use case:     Applications + Libraries                          │
│                                                                  │
│  ADVANTAGES:                                                     │
│  - Fully parallelized (Rust + Rayon)                            │
│  - Built on Oxc (shared parser/resolver)                        │
│  - esbuild-level speed with Rollup-quality output               │
│  - Native code splitting                                         │
│  - Built-in transforms (no separate Babel needed)               │
└─────────────────────────────────────────────────────────────────┘

Rolldown architecture:

┌─────────────────────────────────────────────────────────────────┐
│                      Rolldown Build Pipeline                     │
└─────────────────────────────────────────────────────────────────┘

Entry Points
     │
     ▼
┌─────────────────┐
│   oxc_resolver  │ ← Resolve all imports (parallelized)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   oxc_parser    │ ← Parse all files (parallelized)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ oxc_transformer │ ← Transform TS/JSX (parallelized)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Link & Bundle  │ ← Scope hoisting, tree shaking
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  oxc_minifier   │ ← Minify output (parallelized)
└────────┬────────┘
         │
         ▼
    Output Chunks

EVERYTHING shares the same AST representation
NO re-parsing between steps

How Vite Will Use Rolldown

Vite currently uses different tools for dev vs production:

VITE TODAY (2024):

Development:
  - Native ES modules (fast)
  - esbuild for dependency pre-bundling
  - esbuild for TypeScript/JSX transform

Production:
  - Rollup for bundling
  - Terser or esbuild for minification

PROBLEM: Different tools = different behaviors
  - Dev and prod can have subtle differences
  - Configuration split across tools
  - Can't share optimizations between modes

VITE FUTURE (with Rolldown):

Development:
  - Native ES modules (fast)
  - Rolldown for dependency pre-bundling
  - Oxc for TypeScript/JSX transform

Production:
  - Rolldown for bundling
  - Oxc minifier for minification

BENEFIT: Same tool for dev and prod
  - Consistent behavior
  - Unified configuration
  - Shared caching between modes
  - Even faster production builds

The Complete VoidZero Ecosystem

┌─────────────────────────────────────────────────────────────────┐
│                    VOIDZERO ECOSYSTEM                            │
└─────────────────────────────────────────────────────────────────┘

USER FACING:
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│      Vite       │    │     Vitest      │    │    VitePress    │
│  Build Tool     │    │   Test Runner   │    │  Documentation  │
└────────┬────────┘    └────────┬────────┘    └────────┬────────┘
         │                      │                      │
         └──────────────────────┼──────────────────────┘
                                │
                    INFRASTRUCTURE:
                                │
         ┌──────────────────────┼──────────────────────┐
         │                      │                      │
         ▼                      ▼                      ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│    Rolldown     │    │   oxc-linter    │    │   Lightning     │
│    Bundler      │    │    (Linter)     │    │   CSS (CSS)     │
└────────┬────────┘    └────────┬────────┘    └────────┬────────┘
         │                      │                      │
         └──────────────────────┼──────────────────────┘
                                │
                       CORE FOUNDATION:
                                │
                                ▼
                    ┌─────────────────────┐
                    │         OXC         │
                    │  Parser, Resolver,  │
                    │ Transformer, etc.   │
                    └─────────────────────┘
                                │
                                ▼
                    ┌─────────────────────┐
                    │        NAPI-RS      │
                    │  Rust ↔ Node.js     │
                    │  bindings           │
                    └─────────────────────┘

Why Rust for JavaScript Tooling?

// JAVASCRIPT LIMITATIONS FOR TOOLING:

// 1. SINGLE-THREADED
// JavaScript can only use one CPU core for computation
for (const file of files) {
  parse(file);  // Sequential, can't parallelize
}

// 2. GARBAGE COLLECTION PAUSES
// GC stops the world periodically
parseHugeFile();  // Allocates memory
// ... GC pause ... build freezes for 50-200ms

// 3. INTERPRETED OVERHEAD
// Even with JIT, slower than native code
const ast = parse(source);  // ~10x slower than native

// RUST ADVANTAGES:

// 1. TRUE PARALLELISM
// Rust can use all CPU cores safely
files.par_iter().map(|file| parse(file)).collect()  // 8x speedup on 8 cores

// 2. NO GC PAUSES
// Memory managed at compile time, deterministic
// No random freezes during builds

// 3. NATIVE SPEED
// Compiles to machine code
// ~10-100x faster for parsing/transforming

// 4. MEMORY SAFETY
// Rust's ownership system prevents:
// - Memory leaks
// - Use after free
// - Data races
// Without sacrificing performance

// 5. SIMD/VECTORIZATION
// Rust can use CPU vector instructions
// String operations 4-8x faster with SIMD

Migration Path: Rollup to Rolldown

Rolldown aims for Rollup compatibility:

// CURRENT ROLLUP CONFIG:
// rollup.config.js
import { defineConfig } from 'rollup';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';

export default defineConfig({
  input: 'src/index.ts',
  output: {
    dir: 'dist',
    format: 'esm',
  },
  plugins: [
    resolve(),
    commonjs(),
    typescript(),
  ],
});

// FUTURE ROLLDOWN CONFIG (mostly compatible):
// rolldown.config.js
import { defineConfig } from 'rolldown';
import resolve from '@rollup/plugin-node-resolve';  // Works!
import commonjs from '@rollup/plugin-commonjs';      // Works!
// typescript() not needed - Rolldown handles TS natively via Oxc

export default defineConfig({
  input: 'src/index.ts',
  output: {
    dir: 'dist',
    format: 'esm',
  },
  plugins: [
    resolve(),
    commonjs(),
    // Built-in: TypeScript, JSX, minification
  ],
});

// COMPATIBILITY STATUS:
// ✓ Most Rollup plugins work (via compatibility layer)
// ✓ Same configuration format
// ✓ Same output quality
// ✗ Some plugins need updates (low-level AST manipulation)
// ✗ Plugin hooks have some differences

Comparing Modern Bundlers

┌────────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│            │ Webpack  │ Rollup   │ esbuild  │ Rolldown │ Turbopack│
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Language   │ JS       │ JS       │ Go       │ Rust     │ Rust     │
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Speed      │ Slow     │ Medium   │ Fast     │ Fast     │ Fast     │
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Tree Shake │ Good     │ Best     │ Good     │ Best     │ Good     │
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Code Split │ Best     │ Good     │ Basic    │ Good     │ Good     │
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Plugins    │ Huge     │ Large    │ Limited  │ Rollup*  │ Webpack* │
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Config     │ Complex  │ Simple   │ Simple   │ Simple   │ Low-level│
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Maturity   │ Mature   │ Mature   │ Mature   │ Alpha    │ Beta     │
├────────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Used By    │ Legacy   │ Vite,    │ Vite,    │ Vite     │ Next.js  │
│            │ projects │ libs     │ many     │ (future) │          │
└────────────┴──────────┴──────────┴──────────┴──────────┴──────────┘

* Rolldown: Rollup plugin compatibility
* Turbopack: Webpack plugin compatibility (planned)

The Tooling Evolution Timeline

2012: Webpack created (JS, comprehensive but slow)
      └─► Dominated build tooling for years

2017: Parcel created (JS, zero-config)
      └─► Popularized zero-config bundling

2018: Rollup gains popularity (JS, tree-shaking focus)
      └─► Became standard for libraries

2020: esbuild released (Go, 100x faster)
      └─► Proved native speed was possible

2021: Vite 2.0 released (esbuild + Rollup)
      └─► Combined fast dev + quality production

2022: Turbopack announced (Rust, Vercel)
      └─► Next.js-focused, Webpack successor

2023: Oxc development accelerates (Rust, VoidZero)
      └─► Unified toolchain vision emerges

2024: Rolldown alpha (Rust, VoidZero)
      └─► Rollup replacement for Vite

FUTURE: Unified toolchain
      └─► One parser, one resolver, one transformer
      └─► Consistent behavior dev → prod
      └─► 10-100x faster than current tools

When to Use What (2024 Recommendations)

BUILDING A LIBRARY:
├─► Small/Medium: Rollup (mature, great tree-shaking)
├─► Large: Rolldown when stable, or esbuild for speed
└─► TypeScript: tsup (esbuild wrapper) or unbuild (Rollup wrapper)

BUILDING AN APPLICATION:
├─► New project: Vite (best DX, uses Rollup + esbuild)
├─► Next.js: Turbopack (experimental) or Webpack (stable)
├─► Large legacy: Webpack (ecosystem, stability)
└─► Performance critical: Consider Vite with Rolldown (when stable)

BUILDING A MONOREPO:
├─► Turborepo + Vite (caching + fast builds)
├─► Nx + any bundler (task orchestration)
└─► pnpm workspaces + Vite (simple, fast)

LINTING:
├─► Today: ESLint (comprehensive rules)
├─► Future: oxc-linter (when rule coverage is sufficient)
└─► Consider: Biome (Rust-based, fast, integrated)

FORMATTING:
├─► Today: Prettier (de facto standard)
├─► Alternative: Biome (faster, combined lint+format)
└─► Future: Oxc prettier (planned)

For Framework Authors: Building Bundler Integrations

Implementation Note: The patterns and code examples below represent one proven approach to building bundler integrations. Plugin APIs differ across bundlers—Rollup/Vite use a hook-based system, Webpack uses tapable, and esbuild has a simpler API. The direction shown here focuses on the Rollup/Vite pattern (most common for modern frameworks). Adapt based on which bundlers you need to support and whether you're building plugins or a custom bundler.

Writing Bundler Plugins

// VITE/ROLLUP PLUGIN STRUCTURE

function myPlugin(options = {}) {
  return {
    name: 'my-plugin',

    // Called when config is resolved
    configResolved(config) {
      this.config = config;
    },

    // Transform source code
    transform(code, id) {
      if (!id.endsWith('.special')) return null;

      // Transform the code
      const transformed = processSpecialFile(code);

      return {
        code: transformed,
        map: null, // Source map
      };
    },

    // Resolve import paths
    resolveId(source, importer) {
      if (source.startsWith('virtual:')) {
        return '\0' + source; // Prefix with \0 for virtual modules
      }
      return null; // Let other plugins handle
    },

    // Load virtual modules
    load(id) {
      if (id.startsWith('\0virtual:')) {
        return `export default ${JSON.stringify(getVirtualContent(id))}`;
      }
      return null;
    },

    // Build hooks
    buildStart() {
      console.log('Build starting...');
    },

    buildEnd(error) {
      if (error) console.error('Build failed:', error);
    },

    // Generate bundle output
    generateBundle(options, bundle) {
      // Modify or add to bundle
      this.emitFile({
        type: 'asset',
        fileName: 'manifest.json',
        source: JSON.stringify(generateManifest(bundle)),
      });
    },
  };
}

// Vite-specific hooks
function vitePlugin() {
  return {
    name: 'vite-specific',

    // Dev server middleware
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        if (req.url === '/__my-plugin') {
          res.end(JSON.stringify({ status: 'ok' }));
          return;
        }
        next();
      });
    },

    // HMR handling
    handleHotUpdate({ file, server, modules }) {
      if (file.endsWith('.custom')) {
        // Custom HMR logic
        server.ws.send({
          type: 'custom',
          event: 'custom-update',
          data: { file },
        });
        return []; // Don't do normal HMR
      }
    },

    // Transform index.html
    transformIndexHtml(html) {
      return html.replace(
        '</head>',
        `<script>window.__VERSION__="${Date.now()}"</script></head>`
      );
    },
  };
}

Implementing Code Splitting Logic

// CUSTOM CODE SPLITTING STRATEGY

class ChunkSplitter {
  constructor(options = {}) {
    this.options = {
      minChunkSize: options.minChunkSize || 20000,
      maxChunkSize: options.maxChunkSize || 250000,
      vendorPattern: options.vendorPattern || /node_modules/,
    };
    this.chunks = new Map();
  }

  // Analyze module graph
  analyzeGraph(modules) {
    const graph = {
      nodes: new Map(),
      edges: new Map(),
    };

    for (const mod of modules) {
      graph.nodes.set(mod.id, {
        id: mod.id,
        size: mod.code.length,
        isVendor: this.options.vendorPattern.test(mod.id),
        imports: mod.imports,
        importedBy: [],
      });
    }

    // Build reverse edges
    for (const [id, node] of graph.nodes) {
      for (const imp of node.imports) {
        const target = graph.nodes.get(imp);
        if (target) {
          target.importedBy.push(id);
        }
      }
    }

    return graph;
  }

  // Determine chunks
  splitChunks(graph, entries) {
    const chunks = [];

    // Create vendor chunk
    const vendorModules = [...graph.nodes.values()]
      .filter(n => n.isVendor);

    if (vendorModules.length > 0) {
      chunks.push({
        name: 'vendor',
        modules: vendorModules.map(n => n.id),
      });
    }

    // Create chunks per entry
    for (const entry of entries) {
      const reachable = this.getReachableModules(graph, entry);
      const nonVendor = reachable.filter(id => !graph.nodes.get(id)?.isVendor);

      // Split large chunks
      const subChunks = this.splitBySize(nonVendor, graph);
      chunks.push(...subChunks.map((mods, i) => ({
        name: `${entry}-${i}`,
        modules: mods,
      })));
    }

    // Find shared chunks
    const sharedChunks = this.findSharedChunks(chunks, graph);
    chunks.push(...sharedChunks);

    return chunks;
  }

  getReachableModules(graph, entry) {
    const visited = new Set();
    const queue = [entry];

    while (queue.length > 0) {
      const id = queue.shift();
      if (visited.has(id)) continue;
      visited.add(id);

      const node = graph.nodes.get(id);
      if (node) {
        queue.push(...node.imports);
      }
    }

    return [...visited];
  }

  findSharedChunks(chunks, graph) {
    // Find modules used by multiple chunks
    const moduleUsage = new Map();

    for (const chunk of chunks) {
      for (const modId of chunk.modules) {
        if (!moduleUsage.has(modId)) {
          moduleUsage.set(modId, []);
        }
        moduleUsage.get(modId).push(chunk.name);
      }
    }

    // Extract frequently shared modules
    const shared = [];
    for (const [modId, usedBy] of moduleUsage) {
      if (usedBy.length >= 2) {
        shared.push(modId);
      }
    }

    if (shared.length > 0) {
      return [{ name: 'shared', modules: shared }];
    }

    return [];
  }
}

Building a Module Transformer

// AST-BASED MODULE TRANSFORMER

import * as acorn from 'acorn';
import * as walk from 'acorn-walk';
import MagicString from 'magic-string';

class ModuleTransformer {
  transform(code, options = {}) {
    const ast = acorn.parse(code, {
      ecmaVersion: 'latest',
      sourceType: 'module',
    });

    const s = new MagicString(code);

    // Transform imports
    walk.simple(ast, {
      ImportDeclaration(node) {
        const source = node.source.value;

        // Resolve bare imports
        if (!source.startsWith('.') && !source.startsWith('/')) {
          const resolved = resolveNodeModule(source);
          s.overwrite(
            node.source.start,
            node.source.end,
            `"${resolved}"`
          );
        }
      },

      // Transform dynamic imports
      ImportExpression(node) {
        const source = node.source;
        if (source.type === 'Literal') {
          const resolved = resolvePath(source.value);
          s.overwrite(source.start, source.end, `"${resolved}"`);
        }
      },

      // Transform exports for HMR
      ExportDefaultDeclaration(node) {
        if (options.hmr) {
          const decl = node.declaration;
          s.appendLeft(decl.start, '__hmr_wrap(');
          s.appendRight(decl.end, ')');
        }
      },
    });

    return {
      code: s.toString(),
      map: s.generateMap({ hires: true }),
    };
  }
}

// Import analysis
function analyzeImports(code) {
  const ast = acorn.parse(code, { ecmaVersion: 'latest', sourceType: 'module' });
  const imports = [];
  const exports = [];

  walk.simple(ast, {
    ImportDeclaration(node) {
      imports.push({
        source: node.source.value,
        specifiers: node.specifiers.map(s => ({
          type: s.type,
          imported: s.imported?.name || 'default',
          local: s.local.name,
        })),
      });
    },

    ExportNamedDeclaration(node) {
      if (node.declaration) {
        if (node.declaration.type === 'VariableDeclaration') {
          for (const decl of node.declaration.declarations) {
            exports.push({ name: decl.id.name, type: 'named' });
          }
        } else if (node.declaration.id) {
          exports.push({ name: node.declaration.id.name, type: 'named' });
        }
      }
    },

    ExportDefaultDeclaration() {
      exports.push({ name: 'default', type: 'default' });
    },
  });

  return { imports, exports };
}

Implementing Source Maps

// SOURCE MAP GENERATION

class SourceMapGenerator {
  constructor() {
    this.mappings = [];
    this.sources = [];
    this.sourcesContent = [];
    this.names = [];
  }

  addSource(filename, content) {
    const index = this.sources.indexOf(filename);
    if (index !== -1) return index;

    this.sources.push(filename);
    this.sourcesContent.push(content);
    return this.sources.length - 1;
  }

  addMapping(generated, original, sourceIndex, name) {
    this.mappings.push({
      generatedLine: generated.line,
      generatedColumn: generated.column,
      originalLine: original.line,
      originalColumn: original.column,
      sourceIndex,
      nameIndex: name ? this.addName(name) : undefined,
    });
  }

  addName(name) {
    const index = this.names.indexOf(name);
    if (index !== -1) return index;
    this.names.push(name);
    return this.names.length - 1;
  }

  generate() {
    // Sort mappings
    this.mappings.sort((a, b) =>
      a.generatedLine - b.generatedLine ||
      a.generatedColumn - b.generatedColumn
    );

    // Encode mappings to VLQ
    const encodedMappings = this.encodeMappings();

    return {
      version: 3,
      sources: this.sources,
      sourcesContent: this.sourcesContent,
      names: this.names,
      mappings: encodedMappings,
    };
  }

  encodeMappings() {
    let result = '';
    let previousGeneratedLine = 1;
    let previousGeneratedColumn = 0;
    let previousOriginalLine = 0;
    let previousOriginalColumn = 0;
    let previousSourceIndex = 0;
    let previousNameIndex = 0;

    for (let i = 0; i < this.mappings.length; i++) {
      const mapping = this.mappings[i];

      // New lines
      while (previousGeneratedLine < mapping.generatedLine) {
        result += ';';
        previousGeneratedLine++;
        previousGeneratedColumn = 0;
      }

      if (i > 0 && this.mappings[i - 1].generatedLine === mapping.generatedLine) {
        result += ',';
      }

      // Encode segment
      let segment = this.encodeVLQ(mapping.generatedColumn - previousGeneratedColumn);
      previousGeneratedColumn = mapping.generatedColumn;

      segment += this.encodeVLQ(mapping.sourceIndex - previousSourceIndex);
      previousSourceIndex = mapping.sourceIndex;

      segment += this.encodeVLQ(mapping.originalLine - previousOriginalLine);
      previousOriginalLine = mapping.originalLine;

      segment += this.encodeVLQ(mapping.originalColumn - previousOriginalColumn);
      previousOriginalColumn = mapping.originalColumn;

      if (mapping.nameIndex !== undefined) {
        segment += this.encodeVLQ(mapping.nameIndex - previousNameIndex);
        previousNameIndex = mapping.nameIndex;
      }

      result += segment;
    }

    return result;
  }

  encodeVLQ(value) {
    const VLQ_BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    let encoded = '';
    let vlq = value < 0 ? ((-value) << 1) + 1 : value << 1;

    do {
      let digit = vlq & 0x1f;
      vlq >>>= 5;
      if (vlq > 0) digit |= 0x20;
      encoded += VLQ_BASE64[digit];
    } while (vlq > 0);

    return encoded;
  }
}

Related Skills

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.54%
按下载量换算26

Claude

30.56%
按下载量换算23

Cursor

19.9%
按下载量换算15

Gemini CLI

9.43%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills