diff --git a/.changeset/plugin-externals-rsbuild.md b/.changeset/plugin-externals-rsbuild.md new file mode 100644 index 0000000000..ec1f8d2065 --- /dev/null +++ b/.changeset/plugin-externals-rsbuild.md @@ -0,0 +1,26 @@ +--- +'@lynx-js/external-bundle-rsbuild-plugin': patch +--- + +Introduce `@lynx-js/external-bundle-rsbuild-plugin`. + +```ts +// lynx.config.ts +import { pluginExternalBundle } from '@lynx-js/external-bundle-rsbuild-plugin'; +import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; + +export default { + plugins: [ + pluginReactLynx(), + pluginExternalBundle({ + externals: { + lodash: { + url: 'http://lodash.lynx.bundle', + background: { sectionPath: 'background' }, + mainThread: { sectionPath: 'mainThread' }, + }, + }, + }), + ], +}; +``` diff --git a/.changeset/sixty-emus-call.md b/.changeset/sixty-emus-call.md new file mode 100644 index 0000000000..2a8302b06d --- /dev/null +++ b/.changeset/sixty-emus-call.md @@ -0,0 +1,5 @@ +--- +"@lynx-js/react-rsbuild-plugin": patch +--- + +expose LAYERS via `api.expose` for other rsbuild plugins. diff --git a/examples/react-externals/lynx.config.js b/examples/react-externals/lynx.config.js index e0323b53d5..bcaea076e1 100644 --- a/examples/react-externals/lynx.config.js +++ b/examples/react-externals/lynx.config.js @@ -1,87 +1,12 @@ -import { ExternalsLoadingPlugin } from '@lynx-js/externals-loading-webpack-plugin'; +import { pluginExternalBundle } from '@lynx-js/external-bundle-rsbuild-plugin'; import { pluginQRCode } from '@lynx-js/qrcode-rsbuild-plugin'; -import { LAYERS, pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; +import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin'; import { defineConfig } from '@lynx-js/rspeedy'; const enableBundleAnalysis = !!process.env['RSPEEDY_BUNDLE_ANALYSIS']; const EXTERNAL_BUNDLE_PREFIX = process.env['EXTERNAL_BUNDLE_PREFIX'] || ''; export default defineConfig({ - tools: { - rspack: { - plugins: [ - new ExternalsLoadingPlugin({ - mainThreadLayer: LAYERS.MAIN_THREAD, - backgroundLayer: LAYERS.BACKGROUND, - externals: { - '@lynx-js/react': { - libraryName: ['ReactLynx', 'React'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - '@lynx-js/react/internal': { - libraryName: ['ReactLynx', 'ReactInternal'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - '@lynx-js/react/experimental/lazy/import': { - libraryName: ['ReactLynx', 'ReactLazyImport'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - '@lynx-js/react/legacy-react-runtime': { - libraryName: ['ReactLynx', 'ReactLegacyRuntime'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - '@lynx-js/react/runtime-components': { - libraryName: ['ReactLynx', 'ReactComponents'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - '@lynx-js/react/worklet-runtime/bindings': { - libraryName: ['ReactLynx', 'ReactWorkletRuntime'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - '@lynx-js/react/debug': { - libraryName: ['ReactLynx', 'ReactDebug'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - preact: { - libraryName: ['ReactLynx', 'Preact'], - url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, - background: { sectionPath: 'ReactLynx' }, - mainThread: { sectionPath: 'ReactLynx__main-thread' }, - async: false, - }, - './App.js': { - libraryName: 'CompLib', - url: `${EXTERNAL_BUNDLE_PREFIX}/comp-lib.lynx.bundle`, - background: { sectionPath: 'CompLib' }, - mainThread: { sectionPath: 'CompLib__main-thread' }, - async: true, - }, - }, - }), - ], - }, - }, plugins: [ pluginReactLynx(), pluginQRCode({ @@ -90,6 +15,73 @@ export default defineConfig({ return `${url}?fullscreen=true`; }, }), + pluginExternalBundle({ + externals: { + '@lynx-js/react': { + libraryName: ['ReactLynx', 'React'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + '@lynx-js/react/internal': { + libraryName: ['ReactLynx', 'ReactInternal'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + '@lynx-js/react/experimental/lazy/import': { + libraryName: ['ReactLynx', 'ReactLazyImport'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + '@lynx-js/react/legacy-react-runtime': { + libraryName: ['ReactLynx', 'ReactLegacyRuntime'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + '@lynx-js/react/runtime-components': { + libraryName: ['ReactLynx', 'ReactComponents'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + '@lynx-js/react/worklet-runtime/bindings': { + libraryName: ['ReactLynx', 'ReactWorkletRuntime'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + '@lynx-js/react/debug': { + libraryName: ['ReactLynx', 'ReactDebug'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + preact: { + libraryName: ['ReactLynx', 'Preact'], + url: `${EXTERNAL_BUNDLE_PREFIX}/react.lynx.bundle`, + background: { sectionPath: 'ReactLynx' }, + mainThread: { sectionPath: 'ReactLynx__main-thread' }, + async: false, + }, + './App.js': { + libraryName: 'CompLib', + url: `${EXTERNAL_BUNDLE_PREFIX}/comp-lib.lynx.bundle`, + background: { sectionPath: 'CompLib' }, + mainThread: { sectionPath: 'CompLib__main-thread' }, + async: true, + }, + }, + }), ], environments: { web: {}, diff --git a/examples/react-externals/package.json b/examples/react-externals/package.json index f04b9d960f..e79f237887 100644 --- a/examples/react-externals/package.json +++ b/examples/react-externals/package.json @@ -13,7 +13,7 @@ "@lynx-js/react": "workspace:*" }, "devDependencies": { - "@lynx-js/externals-loading-webpack-plugin": "workspace:*", + "@lynx-js/external-bundle-rsbuild-plugin": "workspace:*", "@lynx-js/lynx-bundle-rslib-config": "workspace:*", "@lynx-js/preact-devtools": "^5.0.1-cf9aef5", "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", diff --git a/packages/rspeedy/lynx-bundle-rslib-config/src/index.ts b/packages/rspeedy/lynx-bundle-rslib-config/src/index.ts index 7da318e5b3..1c714fdc89 100644 --- a/packages/rspeedy/lynx-bundle-rslib-config/src/index.ts +++ b/packages/rspeedy/lynx-bundle-rslib-config/src/index.ts @@ -6,44 +6,6 @@ * @packageDocumentation * * `@lynx-js/lynx-bundle-rslib-config` is the package that provides the configurations for bundling Lynx bundle with {@link https://rslib.rs/ | Rslib}. - * - * 1. Install the package: - * - * ```bash - * pnpm add @lynx-js/lynx-bundle-rslib-config @rslib/core -D - * ``` - * - * 2. Add the following code to `rslib.config.ts`: - * - * ```ts - * import { defineExternalBundleRslibConfig } from '@lynx-js/lynx-bundle-rslib-config' - * - * export default defineExternalBundleRslibConfig({ - * id: 'my-utils', - * source: { - * entry: { - * utils: './src/utils.ts' - * } - * } - * }) - * ``` - * - * 3. Run the command `pnpm rslib build` and you will get the `my-utils.lynx.bundle` in the `dist` directory. You can upload the bundle to CDN or server. - * - * 4. Finally, you can fetch and load the external bundle through: - * - * ```js - * const bundleUrl = 'http://cdn.com/my-utils.lynx.bundle' - * lynx.fetchBundle(bundleUrl).wait(3) // timeout is 3s - * - * if (__BACKGROUND__) { - * const utils = lynx.loadScript('utils', { bundleName: bundleUrl }) - * } else { - * const utils = lynx.loadScript('utils__main-thread', { bundleName: bundleUrl }) - * } - * ``` - * - * For more detail, please refer to the {@link defineExternalBundleRslibConfig}. */ export { defineExternalBundleRslibConfig, diff --git a/packages/rspeedy/plugin-external-bundle/CHANGELOG.md b/packages/rspeedy/plugin-external-bundle/CHANGELOG.md new file mode 100644 index 0000000000..13ef778430 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/CHANGELOG.md @@ -0,0 +1 @@ +# @lynx-js/external-bundle-rsbuild-plugin diff --git a/packages/rspeedy/plugin-external-bundle/README.md b/packages/rspeedy/plugin-external-bundle/README.md new file mode 100644 index 0000000000..b7e00dd7f0 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/README.md @@ -0,0 +1,53 @@ +

+ Rspeedy Logo +

+ +

+ + + + + license + +

+ +## Getting Started + +```bash +npm install -D @lynx-js/external-bundle-rsbuild-plugin +``` + +## Usage + +```ts +// lynx.config.ts +import { pluginExternalBundle } from '@lynx-js/external-bundle-rsbuild-plugin' +import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin' + +export default { + plugins: [ + pluginReactLynx(), + pluginExternalBundle({ + externals: { + lodash: { + url: 'http://lodash.lynx.bundle', + background: { sectionPath: 'background' }, + mainThread: { sectionPath: 'mainThread' }, + }, + }, + }), + ], +} +``` + +## Documentation + +Visit [Lynx Website](https://lynxjs.org/api/rspeedy/external-bundle-rsbuild-plugin) to view the full documentation. + +## Contributing + +Contributions to Rspeedy are welcome and highly appreciated. However, before you jump right into it, we would like you to review our [Contribution Guidelines](/CONTRIBUTING.md) to make sure you have a smooth experience contributing to this project. + +## License + +Rspeedy is Apache-2.0 licensed. diff --git a/packages/rspeedy/plugin-external-bundle/api-extractor.json b/packages/rspeedy/plugin-external-bundle/api-extractor.json new file mode 100644 index 0000000000..65b0c69ca6 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/api-extractor.json @@ -0,0 +1,6 @@ +/** + * Config file for API Extractor. For more info, please visit: https://api-extractor.com + */ +{ + "extends": "../../../api-extractor.json", +} diff --git a/packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md b/packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md new file mode 100644 index 0000000000..78fd501a50 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/etc/external-bundle-rsbuild-plugin.api.md @@ -0,0 +1,16 @@ +## API Report File for "@lynx-js/external-bundle-rsbuild-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { ExternalsLoadingPluginOptions } from '@lynx-js/externals-loading-webpack-plugin'; +import type { RsbuildPlugin } from '@rsbuild/core'; + +// @public +export function pluginExternalBundle(options: PluginExternalBundleOptions): RsbuildPlugin; + +// @public +export type PluginExternalBundleOptions = Pick; + +``` diff --git a/packages/rspeedy/plugin-external-bundle/package.json b/packages/rspeedy/plugin-external-bundle/package.json new file mode 100644 index 0000000000..1f3dce4e2e --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/package.json @@ -0,0 +1,50 @@ +{ + "name": "@lynx-js/external-bundle-rsbuild-plugin", + "version": "0.0.0", + "description": "A rsbuild plugin for loading lynx external bundles.", + "keywords": [ + "rsbuild", + "Lynx", + "externals", + "bundle" + ], + "repository": { + "type": "git", + "url": "https://github.com/lynx-family/lynx-stack.git", + "directory": "packages/rspeedy/plugin-external-bundle" + }, + "license": "Apache-2.0", + "author": { + "name": "Hengchang Lu", + "email": "luhengchang228@gmail.com" + }, + "type": "module", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "default": "./lib/index.js" + }, + "./package.json": "./package.json" + }, + "types": "./lib/index.d.ts", + "files": [ + "lib", + "!lib/**/*.js.map", + "CHANGELOG.md", + "README.md" + ], + "scripts": { + "api-extractor": "api-extractor run --verbose", + "test": "pnpm -w run test --project rspeedy/externals" + }, + "dependencies": { + "@lynx-js/externals-loading-webpack-plugin": "workspace:*" + }, + "devDependencies": { + "@microsoft/api-extractor": "catalog:", + "@rsbuild/core": "catalog:rsbuild" + }, + "engines": { + "node": ">=18" + } +} diff --git a/packages/rspeedy/plugin-external-bundle/src/index.ts b/packages/rspeedy/plugin-external-bundle/src/index.ts new file mode 100644 index 0000000000..f26c216d90 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/src/index.ts @@ -0,0 +1,90 @@ +// 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. + +/** + * @packageDocumentation + * + * A rsbuild plugin for loading external bundles using externals-loading-webpack-plugin. + */ + +import type { RsbuildPlugin } from '@rsbuild/core' + +import type { ExternalsLoadingPluginOptions } from '@lynx-js/externals-loading-webpack-plugin' +import { ExternalsLoadingPlugin } from '@lynx-js/externals-loading-webpack-plugin' + +interface ExposedLayers { + readonly BACKGROUND: string + readonly MAIN_THREAD: string +} + +/** + * Options for the external-bundle-rsbuild-plugin. + * + * @public + */ +export type PluginExternalBundleOptions = Pick< + ExternalsLoadingPluginOptions, + 'externals' +> + +/** + * Create a rsbuild plugin for loading external bundles. + * + * This plugin wraps the externals-loading-webpack-plugin and automatically + * retrieves layer names from the react-rsbuild-plugin via api.useExposed. + * + * @example + * ```ts + * // lynx.config.ts + * import { pluginExternalBundle } from '@lynx-js/external-bundle-rsbuild-plugin' + * import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin' + * + * export default { + * plugins: [ + * pluginReactLynx(), + * pluginExternalBundle({ + * externals: { + * lodash: { + * url: 'http://lodash.lynx.bundle', + * background: { sectionPath: 'background' }, + * mainThread: { sectionPath: 'mainThread' }, + * }, + * }, + * }), + * ], + * } + * ``` + * + * @public + */ +export function pluginExternalBundle( + options: PluginExternalBundleOptions, +): RsbuildPlugin { + return { + name: 'lynx:external-bundle', + setup(api) { + api.modifyRspackConfig((config) => { + // Get layer names from react-rsbuild-plugin + const LAYERS = api.useExposed( + Symbol.for('LAYERS'), + ) + + if (!LAYERS) { + throw new Error( + 'external-bundle-rsbuild-plugin requires exposed `LAYERS`.', + ) + } + config.plugins = config.plugins || [] + config.plugins.push( + new ExternalsLoadingPlugin({ + backgroundLayer: LAYERS.BACKGROUND, + mainThreadLayer: LAYERS.MAIN_THREAD, + externals: options.externals, + }), + ) + return config + }) + }, + } +} diff --git a/packages/rspeedy/plugin-external-bundle/test/index.test.ts b/packages/rspeedy/plugin-external-bundle/test/index.test.ts new file mode 100644 index 0000000000..7e22b2f546 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/test/index.test.ts @@ -0,0 +1,193 @@ +// 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 { createRsbuild } from '@rsbuild/core' +import { describe, expect, test } from 'vitest' + +import { ExternalsLoadingPlugin } from '@lynx-js/externals-loading-webpack-plugin' + +import { pluginStubLayers } from './stub-layers.plugin.js' + +describe('pluginExternalBundle', () => { + test('should register ExternalsLoadingPlugin with correct options', async () => { + const { pluginExternalBundle } = await import('../src/index.js') + + const externalsConfig = { + lodash: { + url: 'http://lodash.lynx.bundle', + background: { sectionPath: 'background' }, + mainThread: { sectionPath: 'mainThread' }, + }, + react: { + url: 'http://react.lynx.bundle', + background: { sectionPath: 'react-background' }, + mainThread: { sectionPath: 'react-main' }, + }, + } + + let capturedPlugins: unknown[] = [] + + const rsbuild = await createRsbuild({ + rsbuildConfig: { + source: { + entry: { + main: './fixtures/basic.tsx', + }, + }, + tools: { + rspack(config) { + // Capture plugins for verification + capturedPlugins = config.plugins || [] + return config + }, + }, + plugins: [ + pluginStubLayers(), + pluginExternalBundle({ + externals: externalsConfig, + }), + ], + }, + }) + + // Trigger the config to be resolved + await rsbuild.inspectConfig() + + // Verify that ExternalsLoadingPlugin is registered + const externalBundlePlugin = capturedPlugins.find( + (plugin) => plugin instanceof ExternalsLoadingPlugin, + ) + + expect(externalBundlePlugin).toBeDefined() + + // Verify plugin options + expect(externalBundlePlugin).toMatchObject({ + options: { + backgroundLayer: 'BACKGROUND_LAYER', + mainThreadLayer: 'MAIN_THREAD_LAYER', + externals: externalsConfig, + }, + }) + }) + + test('should throw error if LAYERS is not exposed', async () => { + const { pluginExternalBundle } = await import('../src/index.js') + + const rsbuild = await createRsbuild({ + rsbuildConfig: { + source: { + entry: { + main: './fixtures/basic.tsx', + }, + }, + plugins: [ + // Not including pluginStubLayers to test error case + pluginExternalBundle({ + externals: { + lodash: { + url: 'http://lodash.lynx.bundle', + background: { sectionPath: 'background' }, + mainThread: { sectionPath: 'mainThread' }, + }, + }, + }), + ], + }, + }) + + // The error should be thrown during config inspection/build + await expect(rsbuild.inspectConfig()).rejects.toThrow( + 'external-bundle-rsbuild-plugin requires exposed `LAYERS`.', + ) + }) + + test('should work with empty externals config', async () => { + const { pluginExternalBundle } = await import('../src/index.js') + + let capturedPlugins: unknown[] = [] + + const rsbuild = await createRsbuild({ + rsbuildConfig: { + source: { + entry: { + main: './fixtures/basic.tsx', + }, + }, + tools: { + rspack(config) { + capturedPlugins = config.plugins || [] + return config + }, + }, + plugins: [pluginStubLayers(), pluginExternalBundle({ externals: {} })], + }, + }) + + await rsbuild.inspectConfig() + + const externalBundlePlugin = capturedPlugins.find( + (plugin) => plugin instanceof ExternalsLoadingPlugin, + ) + + expect(externalBundlePlugin).toBeDefined() + expect(externalBundlePlugin).toMatchObject({ + options: { + externals: {}, + }, + }) + }) + + test('should correctly pass layer names from LAYERS', async () => { + const { pluginExternalBundle } = await import('../src/index.js') + + const customLayers = { + BACKGROUND: 'CUSTOM_BACKGROUND', + MAIN_THREAD: 'CUSTOM_MAIN', + } + + let capturedPlugins: unknown[] = [] + + const rsbuild = await createRsbuild({ + rsbuildConfig: { + source: { + entry: { + main: './fixtures/basic.tsx', + }, + }, + tools: { + rspack(config) { + capturedPlugins = config.plugins || [] + return config + }, + }, + plugins: [ + pluginStubLayers(customLayers), + pluginExternalBundle({ + externals: { + lodash: { + url: 'http://lodash.lynx.bundle', + background: { sectionPath: 'background' }, + mainThread: { sectionPath: 'mainThread' }, + }, + }, + }), + ], + }, + }) + + await rsbuild.inspectConfig() + + const externalBundlePlugin = capturedPlugins.find( + (plugin) => plugin instanceof ExternalsLoadingPlugin, + ) + + expect(externalBundlePlugin).toBeDefined() + expect(externalBundlePlugin).toMatchObject({ + options: { + backgroundLayer: 'CUSTOM_BACKGROUND', + mainThreadLayer: 'CUSTOM_MAIN', + }, + }) + }) +}) diff --git a/packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts b/packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts new file mode 100644 index 0000000000..79b0e16f42 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/test/stub-layers.plugin.ts @@ -0,0 +1,24 @@ +// 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 type { RsbuildPlugin } from '@rsbuild/core' + +interface ExposedLayers { + readonly BACKGROUND: string + readonly MAIN_THREAD: string +} + +/** + * Stub plugin that exposes LAYERS for testing + */ +export const pluginStubLayers = ( + layers: ExposedLayers = { + BACKGROUND: 'BACKGROUND_LAYER', + MAIN_THREAD: 'MAIN_THREAD_LAYER', + }, +): RsbuildPlugin => ({ + name: 'lynx:stub-layers', + setup(api) { + api.expose(Symbol.for('LAYERS'), layers) + }, +}) diff --git a/packages/rspeedy/plugin-external-bundle/tsconfig.build.json b/packages/rspeedy/plugin-external-bundle/tsconfig.build.json new file mode 100644 index 0000000000..b75bf5dd1c --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "composite": true, + "outDir": "./lib", + "rootDir": "./src", + }, + "references": [ + { "path": "../core/tsconfig.build.json" }, + ], + "include": ["src"], +} diff --git a/packages/rspeedy/plugin-external-bundle/tsconfig.json b/packages/rspeedy/plugin-external-bundle/tsconfig.json new file mode 100644 index 0000000000..110e5a0ccb --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": ["./tsconfig.build.json"], + "compilerOptions": { + "rootDir": ".", + "noEmit": true, + }, + "include": ["src", "test", "vitest.config.ts"], + "references": [ + { "path": "../core/tsconfig.build.json" }, + ], +} diff --git a/packages/rspeedy/plugin-external-bundle/vitest.config.ts b/packages/rspeedy/plugin-external-bundle/vitest.config.ts new file mode 100644 index 0000000000..8221393e89 --- /dev/null +++ b/packages/rspeedy/plugin-external-bundle/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineProject } from 'vitest/config' +import type { UserWorkspaceConfig } from 'vitest/config' + +const config: UserWorkspaceConfig = defineProject({ + test: { + name: 'rspeedy/externals', + }, +}) + +export default config diff --git a/packages/rspeedy/plugin-react/src/pluginReactLynx.ts b/packages/rspeedy/plugin-react/src/pluginReactLynx.ts index 4f4c9fd023..b4ae22a386 100644 --- a/packages/rspeedy/plugin-react/src/pluginReactLynx.ts +++ b/packages/rspeedy/plugin-react/src/pluginReactLynx.ts @@ -368,6 +368,8 @@ export function pluginReactLynx( applyLazy(api) } + api.expose(Symbol.for('LAYERS'), LAYERS) + const rspeedyAPIs = api.useExposed( Symbol.for('rspeedy.api'), )! diff --git a/packages/rspeedy/tsconfig.json b/packages/rspeedy/tsconfig.json index 014b25cb83..7595fb6cbd 100644 --- a/packages/rspeedy/tsconfig.json +++ b/packages/rspeedy/tsconfig.json @@ -10,6 +10,7 @@ { "path": "./plugin-react/tsconfig.build.json" }, { "path": "./plugin-react-alias/tsconfig.build.json" }, { "path": "./lynx-bundle-rslib-config/tsconfig.build.json" }, + { "path": "./plugin-external-bundle/tsconfig.build.json" }, /** packages-end */ ], "include": [], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c53119eb7..fbf1554a3f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -248,9 +248,9 @@ importers: specifier: workspace:* version: link:../../packages/react devDependencies: - '@lynx-js/externals-loading-webpack-plugin': + '@lynx-js/external-bundle-rsbuild-plugin': specifier: workspace:* - version: link:../../packages/webpack/externals-loading-webpack-plugin + version: link:../../packages/rspeedy/plugin-external-bundle '@lynx-js/lynx-bundle-rslib-config': specifier: workspace:* version: link:../../packages/rspeedy/lynx-bundle-rslib-config @@ -656,6 +656,19 @@ importers: specifier: ^5.102.0 version: 5.102.0 + packages/rspeedy/plugin-external-bundle: + dependencies: + '@lynx-js/externals-loading-webpack-plugin': + specifier: workspace:* + version: link:../../webpack/externals-loading-webpack-plugin + devDependencies: + '@microsoft/api-extractor': + specifier: 'catalog:' + version: 7.55.2(@types/node@24.6.1) + '@rsbuild/core': + specifier: catalog:rsbuild + version: 1.6.13 + packages/rspeedy/plugin-qrcode: devDependencies: '@clack/prompts': @@ -1518,6 +1531,9 @@ importers: '@lynx-js/css-extract-webpack-plugin': specifier: workspace:* version: link:../packages/webpack/css-extract-webpack-plugin + '@lynx-js/external-bundle-rsbuild-plugin': + specifier: workspace:* + version: link:../packages/rspeedy/plugin-external-bundle '@lynx-js/lynx-bundle-rslib-config': specifier: workspace:* version: link:../packages/rspeedy/lynx-bundle-rslib-config diff --git a/website/package.json b/website/package.json index 760ba97165..4a47632f76 100644 --- a/website/package.json +++ b/website/package.json @@ -21,6 +21,7 @@ "devDependencies": { "@lynx-js/chunk-loading-webpack-plugin": "workspace:*", "@lynx-js/css-extract-webpack-plugin": "workspace:*", + "@lynx-js/external-bundle-rsbuild-plugin": "workspace:*", "@lynx-js/lynx-bundle-rslib-config": "workspace:*", "@lynx-js/qrcode-rsbuild-plugin": "workspace:*", "@lynx-js/react": "workspace:*", diff --git a/website/rspress.config.ts b/website/rspress.config.ts index 1f0c5ad27d..c07cc2b1ca 100644 --- a/website/rspress.config.ts +++ b/website/rspress.config.ts @@ -64,6 +64,9 @@ const SIDEBARS = { 'PluginQRCodeOptions', ], }), + createAPI({ + name: 'external-bundle-rsbuild-plugin', + }), createAPI({ name: 'lynx-bundle-rslib-config', }), @@ -204,6 +207,10 @@ const SIDEBARS_ZH = { 'PluginQRCodeOptions', ], }), + createAPI({ + base: 'zh/api', + name: 'external-bundle-rsbuild-plugin', + }), createAPI({ base: 'zh/api', name: 'lynx-bundle-rslib-config',