From d460139585c8ed61e0cb93573350bd0efe04e6ec Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 15:17:13 +0800 Subject: [PATCH 01/43] feat: allow with.mode attr in swc dynamic import plugin --- .../crates/swc_plugin_dynamic_import/lib.rs | 33 +++++++++++++------ .../lib.rs/should_transform_import_call.js | 22 +++++++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs index 4ef6e20cf1..7526150a82 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs @@ -94,24 +94,31 @@ fn is_import_call_tpl(call_expr: &CallExpr) -> bool { } } -fn is_import_call_with_type(call_expr: &CallExpr) -> (bool, bool, Value) { +fn is_import_call_with_attrs( + call_expr: &CallExpr, + attrs: &[&str], +) -> (bool, Vec, Vec) { + let mut with_keys = vec![false; attrs.len()]; + let mut with_values = vec![Value::Null; attrs.len()]; + match &call_expr.callee { Callee::Import(_) if call_expr.args.len() >= 2 => match &*call_expr.args[1].expr { Expr::Object(object) => { let (is_lit, _) = calc_literal_cost(object, false); if is_lit { let with = jsonify(Expr::Object(object.clone())); - match with.pointer("/with/type") { - Some(value) => (true, true, value.clone()), - _ => (true, false, Value::Null), + for (i, attr) in attrs.iter().enumerate() { + if let Some(value) = with.pointer(&format!("/with/{attr}")) { + with_keys[i] = true; + with_values[i] = value.clone(); + } } - } else { - (true, false, Value::Null) } + (true, with_keys, with_values) } - _ => (true, false, Value::Null), + _ => (true, with_keys, with_values), }, - _ => (false, false, Value::Null), + _ => (false, with_keys, with_values), } } @@ -167,7 +174,9 @@ where } let (is_import_call_lit, is_import_call_str_lit, str_lit) = is_import_call_str_lit(call_expr); - let (has_option, is_import_call_with_type, _with_type) = is_import_call_with_type(call_expr); + let (has_option, with_keys, _with_values) = + is_import_call_with_attrs(call_expr, &["type", "mode"]); + let is_import_call_with_allow_attrs = with_keys.iter().any(|&b| b); // TODO: reject dynamic import without `{ with: { type: "component" } }` @@ -194,7 +203,7 @@ where || str_lit.starts_with("//"); if is_import_call_str_lit && !is_explicitly_external { - if has_option && !is_import_call_with_type { + if has_option && !is_import_call_with_allow_attrs { HANDLER.with(|handler| { handler .struct_span_err( @@ -313,6 +322,8 @@ mod tests { r#" (async function () { await import("./index.js"); + await import("./index.js", { with: { mode: "sync" } }); + await import("./index.js", { with: { mode: "async" } }); await import(`./locales/${name}`); await import("ftp://www/a.js"); await import("https://www/a.js"); @@ -320,6 +331,8 @@ mod tests { await import(url+"?v=1.0"); await import("./index.js", { with: { type: "component" } }); + await import("./index.js", { with: { type: "component", mode: "sync" } }); + await import("./index.js", { with: { type: "component", mode: "async" } }); await import("ftp://www/a.js", { with: { type: "component" } }); await import("https://www/a.js", { with: { type: "component" } }); await import(url, { with: { type: "component" } }); diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js b/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js index 1efb4a12e6..1f218e21c2 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js @@ -2,6 +2,16 @@ import "@lynx-js/react/experimental/lazy/import"; import { __dynamicImport } from "@lynx-js/react/internal"; (async function() { await import(/*webpackChunkName: "./index.js-test"*/ "./index.js"); + await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + mode: "sync" + } + }); + await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + mode: "async" + } + }); await import(`./locales/${name}`); await import(/*webpackChunkName: "ftp://www/a.js-test"*/ "ftp://www/a.js"); await __dynamicImport("https://www/a.js"); @@ -12,6 +22,18 @@ import { __dynamicImport } from "@lynx-js/react/internal"; type: "component" } }); + await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + type: "component", + mode: "sync" + } + }); + await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + type: "component", + mode: "async" + } + }); await import(/*webpackChunkName: "ftp://www/a.js-test"*/ "ftp://www/a.js", { with: { type: "component" From 41fcbf2d53ae70ad3669c5a5f3c3b5ca44e6dfa2 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 16:37:56 +0800 Subject: [PATCH 02/43] feat(swc-dynamic-import): wrap import() with withLazyBundleMode for mode attr Recognize `with: { mode: ... }` on dynamic import and rewrite as `withLazyBundleMode(mode, () => import(...))`. The runtime symbol is imported from `@lynx-js/react/internal` only when the wrapper is actually emitted, gated via Lazy::get to avoid spurious imports. --- .../crates/swc_plugin_dynamic_import/lib.rs | 109 ++++++++++++++++-- .../lib.rs/should_transform_import_call.js | 67 ++++++++--- 2 files changed, 151 insertions(+), 25 deletions(-) diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs index 7526150a82..c272dca45d 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs @@ -1,6 +1,11 @@ +use once_cell::sync::Lazy; use serde::Deserialize; use serde_json::Value; -use std::{borrow::Cow, collections::HashSet, fmt::Debug}; +use std::{ + borrow::Cow, + collections::{HashMap, HashSet}, + fmt::Debug, +}; use swc_core::{ common::{ comments::{Comment, CommentKind, Comments}, @@ -10,7 +15,8 @@ use swc_core::{ }, ecma::{ ast::*, - utils::{calc_literal_cost, prepend_stmt}, + atoms::once_cell, + utils::{calc_literal_cost, prepend_stmt, private_ident}, visit::{VisitMut, VisitMutWith}, }, }; @@ -49,6 +55,7 @@ where has_inner_lazy_bundle: bool, named_imports: HashSet, comments: Option, + with_mode: Lazy, } impl Default for DynamicImportVisitor @@ -70,6 +77,7 @@ where comments, has_inner_lazy_bundle: false, named_imports: HashSet::new(), + with_mode: Lazy::new(|| Expr::Ident(private_ident!("withLazyBundleMode"))), } } } @@ -97,9 +105,9 @@ fn is_import_call_tpl(call_expr: &CallExpr) -> bool { fn is_import_call_with_attrs( call_expr: &CallExpr, attrs: &[&str], -) -> (bool, Vec, Vec) { - let mut with_keys = vec![false; attrs.len()]; - let mut with_values = vec![Value::Null; attrs.len()]; +) -> (bool, HashSet, HashMap) { + let mut with_keys = HashSet::new(); + let mut with_values = HashMap::new(); match &call_expr.callee { Callee::Import(_) if call_expr.args.len() >= 2 => match &*call_expr.args[1].expr { @@ -109,8 +117,8 @@ fn is_import_call_with_attrs( let with = jsonify(Expr::Object(object.clone())); for (i, attr) in attrs.iter().enumerate() { if let Some(value) = with.pointer(&format!("/with/{attr}")) { - with_keys[i] = true; - with_values[i] = value.clone(); + with_keys.insert(attr.to_string()); + with_values.insert(attr.to_string(), value.clone()); } } } @@ -174,9 +182,9 @@ where } let (is_import_call_lit, is_import_call_str_lit, str_lit) = is_import_call_str_lit(call_expr); - let (has_option, with_keys, _with_values) = - is_import_call_with_attrs(call_expr, &["type", "mode"]); - let is_import_call_with_allow_attrs = with_keys.iter().any(|&b| b); + let attrs = &["type", "mode"]; + let (has_option, with_keys, with_values) = is_import_call_with_attrs(call_expr, attrs); + let is_import_call_with_allow_attrs = with_keys.iter().any(|k| attrs.contains(&k.as_str())); // TODO: reject dynamic import without `{ with: { type: "component" } }` @@ -227,6 +235,57 @@ where }, ); self.has_inner_lazy_bundle = true; + + if with_values.contains_key("mode") { + let mode = with_values.get("mode").unwrap(); + if let Value::String(mode) = mode { + let inner = call_expr.take(); + let arrow = ArrowExpr { + span: DUMMY_SP, + ctxt: Default::default(), + params: vec![], + body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Call(inner.clone())))), + is_async: false, + is_generator: false, + type_params: None, + return_type: None, + }; + *call_expr = CallExpr { + span: inner.span, + ctxt: inner.ctxt, + callee: Callee::Expr(Box::new(self.with_mode.clone())), + args: vec![ + ExprOrSpread { + spread: None, + expr: Box::new(Expr::Lit(Lit::Str(Str { + span: DUMMY_SP, + value: mode.to_string().into(), + raw: None, + }))), + }, + ExprOrSpread { + spread: None, + expr: Box::new(Expr::Arrow(arrow)), + }, + ], + type_args: None, + }; + return; + } else { + HANDLER.with(|handler| { + handler + .struct_span_err( + call_expr.span, + "`import(..., { mode: ... })` mode must be a string" + .to_string() + .as_str(), + ) + .emit() + }); + call_expr.visit_mut_children_with(self); + return; + } + } } else { let ident: Ident = "__dynamicImport".into(); *call_expr = CallExpr { @@ -291,6 +350,30 @@ where create_import_decl("data:text/javascript;charset=utf-8,import { loadLazyBundle } from \"@lynx-js/react/internal\";lynx.loadLazyBundle = loadLazyBundle;"), ); } + + if let Some(Expr::Ident(with_mode)) = Lazy::::get(&self.with_mode) { + prepend_stmt( + &mut n.body, + ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { + span: DUMMY_SP, + specifiers: vec![ImportSpecifier::Named(ImportNamedSpecifier { + span: DUMMY_SP, + local: with_mode.clone(), + imported: None, + is_type_only: false, + })], + src: Box::new(Str { + span: DUMMY_SP, + raw: None, + value: "@lynx-js/react/internal".into(), + }), + type_only: Default::default(), + // asserts: Default::default(), + with: Default::default(), + phase: ImportPhase::Evaluation, + })), + ) + } } } @@ -335,8 +418,14 @@ mod tests { await import("./index.js", { with: { type: "component", mode: "async" } }); await import("ftp://www/a.js", { with: { type: "component" } }); await import("https://www/a.js", { with: { type: "component" } }); + await import("https://www/a.js", { with: { type: "component", mode: "sync" } }); + await import("https://www/a.js", { with: { type: "component", mode: "async" } }); await import(url, { with: { type: "component" } }); + await import(url, { with: { type: "component", mode: "sync" } }); + await import(url, { with: { type: "component", mode: "async" } }); await import(url+"?v=1.0", { with: { type: "component" } }); + await import(url+"?v=1.0", { with: { type: "component", mode: "sync" } }); + await import(url+"?v=1.0", { with: { type: "component", mode: "async" } }); })(); "# ); diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js b/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js index 1f218e21c2..9e6eb45c77 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/tests/__swc_snapshots__/lib.rs/should_transform_import_call.js @@ -1,52 +1,77 @@ +import { withLazyBundleMode } from "@lynx-js/react/internal"; import "@lynx-js/react/experimental/lazy/import"; import { __dynamicImport } from "@lynx-js/react/internal"; (async function() { await import(/*webpackChunkName: "./index.js-test"*/ "./index.js"); + await withLazyBundleMode("sync", ()=>import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + mode: "sync" + } + })); + await withLazyBundleMode("async", ()=>import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + mode: "async" + } + })); + await import(`./locales/${name}`); + await import(/*webpackChunkName: "ftp://www/a.js-test"*/ "ftp://www/a.js"); + await __dynamicImport("https://www/a.js"); + await __dynamicImport(url); + await __dynamicImport(url + "?v=1.0"); await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { with: { - mode: "sync" + type: "component" } }); - await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + await withLazyBundleMode("sync", ()=>import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + type: "component", + mode: "sync" + } + })); + await withLazyBundleMode("async", ()=>import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + with: { + type: "component", + mode: "async" + } + })); + await import(/*webpackChunkName: "ftp://www/a.js-test"*/ "ftp://www/a.js", { with: { - mode: "async" + type: "component" } }); - await import(`./locales/${name}`); - await import(/*webpackChunkName: "ftp://www/a.js-test"*/ "ftp://www/a.js"); - await __dynamicImport("https://www/a.js"); - await __dynamicImport(url); - await __dynamicImport(url + "?v=1.0"); - await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + await __dynamicImport("https://www/a.js", { with: { type: "component" } }); - await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + await __dynamicImport("https://www/a.js", { with: { type: "component", mode: "sync" } }); - await import(/*webpackChunkName: "./index.js-test"*/ "./index.js", { + await __dynamicImport("https://www/a.js", { with: { type: "component", mode: "async" } }); - await import(/*webpackChunkName: "ftp://www/a.js-test"*/ "ftp://www/a.js", { + await __dynamicImport(url, { with: { type: "component" } }); - await __dynamicImport("https://www/a.js", { + await __dynamicImport(url, { with: { - type: "component" + type: "component", + mode: "sync" } }); await __dynamicImport(url, { with: { - type: "component" + type: "component", + mode: "async" } }); await __dynamicImport(url + "?v=1.0", { @@ -54,4 +79,16 @@ import { __dynamicImport } from "@lynx-js/react/internal"; type: "component" } }); + await __dynamicImport(url + "?v=1.0", { + with: { + type: "component", + mode: "sync" + } + }); + await __dynamicImport(url + "?v=1.0", { + with: { + type: "component", + mode: "async" + } + }); })(); From e0fb54652d8413e5eb85a09ab49cb2ea1d28962f Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 17:06:49 +0800 Subject: [PATCH 03/43] feat(react): add withLazyBundleMode runtime helper Introduce `withLazyBundleMode(mode, factory)` to temporarily set the lazy bundle import mode via a Symbol on `lynx`, restoring the prior value after the factory returns. Wire `__dynamicImport` to read `mode` from `with` (matching what the SWC plugin forwards) and wrap component-type loads accordingly. Re-export from `react/internal` and the lazy proxy so consumers can resolve it. --- packages/react/runtime/lazy/internal.js | 1 + packages/react/runtime/src/internal.ts | 2 +- .../runtime/src/snapshot/lynx/dynamic-js.ts | 10 +++++++--- .../runtime/src/snapshot/lynx/lazy-bundle.ts | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/react/runtime/lazy/internal.js b/packages/react/runtime/lazy/internal.js index 5d0d3b475c..87baa179f2 100644 --- a/packages/react/runtime/lazy/internal.js +++ b/packages/react/runtime/lazy/internal.js @@ -49,6 +49,7 @@ export const { updateListItemPlatformInfo, updateWorkletRef, withInitDataInState, + withLazyBundleMode, wrapWithLynxComponent, } = target[sExportsReactInternal]; diff --git a/packages/react/runtime/src/internal.ts b/packages/react/runtime/src/internal.ts index 2b3f554567..bc3622a34b 100644 --- a/packages/react/runtime/src/internal.ts +++ b/packages/react/runtime/src/internal.ts @@ -71,7 +71,7 @@ export const __ComponentIsPolyfill: FC<{ is: string }> = /* @__PURE__ */ factory loadLazyBundle, ); -export { loadLazyBundle } from './snapshot/lynx/lazy-bundle.js'; +export { loadLazyBundle, withLazyBundleMode } from './snapshot/lynx/lazy-bundle.js'; export { transformToWorklet } from './snapshot/worklet/call/transformToWorklet.js'; export { registerWorkletOnBackground } from './snapshot/worklet/hmr.js'; diff --git a/packages/react/runtime/src/snapshot/lynx/dynamic-js.ts b/packages/react/runtime/src/snapshot/lynx/dynamic-js.ts index 6780953879..5a3e24ba08 100644 --- a/packages/react/runtime/src/snapshot/lynx/dynamic-js.ts +++ b/packages/react/runtime/src/snapshot/lynx/dynamic-js.ts @@ -1,7 +1,7 @@ // Copyright 2024 The Lynx Authors. All rights reserved. // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. -import { loadLazyBundle } from './lazy-bundle.js'; +import { loadLazyBundle, withLazyBundleMode } from './lazy-bundle.js'; export function loadDynamicJS(url: string): Promise { if (__LEPUS__) { @@ -25,10 +25,14 @@ export function loadDynamicJS(url: string): Promise { export function __dynamicImport( url: string, - options?: { with?: { type?: 'component' | 'tsx' | 'jsx' } }, + options?: { with?: { type?: 'component' | 'tsx' | 'jsx'; mode?: 'sync' | 'async' } }, ): Promise { - const t = options?.with?.type; + const w = options?.with; + const t = w?.type; if (t === 'component' || t === 'tsx' || t === 'jsx') { + if (w?.mode) { + return withLazyBundleMode(w.mode, () => loadLazyBundle(url)); + } return loadLazyBundle(url); } else { return loadDynamicJS(url); diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index f4494e8775..bcd440aada 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -156,3 +156,22 @@ function withSyncResolvers() { return resolver; } + +const __LYNX_LAZY_BUNDLE_MODE__ = Symbol.for('__LYNX_LAZY_BUNDLE_MODE__'); + +/** + * Temporarily set import mode for lazy bundle. + * @param mode Import mode. + * @param factory Factory function. + * @returns Result of factory function. + */ +export function withLazyBundleMode(mode: 'sync' | 'async', factory: () => T): T { + const g = lynx as unknown as Record; + const prev = g[__LYNX_LAZY_BUNDLE_MODE__]; + g[__LYNX_LAZY_BUNDLE_MODE__] = mode; + try { + return factory(); + } finally { + g[__LYNX_LAZY_BUNDLE_MODE__] = prev; + } +} From 7c318ca1adafc4b25d85016cebced119a66dd7f1 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 19:24:15 +0800 Subject: [PATCH 04/43] feat(react): add fetchBundle-based loadLazyBundle path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a `__LAZY_BUNDLE_FETCHER__` define gated by the `REACT_LAZY_BUNDLE_FETCHER` env var (default `'FetchBundle'`, overridable to `'QueryComponent'` for the legacy path) and dispatch `loadLazyBundle` to one of two implementations at module init. The FetchBundle implementation uses `lynx.fetchBundle` + `lynx.loadScript`, with the sync/async behavior driven by the module-local `lazyBundleMode` set via `withLazyBundleMode`. Pin `@lynx-js/types` to a vendored 3.10.0 tarball — that release adds the `fetchBundle` / `loadScript` declarations the new code type-checks against. Existing tests stub the global to `'QueryComponent'` so they still exercise the legacy path. --- package.json | 3 + .../snapshot/lynx/lazy-bundle.test.js | 9 +- .../runtime/src/snapshot/lynx/lazy-bundle.ts | 121 ++- packages/react/runtime/types/types.d.ts | 1 + .../src/ReactWebpackPlugin.ts | 3 + pnpm-lock.yaml | 711 +++++++++++------- vendor/lynx-js-types-3.10.0.tgz | Bin 0 -> 49773 bytes 7 files changed, 579 insertions(+), 269 deletions(-) create mode 100644 vendor/lynx-js-types-3.10.0.tgz diff --git a/package.json b/package.json index 88a37cc038..ab7ec7ef2d 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,9 @@ "allowedVersions": { "rsbuild-plugin-tailwindcss>tailwindcss": "^3 || ^4" } + }, + "overrides": { + "@lynx-js/types": "file:./vendor/lynx-js-types-3.10.0.tgz" } } } diff --git a/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle.test.js b/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle.test.js index 740462f72c..4191b0f39b 100644 --- a/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle.test.js +++ b/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle.test.js @@ -12,7 +12,12 @@ describe('loadLazyBundle', () => { vi .unstubAllGlobals() .stubGlobal('__LEPUS__', true) - .stubGlobal('__MAIN_THREAD__', true); + .stubGlobal('__MAIN_THREAD__', true) + // Force the QueryComponent fetcher path. Production builds get + // `__LAZY_BUNDLE_FETCHER__` stamped in by DefinePlugin (default + // `'FetchBundle'`); unit tests don't run DefinePlugin so the + // global is undefined here unless we stub it explicitly. + .stubGlobal('__LAZY_BUNDLE_FETCHER__', 'QueryComponent'); }); test('should not have lynx.loadLazyBundle when not used', () => { @@ -213,6 +218,8 @@ describe('loadLazyBundle', () => { .stubGlobal('__MAIN_THREAD__', false) .stubGlobal('__BACKGROUND__', true) .stubGlobal('__JS__', true) + // Force the QueryComponent fetcher path (see main-thread block). + .stubGlobal('__LAZY_BUNDLE_FETCHER__', 'QueryComponent') .stubGlobal('lynx', { QueryComponent }) .stubGlobal('lynxCoreInject', { tt: { getDynamicComponentExports } }); }); diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index bcd440aada..97fbfb4beb 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -55,6 +55,13 @@ export const makeSyncThen = function(result: T): Promise['then'] { }; }; +let lazyBundleMode: 'sync' | 'async' | undefined; + +const LYNX_LAZY_SYNC_TIMEOUT_SECONDS = 5; + +const SECTION_MAIN_THREAD = 'main-thread'; +const SECTION_BACKGROUND = 'background'; + /** * Load dynamic component from source. Designed to be used with `lazy`. * @param source - where dynamic component template.js locates @@ -64,9 +71,16 @@ export const makeSyncThen = function(result: T): Promise['then'] { export const loadLazyBundle: < T extends { default: React.ComponentType }, >(source: string) => Promise = /*#__PURE__*/ (() => { - lynx.loadLazyBundle = loadLazyBundle; + const useQueryComponent = typeof __LAZY_BUNDLE_FETCHER__ !== 'undefined' + && __LAZY_BUNDLE_FETCHER__ === 'QueryComponent'; + + const impl = useQueryComponent + ? loadLazyBundleWithQueryComponent + : loadLazyBundleWithFetchBundle; + + lynx.loadLazyBundle = impl; - function loadLazyBundle< + function loadLazyBundleWithQueryComponent< T extends { default: React.ComponentType }, >(source: string): Promise { if (__LEPUS__) { @@ -132,7 +146,99 @@ export const loadLazyBundle: < throw new Error('unreachable'); } - return loadLazyBundle; + function loadLazyBundleWithFetchBundle< + T extends { default: React.ComponentType }, + >(source: string): Promise { + if (__MAIN_THREAD__) { + if (lazyBundleMode !== 'sync') { + return new Promise(() => {}); + } + let response; + try { + response = lynx.fetchBundle(source, {}).wait( + LYNX_LAZY_SYNC_TIMEOUT_SECONDS, + ); + } catch { + return new Promise(() => {}); + } + if (!response || response.code !== 0) { + return new Promise(() => {}); + } + let result: T; + try { + result = lynx.loadScript(SECTION_MAIN_THREAD, { + bundleName: response.url, + }); + } catch { + return new Promise(() => {}); + } + const r: Promise = Promise.resolve(result); + r.then = makeSyncThen(result); + return r; + } else if (__JS__) { + if (lazyBundleMode === 'sync') { + let response; + try { + response = lynx.fetchBundle(source, {}).wait( + LYNX_LAZY_SYNC_TIMEOUT_SECONDS, + ); + } catch (e) { + return Promise.reject(e instanceof Error ? e : new Error(String(e))); + } + if (!response || response.code !== 0) { + const e = new Error('Lazy bundle load failed, schema: ' + source); + // ES5 does not support new Error('message', { cause: 'detail' }) + // So we set cause using `.cause` assignment + e.cause = JSON.stringify(response); + return Promise.reject(e); + } + let result: T; + try { + result = lynx.loadScript(SECTION_BACKGROUND, { + bundleName: response.url, + }); + } catch (e) { + return Promise.reject(e instanceof Error ? e : new Error(String(e))); + } + const r: Promise = Promise.resolve(result); + r.then = makeSyncThen(result); + return r; + } + + // async (default) + return new Promise((resolve, reject) => { + let handler; + try { + handler = lynx.fetchBundle(source, {}); + } catch (e) { + reject(e instanceof Error ? e : new Error(String(e))); + return; + } + handler.then((response) => { + if (!response || response.code !== 0) { + const e = new Error('Lazy bundle load failed, schema: ' + source); + // ES5 does not support new Error('message', { cause: 'detail' }) + // So we set cause using `.cause` assignment + e.cause = JSON.stringify(response); + reject(e); + return; + } + try { + const result = lynx.loadScript(SECTION_BACKGROUND, { + bundleName: response.url, + }); + resolve(result); + } catch (e) { + reject(e instanceof Error ? e : new Error(String(e))); + } + }); + }); + } + + throw new Error('unreachable'); + } + + return impl; })(); function withSyncResolvers() { @@ -157,8 +263,6 @@ function withSyncResolvers() { return resolver; } -const __LYNX_LAZY_BUNDLE_MODE__ = Symbol.for('__LYNX_LAZY_BUNDLE_MODE__'); - /** * Temporarily set import mode for lazy bundle. * @param mode Import mode. @@ -166,12 +270,11 @@ const __LYNX_LAZY_BUNDLE_MODE__ = Symbol.for('__LYNX_LAZY_BUNDLE_MODE__'); * @returns Result of factory function. */ export function withLazyBundleMode(mode: 'sync' | 'async', factory: () => T): T { - const g = lynx as unknown as Record; - const prev = g[__LYNX_LAZY_BUNDLE_MODE__]; - g[__LYNX_LAZY_BUNDLE_MODE__] = mode; + const prev = lazyBundleMode; + lazyBundleMode = mode; try { return factory(); } finally { - g[__LYNX_LAZY_BUNDLE_MODE__] = prev; + lazyBundleMode = prev; } } diff --git a/packages/react/runtime/types/types.d.ts b/packages/react/runtime/types/types.d.ts index 0ed0f34a3e..be6f8c232e 100644 --- a/packages/react/runtime/types/types.d.ts +++ b/packages/react/runtime/types/types.d.ts @@ -23,6 +23,7 @@ declare global { declare const __ALOG_ELEMENT_API__: boolean | undefined; declare const __ENABLE_SSR__: boolean; declare const __GLOBAL_PROPS_MODE__: 'reactive' | 'event' | undefined; + declare const __LAZY_BUNDLE_FETCHER__: 'FetchBundle' | 'QueryComponent'; declare function __CreatePage(componentId: string, cssId: number): FiberElement; declare function __CreateElement( diff --git a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts index 3c3dc8b6b1..2ad6a8030f 100644 --- a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts +++ b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts @@ -248,6 +248,9 @@ class ReactWebpackPlugin { __USE_ELEMENT_TEMPLATE__: JSON.stringify( options.experimental_useElementTemplate, ), + __LAZY_BUNDLE_FETCHER__: JSON.stringify( + process.env['REACT_LAZY_BUNDLE_FETCHER'] ?? 'FetchBundle', + ), }).apply(compiler); compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c0e4be6eb..b3026bd33c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,10 +42,7 @@ catalogs: version: 0.2.0 overrides: - '@rspack/core@^1': 1.7.9 - '@rsbuild/core@1>@rspack/core': 1.7.9 - '@rsdoctor/rspack-plugin>@rspack/core': 1.7.9 - '@rsdoctor/types>@rspack/core': 1.7.9 + '@lynx-js/types': file:./vendor/lynx-js-types-3.10.0.tgz packageExtensionsChecksum: sha256-BUwt5m2tRMyYg9pgFVHNTHCYEBuM0/o7IdJqk+vWTGs= @@ -213,8 +210,8 @@ importers: specifier: 0.0.3 version: 0.0.3 '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -241,8 +238,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -269,8 +266,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -294,8 +291,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -319,11 +316,11 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@1.7.5) + version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -350,8 +347,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -375,8 +372,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -406,8 +403,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -434,8 +431,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -459,8 +456,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -484,8 +481,8 @@ importers: specifier: workspace:* version: link:../../packages/rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -512,8 +509,8 @@ importers: specifier: workspace:* version: link:../../packages/webpack/template-webpack-plugin '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -546,8 +543,8 @@ importers: specifier: workspace:* version: link:../../packages/tailwind-preset '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -595,16 +592,16 @@ importers: version: link:../a2ui-catalog-extractor '@lynx-js/lynx-ui': specifier: ^3.130.0 - version: 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + version: 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/lynx-ui-input': specifier: ^3.130.0 - version: 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + version: 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': specifier: workspace:* version: link:../../react '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -668,8 +665,8 @@ importers: specifier: workspace:* version: link:../../rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/core': specifier: catalog:rsbuild version: 1.7.5 @@ -704,8 +701,8 @@ importers: specifier: workspace:* version: link:../../webpack/template-webpack-plugin '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz i18next: specifier: 26.0.6 version: 26.0.6(typescript@5.9.3) @@ -714,7 +711,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -723,13 +720,14 @@ importers: version: 8.8.5 packages/lynx/gesture-runtime: + dependencies: + '@lynx-js/types': + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz devDependencies: '@lynx-js/react': specifier: workspace:* version: link:../../react - '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -834,6 +832,9 @@ importers: packages/motion: dependencies: + '@lynx-js/types': + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz framer-motion: specifier: 12.34.1 version: 12.34.1(react-dom@19.2.4(react@19.2.5))(react@19.2.5) @@ -847,22 +848,19 @@ importers: '@lynx-js/react': specifier: workspace:* version: link:../react - '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 rsbuild-plugin-publint: specifier: 0.3.4 version: 0.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) packages/react: dependencies: + '@lynx-js/types': + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz preact: specifier: npm:@lynx-js/internal-preact@10.29.1-20260424024911-12b794f version: '@lynx-js/internal-preact@10.29.1-20260424024911-12b794f' devDependencies: - '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 '@microsoft/api-extractor': specifier: 'catalog:' version: 7.58.2(@types/node@24.10.13) @@ -909,8 +907,8 @@ importers: specifier: workspace:* version: link:../transform '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -1013,8 +1011,8 @@ importers: specifier: 0.0.3 version: 0.0.3 '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@lynx-js/web-core': specifier: workspace:* version: link:../web-platform/web-core @@ -1086,7 +1084,7 @@ importers: version: 1.1.1(@rsbuild/core@1.7.5)(lightningcss@1.31.1)(webpack@5.105.2) '@rsdoctor/rspack-plugin': specifier: ~1.5.6 - version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) typescript: specifier: 5.1.6 - 5.9.x version: 5.9.3 @@ -1102,7 +1100,7 @@ importers: version: 12.3.0(patch_hash=926ba262ec682d27369f1a8648a0dfb657fb5f1b28539ca3628d292276c91c3d)(rollup@4.34.9)(tslib@2.8.1)(typescript@5.9.3) '@rsdoctor/core': specifier: ~1.5.6 - version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) chokidar: specifier: ^4.0.3 version: 4.0.3 @@ -1172,7 +1170,7 @@ importers: version: link:../core '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -1415,8 +1413,8 @@ importers: specifier: workspace:* version: link:../core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@lynx-js/web-core': specifier: workspace:* version: link:../../web-platform/web-core @@ -1425,10 +1423,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@1.7.5) + version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@1.7.5) + version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1443,7 +1441,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1533,11 +1531,11 @@ importers: specifier: workspace:* version: link:../../../rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@1.7.5) + version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -1576,8 +1574,8 @@ importers: specifier: workspace:* version: link:../../rspeedy/core '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -1794,7 +1792,7 @@ importers: version: 1.7.5 '@rsdoctor/rspack-plugin': specifier: ~1.5.6 - version: 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -1915,7 +1913,7 @@ importers: version: link:../test-tools '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2096,7 +2094,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2139,7 +2137,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2151,7 +2149,7 @@ importers: version: 1.0.4 css-loader: specifier: ^7.1.4 - version: 7.1.4(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2) webpack: specifier: ^5.105.2 version: 5.105.2 @@ -2287,13 +2285,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@1.7.5) + version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@1.7.5) + version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -3711,6 +3709,7 @@ packages: '@lynx-js/gesture-runtime@2.1.1': resolution: {integrity: sha512-zBDOHakuePjw5wPCButExNgcllyFPGqYzqP2CWCWcQaX4gqJmCmYeRKguihyxH6ma6ExxlH/J2x5CHD91ed3bQ==} + version: 2.1.1 peerDependencies: '@lynx-js/react': '*' '@lynx-js/types': '*' @@ -3723,6 +3722,7 @@ packages: '@lynx-js/lynx-ui-button@3.130.0': resolution: {integrity: sha512-0f13aZROKhTxMEY69rtWlkfvd6NM3A7JwloFQsh2nxcOiABp6dddvzzQJSayt2xAUxRjFl4uh5Rj/ZrQjjCrNw==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3730,6 +3730,7 @@ packages: '@lynx-js/lynx-ui-checkbox@3.130.0': resolution: {integrity: sha512-2xgq7oyGjq7CKYiHd/9nO+gzT2T3KSi4gb3EPxqrENDiiDv5im3ePTwzazUuHaWWK+7cHuJgxZIhwQU0Rk6l8w==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3737,6 +3738,7 @@ packages: '@lynx-js/lynx-ui-common@3.130.0': resolution: {integrity: sha512-6odzHU1z1PomtmskJUxIpj+TkHq9daOhUb7N0a3LquKxz9wp41qM1r2oDLRHdeUlylfId1F87Bto6F7Ql9+37w==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3744,6 +3746,7 @@ packages: '@lynx-js/lynx-ui-dialog@3.130.0': resolution: {integrity: sha512-AFkA7V+xI5EdaA2JShIcK3UAMG1RuaZcWl16f66KNRD1/ZgIQNp7sYOW/bnQmH+BXts7p4ut7NWBNNe5WcSVvQ==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3751,6 +3754,7 @@ packages: '@lynx-js/lynx-ui-draggable@3.130.0': resolution: {integrity: sha512-c9Sw0xahJqttWq/M9SmCIc3X0HIS/d47OBk5oNQRHjhJEaGKP23u/22SfCANXboxLhCxCXXv1OVmW/x8O9Wm2A==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3758,6 +3762,7 @@ packages: '@lynx-js/lynx-ui-feed-list@3.130.0': resolution: {integrity: sha512-5nUNYzRjSiR94N0LAyZ+b8aj5s6WYJGShohL2piKxw5lDI7PafaYt/i30aj0Q52b7ViB8ZZuD/ZtmbD4pKeRLA==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3765,6 +3770,7 @@ packages: '@lynx-js/lynx-ui-form@3.130.0': resolution: {integrity: sha512-hiDetKqgAGSGcuxIaRG/ljNfZrQjh31BtWZDw0aXJZL/ifHqwv2NQHErAPp9mgO8i/5NYYNYQ5Sgs/ophKhUMA==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3772,6 +3778,7 @@ packages: '@lynx-js/lynx-ui-input@3.130.0': resolution: {integrity: sha512-CPBbnDARhs5wfX//78+ATXYhGhU/R4SjFTL/Yzvur3Wh+lLFQz1mEvv0BOfUFnd/lEilc9Y9q00h6g7w7WHd3A==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3779,6 +3786,7 @@ packages: '@lynx-js/lynx-ui-lazy-component@3.130.0': resolution: {integrity: sha512-Xr4jQBM8mB3VtSxKnxxy0VdAT1M0dE5YWx5mEkpTezGVIX5rU+Ub23VFTtSZeGYWX1EFaleTOR17fsD4+C3CfA==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3786,6 +3794,7 @@ packages: '@lynx-js/lynx-ui-list@3.130.0': resolution: {integrity: sha512-MBj7S19iJ3Tnu4qTVFFXMjceQ6pS+Yj84xRqoXdgVO/kvcjTzxJxQJkUt4RvCuvmQ+fOLz3Lt0ePGxVxkOYY+g==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3793,6 +3802,7 @@ packages: '@lynx-js/lynx-ui-overlay@3.130.0': resolution: {integrity: sha512-rc11LA4svUdfX7ZG7pjS+7JzoXllmvv6Ng91QwkYbPIuRlcHu/d0VHtd8cPTgkoBevSWCACBIDoIEgONTfyuTA==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3800,6 +3810,7 @@ packages: '@lynx-js/lynx-ui-popover@3.130.0': resolution: {integrity: sha512-oP37HtY/KPiDruepLnpaJQQD3WOFINIz3g432xo+wZ+ScAKtZxfQm2pDpeb9eyPejKv9KjNIFexYtoFVMvSFSg==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3807,6 +3818,7 @@ packages: '@lynx-js/lynx-ui-presence@3.130.0': resolution: {integrity: sha512-h5a1SNFZdmEcsEJ6NrFcWC/LqEmINDh+LE9+givCvA4IwkYBWvgBQHoe/0LESJV75TC1TlB3L0sULsBVxMvqXg==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3814,6 +3826,7 @@ packages: '@lynx-js/lynx-ui-radio-group@3.130.0': resolution: {integrity: sha512-vRylYRYH41BVFCEt2lsOhnZuTcLu5ACcJvOXpCgTItCDsQ/+g1GSzDl37IAwwI4MBUDPG30uwD0+s7JjYjgn0g==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3821,6 +3834,7 @@ packages: '@lynx-js/lynx-ui-scroll-view@3.130.0': resolution: {integrity: sha512-Q5iwceQKFZ4TTLI/h5ZGWhBLP880g4Kn1h4jOeSGWUaKFyEUdbEd1DQKZA673q6pftyLoU6OQ66ZUzyX7tlaqA==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3828,6 +3842,7 @@ packages: '@lynx-js/lynx-ui-sheet@3.130.0': resolution: {integrity: sha512-OSTgaX5xEJX0cjo9uwwrKcJS8wFZjFr7+yDew7gHK3bv7/FbJUVkJjhyb/bTGMsU+oyUZMUcqTgs1kgiokbPiQ==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3835,6 +3850,7 @@ packages: '@lynx-js/lynx-ui-sortable@3.130.0': resolution: {integrity: sha512-gdFKT6WJOaXSyaej28jGHaLqMu3E/FGNOcqgTXdEJmFbOgpvCABRdZ1flfQMd5tmCV64HXcN6KYJ7X3BBG6uTw==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3842,6 +3858,7 @@ packages: '@lynx-js/lynx-ui-swipe-action@3.130.0': resolution: {integrity: sha512-usfmTKBxVRsHAQQ3XvJOqqR0XRKc9+Gu+QjQdq7sa85m1xeFUocin0E8rBPuUNh82RAKC8NVgSw/olKWN/hi1Q==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3849,6 +3866,7 @@ packages: '@lynx-js/lynx-ui-swiper@3.130.0': resolution: {integrity: sha512-g/kKFEO4hj+pshuJPpugiTqAjiLEr1kaVjTh8GbD40NFo8X+V9tZw92BO1pfVhoRqffqC6gI4mqk7qXqDcqvbA==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3856,6 +3874,7 @@ packages: '@lynx-js/lynx-ui-switch@3.130.0': resolution: {integrity: sha512-AjbqyYAmFI902GrBhsaOsWQdUZjL5RdN8kA3zQfj6c5HzmYqfjWf6Q0HLJP5EoVKl97Inyl8hGlZjECGNEAqVw==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3863,6 +3882,7 @@ packages: '@lynx-js/lynx-ui@3.130.0': resolution: {integrity: sha512-SgzadpXCECf0dYKmrFytU7C+ihxO//z7pOirNMZppe0MOhWrv4Ld0jBt/yWfSv2rBjBRFIyo2xCxn/PM7yq0dw==} + version: 3.130.0 peerDependencies: '@lynx-js/react': '>=0.100.0' '@lynx-js/types': '*' @@ -3870,6 +3890,7 @@ packages: '@lynx-js/motion@0.0.2': resolution: {integrity: sha512-/oA8yBnWlGsIRxI3FGfdjxFOuKr5j3oLLmn5viW9JeuLRfIg2u+FM+UGiaAl1mZ9xfns1jamK+uax+cPwvW2dA==} + version: 0.0.2 peerDependencies: '@lynx-js/react': '*' '@lynx-js/types': '*' @@ -3899,8 +3920,9 @@ packages: '@lynx-js/type-element-api@0.0.3': resolution: {integrity: sha512-e8+V1aU9VD6fmVJhS1VoE5ZxUD2udhEtTTsGBj2jlxYNscND2V6fyYFGF/dUPN+s9EwRiB80vUY/Im8tYSsMWA==} - '@lynx-js/types@3.7.0': - resolution: {integrity: sha512-VEcz5HBJ8m938In1VJj2phR06cWyT0Tx+HnwBJrPINiuWPjN9YfrPl1lX87XWr3eMDhKZY+6F+5eFpJ7JFgjXw==} + '@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz': + resolution: {integrity: sha512-ubhYJ9XKoV5zq1vxowGumhkWjcsWAK2CWxirmbQdqlBGbdkLqm0iqIit7dJVqcvM0JEHp7/cDcnpFRTP5A7zRA==, tarball: file:vendor/lynx-js-types-3.10.0.tgz} + version: 3.10.0 '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -4612,7 +4634,7 @@ packages: '@rsdoctor/rspack-plugin@1.5.6': resolution: {integrity: sha512-IPi4byXW8WhEuB6Tu+yByc1yGQYZlvOpygkRFZzkxtDJZ1GrKjzUzeooX3NzlnXfBXg9Mu3t4Yiym8QWbLa8XA==} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': '*' peerDependenciesMeta: '@rspack/core': optional: true @@ -4623,7 +4645,7 @@ packages: '@rsdoctor/types@1.5.6': resolution: {integrity: sha512-ozLXrRSlUgIICjCs0xL2Nyp7S3JA6zXjrepKqQkcgFdeK70r76a4qYdQQp+bf09P/87uO8O1GOHYk6/R+qbmWw==} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': '*' webpack: 5.x peerDependenciesMeta: '@rspack/core': @@ -4647,6 +4669,11 @@ packages: typescript: optional: true + '@rspack/binding-darwin-arm64@1.7.11': + resolution: {integrity: sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==} + cpu: [arm64] + os: [darwin] + '@rspack/binding-darwin-arm64@1.7.9': resolution: {integrity: sha512-64dgstte0If5czi9bA/cpOe0ryY6wC9AIQRtyJ3DlOF6Tt+y9cKkmUoGu3V+WYaYIZRT7HNk8V7kL8amVjFTYw==} cpu: [arm64] @@ -4657,6 +4684,11 @@ packages: cpu: [arm64] os: [darwin] + '@rspack/binding-darwin-x64@1.7.11': + resolution: {integrity: sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA==} + cpu: [x64] + os: [darwin] + '@rspack/binding-darwin-x64@1.7.9': resolution: {integrity: sha512-2QSLs3w4rLy4UUGVnIlkt6IlIKOzR1e0RPsq2FYQW6s3p9JrwRCtOeHohyh7EJSqF54dtfhe9UZSAwba3LqH1Q==} cpu: [x64] @@ -4667,6 +4699,12 @@ packages: cpu: [x64] os: [darwin] + '@rspack/binding-linux-arm64-gnu@1.7.11': + resolution: {integrity: sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-arm64-gnu@1.7.9': resolution: {integrity: sha512-qhUGI/uVfvLmKWts4QkVHGL8yfUyJkblZs+OFD5Upa2y676EOsbQgWsCwX4xGB6Tv+TOzFP0SLh/UfO8ZfdE+w==} cpu: [arm64] @@ -4679,6 +4717,12 @@ packages: os: [linux] libc: [glibc] + '@rspack/binding-linux-arm64-musl@1.7.11': + resolution: {integrity: sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw==} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rspack/binding-linux-arm64-musl@1.7.9': resolution: {integrity: sha512-VjfmR1hgO9n3L6MaE5KG+DXSrrLVqHHOkVcOtS2LMq3bjMTwbBywY7ycymcLnX5KJsol8d3ZGYep6IfSOt3lFA==} cpu: [arm64] @@ -4691,6 +4735,12 @@ packages: os: [linux] libc: [musl] + '@rspack/binding-linux-x64-gnu@1.7.11': + resolution: {integrity: sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rspack/binding-linux-x64-gnu@1.7.9': resolution: {integrity: sha512-0kldV+3WTs/VYDWzxJ7K40hCW26IHtnk8xPK3whKoo1649rgeXXa0EdsU5P7hG8Ef5SWQjHHHZ/fuHYSO3Y6HA==} cpu: [x64] @@ -4703,6 +4753,12 @@ packages: os: [linux] libc: [glibc] + '@rspack/binding-linux-x64-musl@1.7.11': + resolution: {integrity: sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg==} + cpu: [x64] + os: [linux] + libc: [musl] + '@rspack/binding-linux-x64-musl@1.7.9': resolution: {integrity: sha512-Gi4872cFtc2d83FKATR6Qcf2VBa/tFCqffI/IwRRl6Hx5FulEBqx+tH7gAuRVF693vrbXNxK+FQ+k4iEsEJxrw==} cpu: [x64] @@ -4715,6 +4771,10 @@ packages: os: [linux] libc: [musl] + '@rspack/binding-wasm32-wasi@1.7.11': + resolution: {integrity: sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ==} + cpu: [wasm32] + '@rspack/binding-wasm32-wasi@1.7.9': resolution: {integrity: sha512-5QEzqo6EaolpuZmK6w/mgSueorgGnnzp7dJaAvBj6ECFIg/aLXhXXmWCWbxt7Ws2gKvG5/PgaxDqbUxYL51juA==} cpu: [wasm32] @@ -4723,6 +4783,11 @@ packages: resolution: {integrity: sha512-o6OatnNvb4kCzXbCaomhENGaCsO3naIyAqqErew90HeAwa1lfY3NhRfDLeIyuANQ+xqFl34/R7n8q3ZDx3nd4Q==} cpu: [wasm32] + '@rspack/binding-win32-arm64-msvc@1.7.11': + resolution: {integrity: sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA==} + cpu: [arm64] + os: [win32] + '@rspack/binding-win32-arm64-msvc@1.7.9': resolution: {integrity: sha512-MMqvcrIc8aOqTuHjWkjdzilvoZ3Hv07Od0Foogiyq3JMudsS3Wcmh7T1dFerGg19MOJcRUeEkrg2NQOMOQ6xDA==} cpu: [arm64] @@ -4733,6 +4798,11 @@ packages: cpu: [arm64] os: [win32] + '@rspack/binding-win32-ia32-msvc@1.7.11': + resolution: {integrity: sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw==} + cpu: [ia32] + os: [win32] + '@rspack/binding-win32-ia32-msvc@1.7.9': resolution: {integrity: sha512-4kYYS+NZ2CuNbKjq40yB/UEyB51o1PHj5wpr+Y943oOJXpEKWU2Q4vkF8VEohPEcnA9cKVotYCnqStme+02suA==} cpu: [ia32] @@ -4743,6 +4813,11 @@ packages: cpu: [ia32] os: [win32] + '@rspack/binding-win32-x64-msvc@1.7.11': + resolution: {integrity: sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q==} + cpu: [x64] + os: [win32] + '@rspack/binding-win32-x64-msvc@1.7.9': resolution: {integrity: sha512-1g+QyXXvs+838Un/4GaUvJfARDGHMCs15eXDYWBl5m/Skubyng8djWAgr6ag1+cVoJZXCPOvybTItcblWF3gbQ==} cpu: [x64] @@ -4753,6 +4828,9 @@ packages: cpu: [x64] os: [win32] + '@rspack/binding@1.7.11': + resolution: {integrity: sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q==} + '@rspack/binding@1.7.9': resolution: {integrity: sha512-A56e0NdfNwbOSJoilMkxzaPuVYaKCNn1shuiwWnCIBmhV9ix1n9S1XvquDjkGyv+gCdR1+zfJBOa5DMB7htLHw==} @@ -4763,7 +4841,16 @@ packages: resolution: {integrity: sha512-VwJIO8ZUGnU5v38O2Fp3KczoYVaDy/kA0rBWhoUNhfdlwyVx3ZiA1VnIYF3XtXNlur6YqT2g7Y+KA1cX8qK5zw==} hasBin: true peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': ^1.0.0-alpha || ^1.x + + '@rspack/core@1.7.11': + resolution: {integrity: sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew==} + engines: {node: '>=18.12.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true '@rspack/core@1.7.9': resolution: {integrity: sha512-VHuSKvRkuv42Ya+TxEGO0LE0r9+8P4tKGokmomj4R1f/Nu2vtS3yoaIMfC4fR6VuHGd3MZ+KTI0cNNwHfFcskw==} @@ -4790,7 +4877,7 @@ packages: resolution: {integrity: sha512-cwz0qc6iqqoJhyWqxP7ZqE2wyYNHkBMQUXxoQ0tNoZ4YNRkDyQ4HVJ/3oPSmMKbvJk/iJ16u7xZmwG6sK47q/A==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': '*' '@rspack/lite-tapable@1.1.0': resolution: {integrity: sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==} @@ -4864,7 +4951,7 @@ packages: '@rspack/test-tools@1.5.6': resolution: {integrity: sha512-CZGsCClGB3gElLryuk42dRKFz//X6b1nAA4UczojskBOfdsvjlQkfc/QFpM/tk4zRKtFw5QZoPTX3ZDn3uTYyQ==} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': '>=1.0.0' '@rspress/core@2.0.3': resolution: {integrity: sha512-a+JJFiALqMxGJBqR38/lkN6tas42UF4jRIhu6RilC/3DdqpfqR8j6jjQFOmqoNKo6ZGXW2W+i1Pscn6drvoG3w==} @@ -6504,7 +6591,7 @@ packages: resolution: {integrity: sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': 0.x || ^1.0.0 || ^2.0.0-0 webpack: ^5.27.0 peerDependenciesMeta: '@rspack/core': @@ -10112,7 +10199,7 @@ packages: resolution: {integrity: sha512-w6q+fRHourZ+e+xA1kcsF27iGM6jdB8teexYCfdUw0sYgcDNeZESnDNT9sUmmPm3ooziwUJXGwZJSTF3kOdBfA==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': 0.x || ^1.0.0 || ^2.0.0-0 node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 sass: ^1.3.0 sass-embedded: '*' @@ -10762,7 +10849,7 @@ packages: ts-checker-rspack-plugin@1.3.0: resolution: {integrity: sha512-89oK/BtApjdid1j9CGjPGiYry+EZBhsnTAM481/8ipgr/y2IOgCbW1HPnan+fs5FnzlpUgf9dWGNZ4Ayw3Bd8A==} peerDependencies: - '@rspack/core': 1.7.9 + '@rspack/core': ^1.0.0 || ^2.0.0-0 typescript: '>=3.8.0' peerDependenciesMeta: '@rspack/core': @@ -12814,201 +12901,201 @@ snapshots: dependencies: '@lezer/common': 1.5.2 - '@lynx-js/gesture-runtime@2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)': + '@lynx-js/gesture-runtime@2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)': dependencies: '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@lynx-js/internal-preact@10.29.1-20260424024911-12b794f': {} '@lynx-js/lynx-core@0.1.3': {} - '@lynx-js/lynx-ui-button@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-button@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-checkbox@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-checkbox@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-common@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-common@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0) + '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz) '@lynx-js/react': link:packages/react '@lynx-js/react-use': 0.0.7(@lynx-js/react@packages+react)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-dialog@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-dialog@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-overlay': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-overlay': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-draggable@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-draggable@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react '@lynx-js/react-use': 0.0.7(@lynx-js/react@packages+react)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-feed-list@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-feed-list@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-list': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-list': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-form@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-form@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-checkbox': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-input': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-radio-group': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-switch': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28) + '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-checkbox': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-input': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-radio-group': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-switch': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-input@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-input@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-scroll-view': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-scroll-view': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-lazy-component@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-lazy-component@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-list@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-list@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-overlay@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-overlay@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-popover@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-popover@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-overlay': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-overlay': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-presence@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-presence@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-radio-group@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-radio-group@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-scroll-view@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-scroll-view@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-lazy-component': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-lazy-component': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-sheet@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-sheet@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-dialog': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-overlay': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/motion': 0.0.2(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-dialog': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-overlay': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/motion': 0.0.2(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 transitivePeerDependencies: @@ -13016,83 +13103,83 @@ snapshots: - react - react-dom - '@lynx-js/lynx-ui-sortable@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-sortable@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-draggable': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-draggable': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-swipe-action@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-swipe-action@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/gesture-runtime': 2.1.1(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-swiper@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/lynx-ui-swiper@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) '@lynx-js/react': link:packages/react '@lynx-js/react-use': 0.0.7(@lynx-js/react@packages+react)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - react - react-dom - '@lynx-js/lynx-ui-switch@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)': + '@lynx-js/lynx-ui-switch@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)': dependencies: '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 clsx: 2.1.1 - '@lynx-js/lynx-ui@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': - dependencies: - '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-checkbox': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-dialog': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-draggable': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-feed-list': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-form': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-input': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-lazy-component': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-list': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-popover': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-radio-group': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-scroll-view': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-sheet': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-sortable': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-swipe-action': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-swiper': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) - '@lynx-js/lynx-ui-switch': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(@types/react@18.3.28) + '@lynx-js/lynx-ui@3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + dependencies: + '@lynx-js/lynx-ui-button': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-checkbox': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-common': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-dialog': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-draggable': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-feed-list': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-form': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-input': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-lazy-component': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-list': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-popover': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-presence': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-radio-group': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-scroll-view': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-sheet': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-sortable': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-swipe-action': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-swiper': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.5))(react@19.2.5) + '@lynx-js/lynx-ui-switch': 3.130.0(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(@types/react@18.3.28) '@lynx-js/react': link:packages/react - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz '@types/react': 18.3.28 transitivePeerDependencies: - '@emotion/is-prop-valid' - react - react-dom - '@lynx-js/motion@0.0.2(@lynx-js/react@packages+react)(@lynx-js/types@3.7.0)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': + '@lynx-js/motion@0.0.2(@lynx-js/react@packages+react)(@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz)(react-dom@19.2.4(react@19.2.5))(react@19.2.5)': dependencies: '@lynx-js/react': link:packages/react framer-motion: 12.23.12(react-dom@19.2.4(react@19.2.5))(react@19.2.5) motion-dom: 12.23.12 motion-utils: 12.23.6 optionalDependencies: - '@lynx-js/types': 3.7.0 + '@lynx-js/types': file:vendor/lynx-js-types-3.10.0.tgz transitivePeerDependencies: - '@emotion/is-prop-valid' - react @@ -13121,7 +13208,7 @@ snapshots: '@lynx-js/type-element-api@0.0.3': {} - '@lynx-js/types@3.7.0': + '@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz': dependencies: csstype: 3.1.3 @@ -13722,7 +13809,7 @@ snapshots: '@rsbuild/core@1.7.5': dependencies: - '@rspack/core': 1.7.9(@swc/helpers@0.5.21) + '@rspack/core': 1.7.11(@swc/helpers@0.5.21) '@rspack/lite-tapable': 1.1.0 '@swc/helpers': 0.5.21 core-js: 3.47.0 @@ -13738,13 +13825,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13784,9 +13871,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13815,6 +13902,15 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 + '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + dependencies: + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + deepmerge: 4.3.1 + loader-utils: 2.0.4 + postcss: 8.5.6 + reduce-configs: 1.1.1 + sass-embedded: 1.97.3 + '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13823,25 +13919,12 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - deepmerge: 4.3.1 - json5: 2.2.3 - reduce-configs: 1.1.1 - ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) - optionalDependencies: - '@rsbuild/core': 1.7.5 - transitivePeerDependencies: - - '@rspack/core' - - tslib - - typescript - - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 json5: 2.2.3 reduce-configs: 1.1.1 - ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + ts-checker-rspack-plugin: 1.3.0(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) transitivePeerDependencies: @@ -13853,15 +13936,19 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + optionalDependencies: + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsdoctor/client@1.5.6': {} - '@rsdoctor/core@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/core@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@1.7.5) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) '@rspack/resolver': 0.2.8(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) browserslist-load-config: 1.0.1 es-toolkit: 1.45.1 @@ -13879,13 +13966,13 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@1.7.5) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) '@rspack/resolver': 0.2.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) browserslist-load-config: 1.0.1 es-toolkit: 1.45.1 @@ -13903,10 +13990,10 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/graph@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/graph@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) es-toolkit: 1.45.1 path-browserify: 1.0.1 source-map: 0.7.6 @@ -13914,15 +14001,15 @@ snapshots: - '@rspack/core' - webpack - '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: - '@rsdoctor/core': 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/core': 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) optionalDependencies: - '@rspack/core': 1.7.9(@swc/helpers@0.5.21) + '@rspack/core': 1.7.11(@swc/helpers@0.5.21) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -13932,15 +14019,15 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: - '@rsdoctor/core': 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/core': 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) optionalDependencies: - '@rspack/core': 1.7.9(@swc/helpers@0.5.21) + '@rspack/core': 1.7.11(@swc/helpers@0.5.21) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -13950,12 +14037,12 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/sdk@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/sdk@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@rsdoctor/client': 1.5.6 - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) launch-editor: 2.13.2 safer-buffer: 2.1.2 socket.io: 4.8.1 @@ -13967,20 +14054,20 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/types@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/types@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@types/connect': 3.4.38 '@types/estree': 1.0.5 '@types/tapable': 2.3.0 source-map: 0.7.6 optionalDependencies: - '@rspack/core': 1.7.9(@swc/helpers@0.5.21) + '@rspack/core': 1.7.11(@swc/helpers@0.5.21) webpack: 5.105.2 - '@rsdoctor/utils@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/utils@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@babel/code-frame': 7.26.2 - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) '@types/estree': 1.0.5 acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) @@ -14008,42 +14095,65 @@ snapshots: transitivePeerDependencies: - '@typescript/native-preview' + '@rspack/binding-darwin-arm64@1.7.11': + optional: true + '@rspack/binding-darwin-arm64@1.7.9': optional: true '@rspack/binding-darwin-arm64@2.0.0-beta.0': optional: true + '@rspack/binding-darwin-x64@1.7.11': + optional: true + '@rspack/binding-darwin-x64@1.7.9': optional: true '@rspack/binding-darwin-x64@2.0.0-beta.0': optional: true + '@rspack/binding-linux-arm64-gnu@1.7.11': + optional: true + '@rspack/binding-linux-arm64-gnu@1.7.9': optional: true '@rspack/binding-linux-arm64-gnu@2.0.0-beta.0': optional: true + '@rspack/binding-linux-arm64-musl@1.7.11': + optional: true + '@rspack/binding-linux-arm64-musl@1.7.9': optional: true '@rspack/binding-linux-arm64-musl@2.0.0-beta.0': optional: true + '@rspack/binding-linux-x64-gnu@1.7.11': + optional: true + '@rspack/binding-linux-x64-gnu@1.7.9': optional: true '@rspack/binding-linux-x64-gnu@2.0.0-beta.0': optional: true + '@rspack/binding-linux-x64-musl@1.7.11': + optional: true + '@rspack/binding-linux-x64-musl@1.7.9': optional: true '@rspack/binding-linux-x64-musl@2.0.0-beta.0': optional: true + '@rspack/binding-wasm32-wasi@1.7.11': + dependencies: + '@napi-rs/wasm-runtime': 1.0.7 + optional: true + '@rspack/binding-wasm32-wasi@1.7.9': dependencies: '@napi-rs/wasm-runtime': 1.0.7 @@ -14054,24 +14164,46 @@ snapshots: '@napi-rs/wasm-runtime': 1.0.7 optional: true + '@rspack/binding-win32-arm64-msvc@1.7.11': + optional: true + '@rspack/binding-win32-arm64-msvc@1.7.9': optional: true '@rspack/binding-win32-arm64-msvc@2.0.0-beta.0': optional: true + '@rspack/binding-win32-ia32-msvc@1.7.11': + optional: true + '@rspack/binding-win32-ia32-msvc@1.7.9': optional: true '@rspack/binding-win32-ia32-msvc@2.0.0-beta.0': optional: true + '@rspack/binding-win32-x64-msvc@1.7.11': + optional: true + '@rspack/binding-win32-x64-msvc@1.7.9': optional: true '@rspack/binding-win32-x64-msvc@2.0.0-beta.0': optional: true + '@rspack/binding@1.7.11': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.7.11 + '@rspack/binding-darwin-x64': 1.7.11 + '@rspack/binding-linux-arm64-gnu': 1.7.11 + '@rspack/binding-linux-arm64-musl': 1.7.11 + '@rspack/binding-linux-x64-gnu': 1.7.11 + '@rspack/binding-linux-x64-musl': 1.7.11 + '@rspack/binding-wasm32-wasi': 1.7.11 + '@rspack/binding-win32-arm64-msvc': 1.7.11 + '@rspack/binding-win32-ia32-msvc': 1.7.11 + '@rspack/binding-win32-x64-msvc': 1.7.11 + '@rspack/binding@1.7.9': optionalDependencies: '@rspack/binding-darwin-arm64': 1.7.9 @@ -14115,6 +14247,14 @@ snapshots: - webpack - webpack-cli + '@rspack/core@1.7.11(@swc/helpers@0.5.21)': + dependencies: + '@module-federation/runtime-tools': 0.22.0 + '@rspack/binding': 1.7.11 + '@rspack/lite-tapable': 1.1.0 + optionalDependencies: + '@swc/helpers': 0.5.21 + '@rspack/core@1.7.9(@swc/helpers@0.5.21)': dependencies: '@module-federation/runtime-tools': 0.22.0 @@ -14271,6 +14411,45 @@ snapshots: - utf-8-validate - webpack-cli + '@rspack/test-tools@1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))': + dependencies: + '@babel/generator': 7.28.3 + '@babel/parser': 7.28.4 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) + cross-env: 10.1.0 + csv-to-markdown-table: 1.6.3 + deepmerge: 4.3.1 + filenamify: 4.3.0 + fs-extra: 11.3.3 + glob: 11.1.0 + graceful-fs: 4.2.11 + iconv-lite: 0.6.3 + jest-diff: 29.7.0 + jest-snapshot: 29.7.0 + jsdom: 26.1.0 + loader-utils: 2.0.4 + memfs: 4.38.2 + path-serializer: 0.5.1 + pretty-format: 29.7.0 + rimraf: 5.0.10 + source-map: 0.7.6 + terser-webpack-plugin: 5.3.16(webpack@5.99.9) + wast-loader: 1.14.1 + webpack: 5.99.9 + webpack-merge: 6.0.1 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - bufferutil + - canvas + - esbuild + - supports-color + - uglify-js + - utf-8-validate + - webpack-cli + '@rspress/core@2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0)': dependencies: '@mdx-js/mdx': 3.1.1 @@ -16066,6 +16245,20 @@ snapshots: '@rspack/core': 1.7.9(@swc/helpers@0.5.21) webpack: 5.105.2 + css-loader@7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2): + dependencies: + icss-utils: 5.1.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) + postcss-modules-local-by-default: 4.0.5(postcss@8.5.6) + postcss-modules-scope: 3.2.0(postcss@8.5.6) + postcss-modules-values: 4.0.0(postcss@8.5.6) + postcss-value-parser: 4.2.0 + semver: 7.7.4 + optionalDependencies: + '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) + webpack: 5.105.2 + css-minimizer-webpack-plugin@7.0.2(lightningcss@1.31.1)(webpack@5.105.2): dependencies: '@jridgewell/trace-mapping': 0.3.29 @@ -20147,10 +20340,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20170,15 +20363,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) @@ -21073,7 +21266,7 @@ snapshots: dependencies: typescript: 5.9.3 - ts-checker-rspack-plugin@1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3): + ts-checker-rspack-plugin@1.3.0(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3): dependencies: '@rspack/lite-tapable': 1.1.0 chokidar: 3.6.0 @@ -21081,7 +21274,7 @@ snapshots: picocolors: 1.1.1 typescript: 5.9.3 optionalDependencies: - '@rspack/core': 1.7.9(@swc/helpers@0.5.21) + '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) transitivePeerDependencies: - tslib diff --git a/vendor/lynx-js-types-3.10.0.tgz b/vendor/lynx-js-types-3.10.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..055b2ab183bddbcf114408bac9662a526d5e310a GIT binary patch literal 49773 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 literal 0 HcmV?d00001 From f7a79ee7be92edb83c64e4f16f545f5e8a3c5374 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 21:47:27 +0800 Subject: [PATCH 05/43] feat(template-plugin): emit FetchBundle-mode customSections for lazy bundles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure lazy-bundle binary output when the FetchBundle fetcher is selected (default; fall back via REACT_LAZY_BUNDLE_FETCHER=QueryComponent): - customSections['main-thread'] ← MTS payload, encoding: 'JsBytecode' (compiled to QuickJS bytecode by the lepus encoder; first-screen evaluates bytecode directly) - customSections['background'] ← first real BTS chunk (entry) - customSections['CSS'] ← parsed style ruleList, encoding: 'CSS' - manifest ← remaining BTS chunks (vendor / async), served via lynx.requireModuleAsync - lepusCode = undefined ← MTS moved to customSection - css.cssMap = {} ← CSS moved to customSection The legacy /app-service.js loader stub is dropped — under FetchBundle the platform evaluates the entry chunk directly via loadScript('background'), so the stub is dead weight. React runtime side: lazy-bundle.ts MTS path now also calls __LoadStyleSheet('CSS', url) + __AdoptStyleSheet + __FlushElementTree after loadScript so the lazy bundle's styles are adopted at first-screen. Misc: - WebEncodePlugin: emit empty {} for missing lepusCode (the web encoder's encodeStringMap calls Object.entries which throws on undefined). - types.d.ts: declare __LoadStyleSheet / __AdoptStyleSheet (since 3.7). - rstest.config.ts: force REACT_LAZY_BUNDLE_FETCHER=QueryComponent inside the test process so existing fixtures (which assert legacy lepusCode + manifest shape) keep passing. FetchBundle-specific tests should be written separately and override this. --- .../runtime/src/snapshot/lynx/lazy-bundle.ts | 5 + packages/react/runtime/types/types.d.ts | 6 + .../template-webpack-plugin/rstest.config.ts | 1 + .../src/LynxTemplatePlugin.ts | 112 ++++++++++++++++-- .../src/WebEncodePlugin.ts | 12 +- 5 files changed, 121 insertions(+), 15 deletions(-) diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index 97fbfb4beb..8ae739f2ad 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -61,6 +61,7 @@ const LYNX_LAZY_SYNC_TIMEOUT_SECONDS = 5; const SECTION_MAIN_THREAD = 'main-thread'; const SECTION_BACKGROUND = 'background'; +const SECTION_CSS = 'CSS'; /** * Load dynamic component from source. Designed to be used with `lazy`. @@ -172,6 +173,10 @@ export const loadLazyBundle: < } catch { return new Promise(() => {}); } + const styleSheet = __LoadStyleSheet(SECTION_CSS, response.url); + if (styleSheet !== null) { + __AdoptStyleSheet(styleSheet); + } const r: Promise = Promise.resolve(result); r.then = makeSyncThen(result); return r; diff --git a/packages/react/runtime/types/types.d.ts b/packages/react/runtime/types/types.d.ts index be6f8c232e..6dcad2e982 100644 --- a/packages/react/runtime/types/types.d.ts +++ b/packages/react/runtime/types/types.d.ts @@ -106,6 +106,12 @@ declare global { element: FiberElement, options: FlushOptions, ): void; + declare function __LoadStyleSheet( + sectionName: string, + bundleUrl: string, + ): StyleSheet | null; + declare function __AdoptStyleSheet(styleSheet: StyleSheet): void; + declare interface StyleSheet {} declare function __UpdateListCallbacks( list: FiberElement, componentAtIndex: ComponentAtIndexCallback | null, diff --git a/packages/webpack/template-webpack-plugin/rstest.config.ts b/packages/webpack/template-webpack-plugin/rstest.config.ts index 2dbca041b3..f4186822e0 100644 --- a/packages/webpack/template-webpack-plugin/rstest.config.ts +++ b/packages/webpack/template-webpack-plugin/rstest.config.ts @@ -17,6 +17,7 @@ const config: Parameters[0] = { ], env: { DEBUG: 'rspeedy', + REACT_LAZY_BUNDLE_FETCHER: 'QueryComponent', }, }; diff --git a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts index fa8dcf9df3..6092e37015 100644 --- a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts +++ b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts @@ -37,17 +37,18 @@ export type OriginManifest = Record; + manifest?: Record | undefined; compilerOptions: Record; lepusCode: { root: string | undefined; lepusChunk: Record; filename: string | undefined; - }; + } | undefined; // `customSections` option only takes effect on Lynx >= 2.16. customSections: Record; + encoding?: 'JsBytecode' | 'CSS'; + content: string | Record | undefined; }>; /** * Element template data used by encoders that support element template output. @@ -329,6 +330,7 @@ interface EncodeRawData { // `customSections` option only takes effect on Lynx >= 2.16. customSections: Record; }>; sourceContent: { @@ -482,6 +484,19 @@ interface Hash { digest(encoding?: string): string | Buffer; } +const SECTION_MAIN_THREAD = 'main-thread'; +const SECTION_BACKGROUND = 'background'; +const SECTION_CSS = 'CSS'; + +const __LAZY_BUNDLE_FETCHER__ = process.env['REACT_LAZY_BUNDLE_FETCHER'] + ?? 'FetchBundle'; + +interface CustomSectionEntry { + type?: 'lazy'; + encoding?: 'JsBytecode' | 'CSS'; + content: string | Record; +} + class LynxTemplatePluginImpl { name = 'LynxTemplatePlugin'; @@ -872,23 +887,44 @@ class LynxTemplatePluginImpl { const { lepusCode, css } = encodeData; + const lepusChunk = Object.fromEntries( + lepusCode.chunks.map(asset => { + return [asset.name, asset.source.source().toString()]; + }), + ); + + const isFetchBundleLazy = isAsync + && __LAZY_BUNDLE_FETCHER__ === 'FetchBundle'; + const fetchBundleSplit = isFetchBundleLazy + ? this.#buildLazyBundleFetchBundleSections( + lepusCode.root, + encodeData.manifest, + encodeData.css.chunks, + ) + : null; + const resolvedEncodeOptions: EncodeOptions = { ...encodeData, css: { ...css, + cssMap: fetchBundleSplit ? {} : css.cssMap, + cssSource: fetchBundleSplit ? {} : css.cssSource, chunks: undefined, contentMap: undefined, }, - lepusCode: { + lepusCode: fetchBundleSplit ? undefined : { // TODO: support multiple lepus chunks root: lepusCode.root?.source.source().toString(), - lepusChunk: Object.fromEntries( - lepusCode.chunks.map(asset => { - return [asset.name, asset.source.source().toString()]; - }), - ), + lepusChunk, filename: lepusCode.filename, }, + manifest: fetchBundleSplit + ? fetchBundleSplit.remainingManifest + : encodeData.manifest, + customSections: { + ...encodeData.customSections, + ...(fetchBundleSplit ? fetchBundleSplit.sections : {}), + }, }; const { RawSource } = compiler.webpack.sources; @@ -903,7 +939,7 @@ class LynxTemplatePluginImpl { JSON.stringify(resolvedEncodeOptions, null, 2), ), ); - Object.entries(resolvedEncodeOptions.lepusCode.lepusChunk).forEach( + Object.entries(lepusChunk).forEach( ([name, content]) => { compilation.emitAsset( path.posix.format({ @@ -961,6 +997,62 @@ class LynxTemplatePluginImpl { } } + #buildLazyBundleFetchBundleSections( + mainThreadAsset: Asset | undefined, + manifest: Record, + cssAssets: Asset[], + ): { + sections: Record; + remainingManifest: Record; + } { + const { cssPlugins, enableCSSSelector } = this.#options; + const sections: Record = {}; + + if (mainThreadAsset) { + sections[SECTION_MAIN_THREAD] = { + encoding: 'JsBytecode', + content: mainThreadAsset.source.source().toString(), + }; + } + + const remainingManifest: Record = {}; + let entryChunk: [string, string] | undefined; + for (const [name, content] of Object.entries(manifest)) { + // Drop the legacy `app-service.js` loader stub — see method doc. + // The asset key is always exactly `/app-service.js` in this codepath, + // so a literal compare is enough. + if (name === '/app-service.js') { + continue; + } + if (!entryChunk) { + entryChunk = [name, content]; + continue; + } + remainingManifest[name] = content; + } + + if (entryChunk) { + sections[SECTION_BACKGROUND] = { content: entryChunk[1] }; + } + + // Single CSS section under the fixed key `'CSS'`. Lazy bundles are + // expected to have at most one CSS chunk; only the first is embedded. + const firstCss = cssAssets[0]; + if (firstCss) { + const ruleList = cssChunksToMap( + [firstCss.source.source().toString()], + cssPlugins, + enableCSSSelector, + ).cssMap[0] ?? []; + sections[SECTION_CSS] = { + encoding: 'CSS', + content: { ruleList }, + }; + } + + return { sections, remainingManifest }; + } + /** * Return all chunks from the compilation result which match the exclude and include filters */ diff --git a/packages/webpack/template-webpack-plugin/src/WebEncodePlugin.ts b/packages/webpack/template-webpack-plugin/src/WebEncodePlugin.ts index 8462ba967d..4c8dbf8c5a 100644 --- a/packages/webpack/template-webpack-plugin/src/WebEncodePlugin.ts +++ b/packages/webpack/template-webpack-plugin/src/WebEncodePlugin.ts @@ -95,11 +95,13 @@ export class WebEncodePlugin { cardType: encodeOptions['cardType'] as string, appType: encodeOptions['appType'] as string, pageConfig: encodeOptions['pageConfig'] as Record, - lepusCode: { - // flatten the lepusCode to a single object - ...encodeOptions.lepusCode.lepusChunk, - root: encodeOptions.lepusCode.root!, - }, + lepusCode: encodeOptions.lepusCode + ? { + // flatten the lepusCode to a single object + ...encodeOptions.lepusCode.lepusChunk, + root: encodeOptions.lepusCode.root!, + } + : {}, customSections: encodeOptions.customSections ?? {}, }; if (encodeOptions.elementTemplate !== undefined) { From 453d054ce599d2f10225f7705b12779bad66cf1d Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 21:49:39 +0800 Subject: [PATCH 06/43] chore: move @lynx-js/types override from package.json to pnpm-workspace.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pnpm.overrides` in `package.json` and the `overrides:` block in `pnpm-workspace.yaml` are mutually exclusive — when both exist, pnpm honors the `package.json` one and silently ignores the workspace one, which here pins the cataloged `@rspack/core` version. The clash showed up as `@rspack/core 1.7.9 vs 1.7.11` type-mismatch errors after `pnpm install`. Move the local `@lynx-js/types: file:./vendor/...tgz` override into `pnpm-workspace.yaml` so all overrides live in one place and the cataloged `@rspack/core` pin keeps working. --- package.json | 3 - pnpm-lock.yaml | 228 +++++++++++--------------------------------- pnpm-workspace.yaml | 4 + 3 files changed, 61 insertions(+), 174 deletions(-) diff --git a/package.json b/package.json index ab7ec7ef2d..88a37cc038 100644 --- a/package.json +++ b/package.json @@ -71,9 +71,6 @@ "allowedVersions": { "rsbuild-plugin-tailwindcss>tailwindcss": "^3 || ^4" } - }, - "overrides": { - "@lynx-js/types": "file:./vendor/lynx-js-types-3.10.0.tgz" } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3026bd33c..b2688a66f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,10 @@ catalogs: version: 0.2.0 overrides: + '@rspack/core@^1': 1.7.9 + '@rsbuild/core@1>@rspack/core': 1.7.9 + '@rsdoctor/rspack-plugin>@rspack/core': 1.7.9 + '@rsdoctor/types>@rspack/core': 1.7.9 '@lynx-js/types': file:./vendor/lynx-js-types-3.10.0.tgz packageExtensionsChecksum: sha256-BUwt5m2tRMyYg9pgFVHNTHCYEBuM0/o7IdJqk+vWTGs= @@ -1084,7 +1088,7 @@ importers: version: 1.1.1(@rsbuild/core@1.7.5)(lightningcss@1.31.1)(webpack@5.105.2) '@rsdoctor/rspack-plugin': specifier: ~1.5.6 - version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) typescript: specifier: 5.1.6 - 5.9.x version: 5.9.3 @@ -1100,7 +1104,7 @@ importers: version: 12.3.0(patch_hash=926ba262ec682d27369f1a8648a0dfb657fb5f1b28539ca3628d292276c91c3d)(rollup@4.34.9)(tslib@2.8.1)(typescript@5.9.3) '@rsdoctor/core': specifier: ~1.5.6 - version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) chokidar: specifier: ^4.0.3 version: 4.0.3 @@ -1170,7 +1174,7 @@ importers: version: link:../core '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -1792,7 +1796,7 @@ importers: version: 1.7.5 '@rsdoctor/rspack-plugin': specifier: ~1.5.6 - version: 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -2288,7 +2292,7 @@ importers: version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) @@ -4634,7 +4638,7 @@ packages: '@rsdoctor/rspack-plugin@1.5.6': resolution: {integrity: sha512-IPi4byXW8WhEuB6Tu+yByc1yGQYZlvOpygkRFZzkxtDJZ1GrKjzUzeooX3NzlnXfBXg9Mu3t4Yiym8QWbLa8XA==} peerDependencies: - '@rspack/core': '*' + '@rspack/core': 1.7.9 peerDependenciesMeta: '@rspack/core': optional: true @@ -4645,7 +4649,7 @@ packages: '@rsdoctor/types@1.5.6': resolution: {integrity: sha512-ozLXrRSlUgIICjCs0xL2Nyp7S3JA6zXjrepKqQkcgFdeK70r76a4qYdQQp+bf09P/87uO8O1GOHYk6/R+qbmWw==} peerDependencies: - '@rspack/core': '*' + '@rspack/core': 1.7.9 webpack: 5.x peerDependenciesMeta: '@rspack/core': @@ -4669,11 +4673,6 @@ packages: typescript: optional: true - '@rspack/binding-darwin-arm64@1.7.11': - resolution: {integrity: sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==} - cpu: [arm64] - os: [darwin] - '@rspack/binding-darwin-arm64@1.7.9': resolution: {integrity: sha512-64dgstte0If5czi9bA/cpOe0ryY6wC9AIQRtyJ3DlOF6Tt+y9cKkmUoGu3V+WYaYIZRT7HNk8V7kL8amVjFTYw==} cpu: [arm64] @@ -4684,11 +4683,6 @@ packages: cpu: [arm64] os: [darwin] - '@rspack/binding-darwin-x64@1.7.11': - resolution: {integrity: sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA==} - cpu: [x64] - os: [darwin] - '@rspack/binding-darwin-x64@1.7.9': resolution: {integrity: sha512-2QSLs3w4rLy4UUGVnIlkt6IlIKOzR1e0RPsq2FYQW6s3p9JrwRCtOeHohyh7EJSqF54dtfhe9UZSAwba3LqH1Q==} cpu: [x64] @@ -4699,12 +4693,6 @@ packages: cpu: [x64] os: [darwin] - '@rspack/binding-linux-arm64-gnu@1.7.11': - resolution: {integrity: sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA==} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-arm64-gnu@1.7.9': resolution: {integrity: sha512-qhUGI/uVfvLmKWts4QkVHGL8yfUyJkblZs+OFD5Upa2y676EOsbQgWsCwX4xGB6Tv+TOzFP0SLh/UfO8ZfdE+w==} cpu: [arm64] @@ -4717,12 +4705,6 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-arm64-musl@1.7.11': - resolution: {integrity: sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw==} - cpu: [arm64] - os: [linux] - libc: [musl] - '@rspack/binding-linux-arm64-musl@1.7.9': resolution: {integrity: sha512-VjfmR1hgO9n3L6MaE5KG+DXSrrLVqHHOkVcOtS2LMq3bjMTwbBywY7ycymcLnX5KJsol8d3ZGYep6IfSOt3lFA==} cpu: [arm64] @@ -4735,12 +4717,6 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-linux-x64-gnu@1.7.11': - resolution: {integrity: sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ==} - cpu: [x64] - os: [linux] - libc: [glibc] - '@rspack/binding-linux-x64-gnu@1.7.9': resolution: {integrity: sha512-0kldV+3WTs/VYDWzxJ7K40hCW26IHtnk8xPK3whKoo1649rgeXXa0EdsU5P7hG8Ef5SWQjHHHZ/fuHYSO3Y6HA==} cpu: [x64] @@ -4753,12 +4729,6 @@ packages: os: [linux] libc: [glibc] - '@rspack/binding-linux-x64-musl@1.7.11': - resolution: {integrity: sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg==} - cpu: [x64] - os: [linux] - libc: [musl] - '@rspack/binding-linux-x64-musl@1.7.9': resolution: {integrity: sha512-Gi4872cFtc2d83FKATR6Qcf2VBa/tFCqffI/IwRRl6Hx5FulEBqx+tH7gAuRVF693vrbXNxK+FQ+k4iEsEJxrw==} cpu: [x64] @@ -4771,10 +4741,6 @@ packages: os: [linux] libc: [musl] - '@rspack/binding-wasm32-wasi@1.7.11': - resolution: {integrity: sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ==} - cpu: [wasm32] - '@rspack/binding-wasm32-wasi@1.7.9': resolution: {integrity: sha512-5QEzqo6EaolpuZmK6w/mgSueorgGnnzp7dJaAvBj6ECFIg/aLXhXXmWCWbxt7Ws2gKvG5/PgaxDqbUxYL51juA==} cpu: [wasm32] @@ -4783,11 +4749,6 @@ packages: resolution: {integrity: sha512-o6OatnNvb4kCzXbCaomhENGaCsO3naIyAqqErew90HeAwa1lfY3NhRfDLeIyuANQ+xqFl34/R7n8q3ZDx3nd4Q==} cpu: [wasm32] - '@rspack/binding-win32-arm64-msvc@1.7.11': - resolution: {integrity: sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA==} - cpu: [arm64] - os: [win32] - '@rspack/binding-win32-arm64-msvc@1.7.9': resolution: {integrity: sha512-MMqvcrIc8aOqTuHjWkjdzilvoZ3Hv07Od0Foogiyq3JMudsS3Wcmh7T1dFerGg19MOJcRUeEkrg2NQOMOQ6xDA==} cpu: [arm64] @@ -4798,11 +4759,6 @@ packages: cpu: [arm64] os: [win32] - '@rspack/binding-win32-ia32-msvc@1.7.11': - resolution: {integrity: sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw==} - cpu: [ia32] - os: [win32] - '@rspack/binding-win32-ia32-msvc@1.7.9': resolution: {integrity: sha512-4kYYS+NZ2CuNbKjq40yB/UEyB51o1PHj5wpr+Y943oOJXpEKWU2Q4vkF8VEohPEcnA9cKVotYCnqStme+02suA==} cpu: [ia32] @@ -4813,11 +4769,6 @@ packages: cpu: [ia32] os: [win32] - '@rspack/binding-win32-x64-msvc@1.7.11': - resolution: {integrity: sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q==} - cpu: [x64] - os: [win32] - '@rspack/binding-win32-x64-msvc@1.7.9': resolution: {integrity: sha512-1g+QyXXvs+838Un/4GaUvJfARDGHMCs15eXDYWBl5m/Skubyng8djWAgr6ag1+cVoJZXCPOvybTItcblWF3gbQ==} cpu: [x64] @@ -4828,9 +4779,6 @@ packages: cpu: [x64] os: [win32] - '@rspack/binding@1.7.11': - resolution: {integrity: sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q==} - '@rspack/binding@1.7.9': resolution: {integrity: sha512-A56e0NdfNwbOSJoilMkxzaPuVYaKCNn1shuiwWnCIBmhV9ix1n9S1XvquDjkGyv+gCdR1+zfJBOa5DMB7htLHw==} @@ -4841,16 +4789,7 @@ packages: resolution: {integrity: sha512-VwJIO8ZUGnU5v38O2Fp3KczoYVaDy/kA0rBWhoUNhfdlwyVx3ZiA1VnIYF3XtXNlur6YqT2g7Y+KA1cX8qK5zw==} hasBin: true peerDependencies: - '@rspack/core': ^1.0.0-alpha || ^1.x - - '@rspack/core@1.7.11': - resolution: {integrity: sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew==} - engines: {node: '>=18.12.0'} - peerDependencies: - '@swc/helpers': '>=0.5.1' - peerDependenciesMeta: - '@swc/helpers': - optional: true + '@rspack/core': 1.7.9 '@rspack/core@1.7.9': resolution: {integrity: sha512-VHuSKvRkuv42Ya+TxEGO0LE0r9+8P4tKGokmomj4R1f/Nu2vtS3yoaIMfC4fR6VuHGd3MZ+KTI0cNNwHfFcskw==} @@ -4877,7 +4816,7 @@ packages: resolution: {integrity: sha512-cwz0qc6iqqoJhyWqxP7ZqE2wyYNHkBMQUXxoQ0tNoZ4YNRkDyQ4HVJ/3oPSmMKbvJk/iJ16u7xZmwG6sK47q/A==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': '*' + '@rspack/core': 1.7.9 '@rspack/lite-tapable@1.1.0': resolution: {integrity: sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==} @@ -4951,7 +4890,7 @@ packages: '@rspack/test-tools@1.5.6': resolution: {integrity: sha512-CZGsCClGB3gElLryuk42dRKFz//X6b1nAA4UczojskBOfdsvjlQkfc/QFpM/tk4zRKtFw5QZoPTX3ZDn3uTYyQ==} peerDependencies: - '@rspack/core': '>=1.0.0' + '@rspack/core': 1.7.9 '@rspress/core@2.0.3': resolution: {integrity: sha512-a+JJFiALqMxGJBqR38/lkN6tas42UF4jRIhu6RilC/3DdqpfqR8j6jjQFOmqoNKo6ZGXW2W+i1Pscn6drvoG3w==} @@ -6591,7 +6530,7 @@ packages: resolution: {integrity: sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': 0.x || ^1.0.0 || ^2.0.0-0 + '@rspack/core': 1.7.9 webpack: ^5.27.0 peerDependenciesMeta: '@rspack/core': @@ -10199,7 +10138,7 @@ packages: resolution: {integrity: sha512-w6q+fRHourZ+e+xA1kcsF27iGM6jdB8teexYCfdUw0sYgcDNeZESnDNT9sUmmPm3ooziwUJXGwZJSTF3kOdBfA==} engines: {node: '>= 18.12.0'} peerDependencies: - '@rspack/core': 0.x || ^1.0.0 || ^2.0.0-0 + '@rspack/core': 1.7.9 node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 sass: ^1.3.0 sass-embedded: '*' @@ -10849,7 +10788,7 @@ packages: ts-checker-rspack-plugin@1.3.0: resolution: {integrity: sha512-89oK/BtApjdid1j9CGjPGiYry+EZBhsnTAM481/8ipgr/y2IOgCbW1HPnan+fs5FnzlpUgf9dWGNZ4Ayw3Bd8A==} peerDependencies: - '@rspack/core': ^1.0.0 || ^2.0.0-0 + '@rspack/core': 1.7.9 typescript: '>=3.8.0' peerDependenciesMeta: '@rspack/core': @@ -13809,7 +13748,7 @@ snapshots: '@rsbuild/core@1.7.5': dependencies: - '@rspack/core': 1.7.11(@swc/helpers@0.5.21) + '@rspack/core': 1.7.9(@swc/helpers@0.5.21) '@rspack/lite-tapable': 1.1.0 '@swc/helpers': 0.5.21 core-js: 3.47.0 @@ -13919,12 +13858,12 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 json5: 2.2.3 reduce-configs: 1.1.1 - ts-checker-rspack-plugin: 1.3.0(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) transitivePeerDependencies: @@ -13942,13 +13881,13 @@ snapshots: '@rsdoctor/client@1.5.6': {} - '@rsdoctor/core@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/core@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@1.7.5) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) '@rspack/resolver': 0.2.8(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) browserslist-load-config: 1.0.1 es-toolkit: 1.45.1 @@ -13966,13 +13905,13 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@rsbuild/plugin-check-syntax': 1.6.1(@rsbuild/core@1.7.5) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) '@rspack/resolver': 0.2.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) browserslist-load-config: 1.0.1 es-toolkit: 1.45.1 @@ -13990,10 +13929,10 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/graph@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/graph@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) es-toolkit: 1.45.1 path-browserify: 1.0.1 source-map: 0.7.6 @@ -14001,15 +13940,15 @@ snapshots: - '@rspack/core' - webpack - '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: - '@rsdoctor/core': 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/core': 1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) optionalDependencies: - '@rspack/core': 1.7.11(@swc/helpers@0.5.21) + '@rspack/core': 1.7.9(@swc/helpers@0.5.21) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -14019,15 +13958,15 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/rspack-plugin@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: - '@rsdoctor/core': 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/core': 1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/sdk': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) optionalDependencies: - '@rspack/core': 1.7.11(@swc/helpers@0.5.21) + '@rspack/core': 1.7.9(@swc/helpers@0.5.21) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -14037,12 +13976,12 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/sdk@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/sdk@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@rsdoctor/client': 1.5.6 - '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) - '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/graph': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/utils': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) launch-editor: 2.13.2 safer-buffer: 2.1.2 socket.io: 4.8.1 @@ -14054,20 +13993,20 @@ snapshots: - utf-8-validate - webpack - '@rsdoctor/types@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/types@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@types/connect': 3.4.38 '@types/estree': 1.0.5 '@types/tapable': 2.3.0 source-map: 0.7.6 optionalDependencies: - '@rspack/core': 1.7.11(@swc/helpers@0.5.21) + '@rspack/core': 1.7.9(@swc/helpers@0.5.21) webpack: 5.105.2 - '@rsdoctor/utils@1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2)': + '@rsdoctor/utils@1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': dependencies: '@babel/code-frame': 7.26.2 - '@rsdoctor/types': 1.5.6(@rspack/core@1.7.11(@swc/helpers@0.5.21))(webpack@5.105.2) + '@rsdoctor/types': 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) '@types/estree': 1.0.5 acorn: 8.15.0 acorn-import-attributes: 1.9.5(acorn@8.15.0) @@ -14095,65 +14034,42 @@ snapshots: transitivePeerDependencies: - '@typescript/native-preview' - '@rspack/binding-darwin-arm64@1.7.11': - optional: true - '@rspack/binding-darwin-arm64@1.7.9': optional: true '@rspack/binding-darwin-arm64@2.0.0-beta.0': optional: true - '@rspack/binding-darwin-x64@1.7.11': - optional: true - '@rspack/binding-darwin-x64@1.7.9': optional: true '@rspack/binding-darwin-x64@2.0.0-beta.0': optional: true - '@rspack/binding-linux-arm64-gnu@1.7.11': - optional: true - '@rspack/binding-linux-arm64-gnu@1.7.9': optional: true '@rspack/binding-linux-arm64-gnu@2.0.0-beta.0': optional: true - '@rspack/binding-linux-arm64-musl@1.7.11': - optional: true - '@rspack/binding-linux-arm64-musl@1.7.9': optional: true '@rspack/binding-linux-arm64-musl@2.0.0-beta.0': optional: true - '@rspack/binding-linux-x64-gnu@1.7.11': - optional: true - '@rspack/binding-linux-x64-gnu@1.7.9': optional: true '@rspack/binding-linux-x64-gnu@2.0.0-beta.0': optional: true - '@rspack/binding-linux-x64-musl@1.7.11': - optional: true - '@rspack/binding-linux-x64-musl@1.7.9': optional: true '@rspack/binding-linux-x64-musl@2.0.0-beta.0': optional: true - '@rspack/binding-wasm32-wasi@1.7.11': - dependencies: - '@napi-rs/wasm-runtime': 1.0.7 - optional: true - '@rspack/binding-wasm32-wasi@1.7.9': dependencies: '@napi-rs/wasm-runtime': 1.0.7 @@ -14164,46 +14080,24 @@ snapshots: '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@rspack/binding-win32-arm64-msvc@1.7.11': - optional: true - '@rspack/binding-win32-arm64-msvc@1.7.9': optional: true '@rspack/binding-win32-arm64-msvc@2.0.0-beta.0': optional: true - '@rspack/binding-win32-ia32-msvc@1.7.11': - optional: true - '@rspack/binding-win32-ia32-msvc@1.7.9': optional: true '@rspack/binding-win32-ia32-msvc@2.0.0-beta.0': optional: true - '@rspack/binding-win32-x64-msvc@1.7.11': - optional: true - '@rspack/binding-win32-x64-msvc@1.7.9': optional: true '@rspack/binding-win32-x64-msvc@2.0.0-beta.0': optional: true - '@rspack/binding@1.7.11': - optionalDependencies: - '@rspack/binding-darwin-arm64': 1.7.11 - '@rspack/binding-darwin-x64': 1.7.11 - '@rspack/binding-linux-arm64-gnu': 1.7.11 - '@rspack/binding-linux-arm64-musl': 1.7.11 - '@rspack/binding-linux-x64-gnu': 1.7.11 - '@rspack/binding-linux-x64-musl': 1.7.11 - '@rspack/binding-wasm32-wasi': 1.7.11 - '@rspack/binding-win32-arm64-msvc': 1.7.11 - '@rspack/binding-win32-ia32-msvc': 1.7.11 - '@rspack/binding-win32-x64-msvc': 1.7.11 - '@rspack/binding@1.7.9': optionalDependencies: '@rspack/binding-darwin-arm64': 1.7.9 @@ -14247,14 +14141,6 @@ snapshots: - webpack - webpack-cli - '@rspack/core@1.7.11(@swc/helpers@0.5.21)': - dependencies: - '@module-federation/runtime-tools': 0.22.0 - '@rspack/binding': 1.7.11 - '@rspack/lite-tapable': 1.1.0 - optionalDependencies: - '@swc/helpers': 0.5.21 - '@rspack/core@1.7.9(@swc/helpers@0.5.21)': dependencies: '@module-federation/runtime-tools': 0.22.0 @@ -21266,7 +21152,7 @@ snapshots: dependencies: typescript: 5.9.3 - ts-checker-rspack-plugin@1.3.0(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3): + ts-checker-rspack-plugin@1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3): dependencies: '@rspack/lite-tapable': 1.1.0 chokidar: 3.6.0 @@ -21274,7 +21160,7 @@ snapshots: picocolors: 1.1.1 typescript: 5.9.3 optionalDependencies: - '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) + '@rspack/core': 1.7.9(@swc/helpers@0.5.21) transitivePeerDependencies: - tslib diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9178fcb270..b8ade02f68 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -69,6 +69,10 @@ overrides: "@rsbuild/core@1>@rspack/core": "$@rspack/core" "@rsdoctor/rspack-plugin>@rspack/core": "$@rspack/core" "@rsdoctor/types>@rspack/core": "$@rspack/core" + # Local link to the in-tree @lynx-js/types source (template-assembler) + # so type-only fixes can be tested without publishing. Remove once a + # released version of @lynx-js/types contains the fix. + "@lynx-js/types": "file:./vendor/lynx-js-types-3.10.0.tgz" packageExtensions: "@rspack/test-tools@*": From 6ea297b1c351c7848e0a34f160e5fd3be44d7f12 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 22:01:46 +0800 Subject: [PATCH 07/43] feat(react-webpack-plugin): gate FetchBundle default on engineVersion >= 3.8 Default __LAZY_BUNDLE_FETCHER__ is now derived from the host's engineVersion: >= 3.8 picks 'FetchBundle', otherwise 'QueryComponent'. The REACT_LAZY_BUNDLE_FETCHER env var still forces a specific fetcher, but forcing 'FetchBundle' on engineVersion < 3.8 now throws a build error (the platform doesn't expose lynx.fetchBundle on those hosts). Plumbs engineVersion through pluginReactLynx -> entry.ts -> ReactWebpackPlugin. --- packages/rspeedy/plugin-react/src/entry.ts | 1 + .../src/ReactWebpackPlugin.ts | 6 ++- .../src/resolveLazyBundleFetcher.ts | 48 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts diff --git a/packages/rspeedy/plugin-react/src/entry.ts b/packages/rspeedy/plugin-react/src/entry.ts index 607492d328..366aeec40b 100644 --- a/packages/rspeedy/plugin-react/src/entry.ts +++ b/packages/rspeedy/plugin-react/src/entry.ts @@ -284,6 +284,7 @@ export function applyEntry( workletRuntimePath: await resolve( `@lynx-js/react/${isDev ? 'worklet-dev-runtime' : 'worklet-runtime'}`, ), + engineVersion: targetSdkVersion, }]) function getDefaultProfile(): boolean | undefined { diff --git a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts index 2ad6a8030f..28b3a408bb 100644 --- a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts +++ b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts @@ -15,6 +15,7 @@ import { RuntimeGlobals } from '@lynx-js/webpack-runtime-globals'; import { LAYERS } from './layer.js'; import { ELEMENT_TEMPLATE_BUILD_INFO } from './loaders/main-thread.js'; import { createLynxProcessEvalResultRuntimeModule } from './LynxProcessEvalResultRuntimeModule.js'; +import { resolveLazyBundleFetcher } from './resolveLazyBundleFetcher.js'; const require = createRequire(import.meta.url); @@ -111,6 +112,8 @@ interface ReactWebpackPluginOptions { * @experimental */ experimental_useElementTemplate?: boolean; + + engineVersion?: string; } /** @@ -188,6 +191,7 @@ class ReactWebpackPlugin { profile: undefined, workletRuntimePath: '', experimental_useElementTemplate: false, + engineVersion: '', }); /** @@ -249,7 +253,7 @@ class ReactWebpackPlugin { options.experimental_useElementTemplate, ), __LAZY_BUNDLE_FETCHER__: JSON.stringify( - process.env['REACT_LAZY_BUNDLE_FETCHER'] ?? 'FetchBundle', + resolveLazyBundleFetcher(options.engineVersion), ), }).apply(compiler); diff --git a/packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts b/packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts new file mode 100644 index 0000000000..7c46cd78a1 --- /dev/null +++ b/packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts @@ -0,0 +1,48 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +const FETCH_BUNDLE_MIN_ENGINE_VERSION = '3.8'; + +export function resolveLazyBundleFetcher( + engineVersion: string | undefined, +): string { + const meets = meetsMinEngineVersion( + engineVersion, + FETCH_BUNDLE_MIN_ENGINE_VERSION, + ); + const envOverride = process.env['REACT_LAZY_BUNDLE_FETCHER']; + if (envOverride === 'FetchBundle' && !meets) { + throw new Error( + `[ReactWebpackPlugin] REACT_LAZY_BUNDLE_FETCHER=FetchBundle requires ` + + `engineVersion >= ${FETCH_BUNDLE_MIN_ENGINE_VERSION}, but got ` + + `${engineVersion ? `'${engineVersion}'` : ''}. Older hosts ` + + `do not expose 'lynx.fetchBundle' / 'lynx.loadScript'. Either bump ` + + `'engineVersion' to '${FETCH_BUNDLE_MIN_ENGINE_VERSION}' or higher, ` + + `or unset REACT_LAZY_BUNDLE_FETCHER (the default falls back to ` + + `'QueryComponent' on older hosts).`, + ); + } + if (envOverride === 'FetchBundle' || envOverride === 'QueryComponent') { + return envOverride; + } + return meets ? 'FetchBundle' : 'QueryComponent'; +} + +function meetsMinEngineVersion( + actual: string | undefined, + min: string, +): boolean { + if (!actual) return false; + const actualParts = actual.split('.').map(Number); + const minParts = min.split('.').map(Number); + const len = Math.max(actualParts.length, minParts.length); + for (let i = 0; i < len; i++) { + const a = actualParts[i] ?? 0; + const m = minParts[i] ?? 0; + if (Number.isNaN(a) || Number.isNaN(m)) return false; + if (a > m) return true; + if (a < m) return false; + } + return true; +} From f91bf50a3fdb4411e07e12ceb721445259132c5c Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 22:21:55 +0800 Subject: [PATCH 08/43] chore: regenerate api report + dedupe lockfile CI failures from the previous push: - code-style-check (api-extractor): the new 'engineVersion' field on ReactWebpackPluginOptions wasn't reflected in etc/*.api.md. - sherif (pnpm dedupe --check): @rspack/core had 2.0.0-beta.X variants mixed with the cataloged 1.7.9. The repl build failure was a knock-on effect of that resolution drift. Re-running api-extractor + pnpm dedupe fixes both. --- .../etc/react-webpack-plugin.api.md | 2 + pnpm-lock.yaml | 127 +++++------------- 2 files changed, 39 insertions(+), 90 deletions(-) diff --git a/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md b/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md index ec1ef3a372..4526c544b1 100644 --- a/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md +++ b/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md @@ -47,6 +47,8 @@ export class ReactWebpackPlugin { export interface ReactWebpackPluginOptions { disableCreateSelectorQueryIncompatibleWarning?: boolean | undefined; enableSSR?: boolean; + // (undocumented) + engineVersion?: string; // @alpha experimental_isLazyBundle?: boolean; experimental_useElementTemplate?: boolean; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2688a66f2..d67fc95806 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -324,7 +324,7 @@ importers: version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -715,7 +715,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -1427,10 +1427,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.6.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1445,7 +1445,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1539,7 +1539,7 @@ importers: version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -1917,7 +1917,7 @@ importers: version: link:../test-tools '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2098,7 +2098,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2141,7 +2141,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2153,7 +2153,7 @@ importers: version: 1.0.4 css-loader: specifier: ^7.1.4 - version: 7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 7.1.4(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) webpack: specifier: ^5.105.2 version: 5.105.2 @@ -2289,13 +2289,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.2.2(@rsbuild/core@1.7.5) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -13764,13 +13764,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13810,9 +13810,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13841,15 +13841,6 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 - '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - deepmerge: 4.3.1 - loader-utils: 2.0.4 - postcss: 8.5.6 - reduce-configs: 1.1.1 - sass-embedded: 1.97.3 - '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13858,6 +13849,19 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': + dependencies: + deepmerge: 4.3.1 + json5: 2.2.3 + reduce-configs: 1.1.1 + ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + optionalDependencies: + '@rsbuild/core': 1.7.5 + transitivePeerDependencies: + - '@rspack/core' + - tslib + - typescript + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 @@ -13875,10 +13879,6 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - '@rsdoctor/client@1.5.6': {} '@rsdoctor/core@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': @@ -14297,45 +14297,6 @@ snapshots: - utf-8-validate - webpack-cli - '@rspack/test-tools@1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))': - dependencies: - '@babel/generator': 7.28.3 - '@babel/parser': 7.28.4 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) - cross-env: 10.1.0 - csv-to-markdown-table: 1.6.3 - deepmerge: 4.3.1 - filenamify: 4.3.0 - fs-extra: 11.3.3 - glob: 11.1.0 - graceful-fs: 4.2.11 - iconv-lite: 0.6.3 - jest-diff: 29.7.0 - jest-snapshot: 29.7.0 - jsdom: 26.1.0 - loader-utils: 2.0.4 - memfs: 4.38.2 - path-serializer: 0.5.1 - pretty-format: 29.7.0 - rimraf: 5.0.10 - source-map: 0.7.6 - terser-webpack-plugin: 5.3.16(webpack@5.99.9) - wast-loader: 1.14.1 - webpack: 5.99.9 - webpack-merge: 6.0.1 - webpack-sources: 3.3.3 - transitivePeerDependencies: - - '@swc/core' - - bufferutil - - canvas - - esbuild - - supports-color - - uglify-js - - utf-8-validate - - webpack-cli - '@rspress/core@2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0)': dependencies: '@mdx-js/mdx': 3.1.1 @@ -16131,20 +16092,6 @@ snapshots: '@rspack/core': 1.7.9(@swc/helpers@0.5.21) webpack: 5.105.2 - css-loader@7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) - postcss-modules-local-by-default: 4.0.5(postcss@8.5.6) - postcss-modules-scope: 3.2.0(postcss@8.5.6) - postcss-modules-values: 4.0.0(postcss@8.5.6) - postcss-value-parser: 4.2.0 - semver: 7.7.4 - optionalDependencies: - '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) - webpack: 5.105.2 - css-minimizer-webpack-plugin@7.0.2(lightningcss@1.31.1)(webpack@5.105.2): dependencies: '@jridgewell/trace-mapping': 0.3.29 @@ -20226,10 +20173,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20249,15 +20196,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) From 25edde689fe7833f506145d69fd1d966f1df576c Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 22:25:13 +0800 Subject: [PATCH 09/43] fix(swc-plugin-dynamic-import): drop unused enumerate index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI's clippy runs with RUSTFLAGS=-D warnings, so the unused 'i' from 'attrs.iter().enumerate()' was rejected. The index isn't read inside the loop — drop the enumerate. --- .../react/transform/crates/swc_plugin_dynamic_import/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs index c272dca45d..48bfcf9777 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs @@ -115,7 +115,7 @@ fn is_import_call_with_attrs( let (is_lit, _) = calc_literal_cost(object, false); if is_lit { let with = jsonify(Expr::Object(object.clone())); - for (i, attr) in attrs.iter().enumerate() { + for attr in attrs.iter() { if let Some(value) = with.pointer(&format!("/with/{attr}")) { with_keys.insert(attr.to_string()); with_values.insert(attr.to_string(), value.clone()); From e0275d39ac1ec156c2aefbad0893da7170c3a369 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 22:35:36 +0800 Subject: [PATCH 10/43] chore: regenerate template-webpack-plugin api report --- .../etc/template-webpack-plugin.api.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md b/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md index 69b3445172..8538f44caa 100644 --- a/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md +++ b/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md @@ -32,7 +32,8 @@ export interface EncodeOptions { // (undocumented) customSections: Record; + encoding?: 'JsBytecode' | 'CSS'; + content: string | Record | undefined; }>; elementTemplate?: Record; // (undocumented) @@ -40,9 +41,9 @@ export interface EncodeOptions { root: string | undefined; lepusChunk: Record; filename: string | undefined; - }; + } | undefined; // (undocumented) - manifest: Record; + manifest?: Record | undefined; } // @public @@ -210,6 +211,6 @@ export class WebEncodePlugin { // Warnings were encountered during analysis: // -// lib/LynxTemplatePlugin.d.ts:72:9 - (ae-forgotten-export) The symbol "EncodeRawData" needs to be exported by the entry point index.d.ts +// lib/LynxTemplatePlugin.d.ts:73:9 - (ae-forgotten-export) The symbol "EncodeRawData" needs to be exported by the entry point index.d.ts ``` From 4e8aeaa6892281b4d102797b3f89b5940e5f9ddf Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 22:40:32 +0800 Subject: [PATCH 11/43] chore: add empty changeset for in-flight FetchBundle work --- .changeset/lazy-bundle-fetch-bundle.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/lazy-bundle-fetch-bundle.md diff --git a/.changeset/lazy-bundle-fetch-bundle.md b/.changeset/lazy-bundle-fetch-bundle.md new file mode 100644 index 0000000000..361816f843 --- /dev/null +++ b/.changeset/lazy-bundle-fetch-bundle.md @@ -0,0 +1,12 @@ +--- + +--- + +No package release is required yet. This PR wires the FetchBundle-based +lazy bundle loader path (customSections-based output, JsBytecode encoded +MTS, single CSS section, version-gated default fetcher) behind an +opt-in env var fallback. The feature is incomplete pending downstream +work (engineVersion ≥ 3.8 host availability, @lynx-js/types release with +fetchBundle / loadScript declarations) and will continue to evolve. A +release changeset should be added once the FetchBundle path ships as a +coherent user-visible change. From 6bf0dc1c6ae3708de5eac5fc3a56fa4b79a9897a Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Fri, 8 May 2026 23:06:51 +0800 Subject: [PATCH 12/43] fix(web-core): add ^build to turbo build deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The local task config dropped the root's '^build' when overriding 'dependsOn' to add 'build:wasm'. As a result web-core's build can race ahead of its workspace deps' builds — on a fresh CI checkout, when @lynx-js/web-elements / @lynx-js/web-worker-rpc don't yet have a 'dist/index.js', web-core's rsbuild + rslib produces a partial dist that downstream consumers (e.g. repl) then fail to bundle ('Module not found: Can't resolve @lynx-js/web-worker-rpc' / missing 'dist/client/background/index.js'). Adding '^build' restores the workspace-dep ordering. The hash change also busts the existing poisoned turbo cache. --- packages/web-platform/web-core/turbo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-platform/web-core/turbo.json b/packages/web-platform/web-core/turbo.json index 5e0032ad91..105c31536a 100644 --- a/packages/web-platform/web-core/turbo.json +++ b/packages/web-platform/web-core/turbo.json @@ -8,7 +8,7 @@ "outputs": ["binary/**"] }, "build": { - "dependsOn": ["build:wasm"], + "dependsOn": ["^build", "build:wasm"], "inputs": ["src/**", "ts/**", "css/**", "*.ts"], "outputs": ["dist/**"] } From 370fad7bf7a7be623a92631d74f8f1d15b1323fa Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 10:58:10 +0800 Subject: [PATCH 13/43] chore(vendor): refresh @lynx-js/types tarball with optional loadScript options Picks up `loadScript(sectionName, options?: { bundleName?: string })` from template-assembler, matching how the FetchBundle path actually calls it. --- pnpm-lock.yaml | 2 +- vendor/lynx-js-types-3.10.0.tgz | Bin 49773 -> 49916 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d67fc95806..0d82c01e40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3925,7 +3925,7 @@ packages: resolution: {integrity: sha512-e8+V1aU9VD6fmVJhS1VoE5ZxUD2udhEtTTsGBj2jlxYNscND2V6fyYFGF/dUPN+s9EwRiB80vUY/Im8tYSsMWA==} '@lynx-js/types@file:vendor/lynx-js-types-3.10.0.tgz': - resolution: {integrity: sha512-ubhYJ9XKoV5zq1vxowGumhkWjcsWAK2CWxirmbQdqlBGbdkLqm0iqIit7dJVqcvM0JEHp7/cDcnpFRTP5A7zRA==, tarball: file:vendor/lynx-js-types-3.10.0.tgz} + resolution: {integrity: sha512-YB4eHwD83aABIWzkS+ddyM5nxAdHKP/K4IFaqjjKXOix+sN36+mgUvxsRJ3kfh0Z0WjpLmQCd6Xx8l9U5bWPYg==, tarball: file:vendor/lynx-js-types-3.10.0.tgz} version: 3.10.0 '@manypkg/find-root@1.1.0': diff --git a/vendor/lynx-js-types-3.10.0.tgz b/vendor/lynx-js-types-3.10.0.tgz index 055b2ab183bddbcf114408bac9662a526d5e310a..66475a104884c77c479c5da26959cd8464217a31 100644 GIT binary patch delta 45277 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 F1OTpuL(c#J delta 45089 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�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 Z|GWR)|L%YP@gM*3{{!14`ThV11OVqTMa}>K From f6d3891d7aeaaf45d731af20d5919013b0a2f47f Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 14:15:23 +0800 Subject: [PATCH 14/43] fix(plugin-react): gate lazy-bundle build output on resolved fetcher Hoist `resolveLazyBundleFetcher` into `pluginReactLynx` so the runtime and the build artifact agree on FetchBundle vs QueryComponent. Both ReactWebpackPlugin and LynxTemplatePlugin now take the resolved `lazyBundleFetcher` as a plugin option instead of each computing it (or defaulting to FetchBundle) on its own. Without this, a project on the default `targetSdkVersion` (3.2) would ship a customSections-based lazy bundle that the QueryComponent runtime path does not understand, and `react-lazy-bundle` crashed at load time. --- packages/rspeedy/plugin-react/src/entry.ts | 6 ++- .../src/resolveLazyBundleFetcher.ts | 49 +++++++++++++++++++ .../etc/react-webpack-plugin.api.md | 3 +- .../src/ReactWebpackPlugin.ts | 16 +++--- .../src/resolveLazyBundleFetcher.ts | 48 ------------------ .../etc/template-webpack-plugin.api.md | 1 + .../src/LynxTemplatePlugin.ts | 22 +++++---- 7 files changed, 78 insertions(+), 67 deletions(-) create mode 100644 packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts delete mode 100644 packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts diff --git a/packages/rspeedy/plugin-react/src/entry.ts b/packages/rspeedy/plugin-react/src/entry.ts index 366aeec40b..41bb99a25b 100644 --- a/packages/rspeedy/plugin-react/src/entry.ts +++ b/packages/rspeedy/plugin-react/src/entry.ts @@ -21,6 +21,7 @@ import { } from '@lynx-js/template-webpack-plugin' import type { PluginReactLynxOptions } from './pluginReactLynx.js' +import { resolveLazyBundleFetcher } from './resolveLazyBundleFetcher.js' const PLUGIN_NAME_REACT = 'lynx:react' const PLUGIN_NAME_TEMPLATE = 'lynx:template' @@ -56,6 +57,8 @@ export function applyEntry( experimental_isLazyBundle, } = options + const lazyBundleFetcher = resolveLazyBundleFetcher(targetSdkVersion) + api.modifyBundlerChain(async (chain, { environment, isDev, isProd }) => { const mainThreadChunks: string[] = [] @@ -203,6 +206,7 @@ export function applyEntry( targetSdkVersion, experimental_isLazyBundle, + lazyBundleFetcher, cssPlugins: [], }]) .end() @@ -284,7 +288,7 @@ export function applyEntry( workletRuntimePath: await resolve( `@lynx-js/react/${isDev ? 'worklet-dev-runtime' : 'worklet-runtime'}`, ), - engineVersion: targetSdkVersion, + lazyBundleFetcher, }]) function getDefaultProfile(): boolean | undefined { diff --git a/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts b/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts new file mode 100644 index 0000000000..9f98ce69f5 --- /dev/null +++ b/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts @@ -0,0 +1,49 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +const FETCH_BUNDLE_MIN_ENGINE_VERSION = '3.8' + +export function resolveLazyBundleFetcher( + engineVersion: string | undefined, +): 'FetchBundle' | 'QueryComponent' { + const meets = meetsMinEngineVersion( + engineVersion, + FETCH_BUNDLE_MIN_ENGINE_VERSION, + ) + const envOverride = process.env['REACT_LAZY_BUNDLE_FETCHER'] + if (envOverride === 'FetchBundle' && !meets) { + throw new Error( + `[pluginReactLynx] REACT_LAZY_BUNDLE_FETCHER=FetchBundle ` + + `requires targetSdkVersion >= ${FETCH_BUNDLE_MIN_ENGINE_VERSION}, ` + + `but got ${engineVersion ? `'${engineVersion}'` : ''}. ` + + `Older hosts do not expose 'lynx.fetchBundle' / 'lynx.loadScript'. ` + + `Either bump 'targetSdkVersion' to ` + + `'${FETCH_BUNDLE_MIN_ENGINE_VERSION}' or higher, or unset ` + + `REACT_LAZY_BUNDLE_FETCHER (the default falls back to ` + + `'QueryComponent' on older hosts).`, + ) + } + if (envOverride === 'FetchBundle' || envOverride === 'QueryComponent') { + return envOverride + } + return meets ? 'FetchBundle' : 'QueryComponent' +} + +function meetsMinEngineVersion( + actual: string | undefined, + min: string, +): boolean { + if (!actual) return false + const actualParts = actual.split('.').map(Number) + const minParts = min.split('.').map(Number) + const len = Math.max(actualParts.length, minParts.length) + for (let i = 0; i < len; i++) { + const a = actualParts[i] ?? 0 + const m = minParts[i] ?? 0 + if (Number.isNaN(a) || Number.isNaN(m)) return false + if (a > m) return true + if (a < m) return false + } + return true +} diff --git a/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md b/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md index 4526c544b1..0ad334a5b2 100644 --- a/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md +++ b/packages/webpack/react-webpack-plugin/etc/react-webpack-plugin.api.md @@ -47,14 +47,13 @@ export class ReactWebpackPlugin { export interface ReactWebpackPluginOptions { disableCreateSelectorQueryIncompatibleWarning?: boolean | undefined; enableSSR?: boolean; - // (undocumented) - engineVersion?: string; // @alpha experimental_isLazyBundle?: boolean; experimental_useElementTemplate?: boolean; extractStr?: Partial | boolean; firstScreenSyncTiming?: 'immediately' | 'jsReady'; globalPropsMode?: 'reactive' | 'event'; + lazyBundleFetcher?: 'FetchBundle' | 'QueryComponent'; mainThreadChunks?: string[] | undefined; profile?: boolean | undefined; workletRuntimePath: string; diff --git a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts index 28b3a408bb..3f8af5e971 100644 --- a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts +++ b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts @@ -15,7 +15,6 @@ import { RuntimeGlobals } from '@lynx-js/webpack-runtime-globals'; import { LAYERS } from './layer.js'; import { ELEMENT_TEMPLATE_BUILD_INFO } from './loaders/main-thread.js'; import { createLynxProcessEvalResultRuntimeModule } from './LynxProcessEvalResultRuntimeModule.js'; -import { resolveLazyBundleFetcher } from './resolveLazyBundleFetcher.js'; const require = createRequire(import.meta.url); @@ -113,7 +112,14 @@ interface ReactWebpackPluginOptions { */ experimental_useElementTemplate?: boolean; - engineVersion?: string; + /** + * Resolved lazy-bundle fetcher mode. Decided by the caller (e.g. + * `pluginReactLynx`) from the host engine version and any + * `REACT_LAZY_BUNDLE_FETCHER` env override. + * + * @public + */ + lazyBundleFetcher?: 'FetchBundle' | 'QueryComponent'; } /** @@ -191,7 +197,7 @@ class ReactWebpackPlugin { profile: undefined, workletRuntimePath: '', experimental_useElementTemplate: false, - engineVersion: '', + lazyBundleFetcher: 'QueryComponent', }); /** @@ -252,9 +258,7 @@ class ReactWebpackPlugin { __USE_ELEMENT_TEMPLATE__: JSON.stringify( options.experimental_useElementTemplate, ), - __LAZY_BUNDLE_FETCHER__: JSON.stringify( - resolveLazyBundleFetcher(options.engineVersion), - ), + __LAZY_BUNDLE_FETCHER__: JSON.stringify(options.lazyBundleFetcher), }).apply(compiler); compiler.hooks.thisCompilation.tap(this.constructor.name, compilation => { diff --git a/packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts b/packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts deleted file mode 100644 index 7c46cd78a1..0000000000 --- a/packages/webpack/react-webpack-plugin/src/resolveLazyBundleFetcher.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2026 The Lynx Authors. All rights reserved. -// Licensed under the Apache License Version 2.0 that can be found in the -// LICENSE file in the root directory of this source tree. - -const FETCH_BUNDLE_MIN_ENGINE_VERSION = '3.8'; - -export function resolveLazyBundleFetcher( - engineVersion: string | undefined, -): string { - const meets = meetsMinEngineVersion( - engineVersion, - FETCH_BUNDLE_MIN_ENGINE_VERSION, - ); - const envOverride = process.env['REACT_LAZY_BUNDLE_FETCHER']; - if (envOverride === 'FetchBundle' && !meets) { - throw new Error( - `[ReactWebpackPlugin] REACT_LAZY_BUNDLE_FETCHER=FetchBundle requires ` - + `engineVersion >= ${FETCH_BUNDLE_MIN_ENGINE_VERSION}, but got ` - + `${engineVersion ? `'${engineVersion}'` : ''}. Older hosts ` - + `do not expose 'lynx.fetchBundle' / 'lynx.loadScript'. Either bump ` - + `'engineVersion' to '${FETCH_BUNDLE_MIN_ENGINE_VERSION}' or higher, ` - + `or unset REACT_LAZY_BUNDLE_FETCHER (the default falls back to ` - + `'QueryComponent' on older hosts).`, - ); - } - if (envOverride === 'FetchBundle' || envOverride === 'QueryComponent') { - return envOverride; - } - return meets ? 'FetchBundle' : 'QueryComponent'; -} - -function meetsMinEngineVersion( - actual: string | undefined, - min: string, -): boolean { - if (!actual) return false; - const actualParts = actual.split('.').map(Number); - const minParts = min.split('.').map(Number); - const len = Math.max(actualParts.length, minParts.length); - for (let i = 0; i < len; i++) { - const a = actualParts[i] ?? 0; - const m = minParts[i] ?? 0; - if (Number.isNaN(a) || Number.isNaN(m)) return false; - if (a > m) return true; - if (a < m) return false; - } - return true; -} diff --git a/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md b/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md index 8538f44caa..f900c34b77 100644 --- a/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md +++ b/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md @@ -116,6 +116,7 @@ export interface LynxTemplatePluginOptions { experimental_isLazyBundle?: boolean; filename?: string | ((entryName: string) => string); intermediate?: string; + lazyBundleFetcher?: 'FetchBundle' | 'QueryComponent'; lazyBundleFilename?: string; removeDescendantSelectorScope: boolean; targetSdkVersion: string; diff --git a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts index 6092e37015..386d14d882 100644 --- a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts +++ b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts @@ -300,6 +300,15 @@ export interface LynxTemplatePluginOptions { */ experimental_isLazyBundle?: boolean; + /** + * Resolved lazy-bundle fetcher mode. Decided by the caller (e.g. + * `pluginReactLynx`) from the host engine version and any + * `REACT_LAZY_BUNDLE_FETCHER` env override. + * + * @public + */ + lazyBundleFetcher?: 'FetchBundle' | 'QueryComponent'; + /** * plugins passed to parser */ @@ -411,6 +420,7 @@ export class LynxTemplatePlugin { dsl: 'react_nodiff', experimental_isLazyBundle: false, + lazyBundleFetcher: 'QueryComponent', cssPlugins: [], }); @@ -488,9 +498,6 @@ const SECTION_MAIN_THREAD = 'main-thread'; const SECTION_BACKGROUND = 'background'; const SECTION_CSS = 'CSS'; -const __LAZY_BUNDLE_FETCHER__ = process.env['REACT_LAZY_BUNDLE_FETCHER'] - ?? 'FetchBundle'; - interface CustomSectionEntry { type?: 'lazy'; encoding?: 'JsBytecode' | 'CSS'; @@ -894,7 +901,7 @@ class LynxTemplatePluginImpl { ); const isFetchBundleLazy = isAsync - && __LAZY_BUNDLE_FETCHER__ === 'FetchBundle'; + && this.#options.lazyBundleFetcher === 'FetchBundle'; const fetchBundleSplit = isFetchBundleLazy ? this.#buildLazyBundleFetchBundleSections( lepusCode.root, @@ -1010,7 +1017,7 @@ class LynxTemplatePluginImpl { if (mainThreadAsset) { sections[SECTION_MAIN_THREAD] = { - encoding: 'JsBytecode', + // encoding: 'JsBytecode', content: mainThreadAsset.source.source().toString(), }; } @@ -1018,9 +1025,6 @@ class LynxTemplatePluginImpl { const remainingManifest: Record = {}; let entryChunk: [string, string] | undefined; for (const [name, content] of Object.entries(manifest)) { - // Drop the legacy `app-service.js` loader stub — see method doc. - // The asset key is always exactly `/app-service.js` in this codepath, - // so a literal compare is enough. if (name === '/app-service.js') { continue; } @@ -1035,8 +1039,6 @@ class LynxTemplatePluginImpl { sections[SECTION_BACKGROUND] = { content: entryChunk[1] }; } - // Single CSS section under the fixed key `'CSS'`. Lazy bundles are - // expected to have at most one CSS chunk; only the first is embedded. const firstCss = cssAssets[0]; if (firstCss) { const ruleList = cssChunksToMap( From a02fb76912f78fdb4207c6ed97e687887dc01925 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 14:19:24 +0800 Subject: [PATCH 15/43] fix(react-webpack-plugin): self-invoke main-thread wrapper for FetchBundle The FetchBundle runtime evaluates `customSections['main-thread']` directly, so the wrapper has to execute itself and bind `globDynamicComponentEntry` locally. Switch to a self-invoked IIFE with the literal `__Card__` baked in when `lazyBundleFetcher === 'FetchBundle'`. The QueryComponent path keeps the existing `(function (globDynamicComponentEntry) { ... })` shape since its caller still passes the entry name in. --- .../react-webpack-plugin/src/ReactWebpackPlugin.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts index 3f8af5e971..7a7fd4e25e 100644 --- a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts +++ b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts @@ -398,15 +398,21 @@ class ReactWebpackPlugin { continue; } + const isFetchBundle = + options.lazyBundleFetcher === 'FetchBundle'; compilation.updateAsset( file, old => new ConcatSource( - `(function (globDynamicComponentEntry) {\n`, + isFetchBundle + ? `(function () {\n var globDynamicComponentEntry = '__Card__';\n` + : `(function (globDynamicComponentEntry) {\n`, ` const module = { exports: {} }\n`, ` const exports = module.exports;\n`, old, - `\n ;return module.exports\n})`, + isFetchBundle + ? `\n ;return module.exports\n})()` + : `\n ;return module.exports\n})`, ), ); } From 25196705cb56c65a5be7f67da03fa61883a31d94 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 18:02:48 +0800 Subject: [PATCH 16/43] chore: dev/build/preview commands for FetchBundle in lazy-bundle examples Both lazy-bundle examples now have `dev:fetchbundle`, `build:fetchbundle`, `preview:fetchbundle` scripts that flip the resolver to FetchBundle by bumping engineVersion to 3.8 (gated on `LAZY_BUNDLE_FETCHBUNDLE=1` env). Lazy imports are switched to `with: { mode: 'sync' }` so the demos exercise the sync first-screen path. The runtime also now logs the raw response on FetchBundle load failure to make field debugging easier. --- .../lynx.config.consumer.js | 5 +- .../lynx.config.producer.js | 2 + .../react-lazy-bundle-standalone/package.json | 6 +- .../react-lazy-bundle-standalone/src/App.tsx | 1 + examples/react-lazy-bundle/lynx.config.js | 5 +- examples/react-lazy-bundle/package.json | 9 +- examples/react-lazy-bundle/src/App.tsx | 4 +- .../runtime/src/snapshot/lynx/lazy-bundle.ts | 6 +- pnpm-lock.yaml | 133 +++++++++++++----- 9 files changed, 124 insertions(+), 47 deletions(-) diff --git a/examples/react-lazy-bundle-standalone/lynx.config.consumer.js b/examples/react-lazy-bundle-standalone/lynx.config.consumer.js index 2d53d0577e..3fc6409cb8 100644 --- a/examples/react-lazy-bundle-standalone/lynx.config.consumer.js +++ b/examples/react-lazy-bundle-standalone/lynx.config.consumer.js @@ -9,6 +9,7 @@ import { detectLanHost, producerDevPort } from './demo-ports.js'; const projectRoot = path.dirname(fileURLToPath(import.meta.url)); const enableBundleAnalysis = !!process.env['RSPEEDY_BUNDLE_ANALYSIS']; +const enableFetchBundle = !!process.env['LAZY_BUNDLE_FETCHBUNDLE']; const producerHost = detectLanHost(); export default defineConfig({ @@ -35,7 +36,9 @@ export default defineConfig({ }, }, plugins: [ - pluginReactLynx(), + pluginReactLynx({ + ...(enableFetchBundle ? { engineVersion: '3.8' } : {}), + }), pluginQRCode({ schema(url) { return `${url}?fullscreen=true`; diff --git a/examples/react-lazy-bundle-standalone/lynx.config.producer.js b/examples/react-lazy-bundle-standalone/lynx.config.producer.js index 060865b02a..4ced2f9839 100644 --- a/examples/react-lazy-bundle-standalone/lynx.config.producer.js +++ b/examples/react-lazy-bundle-standalone/lynx.config.producer.js @@ -8,6 +8,7 @@ import { detectLanHost, producerDevPort } from './demo-ports.js'; const projectRoot = path.dirname(fileURLToPath(import.meta.url)); const enableBundleAnalysis = !!process.env['RSPEEDY_BUNDLE_ANALYSIS']; +const enableFetchBundle = !!process.env['LAZY_BUNDLE_FETCHBUNDLE']; const producerPublicPath = `http://${detectLanHost()}:${producerDevPort}/`; export default defineConfig({ @@ -35,6 +36,7 @@ export default defineConfig({ plugins: [ pluginReactLynx({ experimental_isLazyBundle: true, + ...(enableFetchBundle ? { engineVersion: '3.8' } : {}), }), ], environments: { diff --git a/examples/react-lazy-bundle-standalone/package.json b/examples/react-lazy-bundle-standalone/package.json index ca41ae104e..5ae4b9836c 100644 --- a/examples/react-lazy-bundle-standalone/package.json +++ b/examples/react-lazy-bundle-standalone/package.json @@ -6,12 +6,15 @@ "scripts": { "build": "pnpm run --parallel \"/^build:(producer|consumer)$/\"", "build:consumer": "rspeedy build --config lynx.config.consumer.js", + "build:fetchbundle": "cross-env LAZY_BUNDLE_FETCHBUNDLE=1 pnpm run build", "build:producer": "rspeedy build --config lynx.config.producer.js", "dev": "node scripts/serve.mjs dev", "dev:consumer": "rspeedy dev --config lynx.config.consumer.js", + "dev:fetchbundle": "cross-env LAZY_BUNDLE_FETCHBUNDLE=1 node scripts/serve.mjs dev", "dev:producer": "rspeedy dev --config lynx.config.producer.js", "preview": "node scripts/serve.mjs preview", "preview:consumer": "rspeedy preview --config lynx.config.consumer.js", + "preview:fetchbundle": "cross-env LAZY_BUNDLE_FETCHBUNDLE=1 node scripts/serve.mjs preview", "preview:producer": "rspeedy preview --config lynx.config.producer.js" }, "dependencies": { @@ -23,6 +26,7 @@ "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", "@lynx-js/types": "3.7.0", - "@types/react": "^18.3.28" + "@types/react": "^18.3.28", + "cross-env": "^7.0.3" } } diff --git a/examples/react-lazy-bundle-standalone/src/App.tsx b/examples/react-lazy-bundle-standalone/src/App.tsx index 566c4918ce..3c8c5bd9cb 100644 --- a/examples/react-lazy-bundle-standalone/src/App.tsx +++ b/examples/react-lazy-bundle-standalone/src/App.tsx @@ -8,6 +8,7 @@ const LazyComponent = lazy(() => import(createProducerBundleUrl('LazyComponent.lynx.bundle'), { with: { type: 'component', + mode: 'sync', }, }) ); diff --git a/examples/react-lazy-bundle/lynx.config.js b/examples/react-lazy-bundle/lynx.config.js index ed483a4677..4c2bca1d5f 100644 --- a/examples/react-lazy-bundle/lynx.config.js +++ b/examples/react-lazy-bundle/lynx.config.js @@ -3,10 +3,13 @@ import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; import { defineConfig } from '@lynx-js/rspeedy'; const enableBundleAnalysis = !!process.env['RSPEEDY_BUNDLE_ANALYSIS']; +const enableFetchBundle = !!process.env['LAZY_BUNDLE_FETCHBUNDLE']; export default defineConfig({ plugins: [ - pluginReactLynx(), + pluginReactLynx({ + ...(enableFetchBundle ? { engineVersion: '3.8' } : {}), + }), pluginQRCode({ schema(url) { // We use `?fullscreen=true` to open the page in LynxExplorer in full screen mode diff --git a/examples/react-lazy-bundle/package.json b/examples/react-lazy-bundle/package.json index 5240bc0837..19245cf27f 100644 --- a/examples/react-lazy-bundle/package.json +++ b/examples/react-lazy-bundle/package.json @@ -5,7 +5,11 @@ "type": "module", "scripts": { "build": "rspeedy build", - "dev": "rspeedy dev" + "build:fetchbundle": "cross-env LAZY_BUNDLE_FETCHBUNDLE=1 rspeedy build", + "dev": "rspeedy dev", + "dev:fetchbundle": "cross-env LAZY_BUNDLE_FETCHBUNDLE=1 rspeedy dev", + "preview": "rspeedy preview", + "preview:fetchbundle": "cross-env LAZY_BUNDLE_FETCHBUNDLE=1 rspeedy preview" }, "dependencies": { "@lynx-js/react": "workspace:*" @@ -16,6 +20,7 @@ "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", "@lynx-js/types": "3.7.0", - "@types/react": "^18.3.28" + "@types/react": "^18.3.28", + "cross-env": "^7.0.3" } } diff --git a/examples/react-lazy-bundle/src/App.tsx b/examples/react-lazy-bundle/src/App.tsx index de023703f5..79d6309bff 100644 --- a/examples/react-lazy-bundle/src/App.tsx +++ b/examples/react-lazy-bundle/src/App.tsx @@ -2,7 +2,9 @@ import { Suspense, lazy, useEffect } from '@lynx-js/react'; import './App.css'; -const LazyComponent = lazy(() => import('./LazyComponent.js')); +const LazyComponent = lazy(() => + import('./LazyComponent.js', { with: { mode: 'sync' } }) +); export function App() { useEffect(() => { diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index 8ae739f2ad..502c53c941 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -191,9 +191,8 @@ export const loadLazyBundle: < return Promise.reject(e instanceof Error ? e : new Error(String(e))); } if (!response || response.code !== 0) { + console.error('Lazy bundle load failed', response); const e = new Error('Lazy bundle load failed, schema: ' + source); - // ES5 does not support new Error('message', { cause: 'detail' }) - // So we set cause using `.cause` assignment e.cause = JSON.stringify(response); return Promise.reject(e); } @@ -221,9 +220,8 @@ export const loadLazyBundle: < } handler.then((response) => { if (!response || response.code !== 0) { + console.error('Lazy bundle load failed', response); const e = new Error('Lazy bundle load failed, schema: ' + source); - // ES5 does not support new Error('message', { cause: 'detail' }) - // So we set cause using `.cause` assignment e.cause = JSON.stringify(response); reject(e); return; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d82c01e40..13547fa37e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -324,7 +324,7 @@ importers: version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@1.7.5) + version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -440,6 +440,9 @@ importers: '@types/react': specifier: ^18.3.28 version: 18.3.28 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 examples/react-lazy-bundle-standalone: dependencies: @@ -465,6 +468,9 @@ importers: '@types/react': specifier: ^18.3.28 version: 18.3.28 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 examples/react-main-thread-function: dependencies: @@ -715,7 +721,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -1427,10 +1433,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@1.7.5) + version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@1.7.5) + version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1445,7 +1451,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1539,7 +1545,7 @@ importers: version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@1.7.5) + version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -1917,7 +1923,7 @@ importers: version: link:../test-tools '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2098,7 +2104,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2141,7 +2147,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2153,7 +2159,7 @@ importers: version: 1.0.4 css-loader: specifier: ^7.1.4 - version: 7.1.4(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2) webpack: specifier: ^5.105.2 version: 5.105.2 @@ -2289,13 +2295,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@1.7.5) + version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@1.7.5) + version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -13764,13 +13770,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13810,9 +13816,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13841,6 +13847,15 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 + '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + dependencies: + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + deepmerge: 4.3.1 + loader-utils: 2.0.4 + postcss: 8.5.6 + reduce-configs: 1.1.1 + sass-embedded: 1.97.3 + '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13849,19 +13864,6 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - deepmerge: 4.3.1 - json5: 2.2.3 - reduce-configs: 1.1.1 - ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) - optionalDependencies: - '@rsbuild/core': 1.7.5 - transitivePeerDependencies: - - '@rspack/core' - - tslib - - typescript - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 @@ -13879,6 +13881,10 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + optionalDependencies: + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsdoctor/client@1.5.6': {} '@rsdoctor/core@1.5.6(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': @@ -14297,6 +14303,45 @@ snapshots: - utf-8-validate - webpack-cli + '@rspack/test-tools@1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))': + dependencies: + '@babel/generator': 7.28.3 + '@babel/parser': 7.28.4 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) + cross-env: 10.1.0 + csv-to-markdown-table: 1.6.3 + deepmerge: 4.3.1 + filenamify: 4.3.0 + fs-extra: 11.3.3 + glob: 11.1.0 + graceful-fs: 4.2.11 + iconv-lite: 0.6.3 + jest-diff: 29.7.0 + jest-snapshot: 29.7.0 + jsdom: 26.1.0 + loader-utils: 2.0.4 + memfs: 4.38.2 + path-serializer: 0.5.1 + pretty-format: 29.7.0 + rimraf: 5.0.10 + source-map: 0.7.6 + terser-webpack-plugin: 5.3.16(webpack@5.99.9) + wast-loader: 1.14.1 + webpack: 5.99.9 + webpack-merge: 6.0.1 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - bufferutil + - canvas + - esbuild + - supports-color + - uglify-js + - utf-8-validate + - webpack-cli + '@rspress/core@2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0)': dependencies: '@mdx-js/mdx': 3.1.1 @@ -16092,6 +16137,20 @@ snapshots: '@rspack/core': 1.7.9(@swc/helpers@0.5.21) webpack: 5.105.2 + css-loader@7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2): + dependencies: + icss-utils: 5.1.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) + postcss-modules-local-by-default: 4.0.5(postcss@8.5.6) + postcss-modules-scope: 3.2.0(postcss@8.5.6) + postcss-modules-values: 4.0.0(postcss@8.5.6) + postcss-value-parser: 4.2.0 + semver: 7.7.4 + optionalDependencies: + '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) + webpack: 5.105.2 + css-minimizer-webpack-plugin@7.0.2(lightningcss@1.31.1)(webpack@5.105.2): dependencies: '@jridgewell/trace-mapping': 0.3.29 @@ -20173,10 +20232,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20196,15 +20255,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) From ad06fd9faa0c4d9bb70dfd0e34b1cf35a330d38a Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 19:29:10 +0800 Subject: [PATCH 17/43] chore(examples): split lazy bundles into Sync + Async demos Rename the existing LazyComponent to LazyComponentSync (mode: 'sync') and add a sibling LazyComponentAsync (mode: 'async'). Both examples now render the two side-by-side so the difference between sync first-screen and async fallback is visible at a glance. --- .../lynx.config.producer.js | 3 ++- .../react-lazy-bundle-standalone/src/App.tsx | 19 +++++++++++---- .../src/LazyComponent.tsx | 9 -------- .../src/LazyComponentAsync.css | 4 ++++ .../src/LazyComponentAsync.tsx | 9 ++++++++ ...azyComponent.css => LazyComponentSync.css} | 2 +- .../src/LazyComponentSync.tsx | 9 ++++++++ examples/react-lazy-bundle/lynx.config.js | 23 +++++++++++++++++++ examples/react-lazy-bundle/src/App.tsx | 14 +++++++---- .../react-lazy-bundle/src/LazyComponent.tsx | 9 -------- .../src/LazyComponentAsync.css | 4 ++++ .../src/LazyComponentAsync.tsx | 9 ++++++++ ...azyComponent.css => LazyComponentSync.css} | 2 +- .../src/LazyComponentSync.tsx | 9 ++++++++ 14 files changed, 96 insertions(+), 29 deletions(-) delete mode 100644 examples/react-lazy-bundle-standalone/src/LazyComponent.tsx create mode 100644 examples/react-lazy-bundle-standalone/src/LazyComponentAsync.css create mode 100644 examples/react-lazy-bundle-standalone/src/LazyComponentAsync.tsx rename examples/react-lazy-bundle-standalone/src/{LazyComponent.css => LazyComponentSync.css} (65%) create mode 100644 examples/react-lazy-bundle-standalone/src/LazyComponentSync.tsx delete mode 100644 examples/react-lazy-bundle/src/LazyComponent.tsx create mode 100644 examples/react-lazy-bundle/src/LazyComponentAsync.css create mode 100644 examples/react-lazy-bundle/src/LazyComponentAsync.tsx rename examples/react-lazy-bundle/src/{LazyComponent.css => LazyComponentSync.css} (65%) create mode 100644 examples/react-lazy-bundle/src/LazyComponentSync.tsx diff --git a/examples/react-lazy-bundle-standalone/lynx.config.producer.js b/examples/react-lazy-bundle-standalone/lynx.config.producer.js index 4ced2f9839..b588560a2e 100644 --- a/examples/react-lazy-bundle-standalone/lynx.config.producer.js +++ b/examples/react-lazy-bundle-standalone/lynx.config.producer.js @@ -14,7 +14,8 @@ const producerPublicPath = `http://${detectLanHost()}:${producerDevPort}/`; export default defineConfig({ source: { entry: { - LazyComponent: './src/LazyComponent.tsx', + LazyComponentSync: './src/LazyComponentSync.tsx', + LazyComponentAsync: './src/LazyComponentAsync.tsx', add: './src/utils/add.ts', minus: './src/utils/minus.ts', dynamic: './src/utils/dynamic.ts', diff --git a/examples/react-lazy-bundle-standalone/src/App.tsx b/examples/react-lazy-bundle-standalone/src/App.tsx index 3c8c5bd9cb..3fdd3e5949 100644 --- a/examples/react-lazy-bundle-standalone/src/App.tsx +++ b/examples/react-lazy-bundle-standalone/src/App.tsx @@ -4,14 +4,22 @@ import { createProducerBundleUrl } from './entry-url.js'; import './App.css'; -const LazyComponent = lazy(() => - import(createProducerBundleUrl('LazyComponent.lynx.bundle'), { +const LazyComponentSync = lazy(() => + import(createProducerBundleUrl('LazyComponentSync.lynx.bundle'), { with: { type: 'component', mode: 'sync', }, }) ); +const LazyComponentAsync = lazy(() => + import(createProducerBundleUrl('LazyComponentAsync.lynx.bundle'), { + with: { + type: 'component', + mode: 'async', + }, + }) +); export function App() { useEffect(() => { @@ -44,8 +52,11 @@ export function App() { on Lynx - Loading...}> - + Loading sync...}> + + + Loading async...}> + diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponent.tsx b/examples/react-lazy-bundle-standalone/src/LazyComponent.tsx deleted file mode 100644 index bfc3e63537..0000000000 --- a/examples/react-lazy-bundle-standalone/src/LazyComponent.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import './LazyComponent.css'; - -export default function LazyComponent() { - return ( - - LazyComponent - - ); -} diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponentAsync.css b/examples/react-lazy-bundle-standalone/src/LazyComponentAsync.css new file mode 100644 index 0000000000..cdd57eba1c --- /dev/null +++ b/examples/react-lazy-bundle-standalone/src/LazyComponentAsync.css @@ -0,0 +1,4 @@ +.LazyComponentAsync { + font-weight: 700; + color: cyan; +} diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponentAsync.tsx b/examples/react-lazy-bundle-standalone/src/LazyComponentAsync.tsx new file mode 100644 index 0000000000..eb0765ad8c --- /dev/null +++ b/examples/react-lazy-bundle-standalone/src/LazyComponentAsync.tsx @@ -0,0 +1,9 @@ +import './LazyComponentAsync.css'; + +export default function LazyComponentAsync() { + return ( + + LazyComponentAsync + + ); +} diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponent.css b/examples/react-lazy-bundle-standalone/src/LazyComponentSync.css similarity index 65% rename from examples/react-lazy-bundle-standalone/src/LazyComponent.css rename to examples/react-lazy-bundle-standalone/src/LazyComponentSync.css index a7aafb7083..082c6a36f2 100644 --- a/examples/react-lazy-bundle-standalone/src/LazyComponent.css +++ b/examples/react-lazy-bundle-standalone/src/LazyComponentSync.css @@ -1,4 +1,4 @@ -.LazyComponent { +.LazyComponentSync { font-weight: 700; color: yellow; } diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponentSync.tsx b/examples/react-lazy-bundle-standalone/src/LazyComponentSync.tsx new file mode 100644 index 0000000000..0f79cdf792 --- /dev/null +++ b/examples/react-lazy-bundle-standalone/src/LazyComponentSync.tsx @@ -0,0 +1,9 @@ +import './LazyComponentSync.css'; + +export default function LazyComponentSync() { + return ( + + LazyComponentSync + + ); +} diff --git a/examples/react-lazy-bundle/lynx.config.js b/examples/react-lazy-bundle/lynx.config.js index 4c2bca1d5f..9de9038606 100644 --- a/examples/react-lazy-bundle/lynx.config.js +++ b/examples/react-lazy-bundle/lynx.config.js @@ -1,3 +1,5 @@ +import os from 'node:os'; + import { pluginQRCode } from '@lynx-js/qrcode-rsbuild-plugin'; import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; import { defineConfig } from '@lynx-js/rspeedy'; @@ -5,7 +7,28 @@ import { defineConfig } from '@lynx-js/rspeedy'; const enableBundleAnalysis = !!process.env['RSPEEDY_BUNDLE_ANALYSIS']; const enableFetchBundle = !!process.env['LAZY_BUNDLE_FETCHBUNDLE']; +function detectLanHost() { + for (const ifaces of Object.values(os.networkInterfaces())) { + for (const iface of ifaces ?? []) { + if (iface.family === 'IPv4' && !iface.internal) { + return iface.address; + } + } + } + throw new Error('No external IPv4 interface found for lazy bundle host.'); +} + +const port = Number(process.env['LYNX_LAZY_BUNDLE_PORT'] ?? '54173'); +const assetPrefix = `http://${detectLanHost()}:${port}/`; + export default defineConfig({ + output: { + assetPrefix, + }, + server: { + port, + strictPort: true, + }, plugins: [ pluginReactLynx({ ...(enableFetchBundle ? { engineVersion: '3.8' } : {}), diff --git a/examples/react-lazy-bundle/src/App.tsx b/examples/react-lazy-bundle/src/App.tsx index 79d6309bff..136baba25c 100644 --- a/examples/react-lazy-bundle/src/App.tsx +++ b/examples/react-lazy-bundle/src/App.tsx @@ -2,8 +2,11 @@ import { Suspense, lazy, useEffect } from '@lynx-js/react'; import './App.css'; -const LazyComponent = lazy(() => - import('./LazyComponent.js', { with: { mode: 'sync' } }) +const LazyComponentSync = lazy(() => + import('./LazyComponentSync.js', { with: { mode: 'sync' } }) +); +const LazyComponentAsync = lazy(() => + import('./LazyComponentAsync.js', { with: { mode: 'async' } }) ); export function App() { @@ -29,8 +32,11 @@ export function App() { on Lynx - Loading...}> - + Loading sync...}> + + + Loading async...}> + diff --git a/examples/react-lazy-bundle/src/LazyComponent.tsx b/examples/react-lazy-bundle/src/LazyComponent.tsx deleted file mode 100644 index bfc3e63537..0000000000 --- a/examples/react-lazy-bundle/src/LazyComponent.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import './LazyComponent.css'; - -export default function LazyComponent() { - return ( - - LazyComponent - - ); -} diff --git a/examples/react-lazy-bundle/src/LazyComponentAsync.css b/examples/react-lazy-bundle/src/LazyComponentAsync.css new file mode 100644 index 0000000000..cdd57eba1c --- /dev/null +++ b/examples/react-lazy-bundle/src/LazyComponentAsync.css @@ -0,0 +1,4 @@ +.LazyComponentAsync { + font-weight: 700; + color: cyan; +} diff --git a/examples/react-lazy-bundle/src/LazyComponentAsync.tsx b/examples/react-lazy-bundle/src/LazyComponentAsync.tsx new file mode 100644 index 0000000000..eb0765ad8c --- /dev/null +++ b/examples/react-lazy-bundle/src/LazyComponentAsync.tsx @@ -0,0 +1,9 @@ +import './LazyComponentAsync.css'; + +export default function LazyComponentAsync() { + return ( + + LazyComponentAsync + + ); +} diff --git a/examples/react-lazy-bundle/src/LazyComponent.css b/examples/react-lazy-bundle/src/LazyComponentSync.css similarity index 65% rename from examples/react-lazy-bundle/src/LazyComponent.css rename to examples/react-lazy-bundle/src/LazyComponentSync.css index a7aafb7083..082c6a36f2 100644 --- a/examples/react-lazy-bundle/src/LazyComponent.css +++ b/examples/react-lazy-bundle/src/LazyComponentSync.css @@ -1,4 +1,4 @@ -.LazyComponent { +.LazyComponentSync { font-weight: 700; color: yellow; } diff --git a/examples/react-lazy-bundle/src/LazyComponentSync.tsx b/examples/react-lazy-bundle/src/LazyComponentSync.tsx new file mode 100644 index 0000000000..0f79cdf792 --- /dev/null +++ b/examples/react-lazy-bundle/src/LazyComponentSync.tsx @@ -0,0 +1,9 @@ +import './LazyComponentSync.css'; + +export default function LazyComponentSync() { + return ( + + LazyComponentSync + + ); +} From 1a8cf3c83e058a22a42bcf51c70e8df1836b797e Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:02:43 +0800 Subject: [PATCH 18/43] feat(react): coordinate MT prep on FetchBundle BG-triggered async load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When BG triggers a lazy bundle in FetchBundle async mode, MT must register the bundle's snapshots before BG sends any patch — otherwise patches fail with "Snapshot not found". Add an MT-side handler `rLynxPrepareLazyBundleMTS` that loads the main-thread section, runs processEvalResult, and adopts CSS. BG calls it via callLepusMethod inside its own fetchBundle.then so the bundle is already in native cache, MT's `.then` fires synchronously, and the cb truly waits for MT side effects to complete (since callLepusMethod's cb fires when the Lepus function returns and is not Promise-aware in C++). --- packages/react/runtime/src/lynx.ts | 7 +++ .../src/snapshot/lifecycle/constant.ts | 1 + .../runtime/src/snapshot/lynx/lazy-bundle.ts | 47 +++++++++++----- .../src/snapshot/lynx/lazyBundleConstants.ts | 9 ++++ .../src/snapshot/lynx/prepareLazyBundleMTS.ts | 54 +++++++++++++++++++ 5 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 packages/react/runtime/src/snapshot/lynx/lazyBundleConstants.ts create mode 100644 packages/react/runtime/src/snapshot/lynx/prepareLazyBundleMTS.ts diff --git a/packages/react/runtime/src/lynx.ts b/packages/react/runtime/src/lynx.ts index e4a20519af..8993a561e1 100644 --- a/packages/react/runtime/src/lynx.ts +++ b/packages/react/runtime/src/lynx.ts @@ -19,6 +19,7 @@ import { injectCalledByNative } from './snapshot/lynx/calledByNative.js'; import { setupLynxEnv } from './snapshot/lynx/env.js'; import { injectLepusMethods } from './snapshot/lynx/injectLepusMethods.js'; import { initTimingAPI } from './snapshot/lynx/performance.js'; +import { injectPrepareLazyBundleMTS } from './snapshot/lynx/prepareLazyBundleMTS.js'; import { injectTt } from './snapshot/lynx/tt.js'; import { injectUpdateMTRefInitValue } from './snapshot/worklet/ref/updateInitValue.js'; import { lynxQueueMicrotask } from './utils.js'; @@ -37,6 +38,12 @@ if (typeof __MAIN_THREAD__ !== 'undefined' && __MAIN_THREAD__) { injectCalledByNative(); injectUpdateMainThread(); injectUpdateMTRefInitValue(); + if ( + typeof __LAZY_BUNDLE_FETCHER__ !== 'undefined' + && __LAZY_BUNDLE_FETCHER__ === 'FetchBundle' + ) { + injectPrepareLazyBundleMTS(); + } if (__DEV__) { injectLepusMethods(); } diff --git a/packages/react/runtime/src/snapshot/lifecycle/constant.ts b/packages/react/runtime/src/snapshot/lifecycle/constant.ts index cdab91b8af..bce69a3c97 100644 --- a/packages/react/runtime/src/snapshot/lifecycle/constant.ts +++ b/packages/react/runtime/src/snapshot/lifecycle/constant.ts @@ -9,6 +9,7 @@ export const LifecycleConstant = { patchUpdate: 'rLynxChange', publishEvent: 'rLynxPublishEvent', updateMTRefInitValue: 'rLynxChangeRefInitValue', + prepareLazyBundleMTS: 'rLynxPrepareLazyBundleMTS', } as const; export type LifecycleConstant = (typeof LifecycleConstant)[keyof typeof LifecycleConstant]; diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index 502c53c941..39b79c7e4b 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -2,6 +2,14 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. +import { + LYNX_LAZY_SYNC_TIMEOUT_SECONDS, + SECTION_BACKGROUND, + SECTION_CSS, + SECTION_MAIN_THREAD, +} from './lazyBundleConstants.js'; +import { LifecycleConstant } from '../lifecycle/constant.js'; + /** * To make code below works * const App1 = lazy(() => import("./x").then(({App1}) => ({default: App1}))) @@ -57,12 +65,6 @@ export const makeSyncThen = function(result: T): Promise['then'] { let lazyBundleMode: 'sync' | 'async' | undefined; -const LYNX_LAZY_SYNC_TIMEOUT_SECONDS = 5; - -const SECTION_MAIN_THREAD = 'main-thread'; -const SECTION_BACKGROUND = 'background'; -const SECTION_CSS = 'CSS'; - /** * Load dynamic component from source. Designed to be used with `lazy`. * @param source - where dynamic component template.js locates @@ -72,12 +74,16 @@ const SECTION_CSS = 'CSS'; export const loadLazyBundle: < T extends { default: React.ComponentType }, >(source: string) => Promise = /*#__PURE__*/ (() => { - const useQueryComponent = typeof __LAZY_BUNDLE_FETCHER__ !== 'undefined' - && __LAZY_BUNDLE_FETCHER__ === 'QueryComponent'; + // Default to QueryComponent when `__LAZY_BUNDLE_FETCHER__` is missing — + // older react-webpack-plugin builds don't stamp it and they predate + // FetchBundle support, so falling through to QueryComponent is the only + // safe behavior. + const useFetchBundle = typeof __LAZY_BUNDLE_FETCHER__ !== 'undefined' + && __LAZY_BUNDLE_FETCHER__ === 'FetchBundle'; - const impl = useQueryComponent - ? loadLazyBundleWithQueryComponent - : loadLazyBundleWithFetchBundle; + const impl = useFetchBundle + ? loadLazyBundleWithFetchBundle + : loadLazyBundleWithQueryComponent; lynx.loadLazyBundle = impl; @@ -226,11 +232,26 @@ export const loadLazyBundle: < reject(e); return; } + let btsResult: T; try { - const result = lynx.loadScript(SECTION_BACKGROUND, { + btsResult = lynx.loadScript(SECTION_BACKGROUND, { bundleName: response.url, }); - resolve(result); + } catch (e) { + reject(e instanceof Error ? e : new Error(String(e))); + return; + } + // Bundle is now in native cache, so MT's `.then` fires sync and + // the whole prepare runs synchronously inside `Call`, meaning the + // cb fires only after MT snapshots are registered. + try { + lynx.getNativeApp().callLepusMethod( + LifecycleConstant.prepareLazyBundleMTS, + { url: source }, + () => { + resolve(btsResult); + }, + ); } catch (e) { reject(e instanceof Error ? e : new Error(String(e))); } diff --git a/packages/react/runtime/src/snapshot/lynx/lazyBundleConstants.ts b/packages/react/runtime/src/snapshot/lynx/lazyBundleConstants.ts new file mode 100644 index 0000000000..34ee727738 --- /dev/null +++ b/packages/react/runtime/src/snapshot/lynx/lazyBundleConstants.ts @@ -0,0 +1,9 @@ +// Copyright 2025 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +export const SECTION_MAIN_THREAD = 'main-thread'; +export const SECTION_BACKGROUND = 'background'; +export const SECTION_CSS = 'CSS'; + +export const LYNX_LAZY_SYNC_TIMEOUT_SECONDS = 5; diff --git a/packages/react/runtime/src/snapshot/lynx/prepareLazyBundleMTS.ts b/packages/react/runtime/src/snapshot/lynx/prepareLazyBundleMTS.ts new file mode 100644 index 0000000000..763e15a98a --- /dev/null +++ b/packages/react/runtime/src/snapshot/lynx/prepareLazyBundleMTS.ts @@ -0,0 +1,54 @@ +// Copyright 2025 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +import { SECTION_CSS, SECTION_MAIN_THREAD } from './lazyBundleConstants.js'; +import { LifecycleConstant } from '../lifecycle/constant.js'; + +const cache = new Set(); + +function prepareLazyBundleMTS(payload: { url: string }): void { + const { url } = payload; + if (cache.has(url)) return; + cache.add(url); + let handler; + try { + handler = lynx.fetchBundle(url, {}); + } catch { + return; + } + // .then will be a sync function + // since the bundle has been loaded in BTS + handler.then((response) => { + if (!response || response.code !== 0) return; + let loaded: unknown; + try { + loaded = lynx.loadScript(SECTION_MAIN_THREAD, { + bundleName: response.url, + }); + } catch { + // BG-only bundle (no main-thread section) + return; + } + const processEvalResult = ( + globalThis as unknown as { + processEvalResult?: ( + result: ((schema: string) => unknown) | undefined, + schema: string, + ) => unknown; + } + ).processEvalResult; + if (typeof processEvalResult === 'function') { + processEvalResult(() => loaded, url); + } + const styleSheet = __LoadStyleSheet(SECTION_CSS, response.url); + if (styleSheet !== null) __AdoptStyleSheet(styleSheet); + }); +} + +/** @internal */ +export function injectPrepareLazyBundleMTS(): void { + Object.assign(globalThis, { + [LifecycleConstant.prepareLazyBundleMTS]: prepareLazyBundleMTS, + }); +} From 0c1d610911588d793a6c40f99dabcaacd8b058b8 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:05:42 +0800 Subject: [PATCH 19/43] feat(react): throw on lazy bundle mode used with QueryComponent in dev `lazyBundleMode` (set by `import('./X', { with: { mode: ... } })`) is only honored by the FetchBundle path. Under QueryComponent it was silently ignored, leaving users to wonder why sync mode didn't take effect. Throw a clear error in `__DEV__` BG so the misconfiguration is caught at first lazy load; the check is tree-shaken in production. --- packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index 39b79c7e4b..8085046467 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -110,6 +110,12 @@ export const loadLazyBundle: < r.then = makeSyncThen(result); return r; } else if (__JS__) { + if (__DEV__ && lazyBundleMode !== undefined) { + throw new Error( + `Lazy bundle import \`mode: '${lazyBundleMode}'\` requires FetchBundle, but the current build uses QueryComponent. ` + + `Set \`engineVersion: '3.8'\` (or higher) in \`pluginReactLynx\` to enable FetchBundle.`, + ); + } const resolver = withSyncResolvers(); const callback: (result: { code: number; detail: { schema: string } }) => void = result => { From 4a1252773f8fde8ee21372dfcb44c4becfcdc46b Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:24:45 +0800 Subject: [PATCH 20/43] feat(template-plugin): default to bytecode for FetchBundle lazy main-thread Encode the main-thread customSection of FetchBundle lazy bundles as JsBytecode by default. Skip in dev or when DEBUG matches rspeedy so the source remains debuggable while bytecode tooling for FetchBundle matures. --- .../template-webpack-plugin/src/LynxTemplatePlugin.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts index 386d14d882..e2e5a8eaee 100644 --- a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts +++ b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts @@ -902,11 +902,16 @@ class LynxTemplatePluginImpl { const isFetchBundleLazy = isAsync && this.#options.lazyBundleFetcher === 'FetchBundle'; + // Default to bytecode for FetchBundle lazy main-thread sections. Skip + // in dev or when DEBUG matches rspeedy so the source stays debuggable. + const enableLazyBundleBytecode = isFetchBundleLazy && !isDev + && !isDebug(); const fetchBundleSplit = isFetchBundleLazy ? this.#buildLazyBundleFetchBundleSections( lepusCode.root, encodeData.manifest, encodeData.css.chunks, + enableLazyBundleBytecode, ) : null; @@ -1008,6 +1013,7 @@ class LynxTemplatePluginImpl { mainThreadAsset: Asset | undefined, manifest: Record, cssAssets: Asset[], + enableBytecode: boolean, ): { sections: Record; remainingManifest: Record; @@ -1017,7 +1023,7 @@ class LynxTemplatePluginImpl { if (mainThreadAsset) { sections[SECTION_MAIN_THREAD] = { - // encoding: 'JsBytecode', + ...(enableBytecode ? { encoding: 'JsBytecode' as const } : {}), content: mainThreadAsset.source.source().toString(), }; } From b1d9b4430fe4325c6ade5083f74e4e7c202cf033 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:24:59 +0800 Subject: [PATCH 21/43] chore(examples): branch lazy-bundle demos on __LAZY_BUNDLE_FETCHER__ Expose `__LAZY_BUNDLE_FETCHER__` as a typed global on `@lynx-js/react` so consumer code can branch on the build's fetcher choice. Restructure both lazy-bundle example apps so QueryComponent builds render a single generic LazyComponent (mode hints are FetchBundle-only); FetchBundle builds keep the Sync + Async dual-Suspense demo. The standalone producer config now also emits a LazyComponent bundle. --- .../lynx.config.producer.js | 1 + .../react-lazy-bundle-standalone/src/App.tsx | 57 ++++++++++++------- .../src/LazyComponent.css | 4 ++ .../src/LazyComponent.tsx | 9 +++ examples/react-lazy-bundle/src/App.tsx | 39 +++++++++---- .../react-lazy-bundle/src/LazyComponent.css | 4 ++ .../react-lazy-bundle/src/LazyComponent.tsx | 9 +++ packages/react/types/react.docs.d.ts | 6 ++ 8 files changed, 95 insertions(+), 34 deletions(-) create mode 100644 examples/react-lazy-bundle-standalone/src/LazyComponent.css create mode 100644 examples/react-lazy-bundle-standalone/src/LazyComponent.tsx create mode 100644 examples/react-lazy-bundle/src/LazyComponent.css create mode 100644 examples/react-lazy-bundle/src/LazyComponent.tsx diff --git a/examples/react-lazy-bundle-standalone/lynx.config.producer.js b/examples/react-lazy-bundle-standalone/lynx.config.producer.js index b588560a2e..c274fdc040 100644 --- a/examples/react-lazy-bundle-standalone/lynx.config.producer.js +++ b/examples/react-lazy-bundle-standalone/lynx.config.producer.js @@ -14,6 +14,7 @@ const producerPublicPath = `http://${detectLanHost()}:${producerDevPort}/`; export default defineConfig({ source: { entry: { + LazyComponent: './src/LazyComponent.tsx', LazyComponentSync: './src/LazyComponentSync.tsx', LazyComponentAsync: './src/LazyComponentAsync.tsx', add: './src/utils/add.ts', diff --git a/examples/react-lazy-bundle-standalone/src/App.tsx b/examples/react-lazy-bundle-standalone/src/App.tsx index 3fdd3e5949..264d666ddb 100644 --- a/examples/react-lazy-bundle-standalone/src/App.tsx +++ b/examples/react-lazy-bundle-standalone/src/App.tsx @@ -4,22 +4,40 @@ import { createProducerBundleUrl } from './entry-url.js'; import './App.css'; -const LazyComponentSync = lazy(() => - import(createProducerBundleUrl('LazyComponentSync.lynx.bundle'), { - with: { - type: 'component', - mode: 'sync', - }, - }) -); -const LazyComponentAsync = lazy(() => - import(createProducerBundleUrl('LazyComponentAsync.lynx.bundle'), { - with: { - type: 'component', - mode: 'async', - }, - }) -); +let LazyComponentDemo: () => JSX.Element; +if (__LAZY_BUNDLE_FETCHER__ === 'FetchBundle') { + const LazyComponentSync = lazy(() => + import(createProducerBundleUrl('LazyComponentSync.lynx.bundle'), { + with: { type: 'component', mode: 'sync' }, + }) + ); + const LazyComponentAsync = lazy(() => + import(createProducerBundleUrl('LazyComponentAsync.lynx.bundle'), { + with: { type: 'component', mode: 'async' }, + }) + ); + LazyComponentDemo = () => ( + <> + Loading sync...}> + + + Loading async...}> + + + + ); +} else { + const LazyComponent = lazy(() => + import(createProducerBundleUrl('LazyComponent.lynx.bundle'), { + with: { type: 'component' }, + }) + ); + LazyComponentDemo = () => ( + Loading...}> + + + ); +} export function App() { useEffect(() => { @@ -52,12 +70,7 @@ export function App() { on Lynx - Loading sync...}> - - - Loading async...}> - - + diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponent.css b/examples/react-lazy-bundle-standalone/src/LazyComponent.css new file mode 100644 index 0000000000..a7aafb7083 --- /dev/null +++ b/examples/react-lazy-bundle-standalone/src/LazyComponent.css @@ -0,0 +1,4 @@ +.LazyComponent { + font-weight: 700; + color: yellow; +} diff --git a/examples/react-lazy-bundle-standalone/src/LazyComponent.tsx b/examples/react-lazy-bundle-standalone/src/LazyComponent.tsx new file mode 100644 index 0000000000..bfc3e63537 --- /dev/null +++ b/examples/react-lazy-bundle-standalone/src/LazyComponent.tsx @@ -0,0 +1,9 @@ +import './LazyComponent.css'; + +export default function LazyComponent() { + return ( + + LazyComponent + + ); +} diff --git a/examples/react-lazy-bundle/src/App.tsx b/examples/react-lazy-bundle/src/App.tsx index 136baba25c..9450135e23 100644 --- a/examples/react-lazy-bundle/src/App.tsx +++ b/examples/react-lazy-bundle/src/App.tsx @@ -2,12 +2,32 @@ import { Suspense, lazy, useEffect } from '@lynx-js/react'; import './App.css'; -const LazyComponentSync = lazy(() => - import('./LazyComponentSync.js', { with: { mode: 'sync' } }) -); -const LazyComponentAsync = lazy(() => - import('./LazyComponentAsync.js', { with: { mode: 'async' } }) -); +let LazyComponentDemo: () => JSX.Element; +if (__LAZY_BUNDLE_FETCHER__ === 'FetchBundle') { + const LazyComponentSync = lazy(() => + import('./LazyComponentSync.js', { with: { mode: 'sync' } }) + ); + const LazyComponentAsync = lazy(() => + import('./LazyComponentAsync.js', { with: { mode: 'async' } }) + ); + LazyComponentDemo = () => ( + <> + Loading sync...}> + + + Loading async...}> + + + + ); +} else { + const LazyComponent = lazy(() => import('./LazyComponent.js')); + LazyComponentDemo = () => ( + Loading...}> + + + ); +} export function App() { useEffect(() => { @@ -32,12 +52,7 @@ export function App() { on Lynx - Loading sync...}> - - - Loading async...}> - - + diff --git a/examples/react-lazy-bundle/src/LazyComponent.css b/examples/react-lazy-bundle/src/LazyComponent.css new file mode 100644 index 0000000000..a7aafb7083 --- /dev/null +++ b/examples/react-lazy-bundle/src/LazyComponent.css @@ -0,0 +1,4 @@ +.LazyComponent { + font-weight: 700; + color: yellow; +} diff --git a/examples/react-lazy-bundle/src/LazyComponent.tsx b/examples/react-lazy-bundle/src/LazyComponent.tsx new file mode 100644 index 0000000000..bfc3e63537 --- /dev/null +++ b/examples/react-lazy-bundle/src/LazyComponent.tsx @@ -0,0 +1,9 @@ +import './LazyComponent.css'; + +export default function LazyComponent() { + return ( + + LazyComponent + + ); +} diff --git a/packages/react/types/react.docs.d.ts b/packages/react/types/react.docs.d.ts index 51c4d5a598..edef1e42d9 100644 --- a/packages/react/types/react.docs.d.ts +++ b/packages/react/types/react.docs.d.ts @@ -30,6 +30,12 @@ declare global { * Determines if running in profile mode */ let __PROFILE__: boolean; + /** + * Which lazy bundle fetcher the build is wired up to. `'FetchBundle'` + * enables the `lynx.fetchBundle`-based path (and `import(..., { with: { mode } })` + * mode hints); `'QueryComponent'` is the legacy `lynx.QueryComponent` path. + */ + let __LAZY_BUNDLE_FETCHER__: 'FetchBundle' | 'QueryComponent'; } /** From bc70e16ebd01dfa6461eb5d64161906868358e00 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:27:47 +0800 Subject: [PATCH 22/43] chore(examples): use bracket access for env vars in entry-url Pass strict TS index signature checks (TS4111) by switching process.env property access to bracket notation. --- examples/react-lazy-bundle-standalone/src/entry-url.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/react-lazy-bundle-standalone/src/entry-url.ts b/examples/react-lazy-bundle-standalone/src/entry-url.ts index 1dff1852ac..4235546bb3 100644 --- a/examples/react-lazy-bundle-standalone/src/entry-url.ts +++ b/examples/react-lazy-bundle-standalone/src/entry-url.ts @@ -1,6 +1,8 @@ export function createProducerBundleUrl(bundleFileName: string): string { - if (process.env.NODE_ENV === 'production') { - return `http://${process.env.LYNX_STANDALONE_PRODUCER_HOST}:${process.env.LYNX_STANDALONE_PRODUCER_PORT}/${bundleFileName}`; + if (process.env['NODE_ENV'] === 'production') { + return `http://${process.env['LYNX_STANDALONE_PRODUCER_HOST']}:${ + process.env['LYNX_STANDALONE_PRODUCER_PORT'] + }/${bundleFileName}`; } return `${__webpack_public_path__}producer/${bundleFileName}`; } From a99d88f72c53e8e5a4a6eff436fcb2fa3474b983 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:48:37 +0800 Subject: [PATCH 23/43] chore(changeset): convert lazy-bundle-fetch-bundle to a release entry The FetchBundle path is now coherent enough to ship behind `engineVersion: '3.8'`: cross-thread MT prep, mode hints, and bytecoded MTS section are all wired up. --- .changeset/lazy-bundle-fetch-bundle.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.changeset/lazy-bundle-fetch-bundle.md b/.changeset/lazy-bundle-fetch-bundle.md index 361816f843..cc217563d7 100644 --- a/.changeset/lazy-bundle-fetch-bundle.md +++ b/.changeset/lazy-bundle-fetch-bundle.md @@ -1,12 +1,15 @@ --- - +"@lynx-js/react": patch +"@lynx-js/react-rsbuild-plugin": patch +"@lynx-js/react-webpack-plugin": patch +"@lynx-js/react-transform": patch +"@lynx-js/template-webpack-plugin": patch --- -No package release is required yet. This PR wires the FetchBundle-based -lazy bundle loader path (customSections-based output, JsBytecode encoded -MTS, single CSS section, version-gated default fetcher) behind an -opt-in env var fallback. The feature is incomplete pending downstream -work (engineVersion ≥ 3.8 host availability, @lynx-js/types release with -fetchBundle / loadScript declarations) and will continue to evolve. A -release changeset should be added once the FetchBundle path ships as a -coherent user-visible change. +feat(lazy-bundle): add `lynx.fetchBundle`-based loader + +Opt in by setting `engineVersion: '3.8'` (or higher) in `pluginReactLynx`. +Use `import('./X', { with: { mode: 'sync' | 'async' } })` to control whether +the first screen blocks on a sync fetch. The lazy bundle's main-thread +section is bytecoded by default (skipped in dev or when `DEBUG` includes +`rspeedy`). From 036d48e0877d5cc9f4ed73b2e5fbbe688a79f4b6 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:49:43 +0800 Subject: [PATCH 24/43] chore(changeset): bump lazy-bundle FetchBundle entry to minor --- .changeset/lazy-bundle-fetch-bundle.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.changeset/lazy-bundle-fetch-bundle.md b/.changeset/lazy-bundle-fetch-bundle.md index cc217563d7..4bcd5e3575 100644 --- a/.changeset/lazy-bundle-fetch-bundle.md +++ b/.changeset/lazy-bundle-fetch-bundle.md @@ -1,9 +1,9 @@ --- -"@lynx-js/react": patch -"@lynx-js/react-rsbuild-plugin": patch -"@lynx-js/react-webpack-plugin": patch -"@lynx-js/react-transform": patch -"@lynx-js/template-webpack-plugin": patch +"@lynx-js/react": minor +"@lynx-js/react-rsbuild-plugin": minor +"@lynx-js/react-webpack-plugin": minor +"@lynx-js/react-transform": minor +"@lynx-js/template-webpack-plugin": minor --- feat(lazy-bundle): add `lynx.fetchBundle`-based loader From ccdafb867a2c8d5c73ce9affc37c8cca394a4367 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 21:58:12 +0800 Subject: [PATCH 25/43] chore(changeset): satisfy peer ranges for FetchBundle minor bumps Drop the private `@lynx-js/react-transform` from the lazy-bundle release (mixed-changeset error) and extend three peer ranges so the minor bumps of `@lynx-js/react-webpack-plugin` and `@lynx-js/template-webpack-plugin` don't cascade into a major on their peer-dependents. --- .changeset/lazy-bundle-fetch-bundle.md | 1 - packages/webpack/css-extract-webpack-plugin/package.json | 2 +- packages/webpack/react-refresh-webpack-plugin/package.json | 2 +- packages/webpack/react-webpack-plugin/package.json | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.changeset/lazy-bundle-fetch-bundle.md b/.changeset/lazy-bundle-fetch-bundle.md index 4bcd5e3575..d096c5ac56 100644 --- a/.changeset/lazy-bundle-fetch-bundle.md +++ b/.changeset/lazy-bundle-fetch-bundle.md @@ -2,7 +2,6 @@ "@lynx-js/react": minor "@lynx-js/react-rsbuild-plugin": minor "@lynx-js/react-webpack-plugin": minor -"@lynx-js/react-transform": minor "@lynx-js/template-webpack-plugin": minor --- diff --git a/packages/webpack/css-extract-webpack-plugin/package.json b/packages/webpack/css-extract-webpack-plugin/package.json index 1bcd623b3d..9152f68774 100644 --- a/packages/webpack/css-extract-webpack-plugin/package.json +++ b/packages/webpack/css-extract-webpack-plugin/package.json @@ -59,7 +59,7 @@ "webpack": "^5.105.2" }, "peerDependencies": { - "@lynx-js/template-webpack-plugin": "^0.11.0" + "@lynx-js/template-webpack-plugin": "^0.11.0 || ^0.12.0" }, "engines": { "node": ">=18" diff --git a/packages/webpack/react-refresh-webpack-plugin/package.json b/packages/webpack/react-refresh-webpack-plugin/package.json index af1dbd32aa..a85827fa8d 100644 --- a/packages/webpack/react-refresh-webpack-plugin/package.json +++ b/packages/webpack/react-refresh-webpack-plugin/package.json @@ -49,7 +49,7 @@ "webpack": "^5.105.2" }, "peerDependencies": { - "@lynx-js/react-webpack-plugin": "^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0" + "@lynx-js/react-webpack-plugin": "^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0" }, "engines": { "node": ">=18" diff --git a/packages/webpack/react-webpack-plugin/package.json b/packages/webpack/react-webpack-plugin/package.json index 4f7a6acfc8..eba7e42ecc 100644 --- a/packages/webpack/react-webpack-plugin/package.json +++ b/packages/webpack/react-webpack-plugin/package.json @@ -53,7 +53,7 @@ "webpack": "^5.105.2" }, "peerDependencies": { - "@lynx-js/template-webpack-plugin": "^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0" + "@lynx-js/template-webpack-plugin": "^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0" }, "peerDependenciesMeta": { "@lynx-js/react": { From 51eac2a51a57092edd3a417e01bb8bfec74bf44d Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 22:02:00 +0800 Subject: [PATCH 26/43] test(plugin-react): add lazyBundleFetcher to default options snapshot The default `lazyBundleFetcher` ('QueryComponent') is now part of the options handed to LynxTemplatePlugin. --- packages/rspeedy/plugin-react/test/config.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/rspeedy/plugin-react/test/config.test.ts b/packages/rspeedy/plugin-react/test/config.test.ts index 0376185045..d8524de016 100644 --- a/packages/rspeedy/plugin-react/test/config.test.ts +++ b/packages/rspeedy/plugin-react/test/config.test.ts @@ -2245,6 +2245,7 @@ describe('Config', () => { "experimental_isLazyBundle": false, "filename": "main.lynx.bundle", "intermediate": ".rspeedy/main", + "lazyBundleFetcher": "QueryComponent", "removeDescendantSelectorScope": true, "targetSdkVersion": "3.2", } From bc0229ed4107597f0b44cef6526548d462cc5e5d Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 22:14:02 +0800 Subject: [PATCH 27/43] chore: refresh lockfile after merging origin/main Pick up the new `packages/genui/openui` package added by #2600 and dedupe a stack of `@rsbuild/core@2.0.0-beta.3` indirect deps that sherif flagged. --- pnpm-lock.yaml | 131 +++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 92 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf6a2ee24a..6aaa445cc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -320,7 +320,7 @@ importers: version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -708,8 +708,8 @@ importers: specifier: workspace:* version: link:../../react '@lynx-js/types': - specifier: 3.7.0 - version: 3.7.0 + specifier: file:../../../vendor/lynx-js-types-3.10.0.tgz + version: file:vendor/lynx-js-types-3.10.0.tgz '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -739,7 +739,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -1451,10 +1451,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.6.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1469,7 +1469,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1563,7 +1563,7 @@ importers: version: file:vendor/lynx-js-types-3.10.0.tgz '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -1941,7 +1941,7 @@ importers: version: link:../test-tools '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2122,7 +2122,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2165,7 +2165,7 @@ importers: version: 7.58.2(@types/node@24.10.13) '@rspack/test-tools': specifier: catalog:rspack - version: 1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21)) + version: 1.5.6(@rspack/core@1.7.9(@swc/helpers@0.5.21)) '@rstest/core': specifier: catalog:rstest version: 0.8.1(jsdom@27.4.0) @@ -2177,7 +2177,7 @@ importers: version: 1.0.4 css-loader: specifier: ^7.1.4 - version: 7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2) + version: 7.1.4(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2) webpack: specifier: ^5.105.2 version: 5.105.2 @@ -2313,13 +2313,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.2.2(@rsbuild/core@1.7.5) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -13767,13 +13767,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13813,9 +13813,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13844,15 +13844,6 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 - '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - deepmerge: 4.3.1 - loader-utils: 2.0.4 - postcss: 8.5.6 - reduce-configs: 1.1.1 - sass-embedded: 1.97.3 - '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13861,6 +13852,19 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': + dependencies: + deepmerge: 4.3.1 + json5: 2.2.3 + reduce-configs: 1.1.1 + ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + optionalDependencies: + '@rsbuild/core': 1.7.5 + transitivePeerDependencies: + - '@rspack/core' + - tslib + - typescript + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 @@ -13878,10 +13882,6 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - '@rsdoctor/client@1.5.6': {} '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': @@ -14234,45 +14234,6 @@ snapshots: - utf-8-validate - webpack-cli - '@rspack/test-tools@1.5.6(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))': - dependencies: - '@babel/generator': 7.28.3 - '@babel/parser': 7.28.4 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) - cross-env: 10.1.0 - csv-to-markdown-table: 1.6.3 - deepmerge: 4.3.1 - filenamify: 4.3.0 - fs-extra: 11.3.3 - glob: 11.1.0 - graceful-fs: 4.2.11 - iconv-lite: 0.6.3 - jest-diff: 29.7.0 - jest-snapshot: 29.7.0 - jsdom: 26.1.0 - loader-utils: 2.0.4 - memfs: 4.38.2 - path-serializer: 0.5.1 - pretty-format: 29.7.0 - rimraf: 5.0.10 - source-map: 0.7.6 - terser-webpack-plugin: 5.3.16(webpack@5.99.9) - wast-loader: 1.14.1 - webpack: 5.99.9 - webpack-merge: 6.0.1 - webpack-sources: 3.3.3 - transitivePeerDependencies: - - '@swc/core' - - bufferutil - - canvas - - esbuild - - supports-color - - uglify-js - - utf-8-validate - - webpack-cli - '@rspress/core@2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0)': dependencies: '@mdx-js/mdx': 3.1.1 @@ -16068,20 +16029,6 @@ snapshots: '@rspack/core': 1.7.9(@swc/helpers@0.5.21) webpack: 5.105.2 - css-loader@7.1.4(@rspack/core@2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21))(webpack@5.105.2): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) - postcss-modules-local-by-default: 4.0.5(postcss@8.5.6) - postcss-modules-scope: 3.2.0(postcss@8.5.6) - postcss-modules-values: 4.0.0(postcss@8.5.6) - postcss-value-parser: 4.2.0 - semver: 7.7.4 - optionalDependencies: - '@rspack/core': 2.0.0-beta.0(@module-federation/runtime-tools@0.22.0)(@swc/helpers@0.5.21) - webpack: 5.105.2 - css-minimizer-webpack-plugin@7.0.2(lightningcss@1.31.1)(webpack@5.105.2): dependencies: '@jridgewell/trace-mapping': 0.3.29 @@ -20154,10 +20101,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20177,15 +20124,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) From d7126e1fb3042519605250b14eb5f034a835b438 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 22:39:55 +0800 Subject: [PATCH 28/43] test(react): cover FetchBundle runtime path Add 29 tests for the FetchBundle runtime: MT sync first-screen, BG sync, BG async cb-as-readiness ordering, mode + QueryComponent dev throw, withLazyBundleMode mode restoration, and the MT-side prepareLazyBundleMTS handler (cache, success, all failure modes, processEvalResult absent). --- .../lynx/lazy-bundle-fetchbundle.test.js | 435 ++++++++++++++++++ .../lynx/prepareLazyBundleMTS.test.js | 166 +++++++ 2 files changed, 601 insertions(+) create mode 100644 packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js create mode 100644 packages/react/runtime/__test__/snapshot/lynx/prepareLazyBundleMTS.test.js diff --git a/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js b/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js new file mode 100644 index 0000000000..4666e1fc42 --- /dev/null +++ b/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js @@ -0,0 +1,435 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +/* global lynx */ + +const TIMEOUT_SECONDS = 5; + +beforeEach(() => { + vi.resetModules(); + vi.unstubAllGlobals().stubGlobal('__LAZY_BUNDLE_FETCHER__', 'FetchBundle'); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe('loadLazyBundle (FetchBundle) — main thread sync', () => { + let fetchBundle; + let waitMock; + let loadScript; + let loadStyleSheet; + let adoptStyleSheet; + + beforeEach(() => { + waitMock = vi.fn(); + fetchBundle = vi.fn(() => ({ wait: waitMock })); + loadScript = vi.fn(); + loadStyleSheet = vi.fn(); + adoptStyleSheet = vi.fn(); + vi + .stubGlobal('__LEPUS__', true) + .stubGlobal('__MAIN_THREAD__', true) + .stubGlobal('lynx', { fetchBundle, loadScript }) + .stubGlobal('__LoadStyleSheet', loadStyleSheet) + .stubGlobal('__AdoptStyleSheet', adoptStyleSheet); + }); + + test('happy path: .wait → loadScript(main-thread) → CSS adopt → sync then', async () => { + waitMock.mockReturnValueOnce({ code: 0, url: 'cached-url' }); + loadScript.mockReturnValueOnce({ default: 'MTChunk' }); + loadStyleSheet.mockReturnValueOnce({ id: 'sheet' }); + + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + + expect(fetchBundle).toHaveBeenCalledWith('foo', {}); + expect(waitMock).toHaveBeenCalledWith(TIMEOUT_SECONDS); + expect(loadScript).toHaveBeenCalledWith('main-thread', { + bundleName: 'cached-url', + }); + expect(loadStyleSheet).toHaveBeenCalledWith('CSS', 'cached-url'); + expect(adoptStyleSheet).toHaveBeenCalledWith({ id: 'sheet' }); + + let thenCalled = false; + promise.then((v) => { + expect(v).toEqual({ default: 'MTChunk' }); + thenCalled = true; + }); + expect(thenCalled).toBe(true); + }); + + test('async mode (mode !== sync) returns never-resolving promise', async () => { + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('async', () => loadLazyBundle('foo')); + + expect(fetchBundle).not.toHaveBeenCalled(); + promise.then( + () => expect.fail('should not resolve'), + () => expect.fail('should not reject'), + ); + await Promise.resolve(); + }); + + test('.wait throws → never-resolving', async () => { + waitMock.mockImplementationOnce(() => { + throw new Error('timeout'); + }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + + expect(loadScript).not.toHaveBeenCalled(); + promise.then( + () => expect.fail('should not resolve'), + () => expect.fail('should not reject'), + ); + await Promise.resolve(); + }); + + test('response.code !== 0 → never-resolving', async () => { + waitMock.mockReturnValueOnce({ code: 1, url: 'x' }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + + expect(loadScript).not.toHaveBeenCalled(); + promise.then( + () => expect.fail('should not resolve'), + () => expect.fail('should not reject'), + ); + await Promise.resolve(); + }); + + test('loadScript throws → never-resolving', async () => { + waitMock.mockReturnValueOnce({ code: 0, url: 'x' }); + loadScript.mockImplementationOnce(() => { + throw new Error('no MTS section'); + }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + + expect(adoptStyleSheet).not.toHaveBeenCalled(); + promise.then( + () => expect.fail('should not resolve'), + () => expect.fail('should not reject'), + ); + await Promise.resolve(); + }); + + test('null stylesheet → chunk still resolved, no AdoptStyleSheet', async () => { + waitMock.mockReturnValueOnce({ code: 0, url: 'x' }); + loadScript.mockReturnValueOnce({ default: 'C' }); + loadStyleSheet.mockReturnValueOnce(null); + + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + + expect(loadStyleSheet).toHaveBeenCalled(); + expect(adoptStyleSheet).not.toHaveBeenCalled(); + + let resolved; + promise.then((v) => { + resolved = v; + }); + expect(resolved).toEqual({ default: 'C' }); + }); +}); + +describe('loadLazyBundle (FetchBundle) — background sync', () => { + let fetchBundle; + let waitMock; + let loadScript; + + beforeEach(() => { + waitMock = vi.fn(); + fetchBundle = vi.fn(() => ({ wait: waitMock })); + loadScript = vi.fn(); + vi + .stubGlobal('__LEPUS__', false) + .stubGlobal('__MAIN_THREAD__', false) + .stubGlobal('__BACKGROUND__', true) + .stubGlobal('__JS__', true) + .stubGlobal('lynx', { fetchBundle, loadScript }); + }); + + test('happy path: .wait → loadScript(background) → sync then', async () => { + waitMock.mockReturnValueOnce({ code: 0, url: 'u' }); + loadScript.mockReturnValueOnce({ default: 'BG' }); + + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + + expect(fetchBundle).toHaveBeenCalledWith('foo', {}); + expect(loadScript).toHaveBeenCalledWith('background', { bundleName: 'u' }); + + let thenCalled = false; + promise.then((v) => { + expect(v).toEqual({ default: 'BG' }); + thenCalled = true; + }); + expect(thenCalled).toBe(true); + }); + + test('.wait throws → reject', async () => { + waitMock.mockImplementationOnce(() => { + throw new Error('timeout'); + }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + await expect(promise).rejects.toThrow('timeout'); + }); + + test('response.code !== 0 → reject with cause', async () => { + waitMock.mockReturnValueOnce({ code: 2, url: 'u' }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + await expect(promise).rejects.toMatchObject({ + message: 'Lazy bundle load failed, schema: foo', + cause: '{"code":2,"url":"u"}', + }); + }); + + test('loadScript throws → reject', async () => { + waitMock.mockReturnValueOnce({ code: 0, url: 'u' }); + loadScript.mockImplementationOnce(() => { + throw new Error('boom'); + }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); + await expect(promise).rejects.toThrow('boom'); + }); +}); + +describe('loadLazyBundle (FetchBundle) — background async (cb-as-readiness)', () => { + let fetchBundle; + let thenMock; + let loadScript; + let callLepusMethod; + let getNativeApp; + + beforeEach(() => { + thenMock = vi.fn(); + fetchBundle = vi.fn(() => ({ then: thenMock })); + loadScript = vi.fn(); + callLepusMethod = vi.fn(); + getNativeApp = vi.fn(() => ({ callLepusMethod })); + vi + .stubGlobal('__LEPUS__', false) + .stubGlobal('__MAIN_THREAD__', false) + .stubGlobal('__BACKGROUND__', true) + .stubGlobal('__JS__', true) + .stubGlobal('lynx', { fetchBundle, loadScript, getNativeApp }); + }); + + test('happy path: .then → loadScript → callLepusMethod → cb resolves', async () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValueOnce({ default: 'BG' }); + callLepusMethod.mockImplementationOnce((_name, _payload, cb) => cb()); + + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + const promise = loadLazyBundle('foo'); + + expect(callLepusMethod).toHaveBeenCalledWith( + 'rLynxPrepareLazyBundleMTS', + { url: 'foo' }, + expect.any(Function), + ); + await expect(promise).resolves.toEqual({ default: 'BG' }); + }); + + test('cb only fires AFTER loadScript completes (sequencing)', async () => { + const events = []; + thenMock.mockImplementationOnce((cb) => { + events.push('then-start'); + cb({ code: 0, url: 'u' }); + events.push('then-end'); + }); + loadScript.mockImplementationOnce(() => { + events.push('loadScript'); + return { default: 'BG' }; + }); + callLepusMethod.mockImplementationOnce((_n, _p, cb) => { + events.push('callLepusMethod-start'); + cb(); + events.push('callLepusMethod-cb'); + }); + + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + + await loadLazyBundle('foo'); + expect(events).toEqual([ + 'then-start', + 'loadScript', + 'callLepusMethod-start', + 'callLepusMethod-cb', + 'then-end', + ]); + }); + + test('fetchBundle throws sync → reject', async () => { + fetchBundle.mockImplementationOnce(() => { + throw new Error('net'); + }); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow('net'); + expect(callLepusMethod).not.toHaveBeenCalled(); + }); + + test('response.code !== 0 → reject with cause, no loadScript', async () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 1, url: 'u' })); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toMatchObject({ + message: 'Lazy bundle load failed, schema: foo', + cause: '{"code":1,"url":"u"}', + }); + expect(loadScript).not.toHaveBeenCalled(); + expect(callLepusMethod).not.toHaveBeenCalled(); + }); + + test('loadScript throws → reject, no callLepusMethod', async () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockImplementationOnce(() => { + throw new Error('boom'); + }); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow('boom'); + expect(callLepusMethod).not.toHaveBeenCalled(); + }); + + test('callLepusMethod throws → reject', async () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValueOnce({ default: 'BG' }); + callLepusMethod.mockImplementationOnce(() => { + throw new Error('lepus down'); + }); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow('lepus down'); + }); +}); + +describe('mode + QueryComponent — dev throw', () => { + beforeEach(() => { + vi + .stubGlobal('__LEPUS__', false) + .stubGlobal('__MAIN_THREAD__', false) + .stubGlobal('__BACKGROUND__', true) + .stubGlobal('__JS__', true) + .stubGlobal('__LAZY_BUNDLE_FETCHER__', 'QueryComponent') + .stubGlobal('lynx', { QueryComponent: vi.fn() }) + .stubGlobal('lynxCoreInject', { tt: { getDynamicComponentExports: vi.fn() } }); + }); + + test('__DEV__ + mode set → throws', async () => { + vi.stubGlobal('__DEV__', true); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + expect(() => withLazyBundleMode('sync', () => loadLazyBundle('foo'))).toThrow( + /requires FetchBundle/, + ); + }); + + test('prod (__DEV__: false) + mode set → no throw, falls through to QueryComponent', async () => { + vi.stubGlobal('__DEV__', false); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + // Doesn't throw; still calls QueryComponent (callback never fires here, so promise pends). + expect(() => withLazyBundleMode('sync', () => loadLazyBundle('foo'))).not.toThrow(); + expect(lynx.QueryComponent).toHaveBeenCalledWith('foo', expect.any(Function)); + }); + + test('__DEV__ + no mode → no throw', async () => { + vi.stubGlobal('__DEV__', true); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + expect(() => loadLazyBundle('foo')).not.toThrow(); + }); +}); + +describe('withLazyBundleMode helper', () => { + beforeEach(() => { + vi + .stubGlobal('__LEPUS__', false) + .stubGlobal('__MAIN_THREAD__', false) + .stubGlobal('__BACKGROUND__', true) + .stubGlobal('__JS__', true); + }); + + test('restores prior mode after factory returns', async () => { + const { withLazyBundleMode } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + let inner; + withLazyBundleMode('sync', () => { + withLazyBundleMode('async', () => { + inner = 'async'; + }); + inner += '-then-sync'; + }); + expect(inner).toBe('async-then-sync'); + }); + + test('restores prior mode even if factory throws', async () => { + const { withLazyBundleMode } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + expect(() => + withLazyBundleMode('sync', () => { + throw new Error('factory err'); + }) + ).toThrow('factory err'); + // After exit, mode is restored (undefined). Use it again to confirm no leak. + let leaked; + withLazyBundleMode('async', () => { + leaked = 'async'; + }); + expect(leaked).toBe('async'); + }); +}); diff --git a/packages/react/runtime/__test__/snapshot/lynx/prepareLazyBundleMTS.test.js b/packages/react/runtime/__test__/snapshot/lynx/prepareLazyBundleMTS.test.js new file mode 100644 index 0000000000..8ec5abedea --- /dev/null +++ b/packages/react/runtime/__test__/snapshot/lynx/prepareLazyBundleMTS.test.js @@ -0,0 +1,166 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +/* global lynx */ + +// `prepareLazyBundleMTS` is the MT-side handler registered for the +// `rLynxPrepareLazyBundleMTS` lifecycle. It runs after BG calls +// `callLepusMethod`, with the bundle already in native cache (so +// `lynx.fetchBundle(url, {}).then(cb)` fires sync on lepus). + +describe('prepareLazyBundleMTS handler', () => { + let fetchBundle; + let thenMock; + let loadScript; + let loadStyleSheet; + let adoptStyleSheet; + let processEvalResult; + let injectPrepareLazyBundleMTS; + + beforeEach(async () => { + vi.resetModules(); + vi.unstubAllGlobals(); + + thenMock = vi.fn(); + fetchBundle = vi.fn(() => ({ then: thenMock })); + loadScript = vi.fn(); + loadStyleSheet = vi.fn(); + adoptStyleSheet = vi.fn(); + processEvalResult = vi.fn(); + + vi + .stubGlobal('lynx', { fetchBundle, loadScript }) + .stubGlobal('__LoadStyleSheet', loadStyleSheet) + .stubGlobal('__AdoptStyleSheet', adoptStyleSheet) + .stubGlobal('processEvalResult', processEvalResult); + + ({ injectPrepareLazyBundleMTS } = await import( + '../../../src/snapshot/lynx/prepareLazyBundleMTS' + )); + injectPrepareLazyBundleMTS(); + }); + + afterEach(() => { + delete globalThis.rLynxPrepareLazyBundleMTS; + vi.unstubAllGlobals(); + }); + + function invoke(url) { + return globalThis.rLynxPrepareLazyBundleMTS({ url }); + } + + test('happy path: fetchBundle.then → loadScript(main-thread) → processEvalResult → CSS adopt', () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValueOnce({ chunk: 'x' }); + loadStyleSheet.mockReturnValueOnce({ id: 'sheet' }); + + invoke('foo'); + + expect(fetchBundle).toHaveBeenCalledWith('foo', {}); + expect(loadScript).toHaveBeenCalledWith('main-thread', { bundleName: 'u' }); + expect(processEvalResult).toHaveBeenCalledWith(expect.any(Function), 'foo'); + // The factory passed to processEvalResult returns the loaded chunk. + const factory = processEvalResult.mock.calls[0][0]; + expect(factory()).toEqual({ chunk: 'x' }); + expect(loadStyleSheet).toHaveBeenCalledWith('CSS', 'u'); + expect(adoptStyleSheet).toHaveBeenCalledWith({ id: 'sheet' }); + }); + + test('cache: second call with same url is a no-op', () => { + thenMock.mockImplementation((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValue({ chunk: 'x' }); + loadStyleSheet.mockReturnValue(null); + + invoke('foo'); + invoke('foo'); + + expect(fetchBundle).toHaveBeenCalledTimes(1); + expect(loadScript).toHaveBeenCalledTimes(1); + expect(processEvalResult).toHaveBeenCalledTimes(1); + }); + + test('cache: different urls are not deduped', () => { + thenMock.mockImplementation((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValue({ chunk: 'x' }); + loadStyleSheet.mockReturnValue(null); + + invoke('foo'); + invoke('bar'); + + expect(fetchBundle).toHaveBeenCalledTimes(2); + expect(fetchBundle).toHaveBeenNthCalledWith(1, 'foo', {}); + expect(fetchBundle).toHaveBeenNthCalledWith(2, 'bar', {}); + }); + + test('fetchBundle throws sync → silent skip, no side effects', () => { + fetchBundle.mockImplementationOnce(() => { + throw new Error('net'); + }); + + expect(() => invoke('foo')).not.toThrow(); + expect(loadScript).not.toHaveBeenCalled(); + expect(processEvalResult).not.toHaveBeenCalled(); + expect(loadStyleSheet).not.toHaveBeenCalled(); + }); + + test('response.code !== 0 → silent skip', () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 1, url: 'u' })); + + invoke('foo'); + + expect(loadScript).not.toHaveBeenCalled(); + expect(processEvalResult).not.toHaveBeenCalled(); + expect(loadStyleSheet).not.toHaveBeenCalled(); + }); + + test('loadScript throws (BG-only bundle) → no processEvalResult, no CSS', () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockImplementationOnce(() => { + throw new Error('no MTS section'); + }); + + expect(() => invoke('foo')).not.toThrow(); + expect(processEvalResult).not.toHaveBeenCalled(); + expect(loadStyleSheet).not.toHaveBeenCalled(); + }); + + test('processEvalResult absent → still loadScript + CSS adopt', async () => { + // Re-import without processEvalResult global. + vi.resetModules(); + delete globalThis.rLynxPrepareLazyBundleMTS; + vi.unstubAllGlobals(); + thenMock = vi.fn((cb) => cb({ code: 0, url: 'u' })); + fetchBundle = vi.fn(() => ({ then: thenMock })); + loadScript = vi.fn(() => ({ chunk: 'x' })); + loadStyleSheet = vi.fn(() => ({ id: 'sheet' })); + adoptStyleSheet = vi.fn(); + vi + .stubGlobal('lynx', { fetchBundle, loadScript }) + .stubGlobal('__LoadStyleSheet', loadStyleSheet) + .stubGlobal('__AdoptStyleSheet', adoptStyleSheet); + // No processEvalResult stub. + + const fresh = await import( + '../../../src/snapshot/lynx/prepareLazyBundleMTS' + ); + fresh.injectPrepareLazyBundleMTS(); + + expect(() => globalThis.rLynxPrepareLazyBundleMTS({ url: 'foo' })).not.toThrow(); + expect(loadScript).toHaveBeenCalled(); + expect(adoptStyleSheet).toHaveBeenCalledWith({ id: 'sheet' }); + }); + + test('null stylesheet → no AdoptStyleSheet call', () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValueOnce({ chunk: 'x' }); + loadStyleSheet.mockReturnValueOnce(null); + + invoke('foo'); + + expect(loadStyleSheet).toHaveBeenCalled(); + expect(adoptStyleSheet).not.toHaveBeenCalled(); + }); +}); From f54614e97acf64e54e27a609a94b189ae8ee6949 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 22:46:33 +0800 Subject: [PATCH 29/43] test(react): cover remaining FetchBundle branches and unreachable Bring lazy-bundle.ts to 100% coverage by adding tests for the unreachable path under FetchBundle, the `!response` short-circuit, and the non-Error throw fallbacks for fetchBundle/loadScript/.wait/ callLepusMethod. --- .../lynx/lazy-bundle-fetchbundle.test.js | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js b/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js index 4666e1fc42..f999e597e0 100644 --- a/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js +++ b/packages/react/runtime/__test__/snapshot/lynx/lazy-bundle-fetchbundle.test.js @@ -230,6 +230,59 @@ describe('loadLazyBundle (FetchBundle) — background sync', () => { const promise = withLazyBundleMode('sync', () => loadLazyBundle('foo')); await expect(promise).rejects.toThrow('boom'); }); + + test('undefined response → reject (covers !response branch)', async () => { + waitMock.mockReturnValueOnce(undefined); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect( + withLazyBundleMode('sync', () => loadLazyBundle('foo')), + ).rejects.toThrow('Lazy bundle load failed, schema: foo'); + }); + + test('.wait throws non-Error → wrapped reject', async () => { + waitMock.mockImplementationOnce(() => { + // eslint-disable-next-line no-throw-literal + throw 'string err'; + }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect( + withLazyBundleMode('sync', () => loadLazyBundle('foo')), + ).rejects.toThrow('string err'); + }); + + test('loadScript throws non-Error → wrapped reject', async () => { + waitMock.mockReturnValueOnce({ code: 0, url: 'u' }); + loadScript.mockImplementationOnce(() => { + // eslint-disable-next-line no-throw-literal + throw 'load boom'; + }); + const { withLazyBundleMode, loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect( + withLazyBundleMode('sync', () => loadLazyBundle('foo')), + ).rejects.toThrow('load boom'); + }); +}); + +describe('loadLazyBundle (FetchBundle) — unreachable', () => { + test('throws when neither MT nor JS', async () => { + vi.resetModules(); + vi.unstubAllGlobals() + .stubGlobal('__LAZY_BUNDLE_FETCHER__', 'FetchBundle') + .stubGlobal('__MAIN_THREAD__', false) + .stubGlobal('__LEPUS__', false) + .stubGlobal('__JS__', false) + .stubGlobal('__BACKGROUND__', false); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + expect(() => loadLazyBundle('foo')).toThrow('unreachable'); + }); }); describe('loadLazyBundle (FetchBundle) — background async (cb-as-readiness)', () => { @@ -327,6 +380,52 @@ describe('loadLazyBundle (FetchBundle) — background async (cb-as-readiness)', expect(callLepusMethod).not.toHaveBeenCalled(); }); + test('undefined response → reject (covers !response branch)', async () => { + thenMock.mockImplementationOnce((cb) => cb(undefined)); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow( + 'Lazy bundle load failed, schema: foo', + ); + }); + + test('fetchBundle throws non-Error sync → wrapped reject', async () => { + fetchBundle.mockImplementationOnce(() => { + // eslint-disable-next-line no-throw-literal + throw 'string err'; + }); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow('string err'); + }); + + test('callLepusMethod throws non-Error → wrapped reject', async () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockReturnValueOnce({ default: 'BG' }); + callLepusMethod.mockImplementationOnce(() => { + // eslint-disable-next-line no-throw-literal + throw 'lepus boom'; + }); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow('lepus boom'); + }); + + test('loadScript throws non-Error → wrapped reject', async () => { + thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); + loadScript.mockImplementationOnce(() => { + // eslint-disable-next-line no-throw-literal + throw 'load boom'; + }); + const { loadLazyBundle } = await import( + '../../../src/snapshot/lynx/lazy-bundle' + ); + await expect(loadLazyBundle('foo')).rejects.toThrow('load boom'); + }); + test('loadScript throws → reject, no callLepusMethod', async () => { thenMock.mockImplementationOnce((cb) => cb({ code: 0, url: 'u' })); loadScript.mockImplementationOnce(() => { From 5c266dc75225fd56d3ebc2617dc5689ea8c81dad Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 23:10:23 +0800 Subject: [PATCH 30/43] test(template-plugin): cover FetchBundle output shape and bytecode gating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run an async-chunk fixture through LynxTemplatePlugin and capture encode options via beforeEmit to assert: - FetchBundle: lazy bundle emits main-thread + background customSections (lepusCode.root drained, css.cssMap empty) - QueryComponent (default): keeps legacy lepusCode + manifest shape - bytecode default: production → JsBytecode, development → off, DEBUG=rspeedy → off, DEBUG=other → still on --- .../fixtures/lazy-bundle-fetcher/entry.js | 5 + .../fixtures/lazy-bundle-fetcher/foo.bts.js | 4 + .../fixtures/lazy-bundle-fetcher/foo.mts.js | 4 + .../test/lazy-bundle-fetcher.test.ts | 219 ++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/entry.js create mode 100644 packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.bts.js create mode 100644 packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.mts.js create mode 100644 packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts diff --git a/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/entry.js b/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/entry.js new file mode 100644 index 0000000000..d0fade2b33 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/entry.js @@ -0,0 +1,5 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import(/* webpackChunkName: 'foo:main-thread' */ './foo.mts.js'); +import(/* webpackChunkName: 'foo:background' */ './foo.bts.js'); diff --git a/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.bts.js b/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.bts.js new file mode 100644 index 0000000000..5f076d2fec --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.bts.js @@ -0,0 +1,4 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +export const layer = 'background'; diff --git a/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.mts.js b/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.mts.js new file mode 100644 index 0000000000..b340bd7651 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/fixtures/lazy-bundle-fetcher/foo.mts.js @@ -0,0 +1,4 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +export const layer = 'main-thread'; diff --git a/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts b/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts new file mode 100644 index 0000000000..a33517f243 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts @@ -0,0 +1,219 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { dirname } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, test } from '@rstest/core'; +import webpack from 'webpack'; + +import { LynxEncodePlugin, LynxTemplatePlugin } from '../src/index.js'; + +const FIXTURE_ENTRY = './fixtures/lazy-bundle-fetcher/entry.js'; +const CONTEXT = dirname(new URL(import.meta.url).pathname); + +interface CapturedEncode { + outputName: string; + customSections: Record; + manifest: Record | undefined; + lepusCodeRoot: string | undefined; + cssMap: Record | undefined; +} + +function captureBeforeEmit() { + const captured: CapturedEncode[] = []; + const plugin = (compiler: webpack.Compiler) => { + compiler.hooks.thisCompilation.tap('cap', (compilation) => { + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation); + hooks.beforeEmit.tapPromise('cap', (args) => { + captured.push({ + outputName: args.outputName, + customSections: args.finalEncodeOptions.customSections as Record< + string, + { content: unknown; encoding?: string } + >, + manifest: args.finalEncodeOptions.manifest, + lepusCodeRoot: args.finalEncodeOptions.lepusCode?.root, + cssMap: (args.finalEncodeOptions['css'] as + | { cssMap?: Record } + | undefined) + ?.cssMap, + }); + return Promise.resolve(args); + }); + }); + }; + return { captured, plugin }; +} + +function buildConfig( + fetcherOptions: Partial< + NonNullable[0]> + >, + capturePlugin: (compiler: webpack.Compiler) => void, + mode: 'development' | 'production' = 'production', +): webpack.Configuration { + return { + context: CONTEXT, + mode, + devtool: false, + entry: FIXTURE_ENTRY, + output: { iife: false }, + plugins: [ + capturePlugin, + new LynxTemplatePlugin({ + ...fetcherOptions, + intermediate: '.rspeedy/main', + }), + new LynxEncodePlugin(), + // Strip the React-style layer suffixes so MT/BG chunks share a + // template, mirroring the production setup that LynxTemplatePlugin + // is built for. + (compiler) => { + compiler.hooks.thisCompilation.tap('strip', (compilation) => { + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks( + compilation, + ); + hooks.asyncChunkName.tap( + 'strip', + (chunkName) => + chunkName.replace(':main-thread', '').replace(':background', ''), + ); + }); + }, + // Mark assets whose name contains `:main-thread` as + // `lynx:main-thread` so LynxTemplatePlugin routes them into the + // mainThread bucket (mirroring `react-webpack-plugin`'s loader). + (compiler) => { + compiler.hooks.thisCompilation.tap('mark-mt', (compilation) => { + compilation.hooks.processAssets.tap( + { + name: 'mark-mt', + stage: compiler.webpack.Compilation + .PROCESS_ASSETS_STAGE_DERIVED, + }, + (assets) => { + for (const name of Object.keys(assets)) { + if (!name.includes(':main-thread')) continue; + const asset = compilation.getAsset(name); + if (!asset) continue; + compilation.updateAsset(asset.name, asset.source, { + ...asset.info, + 'lynx:main-thread': true, + }); + } + }, + ); + }); + }, + ], + }; +} + +function runWebpack(config: webpack.Configuration): Promise { + const compiler = webpack(config); + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { + if (err) return reject(err); + if (!stats) return reject(new Error('webpack returned empty stats')); + resolve(stats); + compiler.close(() => void 0); + }); + }); +} + +describe('LynxTemplatePlugin: lazyBundleFetcher', () => { + const originalDebug = process.env['DEBUG']; + void beforeEach(() => { + // The vitest/rstest harness sets DEBUG=rspeedy by default, which + // would force bytecode off in every test below. Clear it so each + // test opts into a specific value. + delete process.env['DEBUG']; + }); + void afterEach(() => { + if (originalDebug === undefined) delete process.env['DEBUG']; + else process.env['DEBUG'] = originalDebug; + }); + + test('FetchBundle async chunk emits customSections shape', async () => { + const { captured, plugin } = captureBeforeEmit(); + const stats = await runWebpack( + buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin), + ); + expect(stats.compilation.errors).toEqual([]); + + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + expect(lazy).toBeDefined(); + + expect(lazy!.customSections['main-thread']).toBeDefined(); + expect(lazy!.customSections['main-thread']!.encoding).toBe('JsBytecode'); + expect(typeof lazy!.customSections['main-thread']!.content).toBe('string'); + + expect(lazy!.customSections['background']).toBeDefined(); + expect(lazy!.customSections['background']!.encoding).toBeUndefined(); + expect(typeof lazy!.customSections['background']!.content).toBe('string'); + + // For FetchBundle, lepusCode.root is moved into customSections; the + // legacy slot is empty. + expect(lazy!.lepusCodeRoot).toBeUndefined(); + expect(lazy!.cssMap).toEqual({}); + }); + + test('QueryComponent (default) keeps legacy lepusCode + manifest shape', async () => { + const { captured, plugin } = captureBeforeEmit(); + const stats = await runWebpack(buildConfig({}, plugin)); + expect(stats.compilation.errors).toEqual([]); + + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + expect(lazy).toBeDefined(); + + // Customsections shouldn't carry main-thread/background/CSS for + // QueryComponent — the legacy lepusCode + manifest path owns them. + expect(lazy!.customSections['main-thread']).toBeUndefined(); + expect(lazy!.customSections['background']).toBeUndefined(); + expect(lazy!.lepusCodeRoot).toBeDefined(); + }); + + describe('FetchBundle main-thread bytecode encoding', () => { + test('production → encoding: JsBytecode', async () => { + const { captured, plugin } = captureBeforeEmit(); + await runWebpack( + buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin, 'production'), + ); + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + expect(lazy!.customSections['main-thread']!.encoding).toBe('JsBytecode'); + }); + + test('development → no JsBytecode encoding', async () => { + const { captured, plugin } = captureBeforeEmit(); + await runWebpack( + buildConfig( + { lazyBundleFetcher: 'FetchBundle' }, + plugin, + 'development', + ), + ); + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + expect(lazy!.customSections['main-thread']!.encoding).toBeUndefined(); + }); + + test('DEBUG=rspeedy → no JsBytecode encoding even in production', async () => { + process.env['DEBUG'] = 'rspeedy'; + const { captured, plugin } = captureBeforeEmit(); + await runWebpack( + buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin, 'production'), + ); + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + expect(lazy!.customSections['main-thread']!.encoding).toBeUndefined(); + }); + + test('DEBUG=other → JsBytecode encoding still on', async () => { + process.env['DEBUG'] = 'unrelated'; + const { captured, plugin } = captureBeforeEmit(); + await runWebpack( + buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin, 'production'), + ); + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + expect(lazy!.customSections['main-thread']!.encoding).toBe('JsBytecode'); + }); + }); +}); From c4643926025a06f29c0ceb6d7bc47ce58a59b535 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 23:14:48 +0800 Subject: [PATCH 31/43] test(plugin-react): cover resolveLazyBundleFetcher decision matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 12 cases pinning down version gating + env override semantics: - default (no env): 3.8+ → FetchBundle, below → QueryComponent, undefined → QueryComponent, NaN-safe parse - 3.10 > 3.8 (numeric, not string compare) - REACT_LAZY_BUNDLE_FETCHER=FetchBundle: throws on insufficient version - REACT_LAZY_BUNDLE_FETCHER=QueryComponent: forces legacy regardless - unknown / empty env override: falls through to default --- .../test/resolveLazyBundleFetcher.test.ts | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts diff --git a/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts b/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts new file mode 100644 index 0000000000..a5c654fcd3 --- /dev/null +++ b/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts @@ -0,0 +1,95 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +import { afterEach, beforeEach, describe, expect, test } from 'vitest' + +import { resolveLazyBundleFetcher } from '../src/resolveLazyBundleFetcher.js' + +describe('resolveLazyBundleFetcher', () => { + const originalEnv = process.env['REACT_LAZY_BUNDLE_FETCHER'] + beforeEach(() => { + delete process.env['REACT_LAZY_BUNDLE_FETCHER'] + }) + afterEach(() => { + if (originalEnv === undefined) { + delete process.env['REACT_LAZY_BUNDLE_FETCHER'] + } else { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = originalEnv + } + }) + + describe('default behavior (no env override)', () => { + test('undefined engineVersion → QueryComponent', () => { + expect(resolveLazyBundleFetcher(undefined)).toBe('QueryComponent') + }) + + test('engineVersion below 3.8 → QueryComponent', () => { + expect(resolveLazyBundleFetcher('3.7')).toBe('QueryComponent') + expect(resolveLazyBundleFetcher('3.7.9')).toBe('QueryComponent') + expect(resolveLazyBundleFetcher('2.16')).toBe('QueryComponent') + expect(resolveLazyBundleFetcher('3.0')).toBe('QueryComponent') + }) + + test('engineVersion at or above 3.8 → FetchBundle', () => { + expect(resolveLazyBundleFetcher('3.8')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('3.8.0')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('3.8.1')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('3.9')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('4.0')).toBe('FetchBundle') + }) + + test('multi-digit minor compares numerically (3.10 > 3.8)', () => { + expect(resolveLazyBundleFetcher('3.10')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('3.10.5')).toBe('FetchBundle') + }) + + test('non-numeric version → QueryComponent (NaN guard)', () => { + expect(resolveLazyBundleFetcher('foo')).toBe('QueryComponent') + expect(resolveLazyBundleFetcher('3.x')).toBe('QueryComponent') + expect(resolveLazyBundleFetcher('latest')).toBe('QueryComponent') + }) + }) + + describe('REACT_LAZY_BUNDLE_FETCHER env override', () => { + test('=FetchBundle with sufficient version → FetchBundle', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'FetchBundle' + expect(resolveLazyBundleFetcher('3.8')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('4.0')).toBe('FetchBundle') + }) + + test('=FetchBundle with insufficient version → throws', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'FetchBundle' + expect(() => resolveLazyBundleFetcher('3.7')).toThrow( + /requires targetSdkVersion >= 3\.8/, + ) + }) + + test('=FetchBundle with undefined version → throws (mentions )', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'FetchBundle' + expect(() => resolveLazyBundleFetcher(undefined)).toThrow(//) + }) + + test('=QueryComponent forces legacy path even on 3.8+', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'QueryComponent' + expect(resolveLazyBundleFetcher('3.8')).toBe('QueryComponent') + expect(resolveLazyBundleFetcher('4.0')).toBe('QueryComponent') + }) + + test('=QueryComponent with insufficient version → QueryComponent', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'QueryComponent' + expect(resolveLazyBundleFetcher('3.7')).toBe('QueryComponent') + }) + + test('unrecognized override value falls through to default', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'something-else' + expect(resolveLazyBundleFetcher('3.8')).toBe('FetchBundle') + expect(resolveLazyBundleFetcher('3.7')).toBe('QueryComponent') + }) + + test('empty string override → falls through to default', () => { + process.env['REACT_LAZY_BUNDLE_FETCHER'] = '' + expect(resolveLazyBundleFetcher('3.8')).toBe('FetchBundle') + }) + }) +}) From ffdbea37b491300079294295a3dcec1f8ee772a2 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 23:23:26 +0800 Subject: [PATCH 32/43] test(react-webpack-plugin): cover FetchBundle MT wrapper + define injection - FetchBundle: main-thread chunk wrapped as self-invoking IIFE with hardcoded \`globDynamicComponentEntry = '__Card__'\` - QueryComponent (default): main-thread chunk wrapped as parameterised non-IIFE form - \`__LAZY_BUNDLE_FETCHER__\` define replaces references with the literal fetcher value in compiled background output --- .../fixtures/lazy-bundle-fetcher/index.jsx | 11 ++ .../test/lazy-bundle-fetcher.test.ts | 126 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 packages/webpack/react-webpack-plugin/test/fixtures/lazy-bundle-fetcher/index.jsx create mode 100644 packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts diff --git a/packages/webpack/react-webpack-plugin/test/fixtures/lazy-bundle-fetcher/index.jsx b/packages/webpack/react-webpack-plugin/test/fixtures/lazy-bundle-fetcher/index.jsx new file mode 100644 index 0000000000..541bcfe79e --- /dev/null +++ b/packages/webpack/react-webpack-plugin/test/fixtures/lazy-bundle-fetcher/index.jsx @@ -0,0 +1,11 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +// Reference the build-time define so DefinePlugin inlines it into the +// emitted bundle, where the test can grep for the resolved literal. +globalThis.__lynx_fetcher_probe__ = __LAZY_BUNDLE_FETCHER__; + +export default function App() { + return null; +} diff --git a/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts b/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts new file mode 100644 index 0000000000..7b4995d002 --- /dev/null +++ b/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts @@ -0,0 +1,126 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { mkdtemp, readFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { rspack } from '@rspack/core'; +import type { Configuration, Stats } from '@rspack/core'; +import { describe, expect, test } from 'vitest'; + +import { + LynxEncodePlugin, + LynxTemplatePlugin, +} from '@lynx-js/template-webpack-plugin'; + +// `create-react-config.js` is plain JS without a generated d.ts. +// @ts-expect-error untyped JS helper +import { createConfig as createConfigUntyped } from './create-react-config.js'; + +const createConfig = createConfigUntyped as ( + loaderOptions: Record, + pluginOptions: Record, +) => Configuration; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const FIXTURE = join(__dirname, 'fixtures/lazy-bundle-fetcher/index.jsx'); + +interface BuildResult { + mainThread: string; + background: string; +} + +async function build( + pluginOptions: Record, +): Promise { + const dist = await mkdtemp(join(tmpdir(), 'rwp-fetchbundle-')); + const config = createConfig({}, { + experimental_isLazyBundle: true, + mainThreadChunks: ['main__main-thread.js'], + ...pluginOptions, + }); + config.entry = { + 'main__main-thread': { import: FIXTURE, layer: 'react:main-thread' }, + 'main__background': { import: FIXTURE, layer: 'react:background' }, + }; + config.context = dirname(FIXTURE); + config.output = { ...config.output, filename: '[name].js', path: dist }; + config.mode = 'development'; + config.devtool = false; + // The wrapper-injection branch is gated on a LynxTemplatePlugin being + // present; add a minimal one so the gate passes. + config.plugins = [ + ...(config.plugins ?? []), + new LynxEncodePlugin(), + new LynxTemplatePlugin({ + ...LynxTemplatePlugin.defaultOptions, + chunks: ['main__main-thread', 'main__background'], + filename: 'main/template.js', + intermediate: '.rspeedy/main', + experimental_isLazyBundle: true, + }), + ]; + + const compiler = rspack(config); + const stats: Stats = await new Promise((resolve, reject) => { + compiler.run((err, s) => { + if (err) return reject(err); + if (!s) return reject(new Error('rspack returned empty stats')); + resolve(s); + compiler.close(() => void 0); + }); + }); + if (stats.hasErrors()) { + throw new Error(stats.toString({ all: false, errors: true })); + } + + return { + mainThread: await readFile(join(dist, 'main__main-thread.js'), 'utf8'), + background: await readFile( + join(dist, 'main__background.js'), + 'utf8', + ), + }; +} + +describe('ReactWebpackPlugin: lazyBundleFetcher', () => { + test('FetchBundle: main-thread chunk wrapped as self-invoking IIFE with __Card__', async () => { + const { mainThread } = await build({ lazyBundleFetcher: 'FetchBundle' }); + expect(mainThread).toContain( + `var globDynamicComponentEntry = '__Card__'`, + ); + expect(mainThread.trimStart().startsWith('(function () {')).toBe(true); + expect(mainThread.trimEnd().endsWith('})()')).toBe(true); + }); + + test('QueryComponent (default): main-thread chunk wrapped as parameterised non-IIFE', async () => { + const { mainThread } = await build({}); + expect(mainThread).not.toContain( + `var globDynamicComponentEntry = '__Card__'`, + ); + expect( + mainThread.trimStart().startsWith( + '(function (globDynamicComponentEntry) {', + ), + ).toBe(true); + expect(mainThread.trimEnd().endsWith('})')).toBe(true); + // Importantly: NOT self-invoking. + expect(mainThread.trimEnd().endsWith('})()')).toBe(false); + }); + + describe('__LAZY_BUNDLE_FETCHER__ define injection', () => { + test('FetchBundle: define replaces references with literal "FetchBundle"', async () => { + const { background } = await build({ lazyBundleFetcher: 'FetchBundle' }); + expect(background).toContain('"FetchBundle"'); + expect(background).not.toContain('__LAZY_BUNDLE_FETCHER__'); + }); + + test('QueryComponent (default): define replaces references with literal "QueryComponent"', async () => { + const { background } = await build({}); + expect(background).toContain('"QueryComponent"'); + expect(background).not.toContain('__LAZY_BUNDLE_FETCHER__'); + }); + }); +}); From 82cbb45655dd952cc3d81a5b0df5aeb15c48e131 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 23:29:58 +0800 Subject: [PATCH 33/43] test(template-plugin): cover WebEncodePlugin lepusCode-undefined safety In FetchBundle mode the lepusCode slot is moved into customSections, leaving \`encodeOptions.lepusCode\` undefined. Pin down the JSON template path so we get an empty \`lepusCode: {}\` instead of a crash, and the legacy flattened shape still works when lepusCode is present. --- .../web-encode-plugin-fetchbundle.test.ts | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts diff --git a/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts b/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts new file mode 100644 index 0000000000..3e054280af --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts @@ -0,0 +1,121 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. + +import { SyncHook } from '@rspack/lite-tapable'; +import { afterEach, beforeEach, describe, expect, test } from '@rstest/core'; +import webpack from 'webpack'; + +import { LynxTemplatePlugin, WebEncodePlugin } from '../src/index.js'; + +function makeFakeCompiler(): webpack.Compiler { + return { + options: { mode: 'production' }, + hooks: { + thisCompilation: new SyncHook(['compilation']), + }, + webpack, + } as unknown as webpack.Compiler; +} + +function makeFakeCompilation(): webpack.Compilation { + return { + warnings: [], + errors: [], + chunks: [], + outputOptions: {}, + hooks: { + processAssets: { tap: () => void 0 }, + }, + deleteAsset: () => void 0, + } as unknown as webpack.Compilation; +} + +describe('WebEncodePlugin: lepusCode-undefined safety (FetchBundle)', () => { + // Force the JSON template path; the binary encoder requires more + // structure than these synthetic encodeOptions provide. + const originalBinary = process.env['EXPERIMENTAL_USE_WEB_BINARY_TEMPLATE']; + void beforeEach(() => { + process.env['EXPERIMENTAL_USE_WEB_BINARY_TEMPLATE'] = 'false'; + }); + void afterEach(() => { + if (originalBinary === undefined) { + delete process.env['EXPERIMENTAL_USE_WEB_BINARY_TEMPLATE']; + } else { + process.env['EXPERIMENTAL_USE_WEB_BINARY_TEMPLATE'] = originalBinary; + } + }); + + test('encode hook handles encodeOptions.lepusCode === undefined without crashing', async () => { + const compiler = makeFakeCompiler(); + const compilation = makeFakeCompilation(); + new WebEncodePlugin().apply(compiler); + compiler.hooks.thisCompilation.call(compilation, {} as never); + + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation); + + // Mirror the FetchBundle shape: lepusCode is moved into customSections, + // so the EncodeOptions.lepusCode slot is undefined. + const result = await hooks.encode.promise({ + encodeOptions: { + manifest: { '/main.js': 'console.log(1)' }, + compilerOptions: {}, + lepusCode: undefined, + customSections: { + 'main-thread': { content: '/* mts */' }, + 'background': { content: '/* bts */' }, + 'CSS': { encoding: 'CSS', content: { ruleList: [] } }, + }, + css: { cssMap: {} }, + cardType: 'react', + appType: 'app', + pageConfig: {}, + } as never, + }); + + expect(result).toBeDefined(); + expect(Buffer.isBuffer(result?.buffer)).toBe(true); + // The emitted JSON should at minimum carry an empty lepusCode object, + // not crash on the undefined access we used to do. + const json = JSON.parse(result.buffer.toString()) as Record< + string, + unknown + >; + expect(json.lepusCode).toEqual({}); + expect(json.customSections).toBeDefined(); + }); + + test('legacy lepusCode-set path keeps the flattened shape', async () => { + const compiler = makeFakeCompiler(); + const compilation = makeFakeCompilation(); + new WebEncodePlugin().apply(compiler); + compiler.hooks.thisCompilation.call(compilation, {} as never); + + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation); + + const result = await hooks.encode.promise({ + encodeOptions: { + manifest: { '/main.js': 'console.log(1)' }, + compilerOptions: {}, + lepusCode: { + root: 'main lepus source', + lepusChunk: { worklet: 'worklet src' }, + }, + customSections: {}, + css: { cssMap: {} }, + cardType: 'react', + appType: 'app', + pageConfig: {}, + } as never, + }); + + const json = JSON.parse(result.buffer.toString()) as Record< + string, + unknown + >; + expect(json.lepusCode).toEqual({ + worklet: 'worklet src', + root: 'main lepus source', + }); + }); +}); From 662fb77da6ff1ed7f9497e149d2797ad06cfb64a Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 23:47:39 +0800 Subject: [PATCH 34/43] fix(lazy-bundle): address review nits - resolveLazyBundleFetcher: error message says \`engineVersion\` (the actual config knob), not \`targetSdkVersion\` - lazy-bundle.ts MT sync: wrap CSS load + adopt in try/catch so any stylesheet failure resolves into the never-resolving promise like every other failure mode in the same branch - react-webpack-plugin test: route compiler.close() through finally so it runs even if the run callback rejects --- .../runtime/src/snapshot/lynx/lazy-bundle.ts | 10 +++++++--- .../src/resolveLazyBundleFetcher.ts | 4 ++-- .../test/resolveLazyBundleFetcher.test.ts | 2 +- .../test/lazy-bundle-fetcher.test.ts | 18 +++++++++++------- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index 8085046467..6dabd77f22 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -185,9 +185,13 @@ export const loadLazyBundle: < } catch { return new Promise(() => {}); } - const styleSheet = __LoadStyleSheet(SECTION_CSS, response.url); - if (styleSheet !== null) { - __AdoptStyleSheet(styleSheet); + try { + const styleSheet = __LoadStyleSheet(SECTION_CSS, response.url); + if (styleSheet !== null) { + __AdoptStyleSheet(styleSheet); + } + } catch { + return new Promise(() => {}); } const r: Promise = Promise.resolve(result); r.then = makeSyncThen(result); diff --git a/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts b/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts index 9f98ce69f5..3eed3720dc 100644 --- a/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts +++ b/packages/rspeedy/plugin-react/src/resolveLazyBundleFetcher.ts @@ -15,10 +15,10 @@ export function resolveLazyBundleFetcher( if (envOverride === 'FetchBundle' && !meets) { throw new Error( `[pluginReactLynx] REACT_LAZY_BUNDLE_FETCHER=FetchBundle ` - + `requires targetSdkVersion >= ${FETCH_BUNDLE_MIN_ENGINE_VERSION}, ` + + `requires engineVersion >= ${FETCH_BUNDLE_MIN_ENGINE_VERSION}, ` + `but got ${engineVersion ? `'${engineVersion}'` : ''}. ` + `Older hosts do not expose 'lynx.fetchBundle' / 'lynx.loadScript'. ` - + `Either bump 'targetSdkVersion' to ` + + `Either bump 'engineVersion' to ` + `'${FETCH_BUNDLE_MIN_ENGINE_VERSION}' or higher, or unset ` + `REACT_LAZY_BUNDLE_FETCHER (the default falls back to ` + `'QueryComponent' on older hosts).`, diff --git a/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts b/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts index a5c654fcd3..01933cdca2 100644 --- a/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts +++ b/packages/rspeedy/plugin-react/test/resolveLazyBundleFetcher.test.ts @@ -61,7 +61,7 @@ describe('resolveLazyBundleFetcher', () => { test('=FetchBundle with insufficient version → throws', () => { process.env['REACT_LAZY_BUNDLE_FETCHER'] = 'FetchBundle' expect(() => resolveLazyBundleFetcher('3.7')).toThrow( - /requires targetSdkVersion >= 3\.8/, + /requires engineVersion >= 3\.8/, ) }) diff --git a/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts b/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts index 7b4995d002..336cc995f4 100644 --- a/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts +++ b/packages/webpack/react-webpack-plugin/test/lazy-bundle-fetcher.test.ts @@ -64,14 +64,18 @@ async function build( ]; const compiler = rspack(config); - const stats: Stats = await new Promise((resolve, reject) => { - compiler.run((err, s) => { - if (err) return reject(err); - if (!s) return reject(new Error('rspack returned empty stats')); - resolve(s); - compiler.close(() => void 0); + let stats: Stats; + try { + stats = await new Promise((resolve, reject) => { + compiler.run((err, s) => { + if (err) return reject(err); + if (!s) return reject(new Error('rspack returned empty stats')); + resolve(s); + }); }); - }); + } finally { + await new Promise((r) => compiler.close(() => r())); + } if (stats.hasErrors()) { throw new Error(stats.toString({ all: false, errors: true })); } From 06d6697b5b1012f764999db0be398b94a65cc295 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Mon, 11 May 2026 23:50:58 +0800 Subject: [PATCH 35/43] refactor(lazy-bundle): merge MT loadScript+CSS into one try block Same catch behavior, no need for two. --- packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts index 6dabd77f22..2582341531 100644 --- a/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts +++ b/packages/react/runtime/src/snapshot/lynx/lazy-bundle.ts @@ -182,10 +182,6 @@ export const loadLazyBundle: < result = lynx.loadScript(SECTION_MAIN_THREAD, { bundleName: response.url, }); - } catch { - return new Promise(() => {}); - } - try { const styleSheet = __LoadStyleSheet(SECTION_CSS, response.url); if (styleSheet !== null) { __AdoptStyleSheet(styleSheet); From 4c4333d1f85af476e06cedb643455929e631853f Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 00:16:25 +0800 Subject: [PATCH 36/43] chore(codecov): ignore examples/ Example apps are demonstration projects without unit tests, so they should not count toward project / patch coverage. This brings the ignore list in line with packages/genui/** which is treated the same way. --- codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/codecov.yml b/codecov.yml index 89e92302b8..ff574b05f4 100644 --- a/codecov.yml +++ b/codecov.yml @@ -27,6 +27,7 @@ coverage: ignore: - ".github/**" - "codecov.yml" + - "examples/**" - "packages/genui/**" - "pnpm-lock.yaml" - "rstest.config.ts" From c126bbd6a9004fd53e9eadb502c5a983289cf692 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 00:34:44 +0800 Subject: [PATCH 37/43] chore(codecov): ignore generated snapshot fixtures `__swc_snapshots__` and `__snapshots__` directories hold generated test outputs (vitest/cargo snapshots), not source code that should contribute to coverage. --- codecov.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codecov.yml b/codecov.yml index ff574b05f4..02aa737666 100644 --- a/codecov.yml +++ b/codecov.yml @@ -31,6 +31,8 @@ ignore: - "packages/genui/**" - "pnpm-lock.yaml" - "rstest.config.ts" + - "**/__swc_snapshots__/**" + - "**/__snapshots__/**" fixes: - "/home/runner/_work/lynx-stack::" From f6bc1e3b4e1980656f1572eaf6a9e02f18441883 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 11:31:07 +0800 Subject: [PATCH 38/43] test(template-plugin): migrate FetchBundle shape tests to cases framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two pure shape tests (FetchBundle customSections / QueryComponent legacy lepusCode) belong with the rest of the package's case-based tests under \`test/cases/\` — they assert on the on-disk \`tasm.json\` shape and don't need env mutation. The 4 bytecode-gating tests stay standalone in \`lazy-bundle-fetcher.test.ts\` because they flip \`process.env.DEBUG\` per test, and \`cases.test.ts\` runs all cases in one process. Drive-by: standalone test now writes to a per-test \`mkdtemp\` output dir instead of the package's shared \`dist/\`, and the \`web-encode-plugin\` test uses bracket access on the parsed JSON to appease tsc's \`noPropertyAccessFromIndexSignature\`. --- .../fetchbundle/foo.bts.js | 4 + .../fetchbundle/foo.mts.js | 4 + .../lazy-bundle-fetcher/fetchbundle/index.js | 30 ++++ .../fetchbundle/rspack.config.js | 62 ++++++++ .../querycomponent/foo.bts.js | 4 + .../querycomponent/foo.mts.js | 4 + .../querycomponent/index.js | 25 ++++ .../querycomponent/rspack.config.js | 57 +++++++ .../test/lazy-bundle-fetcher.test.ts | 140 +++++------------- .../web-encode-plugin-fetchbundle.test.ts | 6 +- 10 files changed, 232 insertions(+), 104 deletions(-) create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.bts.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.mts.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/index.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/rspack.config.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.bts.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.mts.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/index.js create mode 100644 packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/rspack.config.js diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.bts.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.bts.js new file mode 100644 index 0000000000..5f076d2fec --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.bts.js @@ -0,0 +1,4 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +export const layer = 'background'; diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.mts.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.mts.js new file mode 100644 index 0000000000..b340bd7651 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/foo.mts.js @@ -0,0 +1,4 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +export const layer = 'main-thread'; diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/index.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/index.js new file mode 100644 index 0000000000..9877af8fe1 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/index.js @@ -0,0 +1,30 @@ +/* +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +*/ +/// + +import { existsSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; + +void import(/* webpackChunkName: 'foo:main-thread' */ './foo.mts.js'); +void import(/* webpackChunkName: 'foo:background' */ './foo.bts.js'); + +it('FetchBundle: lazy bundle tasm.json carries customSections shape', async () => { + const tasmJSONPath = resolve(__dirname, '.rspeedy/async/foo/tasm.json'); + expect(existsSync(tasmJSONPath)).toBeTruthy(); + + const tasm = JSON.parse(await readFile(tasmJSONPath, 'utf-8')); + // FetchBundle moves MT/BG/CSS into customSections and drops the legacy + // lepusCode + manifest slots for lazy bundles. + expect(tasm.customSections).toHaveProperty('main-thread'); + expect(tasm.customSections).toHaveProperty('background'); + expect(tasm.customSections['main-thread'].content).toEqual( + expect.any(String), + ); + expect(tasm.customSections['background'].content).toEqual(expect.any(String)); + expect(tasm.lepusCode).toBeUndefined(); + expect(tasm.css.cssMap).toEqual({}); +}); diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/rspack.config.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/rspack.config.js new file mode 100644 index 0000000000..e53c8d70f2 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/fetchbundle/rspack.config.js @@ -0,0 +1,62 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { LynxEncodePlugin, LynxTemplatePlugin } from '../../../../lib/index.js'; + +/** @type {import('@rspack/core').Configuration} */ +export default { + devtool: false, + mode: 'development', + plugins: [ + new LynxEncodePlugin(), + new LynxTemplatePlugin({ + ...LynxTemplatePlugin.defaultOptions, + intermediate: '.rspeedy/main', + lazyBundleFetcher: 'FetchBundle', + }), + /** + * Strip the React-style layer suffixes so MT/BG chunks share a template + * (mirrors `react-webpack-plugin`'s `asyncChunkName` hook). + * @param {import('@rspack/core').Compiler} compiler + */ + (compiler) => { + compiler.hooks.thisCompilation.tap('strip', (compilation) => { + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks( + compilation, + ); + hooks.asyncChunkName.tap( + 'strip', + (chunkName) => + chunkName.replace(':main-thread', '').replace(':background', ''), + ); + }); + }, + /** + * Mark assets whose chunk name contains `:main-thread` as + * `lynx:main-thread` so LynxTemplatePlugin routes them into the + * mainThread bucket (mirrors `react-webpack-plugin`'s loader). + * @param {import('@rspack/core').Compiler} compiler + */ + (compiler) => { + compiler.hooks.thisCompilation.tap('mark-mt', (compilation) => { + compilation.hooks.processAssets.tap( + { + name: 'mark-mt', + stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_DERIVED, + }, + (assets) => { + for (const name of Object.keys(assets)) { + if (!name.includes(':main-thread')) continue; + const asset = compilation.getAsset(name); + if (!asset) continue; + compilation.updateAsset(asset.name, asset.source, { + ...asset.info, + 'lynx:main-thread': true, + }); + } + }, + ); + }); + }, + ], +}; diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.bts.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.bts.js new file mode 100644 index 0000000000..5f076d2fec --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.bts.js @@ -0,0 +1,4 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +export const layer = 'background'; diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.mts.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.mts.js new file mode 100644 index 0000000000..b340bd7651 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/foo.mts.js @@ -0,0 +1,4 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +export const layer = 'main-thread'; diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/index.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/index.js new file mode 100644 index 0000000000..a83c41c3b0 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/index.js @@ -0,0 +1,25 @@ +/* +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +*/ +/// + +import { existsSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; + +void import(/* webpackChunkName: 'foo:main-thread' */ './foo.mts.js'); +void import(/* webpackChunkName: 'foo:background' */ './foo.bts.js'); + +it('QueryComponent (default): lazy bundle keeps lepusCode + manifest shape', async () => { + const tasmJSONPath = resolve(__dirname, '.rspeedy/async/foo/tasm.json'); + expect(existsSync(tasmJSONPath)).toBeTruthy(); + + const tasm = JSON.parse(await readFile(tasmJSONPath, 'utf-8')); + // Default fetcher path: customSections is empty (legacy slots own MT/BG). + expect(tasm.customSections['main-thread']).toBeUndefined(); + expect(tasm.customSections['background']).toBeUndefined(); + expect(tasm.lepusCode).toBeDefined(); + expect(tasm.lepusCode.root).toEqual(expect.any(String)); +}); diff --git a/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/rspack.config.js b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/rspack.config.js new file mode 100644 index 0000000000..934bb89c23 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/lazy-bundle-fetcher/querycomponent/rspack.config.js @@ -0,0 +1,57 @@ +// Copyright 2026 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +import { LynxEncodePlugin, LynxTemplatePlugin } from '../../../../lib/index.js'; + +/** @type {import('@rspack/core').Configuration} */ +export default { + devtool: false, + mode: 'development', + plugins: [ + new LynxEncodePlugin(), + new LynxTemplatePlugin({ + ...LynxTemplatePlugin.defaultOptions, + intermediate: '.rspeedy/main', + // No `lazyBundleFetcher` — defaults to QueryComponent. + }), + /** + * @param {import('@rspack/core').Compiler} compiler + */ + (compiler) => { + compiler.hooks.thisCompilation.tap('strip', (compilation) => { + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks( + compilation, + ); + hooks.asyncChunkName.tap( + 'strip', + (chunkName) => + chunkName.replace(':main-thread', '').replace(':background', ''), + ); + }); + }, + /** + * @param {import('@rspack/core').Compiler} compiler + */ + (compiler) => { + compiler.hooks.thisCompilation.tap('mark-mt', (compilation) => { + compilation.hooks.processAssets.tap( + { + name: 'mark-mt', + stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_DERIVED, + }, + (assets) => { + for (const name of Object.keys(assets)) { + if (!name.includes(':main-thread')) continue; + const asset = compilation.getAsset(name); + if (!asset) continue; + compilation.updateAsset(asset.name, asset.source, { + ...asset.info, + 'lynx:main-thread': true, + }); + } + }, + ); + }); + }, + ], +}; diff --git a/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts b/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts index a33517f243..99cf6138dc 100644 --- a/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts +++ b/packages/webpack/template-webpack-plugin/test/lazy-bundle-fetcher.test.ts @@ -1,7 +1,16 @@ // Copyright 2026 The Lynx Authors. All rights reserved. // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. -import { dirname } from 'node:path'; + +// Output-shape tests live in `test/cases/lazy-bundle-fetcher/{fetchbundle, +// querycomponent}/`. This file is a separate runner because the bytecode +// gating is driven by env vars (`process.env.DEBUG`) that need to be +// flipped per test — `cases.test.ts` runs all cases in the same process, +// so env mutations would leak. + +import { mkdtempSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; import { afterEach, beforeEach, describe, expect, test } from '@rstest/core'; import webpack from 'webpack'; @@ -14,9 +23,6 @@ const CONTEXT = dirname(new URL(import.meta.url).pathname); interface CapturedEncode { outputName: string; customSections: Record; - manifest: Record | undefined; - lepusCodeRoot: string | undefined; - cssMap: Record | undefined; } function captureBeforeEmit() { @@ -31,12 +37,6 @@ function captureBeforeEmit() { string, { content: unknown; encoding?: string } >, - manifest: args.finalEncodeOptions.manifest, - lepusCodeRoot: args.finalEncodeOptions.lepusCode?.root, - cssMap: (args.finalEncodeOptions['css'] as - | { cssMap?: Record } - | undefined) - ?.cssMap, }); return Promise.resolve(args); }); @@ -46,28 +46,26 @@ function captureBeforeEmit() { } function buildConfig( - fetcherOptions: Partial< - NonNullable[0]> - >, capturePlugin: (compiler: webpack.Compiler) => void, - mode: 'development' | 'production' = 'production', + mode: 'development' | 'production', ): webpack.Configuration { + // Each build gets its own temp output dir so parallel/serial test runs + // don't clobber each other (or the package's `dist/`). + const dist = mkdtempSync(join(tmpdir(), 'tmpl-fetchbundle-')); return { context: CONTEXT, mode, devtool: false, entry: FIXTURE_ENTRY, - output: { iife: false }, + output: { iife: false, path: dist }, plugins: [ capturePlugin, new LynxTemplatePlugin({ - ...fetcherOptions, + ...LynxTemplatePlugin.defaultOptions, + lazyBundleFetcher: 'FetchBundle', intermediate: '.rspeedy/main', }), new LynxEncodePlugin(), - // Strip the React-style layer suffixes so MT/BG chunks share a - // template, mirroring the production setup that LynxTemplatePlugin - // is built for. (compiler) => { compiler.hooks.thisCompilation.tap('strip', (compilation) => { const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks( @@ -80,16 +78,12 @@ function buildConfig( ); }); }, - // Mark assets whose name contains `:main-thread` as - // `lynx:main-thread` so LynxTemplatePlugin routes them into the - // mainThread bucket (mirroring `react-webpack-plugin`'s loader). (compiler) => { compiler.hooks.thisCompilation.tap('mark-mt', (compilation) => { compilation.hooks.processAssets.tap( { name: 'mark-mt', - stage: compiler.webpack.Compilation - .PROCESS_ASSETS_STAGE_DERIVED, + stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_DERIVED, }, (assets) => { for (const name of Object.keys(assets)) { @@ -121,7 +115,16 @@ function runWebpack(config: webpack.Configuration): Promise { }); } -describe('LynxTemplatePlugin: lazyBundleFetcher', () => { +async function runAndGetMtEncoding( + mode: 'development' | 'production', +): Promise { + const { captured, plugin } = captureBeforeEmit(); + await runWebpack(buildConfig(plugin, mode)); + const lazy = captured.find((c) => c.outputName.startsWith('async/')); + return lazy?.customSections['main-thread']?.encoding; +} + +describe('LynxTemplatePlugin: FetchBundle main-thread bytecode encoding', () => { const originalDebug = process.env['DEBUG']; void beforeEach(() => { // The vitest/rstest harness sets DEBUG=rspeedy by default, which @@ -134,86 +137,21 @@ describe('LynxTemplatePlugin: lazyBundleFetcher', () => { else process.env['DEBUG'] = originalDebug; }); - test('FetchBundle async chunk emits customSections shape', async () => { - const { captured, plugin } = captureBeforeEmit(); - const stats = await runWebpack( - buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin), - ); - expect(stats.compilation.errors).toEqual([]); - - const lazy = captured.find((c) => c.outputName.startsWith('async/')); - expect(lazy).toBeDefined(); - - expect(lazy!.customSections['main-thread']).toBeDefined(); - expect(lazy!.customSections['main-thread']!.encoding).toBe('JsBytecode'); - expect(typeof lazy!.customSections['main-thread']!.content).toBe('string'); - - expect(lazy!.customSections['background']).toBeDefined(); - expect(lazy!.customSections['background']!.encoding).toBeUndefined(); - expect(typeof lazy!.customSections['background']!.content).toBe('string'); - - // For FetchBundle, lepusCode.root is moved into customSections; the - // legacy slot is empty. - expect(lazy!.lepusCodeRoot).toBeUndefined(); - expect(lazy!.cssMap).toEqual({}); + test('production → encoding: JsBytecode', async () => { + expect(await runAndGetMtEncoding('production')).toBe('JsBytecode'); }); - test('QueryComponent (default) keeps legacy lepusCode + manifest shape', async () => { - const { captured, plugin } = captureBeforeEmit(); - const stats = await runWebpack(buildConfig({}, plugin)); - expect(stats.compilation.errors).toEqual([]); - - const lazy = captured.find((c) => c.outputName.startsWith('async/')); - expect(lazy).toBeDefined(); - - // Customsections shouldn't carry main-thread/background/CSS for - // QueryComponent — the legacy lepusCode + manifest path owns them. - expect(lazy!.customSections['main-thread']).toBeUndefined(); - expect(lazy!.customSections['background']).toBeUndefined(); - expect(lazy!.lepusCodeRoot).toBeDefined(); + test('development → no JsBytecode encoding', async () => { + expect(await runAndGetMtEncoding('development')).toBeUndefined(); }); - describe('FetchBundle main-thread bytecode encoding', () => { - test('production → encoding: JsBytecode', async () => { - const { captured, plugin } = captureBeforeEmit(); - await runWebpack( - buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin, 'production'), - ); - const lazy = captured.find((c) => c.outputName.startsWith('async/')); - expect(lazy!.customSections['main-thread']!.encoding).toBe('JsBytecode'); - }); - - test('development → no JsBytecode encoding', async () => { - const { captured, plugin } = captureBeforeEmit(); - await runWebpack( - buildConfig( - { lazyBundleFetcher: 'FetchBundle' }, - plugin, - 'development', - ), - ); - const lazy = captured.find((c) => c.outputName.startsWith('async/')); - expect(lazy!.customSections['main-thread']!.encoding).toBeUndefined(); - }); - - test('DEBUG=rspeedy → no JsBytecode encoding even in production', async () => { - process.env['DEBUG'] = 'rspeedy'; - const { captured, plugin } = captureBeforeEmit(); - await runWebpack( - buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin, 'production'), - ); - const lazy = captured.find((c) => c.outputName.startsWith('async/')); - expect(lazy!.customSections['main-thread']!.encoding).toBeUndefined(); - }); + test('DEBUG=rspeedy → no JsBytecode encoding even in production', async () => { + process.env['DEBUG'] = 'rspeedy'; + expect(await runAndGetMtEncoding('production')).toBeUndefined(); + }); - test('DEBUG=other → JsBytecode encoding still on', async () => { - process.env['DEBUG'] = 'unrelated'; - const { captured, plugin } = captureBeforeEmit(); - await runWebpack( - buildConfig({ lazyBundleFetcher: 'FetchBundle' }, plugin, 'production'), - ); - const lazy = captured.find((c) => c.outputName.startsWith('async/')); - expect(lazy!.customSections['main-thread']!.encoding).toBe('JsBytecode'); - }); + test('DEBUG=other → JsBytecode encoding still on', async () => { + process.env['DEBUG'] = 'unrelated'; + expect(await runAndGetMtEncoding('production')).toBe('JsBytecode'); }); }); diff --git a/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts b/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts index 3e054280af..d16dab9e3d 100644 --- a/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts +++ b/packages/webpack/template-webpack-plugin/test/web-encode-plugin-fetchbundle.test.ts @@ -81,8 +81,8 @@ describe('WebEncodePlugin: lepusCode-undefined safety (FetchBundle)', () => { string, unknown >; - expect(json.lepusCode).toEqual({}); - expect(json.customSections).toBeDefined(); + expect(json['lepusCode']).toEqual({}); + expect(json['customSections']).toBeDefined(); }); test('legacy lepusCode-set path keeps the flattened shape', async () => { @@ -113,7 +113,7 @@ describe('WebEncodePlugin: lepusCode-undefined safety (FetchBundle)', () => { string, unknown >; - expect(json.lepusCode).toEqual({ + expect(json['lepusCode']).toEqual({ worklet: 'worklet src', root: 'main lepus source', }); From c75de420ec7e1468150ddc8474a94bdb514c8178 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 17:58:09 +0800 Subject: [PATCH 39/43] chore: pnpm dedupe after merge Drop duplicate `@rsbuild/core@2.0.0-beta.3` indirect deps that sherif flagged after the main merge. --- pnpm-lock.yaml | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25b9275229..085fa18ee4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -320,7 +320,7 @@ importers: version: 3.10.2-alpha.0 '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -736,7 +736,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -1447,10 +1447,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.6.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1465,7 +1465,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1559,7 +1559,7 @@ importers: version: 3.10.2-alpha.0 '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -2309,13 +2309,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.2.2(@rsbuild/core@1.7.5) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -13739,13 +13739,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13785,9 +13785,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13816,15 +13816,6 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 - '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - deepmerge: 4.3.1 - loader-utils: 2.0.4 - postcss: 8.5.6 - reduce-configs: 1.1.1 - sass-embedded: 1.97.3 - '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13833,6 +13824,19 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': + dependencies: + deepmerge: 4.3.1 + json5: 2.2.3 + reduce-configs: 1.1.1 + ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + optionalDependencies: + '@rsbuild/core': 1.7.5 + transitivePeerDependencies: + - '@rspack/core' + - tslib + - typescript + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 @@ -13850,10 +13854,6 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - '@rsdoctor/client@1.5.6': {} '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': @@ -20073,10 +20073,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20096,15 +20096,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) From db3c74cf11d9217a36f194bc783db01d65b49cd2 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 18:56:32 +0800 Subject: [PATCH 40/43] chore(deps): bump @lynx-js/types to 3.10.2-alpha.0 Drop the workspace override; the alpha is now referenced directly from each consumer's package.json so resolution behaves like any other dependency. --- benchmark/react/package.json | 2 +- examples/gesture/package.json | 2 +- examples/motion/package.json | 2 +- examples/react-compiler/package.json | 2 +- examples/react-element-template/package.json | 2 +- examples/react-element/package.json | 2 +- examples/react-externals/package.json | 2 +- .../react-lazy-bundle-standalone/package.json | 2 +- examples/react-lazy-bundle/package.json | 2 +- .../react-main-thread-function/package.json | 2 +- examples/react-ui-sourcemap/package.json | 2 +- examples/react/package.json | 2 +- examples/tailwindcss/package.json | 2 +- packages/genui/a2ui-playground/package.json | 2 +- packages/genui/a2ui/package.json | 2 +- packages/genui/openui/package.json | 2 +- .../i18next-translation-dedupe/package.json | 2 +- packages/lynx/gesture-runtime/package.json | 2 +- packages/motion/package.json | 2 +- packages/react/package.json | 2 +- packages/react/runtime/package.json | 2 +- packages/repl/package.json | 2 +- .../template-react-ts/package.json | 2 +- packages/rspeedy/upgrade-rspeedy/package.json | 2 +- .../examples/react-compiler/package.json | 2 +- .../testing-library/kitten-lynx/package.json | 2 +- pnpm-lock.yaml | 113 +++++++++--------- pnpm-workspace.yaml | 3 - 28 files changed, 82 insertions(+), 86 deletions(-) diff --git a/benchmark/react/package.json b/benchmark/react/package.json index 414884ffa4..8dd47d91e9 100644 --- a/benchmark/react/package.json +++ b/benchmark/react/package.json @@ -40,7 +40,7 @@ "@lynx-js/rspeedy": "workspace:*", "@lynx-js/trace-processor": "^0.0.1", "@lynx-js/type-element-api": "0.0.3", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/gesture/package.json b/examples/gesture/package.json index a4a463829c..7a93147f17 100644 --- a/examples/gesture/package.json +++ b/examples/gesture/package.json @@ -17,7 +17,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/motion/package.json b/examples/motion/package.json index c1cf64fd75..676cdf345a 100644 --- a/examples/motion/package.json +++ b/examples/motion/package.json @@ -16,7 +16,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/react-compiler/package.json b/examples/react-compiler/package.json index 4ef711e246..12e16528dd 100644 --- a/examples/react-compiler/package.json +++ b/examples/react-compiler/package.json @@ -15,7 +15,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@rsbuild/plugin-babel": "1.1.0", "@types/react": "^18.3.28", "babel-plugin-react-compiler": "0.0.0-experimental-fe727a3-20250909" diff --git a/examples/react-element-template/package.json b/examples/react-element-template/package.json index 76620154f8..93bbf5f4b0 100644 --- a/examples/react-element-template/package.json +++ b/examples/react-element-template/package.json @@ -15,7 +15,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/react-element/package.json b/examples/react-element/package.json index cbdf632345..d35ed8dc48 100644 --- a/examples/react-element/package.json +++ b/examples/react-element/package.json @@ -15,7 +15,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/react-externals/package.json b/examples/react-externals/package.json index c5e9d0f26b..6fb115716c 100644 --- a/examples/react-externals/package.json +++ b/examples/react-externals/package.json @@ -20,7 +20,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28", "cross-env": "^7.0.3" } diff --git a/examples/react-lazy-bundle-standalone/package.json b/examples/react-lazy-bundle-standalone/package.json index 5ae4b9836c..f81296a01f 100644 --- a/examples/react-lazy-bundle-standalone/package.json +++ b/examples/react-lazy-bundle-standalone/package.json @@ -25,7 +25,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28", "cross-env": "^7.0.3" } diff --git a/examples/react-lazy-bundle/package.json b/examples/react-lazy-bundle/package.json index 19245cf27f..234a69eca8 100644 --- a/examples/react-lazy-bundle/package.json +++ b/examples/react-lazy-bundle/package.json @@ -19,7 +19,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28", "cross-env": "^7.0.3" } diff --git a/examples/react-main-thread-function/package.json b/examples/react-main-thread-function/package.json index ec0d610657..c4028dbc45 100644 --- a/examples/react-main-thread-function/package.json +++ b/examples/react-main-thread-function/package.json @@ -16,7 +16,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/react-ui-sourcemap/package.json b/examples/react-ui-sourcemap/package.json index db95a865c3..197998b139 100644 --- a/examples/react-ui-sourcemap/package.json +++ b/examples/react-ui-sourcemap/package.json @@ -16,7 +16,7 @@ "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", "@lynx-js/template-webpack-plugin": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/react/package.json b/examples/react/package.json index 86dc4ea715..eed948847e 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -16,7 +16,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/examples/tailwindcss/package.json b/examples/tailwindcss/package.json index bef7860626..c88f06154c 100644 --- a/examples/tailwindcss/package.json +++ b/examples/tailwindcss/package.json @@ -19,7 +19,7 @@ "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", "@lynx-js/tailwind-preset": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28", "rsbuild-plugin-tailwindcss": "0.2.4", "tailwindcss": "^3.4.19" diff --git a/packages/genui/a2ui-playground/package.json b/packages/genui/a2ui-playground/package.json index f009a1b720..459cb76dce 100644 --- a/packages/genui/a2ui-playground/package.json +++ b/packages/genui/a2ui-playground/package.json @@ -28,7 +28,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@rsbuild/core": "catalog:rsbuild", "@rsbuild/plugin-react": "^1.4.5", "@types/qrcode": "^1.5.5", diff --git a/packages/genui/a2ui/package.json b/packages/genui/a2ui/package.json index 1d0dcdcfb7..9da53c614a 100644 --- a/packages/genui/a2ui/package.json +++ b/packages/genui/a2ui/package.json @@ -89,7 +89,7 @@ "@lynx-js/a2ui-catalog-extractor": "workspace:*", "@lynx-js/lynx-ui": "^3.130.0", "@lynx-js/react": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@rstest/core": "catalog:rstest", "@types/react": "^18.3.28" }, diff --git a/packages/genui/openui/package.json b/packages/genui/openui/package.json index 9b62bf3bd6..4ad8bbdfcc 100644 --- a/packages/genui/openui/package.json +++ b/packages/genui/openui/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@lynx-js/react": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28" } } diff --git a/packages/i18n/i18next-translation-dedupe/package.json b/packages/i18n/i18next-translation-dedupe/package.json index 94a69c0644..d0dd5fb145 100644 --- a/packages/i18n/i18next-translation-dedupe/package.json +++ b/packages/i18n/i18next-translation-dedupe/package.json @@ -38,7 +38,7 @@ "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", "@lynx-js/template-webpack-plugin": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "i18next": "26.0.6", "i18next-cli": "1.54.2", "rsbuild-plugin-i18next-extractor": "0.2.1" diff --git a/packages/lynx/gesture-runtime/package.json b/packages/lynx/gesture-runtime/package.json index 7df386907a..e868d0f585 100644 --- a/packages/lynx/gesture-runtime/package.json +++ b/packages/lynx/gesture-runtime/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@lynx-js/react": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@testing-library/jest-dom": "^6.9.1", "rsbuild-plugin-publint": "0.3.4" }, diff --git a/packages/motion/package.json b/packages/motion/package.json index 3a6920f4d5..dce0c24168 100644 --- a/packages/motion/package.json +++ b/packages/motion/package.json @@ -53,7 +53,7 @@ }, "devDependencies": { "@lynx-js/react": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "rsbuild-plugin-publint": "0.3.4" }, "peerDependencies": { diff --git a/packages/react/package.json b/packages/react/package.json index 3a914e28a4..5bedd50643 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -227,7 +227,7 @@ "preact": "npm:@lynx-js/internal-preact@10.29.1-20260424024911-12b794f" }, "devDependencies": { - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@microsoft/api-extractor": "catalog:", "@types/react": "^18.3.28" }, diff --git a/packages/react/runtime/package.json b/packages/react/runtime/package.json index 9d0bf2ac92..21a91c5493 100644 --- a/packages/react/runtime/package.json +++ b/packages/react/runtime/package.json @@ -24,7 +24,7 @@ "devDependencies": { "@lynx-js/react": "workspace:*", "@lynx-js/react-transform": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28", "pretty-format": "^30.2.0" }, diff --git a/packages/repl/package.json b/packages/repl/package.json index 36c2a90868..7928dd6899 100644 --- a/packages/repl/package.json +++ b/packages/repl/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@lynx-js/lynx-core": "0.1.3", "@lynx-js/type-element-api": "0.0.3", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@lynx-js/web-core": "workspace:*", "@lynx-js/web-platform-rsbuild-plugin": "workspace:*", "@rsbuild/core": "catalog:rsbuild", diff --git a/packages/rspeedy/create-rspeedy/template-react-ts/package.json b/packages/rspeedy/create-rspeedy/template-react-ts/package.json index a26a4e6545..f331a1485b 100644 --- a/packages/rspeedy/create-rspeedy/template-react-ts/package.json +++ b/packages/rspeedy/create-rspeedy/template-react-ts/package.json @@ -15,7 +15,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@rsbuild/plugin-type-check": "1.3.4", "@types/react": "^18.3.28", "typescript": "~5.9.3" diff --git a/packages/rspeedy/upgrade-rspeedy/package.json b/packages/rspeedy/upgrade-rspeedy/package.json index bc64d1c48a..6c2eaec493 100644 --- a/packages/rspeedy/upgrade-rspeedy/package.json +++ b/packages/rspeedy/upgrade-rspeedy/package.json @@ -38,7 +38,7 @@ "@lynx-js/react": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@lynx-js/web-core": "workspace:*", "@lynx-js/web-elements": "workspace:*", "@rsbuild/plugin-less": "1.6.0", diff --git a/packages/testing-library/examples/react-compiler/package.json b/packages/testing-library/examples/react-compiler/package.json index 7824f3f319..56b2a2bd0d 100644 --- a/packages/testing-library/examples/react-compiler/package.json +++ b/packages/testing-library/examples/react-compiler/package.json @@ -22,7 +22,7 @@ "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@rsbuild/plugin-babel": "1.1.0", "@testing-library/jest-dom": "^6.9.1", "@types/react": "^18.3.28", diff --git a/packages/testing-library/kitten-lynx/package.json b/packages/testing-library/kitten-lynx/package.json index 497dfb7730..a8612e85b7 100644 --- a/packages/testing-library/kitten-lynx/package.json +++ b/packages/testing-library/kitten-lynx/package.json @@ -45,7 +45,7 @@ "@lynx-js/react": "workspace:*", "@lynx-js/react-rsbuild-plugin": "workspace:*", "@lynx-js/rspeedy": "workspace:*", - "@lynx-js/types": "3.7.0", + "@lynx-js/types": "3.10.2-alpha.0", "@types/react": "^18.3.28", "execa": "^9.6.1", "jpeg-js": "^0.4.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 085fa18ee4..175b2394cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,6 @@ overrides: '@rsbuild/core@1>@rspack/core': 1.7.9 '@rsdoctor/rspack-plugin>@rspack/core': 1.7.9 '@rsdoctor/types>@rspack/core': 1.7.9 - '@lynx-js/types': 3.10.2-alpha.0 packageExtensionsChecksum: sha256-BUwt5m2tRMyYg9pgFVHNTHCYEBuM0/o7IdJqk+vWTGs= @@ -320,7 +319,7 @@ importers: version: 3.10.2-alpha.0 '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@1.7.5) + version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -736,7 +735,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -1447,10 +1446,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@1.7.5) + version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@1.7.5) + version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1465,7 +1464,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1559,7 +1558,7 @@ importers: version: 3.10.2-alpha.0 '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@1.7.5) + version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -2309,13 +2308,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@1.7.5) + version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@1.7.5) + version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -3726,7 +3725,7 @@ packages: resolution: {integrity: sha512-zBDOHakuePjw5wPCButExNgcllyFPGqYzqP2CWCWcQaX4gqJmCmYeRKguihyxH6ma6ExxlH/J2x5CHD91ed3bQ==} peerDependencies: '@lynx-js/react': '*' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@lynx-js/internal-preact@10.29.1-20260424024911-12b794f': resolution: {integrity: sha512-MQ+xjPL2f1P9/eCAdkT2h9cJRXl1qqhSJDX9GkPETt3UAepLo5N+HbGB8Qr3IUzqGDWMr3Mj76my1P0pLkKVDg==} @@ -3738,154 +3737,154 @@ packages: resolution: {integrity: sha512-0f13aZROKhTxMEY69rtWlkfvd6NM3A7JwloFQsh2nxcOiABp6dddvzzQJSayt2xAUxRjFl4uh5Rj/ZrQjjCrNw==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-checkbox@3.130.0': resolution: {integrity: sha512-2xgq7oyGjq7CKYiHd/9nO+gzT2T3KSi4gb3EPxqrENDiiDv5im3ePTwzazUuHaWWK+7cHuJgxZIhwQU0Rk6l8w==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-common@3.130.0': resolution: {integrity: sha512-6odzHU1z1PomtmskJUxIpj+TkHq9daOhUb7N0a3LquKxz9wp41qM1r2oDLRHdeUlylfId1F87Bto6F7Ql9+37w==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-dialog@3.130.0': resolution: {integrity: sha512-AFkA7V+xI5EdaA2JShIcK3UAMG1RuaZcWl16f66KNRD1/ZgIQNp7sYOW/bnQmH+BXts7p4ut7NWBNNe5WcSVvQ==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-draggable@3.130.0': resolution: {integrity: sha512-c9Sw0xahJqttWq/M9SmCIc3X0HIS/d47OBk5oNQRHjhJEaGKP23u/22SfCANXboxLhCxCXXv1OVmW/x8O9Wm2A==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-feed-list@3.130.0': resolution: {integrity: sha512-5nUNYzRjSiR94N0LAyZ+b8aj5s6WYJGShohL2piKxw5lDI7PafaYt/i30aj0Q52b7ViB8ZZuD/ZtmbD4pKeRLA==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-form@3.130.0': resolution: {integrity: sha512-hiDetKqgAGSGcuxIaRG/ljNfZrQjh31BtWZDw0aXJZL/ifHqwv2NQHErAPp9mgO8i/5NYYNYQ5Sgs/ophKhUMA==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-input@3.130.0': resolution: {integrity: sha512-CPBbnDARhs5wfX//78+ATXYhGhU/R4SjFTL/Yzvur3Wh+lLFQz1mEvv0BOfUFnd/lEilc9Y9q00h6g7w7WHd3A==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-lazy-component@3.130.0': resolution: {integrity: sha512-Xr4jQBM8mB3VtSxKnxxy0VdAT1M0dE5YWx5mEkpTezGVIX5rU+Ub23VFTtSZeGYWX1EFaleTOR17fsD4+C3CfA==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-list@3.130.0': resolution: {integrity: sha512-MBj7S19iJ3Tnu4qTVFFXMjceQ6pS+Yj84xRqoXdgVO/kvcjTzxJxQJkUt4RvCuvmQ+fOLz3Lt0ePGxVxkOYY+g==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-overlay@3.130.0': resolution: {integrity: sha512-rc11LA4svUdfX7ZG7pjS+7JzoXllmvv6Ng91QwkYbPIuRlcHu/d0VHtd8cPTgkoBevSWCACBIDoIEgONTfyuTA==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-popover@3.130.0': resolution: {integrity: sha512-oP37HtY/KPiDruepLnpaJQQD3WOFINIz3g432xo+wZ+ScAKtZxfQm2pDpeb9eyPejKv9KjNIFexYtoFVMvSFSg==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-presence@3.130.0': resolution: {integrity: sha512-h5a1SNFZdmEcsEJ6NrFcWC/LqEmINDh+LE9+givCvA4IwkYBWvgBQHoe/0LESJV75TC1TlB3L0sULsBVxMvqXg==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-radio-group@3.130.0': resolution: {integrity: sha512-vRylYRYH41BVFCEt2lsOhnZuTcLu5ACcJvOXpCgTItCDsQ/+g1GSzDl37IAwwI4MBUDPG30uwD0+s7JjYjgn0g==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-scroll-view@3.130.0': resolution: {integrity: sha512-Q5iwceQKFZ4TTLI/h5ZGWhBLP880g4Kn1h4jOeSGWUaKFyEUdbEd1DQKZA673q6pftyLoU6OQ66ZUzyX7tlaqA==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-sheet@3.130.0': resolution: {integrity: sha512-OSTgaX5xEJX0cjo9uwwrKcJS8wFZjFr7+yDew7gHK3bv7/FbJUVkJjhyb/bTGMsU+oyUZMUcqTgs1kgiokbPiQ==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-sortable@3.130.0': resolution: {integrity: sha512-gdFKT6WJOaXSyaej28jGHaLqMu3E/FGNOcqgTXdEJmFbOgpvCABRdZ1flfQMd5tmCV64HXcN6KYJ7X3BBG6uTw==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-swipe-action@3.130.0': resolution: {integrity: sha512-usfmTKBxVRsHAQQ3XvJOqqR0XRKc9+Gu+QjQdq7sa85m1xeFUocin0E8rBPuUNh82RAKC8NVgSw/olKWN/hi1Q==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-swiper@3.130.0': resolution: {integrity: sha512-g/kKFEO4hj+pshuJPpugiTqAjiLEr1kaVjTh8GbD40NFo8X+V9tZw92BO1pfVhoRqffqC6gI4mqk7qXqDcqvbA==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui-switch@3.130.0': resolution: {integrity: sha512-AjbqyYAmFI902GrBhsaOsWQdUZjL5RdN8kA3zQfj6c5HzmYqfjWf6Q0HLJP5EoVKl97Inyl8hGlZjECGNEAqVw==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/lynx-ui@3.130.0': resolution: {integrity: sha512-SgzadpXCECf0dYKmrFytU7C+ihxO//z7pOirNMZppe0MOhWrv4Ld0jBt/yWfSv2rBjBRFIyo2xCxn/PM7yq0dw==} peerDependencies: '@lynx-js/react': '>=0.100.0' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' '@types/react': ^18 '@lynx-js/motion@0.0.2': resolution: {integrity: sha512-/oA8yBnWlGsIRxI3FGfdjxFOuKr5j3oLLmn5viW9JeuLRfIg2u+FM+UGiaAl1mZ9xfns1jamK+uax+cPwvW2dA==} peerDependencies: '@lynx-js/react': '*' - '@lynx-js/types': 3.10.2-alpha.0 + '@lynx-js/types': '*' peerDependenciesMeta: '@lynx-js/types': optional: true @@ -13739,13 +13738,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13785,9 +13784,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13816,6 +13815,15 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 + '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + dependencies: + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + deepmerge: 4.3.1 + loader-utils: 2.0.4 + postcss: 8.5.6 + reduce-configs: 1.1.1 + sass-embedded: 1.97.3 + '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13824,19 +13832,6 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - deepmerge: 4.3.1 - json5: 2.2.3 - reduce-configs: 1.1.1 - ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) - optionalDependencies: - '@rsbuild/core': 1.7.5 - transitivePeerDependencies: - - '@rspack/core' - - tslib - - typescript - '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 @@ -13854,6 +13849,10 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + optionalDependencies: + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsdoctor/client@1.5.6': {} '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': @@ -20073,10 +20072,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20096,15 +20095,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: - '@rsbuild/core': 1.7.5 + '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e86820ec0e..5b35a5b40e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -69,9 +69,6 @@ overrides: "@rsbuild/core@1>@rspack/core": "$@rspack/core" "@rsdoctor/rspack-plugin>@rspack/core": "$@rspack/core" "@rsdoctor/types>@rspack/core": "$@rspack/core" - # Pin to the alpha that ships the FetchBundle / loadScript types. - # Drop this override once 3.10.2 (or later) is the natural resolution. - "@lynx-js/types": "3.10.2-alpha.0" packageExtensions: "@rspack/test-tools@*": From 1828a25bd78ee46597c453da84c9551d3c31188d Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 19:13:09 +0800 Subject: [PATCH 41/43] fix(swc-dynamic-import): declare \`once_cell\` workspace dep \`use once_cell::sync::Lazy\` resolved transitively through swc_core's deps, but cargo guarantees nothing about reaching transitive crates by their bare name. Declare \`once_cell\` explicitly to match the sibling swc plugins and lock the resolution. Spotted by Codex review. --- Cargo.lock | 1 + .../react/transform/crates/swc_plugin_dynamic_import/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index d675d5299a..4986b5aa1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3220,6 +3220,7 @@ version = "0.1.0" dependencies = [ "napi", "napi-derive", + "once_cell", "serde", "serde_json", "swc_core", diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/Cargo.toml b/packages/react/transform/crates/swc_plugin_dynamic_import/Cargo.toml index 7c7cfb7231..d86fc57dfc 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/Cargo.toml +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/Cargo.toml @@ -9,6 +9,7 @@ path = "lib.rs" [dependencies] napi = { workspace = true, optional = true } napi-derive = { workspace = true, optional = true } +once_cell = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["preserve_order"] } swc_core = { workspace = true, features = ["ecma_parser", "ecma_utils", "ecma_visit", "testing_transform"] } From 00ed6179c7d110a9eb27b3f58d749415b5c6e873 Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 20:14:19 +0800 Subject: [PATCH 42/43] refactor(swc-dynamic-import): drop redundant atoms::once_cell import Now that `once_cell` is declared in Cargo.toml, the indirect `swc_core::ecma::atoms::once_cell` re-export trick is no longer needed. Match `swc_plugin_snapshot`'s simpler import style. --- packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs index 48bfcf9777..d840c7d1f7 100644 --- a/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs +++ b/packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs @@ -15,7 +15,6 @@ use swc_core::{ }, ecma::{ ast::*, - atoms::once_cell, utils::{calc_literal_cost, prepend_stmt, private_ident}, visit::{VisitMut, VisitMutWith}, }, From 9ea21057b7b2322a93bb999fac671ecfa918339d Mon Sep 17 00:00:00 2001 From: Yiming Li Date: Tue, 12 May 2026 21:27:46 +0800 Subject: [PATCH 43/43] chore: pnpm dedupe after types bump The @lynx-js/types bump pulled some packages back to `@rsbuild/core@2.0.0-beta.3`; dedupe collapses them to the overridden 1.7.5 again. --- pnpm-lock.yaml | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 175b2394cf..2f319fc88d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -319,7 +319,7 @@ importers: version: 3.10.2-alpha.0 '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@types/react': specifier: ^18.3.28 version: 18.3.28 @@ -735,7 +735,7 @@ importers: version: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) rsbuild-plugin-i18next-extractor: specifier: 0.2.1 - version: 0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) + version: 0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9) packages/lynx/benchx_cli: dependencies: @@ -1446,10 +1446,10 @@ importers: version: link:../../web-platform/web-elements '@rsbuild/plugin-less': specifier: 1.6.0 - version: 1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.6.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) commander: specifier: ^13.1.0 version: 13.1.0 @@ -1464,7 +1464,7 @@ importers: version: 1.1.1 rsbuild-plugin-tailwindcss: specifier: 0.2.4 - version: 0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1) + version: 0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1) rslog: specifier: ^1.3.2 version: 1.3.2 @@ -1558,7 +1558,7 @@ importers: version: 3.10.2-alpha.0 '@rsbuild/plugin-babel': specifier: 1.1.0 - version: 1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.1.0(@rsbuild/core@1.7.5) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -2308,13 +2308,13 @@ importers: version: 7.33.6(@types/node@24.10.13) '@rsbuild/plugin-sass': specifier: 1.5.0 - version: 1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.5.0(@rsbuild/core@1.7.5) '@rsbuild/plugin-type-check': specifier: 1.3.4 - version: 1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + version: 1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) '@rsbuild/plugin-typed-css-modules': specifier: 1.2.2 - version: 1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.2.2(@rsbuild/core@1.7.5) '@rspress/core': specifier: 2.0.3 version: 2.0.3(@module-federation/runtime-tools@0.22.0)(@types/react@19.2.14)(core-js@3.48.0) @@ -13738,13 +13738,13 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-babel@1.1.0(@rsbuild/core@1.7.5)': dependencies: '@babel/core': 7.29.0 '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@types/babel__core': 7.20.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13784,9 +13784,9 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': + '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.5)': dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 deepmerge: 4.3.1 reduce-configs: 1.1.1 @@ -13815,15 +13815,6 @@ snapshots: reduce-configs: 1.1.1 sass-embedded: 1.97.3 - '@rsbuild/plugin-sass@1.5.0(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - dependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - deepmerge: 4.3.1 - loader-utils: 2.0.4 - postcss: 8.5.6 - reduce-configs: 1.1.1 - sass-embedded: 1.97.3 - '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.5)': dependencies: fast-glob: 3.3.3 @@ -13832,6 +13823,19 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': + dependencies: + deepmerge: 4.3.1 + json5: 2.2.3 + reduce-configs: 1.1.1 + ts-checker-rspack-plugin: 1.3.0(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3) + optionalDependencies: + '@rsbuild/core': 1.7.5 + transitivePeerDependencies: + - '@rspack/core' + - tslib + - typescript + '@rsbuild/plugin-type-check@1.3.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(@rspack/core@1.7.9(@swc/helpers@0.5.21))(tslib@2.8.1)(typescript@5.9.3)': dependencies: deepmerge: 4.3.1 @@ -13849,10 +13853,6 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.5 - '@rsbuild/plugin-typed-css-modules@1.2.2(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': - optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - '@rsdoctor/client@1.5.6': {} '@rsdoctor/core@1.5.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@rsbuild/core@1.7.5)(@rspack/core@1.7.9(@swc/helpers@0.5.21))(webpack@5.105.2)': @@ -20072,10 +20072,10 @@ snapshots: '@typescript/native-preview': 7.0.0-dev.20260212.1 typescript: 5.9.3 - rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): + rsbuild-plugin-i18next-extractor@0.2.1(@rsbuild/core@1.7.5)(i18next-cli@1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3))(rollup@4.34.9): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.34.9) - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 '@rspack/lite-tapable': 1.1.0 i18next-cli: 1.54.2(@swc/helpers@0.5.21)(@types/node@24.10.13)(i18next@26.0.6(typescript@5.9.3))(typescript@5.9.3) transitivePeerDependencies: @@ -20095,15 +20095,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@1.7.5)(tailwindcss@4.2.1): dependencies: - tailwindcss: 3.4.19 + tailwindcss: 4.2.1 optionalDependencies: - '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) + '@rsbuild/core': 1.7.5 - rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@4.2.1): + rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))(tailwindcss@3.4.19): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 3.4.19 optionalDependencies: '@rsbuild/core': 2.0.0-beta.3(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)