Skip to content

Latest commit

 

History

History
215 lines (160 loc) · 8.71 KB

File metadata and controls

215 lines (160 loc) · 8.71 KB

Legolas

한국어 | English | 中文 | Español | 日本語

Slim bundles with precision.

Legolas is a Rust-powered CLI, distributed through npm with native binaries, for finding bundle-weight problems in modern web projects. It combines source-import analysis, lockfile inspection, optional bundle-artifact evidence, budget gates, and machine-readable output so optimization work can move from local triage to CI.

What It Checks

  • Framework and project shape for Next.js, Vite, Webpack, Rollup, Astro, Nuxt, React, Vue, and Svelte projects
  • Static and dynamic imports in JavaScript, TypeScript, JSX, TSX, Vue, and Svelte files
  • Heavy client dependencies such as charting, editor, icon, SDK, animation, map, monitoring, and UI packages
  • Duplicate package versions from npm, pnpm, and Yarn lockfiles
  • Tree-shaking risks, including broad icon imports, root utility imports, and repeated locale subpath imports
  • Lazy-loading opportunities on route-like, dashboard, modal, editor, map, and chart surfaces
  • Server/client boundary warnings for patterns such as browser surfaces importing Node-only modules
  • Bundle artifacts when present, including Webpack stats.json and esbuild/Rollup meta.json files in known locations

Legolas estimates savings directionally. Treat the numbers as prioritization signals, then confirm production impact with your own bundle analyzer and performance telemetry.

Install and Run

Run without adding a dependency:

npx @jeremyfellaz/legolas scan .
npx @jeremyfellaz/legolas visualize .
npx @jeremyfellaz/legolas optimize .

Or install it in a project:

npm install -D @jeremyfellaz/legolas
npx legolas scan .

The npm package requires Node.js >=18.17 and ships prebuilt Rust binaries for macOS arm64/x64, Linux x64 with glibc, and Windows x64.

Commands

Command Purpose Common options
scan Full analysis report with dependency, lockfile, import, artifact, and boundary findings [path], --config, --lang ko|en, --json, --sarif, --write-baseline, --baseline, --regression-only
visualize Text bars for estimated dependency weight and duplicate package pressure [path], --config, --lang ko|en, --limit
optimize Ranked action list with difficulty, confidence, target files, and suggested fixes [path], --config, --lang ko|en, --top, --json, --baseline, --regression-only
budget Evaluates bundle-health budget rules [path], --config, --lang ko|en, --json, --baseline, --regression-only
ci CI-oriented budget gate that exits with code 1 on failures [path], --config, --lang ko|en, --json, --sarif, --baseline, --regression-only

Help and text reports default to Korean. Pass --lang en for English output. Use legolas help --lang en for English command help.

npx @jeremyfellaz/legolas help --lang en

Common Workflows

Scan an app:

npx @jeremyfellaz/legolas scan ./apps/storefront --lang en

Get JSON for automation:

npx @jeremyfellaz/legolas scan ./apps/storefront --json --lang en

Upload SARIF from a scan-capable workflow:

npx @jeremyfellaz/legolas scan ./apps/storefront --sarif --lang en

Create and compare a baseline:

npx @jeremyfellaz/legolas scan ./apps/storefront --write-baseline ./legolas-baseline.json --json --lang en
npx @jeremyfellaz/legolas scan ./apps/storefront --baseline ./legolas-baseline.json --regression-only --json --lang en

Fail CI on budget regressions:

npx @jeremyfellaz/legolas ci ./apps/storefront --baseline ./legolas-baseline.json --regression-only --sarif --lang en

Configuration

Legolas automatically discovers legolas.config.json from the project root. You can also pass a file explicitly with --config.

{
  "scan": {
    "path": "src",
    "ignorePatterns": ["generated/**", "!generated/keep.ts"]
  },
  "visualize": {
    "limit": 12
  },
  "optimize": {
    "top": 7
  },
  "budget": {
    "rules": {
      "potentialKbSaved": {
        "warnAt": 40,
        "failAt": 80
      },
      "duplicatePackageCount": {
        "warnAt": 2,
        "failAt": 4
      },
      "dynamicImportCount": {
        "warnAt": 1,
        "failAt": 0
      }
    }
  }
}

Source scanning also honors the project's .gitignore and root .legolasignore. scan.ignorePatterns uses POSIX-style path patterns relative to the resolved project root and supports ! exception patterns like .gitignore.

potentialKbSaved and duplicatePackageCount are maximum-style rules: higher actual values are worse. dynamicImportCount is a minimum-style rule: too few dynamic imports can warn or fail.

Output Formats

JSON output includes a top-level reportSummary. SARIF output carries the same summary at runs[0].properties.reportSummary. The summary includes language, verdictKey, confirmedInitialPayloadKbSaved, directionalOpportunityKb, estimatedLcpImprovementMs, and topActions.

--json and --sarif are mutually exclusive. ci returns a non-zero exit code when budget rules fail.

Example Output

Use --lang en when you want English human-readable output. scan summarizes the project, verdict, confirmed initial payload savings, directional cleanup opportunity, next actions, evidence, and finding groups:

Legolas scan for basic-parity-app
Project root: <PROJECT_ROOT>
Mode: heuristic
Frameworks: Vite, React
Package manager: pnpm
Scanned 1 source files and 4 imported packages

Verdict: high impact
Confirmed initial payload savings: ~348 KB (estimated LCP improvement ~731 ms)
Directional cleanup opportunity: ~366 KB

Top next actions:
1. Review chart.js upfront bundle weight [hard | high confidence | ~160 KB]
   recommended fix: lazy-load - Register only the chart primitives you use and lazy load dashboard surfaces.
   targets: src/Dashboard.tsx
   evidence: src/Dashboard.tsx | specifier: chart.js | static import; Charting code is often only needed on a subset of screens.
2. Lazy load chart.js [medium | low confidence | ~120 KB]
   evidence: src/Dashboard.tsx | specifier: chart.js | route-like UI surface matched `dashboard` keyword

Heaviest known dependencies:
- chart.js (160 KB) [high confidence]: Charting code is often only needed on a subset of screens. imported in 1 file(s).

Confirmed initial payload savings sums only findings with source-import or bundle-artifact evidence for initial payload impact. Lockfile-only duplication is not counted in that confirmed/LCP number; it is treated as a Directional cleanup opportunity dependency-hygiene signal. Development/test-only duplicates are also presented as dependency-hygiene cleanup work, not as LCP improvement.

optimize turns findings into ranked actions:

Legolas optimize for basic-parity-app

1. Review chart.js upfront bundle weight [hard | high confidence | ~160 KB]
   recommended fix: lazy-load - Register only the chart primitives you use and lazy load dashboard surfaces.
   targets: src/Dashboard.tsx
   evidence: src/Dashboard.tsx | specifier: chart.js | static import; Charting code is often only needed on a subset of screens.

budget reports pass, warn, or fail for each rule:

Legolas budget for basic-parity-app

Overall status: Fail

Rule results:
- potentialKbSaved: Fail (actual: 348, warnAt: 40, failAt: 80)
- duplicatePackageCount: Pass (actual: 1, warnAt: 2, failAt: 4)
- dynamicImportCount: Fail (actual: 0, warnAt: 1, failAt: 0)

Development

cargo run -p legolas-cli -- help
cargo test --workspace

Contributor workflows use cargo run -p legolas-cli -- ... as the source of truth. The npm package wraps the compiled Rust binary from vendor/<triple>/legolas[.exe]. When release packaging has staged those vendor binaries, validate the package layout with npm run pack:check.

Open Source