diff --git a/.changeset/wet-humans-teach.md b/.changeset/wet-humans-teach.md new file mode 100644 index 0000000000..ebc73b7db3 --- /dev/null +++ b/.changeset/wet-humans-teach.md @@ -0,0 +1,6 @@ +--- +'@lynx-js/qrcode-rsbuild-plugin': patch +'@lynx-js/rspeedy': patch +--- + +feat(qrcode): support get entry from api exposed from rspeedy.env.entries diff --git a/packages/rspeedy/core/etc/rspeedy.api.md b/packages/rspeedy/core/etc/rspeedy.api.md index a21870c23b..3fa24dba39 100644 --- a/packages/rspeedy/core/etc/rspeedy.api.md +++ b/packages/rspeedy/core/etc/rspeedy.api.md @@ -13,6 +13,7 @@ import { logger } from '@rsbuild/core'; import type { PerformanceConfig } from '@rsbuild/core'; import type { ProxyConfig } from '@rsbuild/core'; import type { RsbuildConfig } from '@rsbuild/core'; +import type { RsbuildEntry } from '@rsbuild/core'; import type { RsbuildInstance } from '@rsbuild/core'; import { RsbuildPlugin } from '@rsbuild/core'; import { RsbuildPluginAPI } from '@rsbuild/core'; @@ -195,6 +196,7 @@ export interface EntryDescription { export interface ExposedAPI { config: Config; debug: (message: string | (() => string)) => void; + entries?: RsbuildEntry; exit: (code?: number) => Promise | void; logger: typeof logger; version: string; diff --git a/packages/rspeedy/core/src/api.ts b/packages/rspeedy/core/src/api.ts index 00a8e0f226..ae4e6fc71f 100644 --- a/packages/rspeedy/core/src/api.ts +++ b/packages/rspeedy/core/src/api.ts @@ -2,6 +2,7 @@ // 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 { logger } from '@rsbuild/core' +import type { RsbuildEntry } from '@rsbuild/core' import type { Config } from './config/index.js' @@ -52,4 +53,9 @@ export interface ExposedAPI { * The version of Rspeedy. */ version: string + + /** + * Used for plugin qrcode get entry points from self-defined environments rather than default lynx environment. + */ + entries?: RsbuildEntry } diff --git a/packages/rspeedy/core/turbo.json b/packages/rspeedy/core/turbo.json index cbebb209ee..725b3408cf 100644 --- a/packages/rspeedy/core/turbo.json +++ b/packages/rspeedy/core/turbo.json @@ -6,6 +6,7 @@ "tasks": { "build": { "dependsOn": [ + "//#build", "^build" ], "env": [ diff --git a/packages/rspeedy/plugin-qrcode/src/index.ts b/packages/rspeedy/plugin-qrcode/src/index.ts index 9110f4a4b6..8acf59a9c1 100644 --- a/packages/rspeedy/plugin-qrcode/src/index.ts +++ b/packages/rspeedy/plugin-qrcode/src/index.ts @@ -8,7 +8,13 @@ * A rsbuild plugin that print the template.js url using QRCode. */ -import type { EnvironmentContext, RsbuildPlugin } from '@rsbuild/core' +import type { + EnvironmentContext, + RsbuildEntry, + RsbuildPlugin, +} from '@rsbuild/core' + +import type { ExposedAPI } from '@lynx-js/rspeedy' import { registerConsoleShortcuts } from './shortcuts.js' @@ -102,7 +108,7 @@ export function pluginQRCode( pre: ['lynx:rsbuild:api'], setup(api) { api.onAfterStartProdServer(async ({ environments, port }) => { - await main(environments['lynx'], port) + await main(getEntries(environments), port) }) let printedQRCode = false @@ -122,27 +128,35 @@ export function pluginQRCode( printedQRCode = true - await main(environments['lynx'], api.context.devServer.port) + await main(getEntries(environments), api.context.devServer.port) }) + function getEntries( + environments: Record | undefined, + ) { + // biome-ignore lint/correctness/useHookAtTopLevel: not react hooks + return api.useExposed(Symbol.for('rspeedy.env.entries')) + ?.entries ?? environments?.['lynx']?.entry + } + async function main( - environmentContext: EnvironmentContext | undefined, + entries: RsbuildEntry | undefined, port: number, ) { - if (!environmentContext) { - // Not lynx environment, skip print QRCode + if (!entries) { + // No entry points, skip print QRCode return } - const entries = Object.keys(environmentContext.entry) + const entriesArray = Object.keys(entries) - if (entries.length === 0) { + if (entriesArray.length === 0) { return } const unregister = await registerConsoleShortcuts( { - entries, + entries: entriesArray, api, port, schema, diff --git a/packages/rspeedy/plugin-qrcode/test/index.test.ts b/packages/rspeedy/plugin-qrcode/test/index.test.ts index 677302c6af..eba48a2728 100644 --- a/packages/rspeedy/plugin-qrcode/test/index.test.ts +++ b/packages/rspeedy/plugin-qrcode/test/index.test.ts @@ -7,7 +7,11 @@ import { fileURLToPath } from 'node:url' import { isCancel } from '@clack/prompts' import { createRsbuild, logger } from '@rsbuild/core' -import type { RsbuildInstance, RsbuildPlugin } from '@rsbuild/core' +import type { + RsbuildEntry, + RsbuildInstance, + RsbuildPlugin, +} from '@rsbuild/core' import { beforeEach, describe, expect, onTestFinished, test, vi } from 'vitest' import type { Config, ExposedAPI } from '@lynx-js/rspeedy' @@ -30,6 +34,13 @@ const pluginStubRspeedyAPI = (config: Config = {}): RsbuildPlugin => ({ }, }) +const pluginStubEnvEntries = (entries: RsbuildEntry): RsbuildPlugin => ({ + name: 'lynx:rsbuild:env-entries', + setup(api) { + api.expose(Symbol.for('rspeedy.env.entries'), { entries }) + }, +}) + vi.mock('@clack/prompts') describe('Plugins - Terminal', () => { @@ -340,6 +351,55 @@ describe('Plugins - Terminal', () => { expect(renderUnicodeCompact).toBeCalledTimes(1) }) + test('print qrcode with exposed custom environment entries', async () => { + vi.stubEnv('NODE_ENV', 'development') + const { selectKey, isCancel } = await import('@clack/prompts') + vi.mocked(selectKey).mockResolvedValue('foo') + vi.mocked(isCancel).mockReturnValueOnce(false) + const { renderUnicodeCompact } = await import('uqr') + vi.mocked(renderUnicodeCompact).mockReturnValueOnce('') + + const entry = join( + dirname(fileURLToPath(import.meta.url)), + 'fixtures', + 'hello-world', + ) + + const rsbuild = await createRsbuild( + { + rsbuildConfig: { + dev: { + assetPrefix: 'http://example.com/foo/', + }, + environments: { + custom: {}, + }, + server: { + port: getRandomNumberInRange(3000, 60000), + }, + source: { + entry: { + main: entry, + }, + }, + plugins: [ + pluginStubRspeedyAPI(), + pluginStubEnvEntries({ + main: entry, + }), + pluginQRCode(), + ], + }, + }, + ) + + await using server = await usingDevServer(rsbuild) + + await server.waitDevCompileDone() + + expect(renderUnicodeCompact).toBeCalledTimes(1) + }) + test('print qrcode when dev with host specified', async () => { vi.stubEnv('NODE_ENV', 'development') vi.mock('qrcode', () => ({ diff --git a/packages/rspeedy/plugin-qrcode/test/preview.test.ts b/packages/rspeedy/plugin-qrcode/test/preview.test.ts index 7fc56b84af..9e622b85c2 100644 --- a/packages/rspeedy/plugin-qrcode/test/preview.test.ts +++ b/packages/rspeedy/plugin-qrcode/test/preview.test.ts @@ -2,6 +2,7 @@ // 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, logger } from '@rsbuild/core' +import type { RsbuildEntry } from '@rsbuild/core' import { beforeEach, describe, expect, test, vi } from 'vitest' import type { Config, ExposedAPI, RsbuildPlugin } from '@lynx-js/rspeedy' @@ -27,6 +28,13 @@ const pluginStubRspeedyAPI = (config: Config = {}): RsbuildPlugin => ({ }, }) +const pluginStubEnvEntries = (entries: RsbuildEntry): RsbuildPlugin => ({ + name: 'lynx:rsbuild:env-entries', + setup(api) { + api.expose(Symbol.for('rspeedy.env.entries'), { entries }) + }, +}) + describe('Preview', () => { beforeEach(() => { vi.restoreAllMocks() @@ -231,7 +239,7 @@ describe('Preview', () => { expect(exit).not.toBeCalled() }) - test('preview without entry', async () => { + test('preview with exposed custom environment entries', async () => { vi.stubEnv('NODE_ENV', 'development') const { renderUnicodeCompact } = await import('uqr') @@ -243,12 +251,65 @@ describe('Preview', () => { const rsbuild = await createRsbuild({ rsbuildConfig: { + source: { + entry: { + main: './fixtures/hello-world/index.js', + }, + }, plugins: [ pluginStubRspeedyAPI(), + pluginStubEnvEntries({ + main: './fixtures/hello-world/index.js', + }), pluginQRCode(), ], - source: { - entry: {}, + environments: { + custom: {}, + }, + dev: { + assetPrefix: 'http://example.com/', + }, + server: { + port: getRandomNumberInRange(3000, 60000), + }, + }, + }) + + const { server } = await rsbuild.preview({ checkDistDir: false }) + + expect(renderUnicodeCompact).toBeCalled() + expect(renderUnicodeCompact).toBeCalledWith( + 'http://example.com/main.lynx.bundle', + ) + + await server.close() + await vi.waitFor(() => { + expect(exit).toBeCalledTimes(1) + }) + }) + + test('preview with empty exposed entries', async () => { + vi.stubEnv('NODE_ENV', 'development') + const { renderUnicodeCompact } = await import('uqr') + + const { selectKey, isCancel } = await import('@clack/prompts') + vi.mocked(selectKey).mockResolvedValue('foo') + vi.mocked(isCancel).mockReturnValue(true) + + vi.mocked(renderUnicodeCompact).mockReturnValueOnce('') + + const rsbuild = await createRsbuild({ + rsbuildConfig: { + plugins: [ + pluginStubRspeedyAPI(), + pluginStubEnvEntries({}), + pluginQRCode(), + ], + environments: { + custom: {}, + }, + dev: { + assetPrefix: 'http://example.com/', }, server: { port: getRandomNumberInRange(3000, 50000),