diff --git a/.changeset/inline-worklet-runtime.md b/.changeset/inline-worklet-runtime.md new file mode 100644 index 0000000000..05e2dea53e --- /dev/null +++ b/.changeset/inline-worklet-runtime.md @@ -0,0 +1,6 @@ +--- +"@lynx-js/react-rsbuild-plugin": minor +"@lynx-js/react-webpack-plugin": minor +--- + +Inline worklet-runtime into main-thread.js entry instead of injecting it as a separate Lepus chunk. diff --git a/packages/react/worklet-runtime/src/bindings/loadRuntime.ts b/packages/react/worklet-runtime/src/bindings/loadRuntime.ts index 325e6618c4..294ff3927f 100644 --- a/packages/react/worklet-runtime/src/bindings/loadRuntime.ts +++ b/packages/react/worklet-runtime/src/bindings/loadRuntime.ts @@ -5,21 +5,18 @@ import '../global.js'; /** - * Loads and initializes the Lepus chunk in the main thread. - * @param __schema - The dynamic component entry for loading the Lepus chunk. - * @returns A boolean indicating whether the Lepus chunk was loaded and initialized successfully. + * Guard function for worklet runtime availability. + * + * The worklet-runtime is now bundled directly into the main-thread.js entry, + * so there is no need to load it via `__LoadLepusChunk`. This function is + * kept as a guard because SWC-generated code still calls it before + * `registerWorkletInternal`. + * + * @param __schema - Unused. Kept for backward compatibility with SWC-generated call sites. + * @returns Whether the worklet runtime has been initialized. */ function loadWorkletRuntime(__schema?: string): boolean { - if (typeof __LoadLepusChunk === 'undefined') { - return false; - } - if (globalThis.lynxWorkletImpl) { - return true; - } - return __LoadLepusChunk('worklet-runtime', { - dynamicComponentEntry: __schema, - chunkType: 0, - }); + return !!globalThis.lynxWorkletImpl; } export { loadWorkletRuntime }; diff --git a/packages/rspeedy/plugin-react/src/entry.ts b/packages/rspeedy/plugin-react/src/entry.ts index 52151fa067..89aa281543 100644 --- a/packages/rspeedy/plugin-react/src/entry.ts +++ b/packages/rspeedy/plugin-react/src/entry.ts @@ -63,6 +63,14 @@ export function applyEntry( const enableChunkSplitting = rsbuildConfig.performance?.chunkSplit?.strategy !== 'all-in-one' + const { resolve } = api.useExposed< + { resolve: (request: string) => Promise } + >(Symbol.for('@lynx-js/react/internal:resolve'))! + + const workletRuntimePath = await resolve( + `@lynx-js/react/${isDev ? 'worklet-dev-runtime' : 'worklet-runtime'}`, + ) + const isRspeedy = api.context.callerName === 'rspeedy' if (isRspeedy) { // biome-ignore lint/correctness/useHookAtTopLevel: This is not a React hook. @@ -127,7 +135,7 @@ export function applyEntry( .entry(mainThreadEntry) .add({ layer: LAYERS.MAIN_THREAD, - import: imports, + import: [...imports, workletRuntimePath], filename: mainThreadName, }) .when(enabledHMR, entry => { @@ -261,10 +269,6 @@ export function applyEntry( extractStr = false } - const { resolve } = api.useExposed< - { resolve: (request: string) => Promise } - >(Symbol.for('@lynx-js/react/internal:resolve'))! - chain .plugin(PLUGIN_NAME_REACT) .after(PLUGIN_NAME_TEMPLATE) @@ -277,9 +281,7 @@ export function applyEntry( extractStr, experimental_isLazyBundle, profile: getDefaultProfile(), - workletRuntimePath: await resolve( - `@lynx-js/react/${isDev ? 'worklet-dev-runtime' : 'worklet-runtime'}`, - ), + workletRuntimePath, }]) 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 af12ce91f5..075f535764 100644 --- a/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts +++ b/packages/webpack/react-webpack-plugin/src/ReactWebpackPlugin.ts @@ -2,7 +2,6 @@ // 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 * as fs from 'node:fs'; import { createRequire } from 'node:module'; import type { Chunk, Compilation, Compiler } from '@rspack/core'; @@ -262,30 +261,7 @@ class ReactWebpackPlugin { // @ts-expect-error Rspack x Webpack compilation not match const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks(compilation); - const { RawSource, ConcatSource } = compiler.webpack.sources; - hooks.beforeEncode.tap( - this.constructor.name, - (args) => { - const lepusCode = args.encodeData.lepusCode; - if ( - lepusCode.root?.source.source().toString()?.includes( - 'registerWorkletInternal', - ) - ) { - lepusCode.chunks.push({ - name: 'worklet-runtime', - source: new RawSource(fs.readFileSync( - options.workletRuntimePath, - 'utf8', - )), - info: { - ['lynx:main-thread']: true, - }, - }); - } - return args; - }, - ); + const { ConcatSource } = compiler.webpack.sources; // Inject `module.exports` for async main-thread chunks hooks.beforeEncode.tap(this.constructor.name, (args) => { diff --git a/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/index.js b/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/index.js index f2ee0341b2..4eab86b3ba 100644 --- a/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/index.js +++ b/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/index.js @@ -6,7 +6,7 @@ import path from 'node:path'; import './a.jsx'; -it('should have worklet-runtime', async () => { +it('should have worklet-runtime inlined in main-thread', async () => { const source = await fs.readFile( path.resolve( path.join( @@ -18,6 +18,11 @@ it('should have worklet-runtime', async () => { 'utf-8', ); const json = JSON.parse(source); - expect(json['lepusCode']['lepusChunk']['worklet-runtime'].length > 0) + // worklet-runtime is now bundled into main-thread.js entry, + // not as a separate lepus chunk + expect(json['lepusCode']['lepusChunk']['worklet-runtime']) + .toBe(undefined); + // Verify the worklet runtime code is in the main-thread root + expect(json['lepusCode']['root'].includes('lynxWorkletImpl')) .toBe(true); }); diff --git a/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/rspack.config.js b/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/rspack.config.js index 6cebcf7671..3c869d6859 100644 --- a/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/rspack.config.js +++ b/packages/webpack/react-webpack-plugin/test/cases/worklet-runtime/chunk/rspack.config.js @@ -1,3 +1,4 @@ +import { createRequire } from 'node:module'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -8,11 +9,18 @@ import { } from '@lynx-js/template-webpack-plugin'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const require = createRequire(import.meta.url); const defaultConfig = createConfig({}, { mainThreadChunks: ['main__main-thread.js'], }, {}); +// Add worklet-runtime to main-thread entry (simulating rspeedy entry setup) +defaultConfig.entry['main__main-thread'].import = [ + defaultConfig.entry['main__main-thread'].import, + require.resolve('@lynx-js/react/worklet-dev-runtime'), +].flat(); + /** @type {import('@rspack/core').Configuration} */ export default { context: __dirname,