Skip to content

perf(loader): lazily bridge boxed loader contexts and sources - #15635

Draft
intellild wants to merge 2 commits into
mainfrom
codex/js-loader-context-class
Draft

intellild wants to merge 2 commits into
mainfrom
codex/js-loader-context-class

Conversation

@intellild

@intellild intellild commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Motivation

Crossing the Rust/JavaScript loader boundary currently materializes the loader context and splits source content from its source map, even when JavaScript does not consume them. Builtin loaders also pass content and maps separately, losing the opportunity to preserve native source graphs between loaders.

For example, a JavaScript pitch loader that returns no output should leave the native source untouched. A chain of builtin loaders should retain BoxSource until a JavaScript normal loader actually needs a string or Buffer and a separate source map. When a native consumer needs owned text, consuming a uniquely owned raw buffer can reuse its allocation instead of copying the whole file. No benchmark speedup is claimed.

Changes

  • Turn JsLoaderContext into a N-API class directly owning Option<Box<LoaderContext>>. The JavaScript loader runner receives and returns the same Box; return-value conversion takes it on the JavaScript thread, leaving retained instances empty.
  • Batch mutable fields in a napi(object) state. The JavaScript facade reads and updates this state locally and writes it back once, while source content and maps remain lazy.
  • Keep ordinary native loader hooks on &mut LoaderContext. JavaScript hooks exchange a state snapshot and return the complete state without moving the native context. Preserve hook-installed properties, loader object identity, and native/JavaScript hook ordering.
  • Carry BoxSource through builtin loaders and normal module processing. Add consuming Source access that reuses uniquely owned leaf allocations, including after cache restoration, and use SIMD UTF-8 validation. Remove full-content copies in NormalModule and SWC and per-module static runtime copies in React/Preact refresh.
  • Preserve native source graphs when JavaScript produces no output, and retain invalid UTF-8 bytes in mapped sources and cache serialization.
  • Update generated bindings, WASI exports, regression cases, and English and Chinese architecture documentation.

Validation

  • Native binding and JavaScript package builds passed.
  • Clippy with -D warnings passed for the binding API, loader runner, sources, builtin loader crates, and HMR.
  • Rust tests passed for rspack_loader_runner, rspack_sources, and rspack_cacheable_test (135 tests plus 11 doc tests). Pointer checks verify allocation reuse before and after cache restoration and shared-source preservation.
  • Loader regressions passed (351 tests), and source-map regressions passed (184 tests), using the final native build.
  • Rust formatting, JavaScript lint/format checks, documentation spelling checks, and git diff --check passed.
  • CodSpeed has not yet been rerun for these changes.

by OpenAI Codex

@intellild
intellild force-pushed the codex/js-loader-context-class branch from 0c244ef to a3d45c1 Compare September 11, 2026 05:37
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 11, 2026

Copy link
Copy Markdown

Deploying rspack with  Cloudflare Pages  Cloudflare Pages

Latest commit: 78a6a63
Status: ✅  Deploy successful!
Preview URL: https://43fefc37.rspack-v2.pages.dev
Branch Preview URL: https://codex-js-loader-context-clas.rspack-v2.pages.dev

View logs

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing 78a6a63 to fix(rstest): resolve manual mocks next to package entries (#15689) by 9aoy

❌ Size increased by 44.13KB from 68.82MB to 68.87MB (⬆️0.06%)

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

Found 5 projects in monorepo, 0 projects with changes.

📊 Quick Summary
Project Total Size Gzip Size Change Gzip Change
popular-libs 1.7 MB 523.6 KB 0 0
react-10k 5.3 MB 1.3 MB 0 0
react-1k 799.2 KB 217.5 KB 0 0
react-5k 2.6 MB 662.0 KB 0 0
ui-components 4.9 MB 1.4 MB 0 0

Generated by Rsdoctor GitHub Action

@codspeed

codspeed Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 50 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing codex/js-loader-context-class (78a6a63) with main (7857019)

Open in CodSpeed

Footnotes

  1. 47 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@intellild
intellild force-pushed the codex/js-loader-context-class branch 2 times, most recently from c9db7a3 to 8680131 Compare September 15, 2026 03:26
Separate reusable loader metadata from execution state and move the boxed context through the JavaScript boundary. Batch mutable state writeback while preserving borrowed native hook access.

Cache native getter results per JavaScript entry, including missing values. Keep content and source maps separate throughout the loader chain, with regression coverage for ownership, state updates, and raw buffer handling.
@intellild
intellild force-pushed the codex/js-loader-context-class branch from 8680131 to ab73d39 Compare September 15, 2026 09:16
Add typed lifecycle guards and environment-scoped thread-local reference caching in rspack_napi. Batch reference cleanup on owning JavaScript threads when native guards drop.

Reuse loader context classes and JavaScript wrappers without carrying facade state through Rust. Preserve boxed ownership, borrowed hooks, and per-entry read cache resets, with identity and cross-environment GC regression coverage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant