From 5e61905a563b8ee2ebea1d0ffdc06f5c503429fe Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Thu, 29 Jan 2026 15:00:26 +0800 Subject: [PATCH 01/27] feat: server bundle mode --- packages/cli/plugin-data-loader/package.json | 1 - .../plugin-runtime/src/cli/constants.ts | 19 +- packages/runtime/plugin-runtime/src/common.ts | 4 +- .../src/core/compat/requestContext.ts | 1 + .../plugin-runtime/src/core/server/helmet.ts | 4 +- .../runtime/plugin-runtime/src/core/types.ts | 1 + .../server/core/src/plugins/render/index.ts | 5 +- .../server/core/src/types/config/server.ts | 1 + packages/server/create-request/package.json | 3 +- packages/server/create-request/src/node.ts | 12 +- .../create-request/tests/browser.test.ts | 6 - packages/solutions/app-tools/package.json | 1 + packages/solutions/app-tools/rslib.config.mts | 19 ++ .../app-tools/src/builder/generator/index.ts | 2 +- .../shared/builderPlugins/adapterSSR.ts | 4 +- .../app-tools/src/plugins/analyze/utils.ts | 2 +- .../app-tools/src/plugins/deploy/index.ts | 5 +- .../src/plugins/deploy/platforms/gh-pages.ts | 5 +- .../src/plugins/deploy/platforms/netlify.ts | 75 ++----- .../src/plugins/deploy/platforms/node.ts | 198 +++++++++--------- .../src/plugins/deploy/platforms/platform.ts | 14 +- .../{ => templates}/netlify-entry.cjs | 0 .../{ => templates}/netlify-entry.mjs | 0 .../{ => templates}/netlify-handler.cjs | 0 .../templates/node-entry-single-bundle.mjs | 46 ++++ .../node-entry.cjs} | 0 .../deploy/platforms/templates/node-entry.mjs | 61 ++++++ .../vercel-entry.cjs} | 0 .../{ => templates}/vercel-entry.mjs | 0 .../{ => templates}/vercel-handler.cjs | 0 .../src/plugins/deploy/platforms/vercel.ts | 72 ++----- .../plugins/deploy/server-bundle/builder.ts | 143 +++++++++++++ .../deploy/server-bundle/config/apply.ts | 129 ++++++++++++ .../server-bundle/config/chunk-loader.ts | 75 +++++++ .../plugins/deploy/server-bundle/constant.ts | 46 ++++ .../deploy/server-bundle/dep-generator.ts | 128 +++++++++++ .../plugins/deploy/server-bundle/generator.ts | 104 +++++++++ .../src/plugins/deploy/server-bundle/index.ts | 6 + .../src/plugins/deploy/server-bundle/utils.ts | 29 +++ .../app-tools/src/plugins/deploy/types.ts | 5 + .../app-tools/src/plugins/deploy/utils.ts | 99 --------- .../src/plugins/deploy/utils/generator.ts | 129 ++++++++++++ .../src/plugins/deploy/utils/index.ts | 56 +++++ .../toolkit/runtime-utils/src/node/stream.ts | 5 +- packages/toolkit/utils/package.json | 14 ++ packages/toolkit/utils/src/cli/constants.ts | 20 ++ .../toolkit/utils/src/universal/constants.ts | 5 + pnpm-lock.yaml | 118 +++++++---- .../bff-corss-project/tests/index.test.ts | 1 - .../integration/bff-hono/tests/index.test.ts | 1 - tests/integration/deploy-server/package.json | 1 + .../pure-esm-project/tests/index.test.ts | 3 +- tests/integration/rsc-ssr-app/package.json | 1 - .../server-config/tests/index.test.ts | 1 - 54 files changed, 1270 insertions(+), 410 deletions(-) rename packages/solutions/app-tools/src/plugins/deploy/platforms/{ => templates}/netlify-entry.cjs (100%) rename packages/solutions/app-tools/src/plugins/deploy/platforms/{ => templates}/netlify-entry.mjs (100%) rename packages/solutions/app-tools/src/plugins/deploy/platforms/{ => templates}/netlify-handler.cjs (100%) create mode 100644 packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs rename packages/solutions/app-tools/src/plugins/deploy/platforms/{node-entry.js => templates/node-entry.cjs} (100%) create mode 100644 packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs rename packages/solutions/app-tools/src/plugins/deploy/platforms/{vercel-entry.js => templates/vercel-entry.cjs} (100%) rename packages/solutions/app-tools/src/plugins/deploy/platforms/{ => templates}/vercel-entry.mjs (100%) rename packages/solutions/app-tools/src/plugins/deploy/platforms/{ => templates}/vercel-handler.cjs (100%) create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/constant.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/dep-generator.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/types.ts delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/utils.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/utils/index.ts diff --git a/packages/cli/plugin-data-loader/package.json b/packages/cli/plugin-data-loader/package.json index cd95528b463b..3b71792281de 100644 --- a/packages/cli/plugin-data-loader/package.json +++ b/packages/cli/plugin-data-loader/package.json @@ -63,7 +63,6 @@ "@scripts/rstest-config": "workspace:*", "@types/node": "^20", "@types/supertest": "^2.0.16", - "isomorphic-fetch": "^3.0.0", "memfs": "^3.5.3", "react": "^19.2.3", "react-dom": "^19.2.3", diff --git a/packages/runtime/plugin-runtime/src/cli/constants.ts b/packages/runtime/plugin-runtime/src/cli/constants.ts index 741fb8049a51..b25cc90f3eca 100644 --- a/packages/runtime/plugin-runtime/src/cli/constants.ts +++ b/packages/runtime/plugin-runtime/src/cli/constants.ts @@ -1,18 +1 @@ -export const APP_FILE_NAME = 'App'; - -export const ENTRY_POINT_FILE_NAME = 'index.jsx'; - -export const SERVER_ENTRY_POINT_FILE_NAME = 'index.server.jsx'; - -export const INDEX_FILE_NAME = 'index'; - -export const ENTRY_BOOTSTRAP_FILE_NAME = 'bootstrap.jsx'; - -export const ENTRY_SERVER_BOOTSTRAP_FILE_NAME = 'bootstrap.server.jsx'; - -export const ENTRY_POINT_RUNTIME_REGISTER_FILE_NAME = 'runtime-register.js'; - -export const ENTRY_POINT_RUNTIME_GLOBAL_CONTEXT_FILE_NAME = - 'runtime-global-context'; - -export const ENTRY_POINT_REGISTER_FILE_NAME = 'register.js'; +export * from '@modern-js/utils/cli/constants'; diff --git a/packages/runtime/plugin-runtime/src/common.ts b/packages/runtime/plugin-runtime/src/common.ts index c392b3297262..4f797b5d1a92 100644 --- a/packages/runtime/plugin-runtime/src/common.ts +++ b/packages/runtime/plugin-runtime/src/common.ts @@ -1,7 +1,9 @@ import type { RuntimePlugin } from './core/plugin'; export const isBrowser = () => - typeof window !== 'undefined' && window.name !== 'nodejs'; + typeof window !== 'undefined' && + window.name !== 'nodejs' && + typeof document !== 'undefined'; export interface RuntimeConfig { plugins?: RuntimePlugin[]; diff --git a/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts b/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts index a769689291ac..74d850c8f97b 100644 --- a/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts +++ b/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts @@ -10,6 +10,7 @@ export const makeRequestContext = ( const baseSSRContext = context.ssrContext; if (baseSSRContext) { return { + loaderContext: baseSSRContext.loaderContext, request: baseSSRContext.request, response: baseSSRContext.response, }; diff --git a/packages/runtime/plugin-runtime/src/core/server/helmet.ts b/packages/runtime/plugin-runtime/src/core/server/helmet.ts index e416559b1266..a7ae099e9822 100644 --- a/packages/runtime/plugin-runtime/src/core/server/helmet.ts +++ b/packages/runtime/plugin-runtime/src/core/server/helmet.ts @@ -1,5 +1,3 @@ -// 用于 react-helmet 正则替换 -import { EOL } from 'os'; import type { HelmetData } from 'react-helmet'; import { safeReplace } from './utils'; @@ -54,7 +52,7 @@ export function helmetReplace(content: string, helmetData: HelmetData) { style, !existTitleTag ? title : '', ].reduce((pre, cur) => { - return pre + (cur.length > 0 ? ` ${cur}${EOL}` : ''); + return pre + (cur.length > 0 ? ` ${cur}\n` : ''); }, ''); return safeReplace(result, RE_LAST_IN_HEAD, `${helmetStr}`); diff --git a/packages/runtime/plugin-runtime/src/core/types.ts b/packages/runtime/plugin-runtime/src/core/types.ts index 97ca318101ae..67ab29485c8e 100644 --- a/packages/runtime/plugin-runtime/src/core/types.ts +++ b/packages/runtime/plugin-runtime/src/core/types.ts @@ -61,6 +61,7 @@ export type SSRServerContext = Pick< }; export type RequestContext = { + loaderContext?: BaseSSRServerContext['loaderContext']; request: BaseSSRServerContext['request']; response: BaseSSRServerContext['response']; }; diff --git a/packages/server/core/src/plugins/render/index.ts b/packages/server/core/src/plugins/render/index.ts index bf029687f0a4..fd02b9089b06 100644 --- a/packages/server/core/src/plugins/render/index.ts +++ b/packages/server/core/src/plugins/render/index.ts @@ -107,7 +107,10 @@ function createRenderHandler( const contextForceCSR = c.get('forceCSR'); const request = c.req.raw; - const nodeReq = c.env.node?.req; + const bindings = c.env; + const nodeReq = bindings.node?.req; + + loaderContext.set('bindings', bindings); const res = await render(request, { nodeReq, diff --git a/packages/server/core/src/types/config/server.ts b/packages/server/core/src/types/config/server.ts index 84d778447ec2..05d639a9cae6 100644 --- a/packages/server/core/src/types/config/server.ts +++ b/packages/server/core/src/types/config/server.ts @@ -19,6 +19,7 @@ export type SSR = inlineScript?: boolean; unsafeHeaders?: string[]; loaderFailureMode?: 'clientRender' | 'errorBoundary'; + bundleServer?: boolean; }; export type SSRByEntries = Record; diff --git a/packages/server/create-request/package.json b/packages/server/create-request/package.json index c710f33a4cb4..e47596ca3153 100644 --- a/packages/server/create-request/package.json +++ b/packages/server/create-request/package.json @@ -118,8 +118,7 @@ "@types/node": "^20", "@types/node-fetch": "^2.6.13", "@types/qs": "^6.14.0", - "isomorphic-fetch": "^3.0.0", - "nock": "^13.5.6", + "nock": "^14.0.10", "typescript": "^5" }, "sideEffects": false, diff --git a/packages/server/create-request/src/node.ts b/packages/server/create-request/src/node.ts index 166138f9ba4e..ae7a2bcaa529 100644 --- a/packages/server/create-request/src/node.ts +++ b/packages/server/create-request/src/node.ts @@ -15,6 +15,16 @@ import { getUploadPayload } from './utiles'; type Fetch = typeof nodeFetch; +const getFetch = () => { + if (global && typeof global.fetch === 'function') { + return global.fetch as unknown as Fetch; + } + if (globalThis && typeof globalThis.fetch === 'function') { + return globalThis.fetch as unknown as Fetch; + } + return nodeFetch; +}; + const realRequest: Map = new Map(); const realAllowedHeaders: Map = new Map(); @@ -28,7 +38,7 @@ const originFetch = (...params: Parameters) => { init.body = undefined; } - return nodeFetch(...params).then(handleRes); + return getFetch()(...params).then(handleRes); }; export const configure = (options: IOptions) => { diff --git a/packages/server/create-request/tests/browser.test.ts b/packages/server/create-request/tests/browser.test.ts index 3016787fc5f7..9e3c0d4020e6 100644 --- a/packages/server/create-request/tests/browser.test.ts +++ b/packages/server/create-request/tests/browser.test.ts @@ -12,12 +12,6 @@ describe('configure', () => { }, }; - beforeAll(async () => { - delete (global as any).fetch; - // @ts-expect-error - await import('isomorphic-fetch'); - }); - // TODO: 如果 disableNetConnect 之后,会影响到其他的 testcase 偶发性的出现 NetConnectNotAllowedError: Nock: Disallowed net connect for "127.0.0.1:49552/" 的错误 // beforeEach(() => { // nock.disableNetConnect(); diff --git a/packages/solutions/app-tools/package.json b/packages/solutions/app-tools/package.json index 2954038cd40f..246acba0137b 100644 --- a/packages/solutions/app-tools/package.json +++ b/packages/solutions/app-tools/package.json @@ -120,6 +120,7 @@ "esbuild": "0.25.5", "esbuild-register": "^3.6.0", "flatted": "^3.3.3", + "import-meta-resolve": "^4.2.0", "mlly": "^1.8.0", "ndepe": "^0.1.13", "pkg-types": "^1.3.1", diff --git a/packages/solutions/app-tools/rslib.config.mts b/packages/solutions/app-tools/rslib.config.mts index 25fafd43ee4b..5bede70d69ae 100644 --- a/packages/solutions/app-tools/rslib.config.mts +++ b/packages/solutions/app-tools/rslib.config.mts @@ -1,3 +1,4 @@ +import path from 'path'; import { rslibConfig } from '@modern-js/rslib'; import { defineConfig } from '@rslib/core'; @@ -6,6 +7,16 @@ export default defineConfig({ lib: rslibConfig.lib?.map(libConfig => { return { ...libConfig, + source: { + ...libConfig.source, + entry: { + index: [ + './src/**', + '!src/plugins/deploy/platforms/templates/*.mjs', + '!src/plugins/deploy/platforms/templates/*.cjs', + ], + }, + }, output: { ...libConfig.output, copy: [ @@ -13,6 +24,14 @@ export default defineConfig({ from: './src/esm', to: './esm', }, + { + from: 'plugins/deploy/platforms/templates/*.cjs', + context: path.join(__dirname, 'src'), + }, + { + from: 'plugins/deploy/platforms/templates/*.mjs', + context: path.join(__dirname, 'src'), + }, ], }, }; diff --git a/packages/solutions/app-tools/src/builder/generator/index.ts b/packages/solutions/app-tools/src/builder/generator/index.ts index 19abdbea7a02..09cfe112eb3b 100644 --- a/packages/solutions/app-tools/src/builder/generator/index.ts +++ b/packages/solutions/app-tools/src/builder/generator/index.ts @@ -74,7 +74,7 @@ export async function generateBuilder( return builder; } -async function applyBuilderPlugins( +export async function applyBuilderPlugins( builder: BuilderInstance, options: BuilderOptions, ) { diff --git a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts index 3fc35d9f7e8d..bdd849cad6f5 100644 --- a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts +++ b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts @@ -10,7 +10,7 @@ import { type RspackChain, mergeRsbuildConfig, } from '@rsbuild/core'; -import { getServerCombinedModueFile } from '../../../plugins/analyze/utils'; +import { getServerCombinedModuleFile } from '../../../plugins/analyze/utils'; import type { AppNormalizedConfig, SSGMultiEntryOptions, @@ -243,7 +243,7 @@ async function applySSRLoaderEntry( await Promise.all( entrypoints.map(async entrypoint => { const { entryName } = entrypoint; - const serverLoadersFile = getServerCombinedModueFile( + const serverLoadersFile = getServerCombinedModuleFile( internalDirectory, entryName, ); diff --git a/packages/solutions/app-tools/src/plugins/analyze/utils.ts b/packages/solutions/app-tools/src/plugins/analyze/utils.ts index 9716221ff9d1..0f18d178efe8 100644 --- a/packages/solutions/app-tools/src/plugins/analyze/utils.ts +++ b/packages/solutions/app-tools/src/plugins/analyze/utils.ts @@ -53,7 +53,7 @@ export const parseModule = async ({ return await parse(content); }; -export const getServerCombinedModueFile = ( +export const getServerCombinedModuleFile = ( internalDirectory: string, entryName: string, ) => { diff --git a/packages/solutions/app-tools/src/plugins/deploy/index.ts b/packages/solutions/app-tools/src/plugins/deploy/index.ts index a547e93e683d..e07527b3f1b1 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/index.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/index.ts @@ -9,6 +9,7 @@ import { createGhPagesPreset } from './platforms/gh-pages'; import { createNetlifyPreset } from './platforms/netlify'; import { createNodePreset } from './platforms/node'; import { createVercelPreset } from './platforms/vercel'; +import type { PluginAPI } from './types'; import { getProjectUsage } from './utils'; type DeployPresetCreators = { node: typeof createNodePreset; @@ -30,6 +31,7 @@ async function getDeployPreset( appContext: AppToolsContext, modernConfig: AppToolsNormalizedConfig, deployTarget: DeployTarget, + api: PluginAPI, ) { const { appDirectory, distDirectory, metaName } = appContext; const { useSSR, useAPI, useWebServer } = getProjectUsage( @@ -47,7 +49,7 @@ async function getDeployPreset( ); } - return createPreset(appContext, modernConfig, needModernServer); + return createPreset({ appContext, modernConfig, needModernServer, api }); } export default (): CliPlugin => ({ @@ -66,6 +68,7 @@ export default (): CliPlugin => ({ appContext, modernConfig, deployTarget as DeployTarget, + api, ); deployPreset?.prepare && (await deployPreset?.prepare()); diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/gh-pages.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/gh-pages.ts index dd27a7baa847..bff74778bd0c 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/gh-pages.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/gh-pages.ts @@ -57,7 +57,10 @@ async function reorganizeHtmlFiles( await Promise.all(copyPromises); } -export const createGhPagesPreset: CreatePreset = (appContext, modernConfig) => { +export const createGhPagesPreset: CreatePreset = ({ + appContext, + modernConfig, +}) => { const { serverRoutes, appDirectory, distDirectory } = appContext; const { diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify.ts index 2efc1738d2f0..89fd320777ae 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify.ts @@ -1,19 +1,9 @@ import path from 'node:path'; -import { - ROUTE_SPEC_FILE, - SERVER_DIR, - fs as fse, - getMeta, - removeModuleSyncFromExports, -} from '@modern-js/utils'; +import { fs as fse, removeModuleSyncFromExports } from '@modern-js/utils'; import { nodeDepEmit as handleDependencies } from 'ndepe'; import { isMainEntry } from '../../../utils/routes'; -import { - type PluginItem, - genPluginImportsCode, - getPluginsCode, - serverAppContenxtTemplate, -} from '../utils'; +import { getTemplatePath, readTemplate } from '../utils'; +import { type PluginItem, generateHandler } from '../utils/generator'; import type { CreatePreset } from './platform'; async function cleanDistDirectory(dir: string) { @@ -31,11 +21,11 @@ async function cleanDistDirectory(dir: string) { } } -export const createNetlifyPreset: CreatePreset = ( +export const createNetlifyPreset: CreatePreset = ({ appContext, modernConfig, needModernServer, -) => { +}) => { const { appDirectory, distDirectory, @@ -116,60 +106,21 @@ export const createNetlifyPreset: CreatePreset = ( if (!needModernServer) { return; } - const serverConfig = { - bff: { - prefix: modernConfig?.bff?.prefix, - }, - output: { - distPath: { - root: '.', - }, - }, - }; - - const meta = getMeta(metaName); - - const pluginImportCode = genPluginImportsCode(plugins || []); - const dynamicProdOptions = { - config: serverConfig, - }; - const serverConfigPath = `path.join(__dirname, "${SERVER_DIR}", "${meta}.server")`; + let handlerCode = await readTemplate('netlify-handler.cjs'); - const pluginsCode = getPluginsCode(plugins); - - let handlerCode = ( - await fse.readFile(path.join(__dirname, './netlify-handler.js')) - ).toString(); - - const serverAppContext = serverAppContenxtTemplate(appContext); - - handlerCode = handlerCode - .replace('p_genPluginImportsCode', pluginImportCode) - .replace('p_ROUTE_SPEC_FILE', `"${ROUTE_SPEC_FILE}"`) - .replace('p_dynamicProdOptions', JSON.stringify(dynamicProdOptions)) - .replace('p_plugins', pluginsCode) - .replace( - 'p_bffRuntimeFramework', - `"${serverAppContext.bffRuntimeFramework}"`, - ) - .replace('p_serverDirectory', serverConfigPath) - .replace('p_sharedDirectory', serverAppContext.sharedDirectory) - .replace('p_apiDirectory', serverAppContext.apiDirectory) - .replace('p_lambdaDirectory', serverAppContext.lambdaDirectory); + handlerCode = await generateHandler({ + template: handlerCode, + appContext, + config: modernConfig, + }); await fse.writeFile(handlerFilePath, handlerCode); if (isEsmProject) { // We will not modify the entry file for the time, because we have not yet converted all the packages available for esm. - await fse.copy( - path.join(__dirname, './netlify-entry.mjs'), - entryFilePath, - ); + await fse.copy(getTemplatePath('netlify-entry.mjs'), entryFilePath); } else { - await fse.copy( - path.join(__dirname, './netlify-entry.js'), - entryFilePath, - ); + await fse.copy(getTemplatePath('netlify-entry.cjs'), entryFilePath); } }, async end() { diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 7fd6a5b47928..1750724fb71c 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -1,30 +1,33 @@ -import path from 'node:path'; +import path, { join } from 'node:path'; import { - ROUTE_SPEC_FILE, - SERVER_DIR, chalk, fs as fse, - getMeta, removeModuleSyncFromExports, } from '@modern-js/utils'; import { nodeDepEmit as handleDependencies } from 'ndepe'; import { - type PluginItem, - genPluginImportsCode, - getPluginsCode, - serverAppContenxtTemplate, -} from '../utils'; + NODE_BUILTIN_MODULES, + bundleServer, + generateNodeExternals, + generateHandler as generateSingleBundleHandler, +} from '../server-bundle'; +import { scanDeps } from '../server-bundle/dep-generator'; +import { readTemplate } from '../utils'; +import { generateHandler } from '../utils/generator'; import type { CreatePreset } from './platform'; -export const createNodePreset: CreatePreset = (appContext, config) => { +export const createNodePreset: CreatePreset = ({ + appContext, + modernConfig, + api, +}) => { const { appDirectory, distDirectory, serverPlugins, moduleType, metaName } = appContext; const isEsmProject = moduleType === 'module'; - const plugins: PluginItem[] = serverPlugins.map(plugin => [ - plugin.name, - plugin.options, - ]); + const isBundleServer = + typeof modernConfig?.server?.ssr === 'object' && + modernConfig.server.ssr.bundleServer; const outputDirectory = path.join(appDirectory, '.output'); const staticDirectory = path.join(outputDirectory, 'static'); @@ -37,98 +40,103 @@ export const createNodePreset: CreatePreset = (appContext, config) => { await fse.copy(distDirectory, outputDirectory); }, async genEntry() { - const serverConfig = { - server: { - port: 8080, - }, - bff: { - prefix: config?.bff?.prefix, - }, - output: { - distPath: { - root: '.', - }, - }, - }; - - const pluginImportCode = genPluginImportsCode(plugins || []); - - const dynamicProdOptions = { - config: serverConfig, - }; - - const meta = getMeta(metaName); - - const serverConfigPath = `path.join(__dirname, "${SERVER_DIR}", "${meta}.server")`; - - const pluginsCode = getPluginsCode(plugins); + if (!isBundleServer) { + const handlerTemplate = await readTemplate( + `node-entry.${isEsmProject ? 'mjs' : 'cjs'}`, + ); - let entryCode = ( - await fse.readFile(path.join(__dirname, './node-entry.js')) - ).toString(); + const code = await generateHandler({ + template: handlerTemplate, + appContext, + config: modernConfig, + }); - const serverAppContext = serverAppContenxtTemplate(appContext); + await fse.writeFile(entryFilePath, code); + return; + } - entryCode = entryCode - .replace('p_genPluginImportsCode', pluginImportCode) - .replace('p_ROUTE_SPEC_FILE', `"${ROUTE_SPEC_FILE}"`) - .replace('p_dynamicProdOptions', JSON.stringify(dynamicProdOptions)) - .replace('p_plugins', pluginsCode) - .replace('p_serverDirectory', serverConfigPath) - .replace('p_sharedDirectory', serverAppContext.sharedDirectory) - .replace('p_apiDirectory', serverAppContext.apiDirectory) - .replace( - 'p_bffRuntimeFramework', - `"${serverAppContext.bffRuntimeFramework}"`, - ) - .replace('p_lambdaDirectory', serverAppContext.lambdaDirectory); + const handlerTemplate = await readTemplate( + 'node-entry-single-bundle.mjs', + ); - if (isEsmProject) { - // We will not modify the entry file for the time, because we have not yet converted all the packages available for esm. - const cjsEntryFilePath = path.join(outputDirectory, 'index.cjs'); - await fse.writeFile(cjsEntryFilePath, entryCode); - await fse.writeFile(entryFilePath, `import('./index.cjs');`); - } else { - await fse.writeFile(entryFilePath, entryCode); - } + const { code: depCode } = await scanDeps( + distDirectory, + appContext.internalDirectory, + [ + path.join(distDirectory, 'static'), + path.join(distDirectory, 'bundles'), + ], + ); + const code = await generateSingleBundleHandler({ + template: handlerTemplate, + appContext, + config: modernConfig, + depCode, + serverType: 'node', + }); + const nodeExternals = Object.fromEntries( + generateNodeExternals( + api => `module-import node:${api}`, + NODE_BUILTIN_MODULES, + ), + ); + await bundleServer(code, api, { + config: { + output: { + externals: [nodeExternals], + distPath: { + root: join(outputDirectory, 'server-bundle'), + js: '.', + }, + }, + }, + }); }, async end() { + if (!isBundleServer) { + const filter = (filePath: string) => { + return ( + !filePath.startsWith(staticDirectory) && !filePath.endsWith('.map') + ); + }; + // Because @modern-js/prod-server is an implicit dependency of the entry, so we add it to the include here. + await handleDependencies({ + appDir: appDirectory, + sourceDir: outputDirectory, + includeEntries: [require.resolve('@modern-js/prod-server')], + copyWholePackage(pkgName) { + return pkgName === '@modern-js/utils'; + }, + entryFilter: filter, + transformPackageJson: ({ pkgJSON }) => { + if (!pkgJSON.exports) { + return pkgJSON; + } + + return { + ...pkgJSON, + exports: removeModuleSyncFromExports( + pkgJSON.exports as Record, + ), + }; + }, + }); + } console.log( 'Static directory:', chalk.blue(path.relative(appDirectory, staticDirectory)), ); - console.log( - `You can preview this build by`, - chalk.blue(`node .output/index`), - ); - - const filter = (filePath: string) => { - return ( - !filePath.startsWith(staticDirectory) && !filePath.endsWith('.map') + if (isBundleServer) { + console.log( + `You can preview this build by`, + chalk.blue(`node .output/server-bundle/index`), ); - }; - // Because @modern-js/prod-server is an implicit dependency of the entry, so we add it to the include here. - await handleDependencies({ - appDir: appDirectory, - sourceDir: outputDirectory, - includeEntries: [require.resolve('@modern-js/prod-server')], - copyWholePackage(pkgName) { - return pkgName === '@modern-js/utils'; - }, - entryFilter: filter, - transformPackageJson: ({ pkgJSON }) => { - if (!pkgJSON.exports) { - return pkgJSON; - } - - return { - ...pkgJSON, - exports: removeModuleSyncFromExports( - pkgJSON.exports as Record, - ), - }; - }, - }); + } else { + console.log( + `You can preview this build by`, + chalk.blue(`node .output/index`), + ); + } }, }; }; diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/platform.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/platform.ts index 00ed165e97bd..24b6028363b5 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/platform.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/platform.ts @@ -1,11 +1,15 @@ import type { AppToolsNormalizedConfig } from '../../../types'; import type { AppToolsContext } from '../../../types/plugin'; +import type { PluginAPI } from '../types'; -export type CreatePreset = ( - appContext: AppToolsContext, - config: AppToolsNormalizedConfig, - needModernServer?: boolean, -) => DeployPreset; +interface CreatePresetParams { + appContext: AppToolsContext; + modernConfig: AppToolsNormalizedConfig; + api: PluginAPI; + needModernServer?: boolean; +} + +export type CreatePreset = (params: CreatePresetParams) => DeployPreset; type DeployPreset = { prepare?: () => Promise; diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify-entry.cjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-entry.cjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/netlify-entry.cjs rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-entry.cjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify-entry.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-entry.mjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/netlify-entry.mjs rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-entry.mjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/netlify-handler.cjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-handler.cjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/netlify-handler.cjs rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-handler.cjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs new file mode 100644 index 000000000000..c976d0d563b5 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs @@ -0,0 +1,46 @@ +import { createProdServer } from 'p_prodServerEntry'; + +globalThis[p_bundleDepVarName] = p_genDepCode; + +p_genPluginImportsCode; + +if (!process.env.NODE_ENV) { + process.env.NODE_ENV = 'production'; +} + +const routes = p_ROUTES; + +async function main() { + const dynamicProdOptions = p_dynamicProdOptions; + const prodServerOptions = { + pwd: __dirname, + routes, + disableCustomHook: true, + appContext: { + sharedDirectory: p_sharedDirectory, + apiDirectory: p_apiDirectory, + lambdaDirectory: p_lambdaDirectory, + bffRuntimeFramework: p_bffRuntimeFramework, + }, + plugins: p_plugins, + serverConfigPath: p_serverDirectory, + ...dynamicProdOptions, + }; + + const app = await createProdServer(prodServerOptions); + const port = process.env.PORT || 8080; + app.listen( + { + host: '::', + port, + }, + () => { + console.log( + `\x1b[32mServer is listening on http://[::]:${port}`, + '\x1b[0m', + ); + }, + ); +} + +main(); diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node-entry.js b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.cjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/node-entry.js rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.cjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs new file mode 100644 index 000000000000..0714c38654f9 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs @@ -0,0 +1,61 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { createProdServer } from '@modern-js/prod-server'; + +p_genPluginImportsCode; + +if (!process.env.NODE_ENV) { + process.env.NODE_ENV = 'production'; +} + +async function loadRoutes(routeFilepath) { + try { + await fs.access(routeFilepath); + const content = await fs.readFile(routeFilepath, 'utf-8'); + const routeSpec = JSON.parse(content); + return routeSpec.routes || []; + } catch (error) { + console.warn( + 'route.json not found or invalid, continuing with empty routes.', + ); + return []; + } +} + +async function main() { + const routeFilepath = path.join(__dirname, p_ROUTE_SPEC_FILE); + const routes = await loadRoutes(routeFilepath); + + const dynamicProdOptions = p_dynamicProdOptions; + const prodServerOptions = { + pwd: __dirname, + routes, + disableCustomHook: true, + appContext: { + sharedDirectory: p_sharedDirectory, + apiDirectory: p_apiDirectory, + lambdaDirectory: p_lambdaDirectory, + bffRuntimeFramework: p_bffRuntimeFramework, + }, + plugins: p_plugins, + serverConfigPath: p_serverDirectory, + ...dynamicProdOptions, + }; + + const app = await createProdServer(prodServerOptions); + const port = process.env.PORT || 8080; + app.listen( + { + host: '::', + port, + }, + () => { + console.log( + `\x1b[32mServer is listening on http://[::]:${port}`, + '\x1b[0m', + ); + }, + ); +} + +main(); diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel-entry.js b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-entry.cjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/vercel-entry.js rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-entry.cjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel-entry.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-entry.mjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/vercel-entry.mjs rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-entry.mjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel-handler.cjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-handler.cjs similarity index 100% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/vercel-handler.cjs rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-handler.cjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel.ts index b2138ac561a5..d1c9d5479dad 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/vercel.ts @@ -1,26 +1,16 @@ import path from 'node:path'; -import { - ROUTE_SPEC_FILE, - SERVER_DIR, - fs as fse, - getMeta, - removeModuleSyncFromExports, -} from '@modern-js/utils'; +import { fs as fse, removeModuleSyncFromExports } from '@modern-js/utils'; import { nodeDepEmit as handleDependencies } from 'ndepe'; import { isMainEntry } from '../../../utils/routes'; -import { - type PluginItem, - genPluginImportsCode, - getPluginsCode, - serverAppContenxtTemplate, -} from '../utils'; +import { getTemplatePath, readTemplate } from '../utils'; +import { type PluginItem, generateHandler } from '../utils/generator'; import type { CreatePreset } from './platform'; -export const createVercelPreset: CreatePreset = ( +export const createVercelPreset: CreatePreset = ({ appContext, modernConfig, needModernServer, -) => { +}) => { const { appDirectory, distDirectory, @@ -125,56 +115,20 @@ export const createVercelPreset: CreatePreset = ( return; } - const serverConfig = { - bff: { - prefix: modernConfig?.bff?.prefix, - }, - output: { - distPath: { - root: '.', - }, - }, - }; - - const pluginImportCode = genPluginImportsCode(plugins || []); - const dynamicProdOptions = { - config: serverConfig, - }; - - const meta = getMeta(metaName); + let handlerCode = await readTemplate('vercel-handler.cjs'); - const serverConfigPath = `path.join(__dirname, "${SERVER_DIR}", "${meta}.server")`; - - const pluginsCode = getPluginsCode(plugins || []); - - const serverAppContext = serverAppContenxtTemplate(appContext); - - let handlerCode = ( - await fse.readFile(path.join(__dirname, './vercel-handler.js')) - ).toString(); - - handlerCode = handlerCode - .replace('p_genPluginImportsCode', pluginImportCode) - .replace('p_ROUTE_SPEC_FILE', `"${ROUTE_SPEC_FILE}"`) - .replace('p_dynamicProdOptions', JSON.stringify(dynamicProdOptions)) - .replace('p_plugins', pluginsCode) - .replace('p_serverDirectory', serverConfigPath) - .replace('p_sharedDirectory', serverAppContext.sharedDirectory) - .replace('p_apiDirectory', serverAppContext.apiDirectory) - .replace('p_lambdaDirectory', serverAppContext.lambdaDirectory); + handlerCode = await generateHandler({ + template: handlerCode, + appContext, + config: modernConfig, + }); await fse.writeFile(handlerFilePath, handlerCode); if (isEsmProject) { // We will not modify the entry file for the time, because we have not yet converted all the packages available for esm. - await fse.copy( - path.join(__dirname, './vercel-entry.mjs'), - entryFilePath, - ); + await fse.copy(getTemplatePath('vercel-entry.mjs'), entryFilePath); } else { - await fse.copy( - path.join(__dirname, './vercel-entry.js'), - entryFilePath, - ); + await fse.copy(getTemplatePath('vercel-entry.cjs'), entryFilePath); } }, async end() { diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts new file mode 100644 index 000000000000..fb7e2b7a61bc --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -0,0 +1,143 @@ +import path from 'node:path'; +import { + type BuilderConfig, + type BuilderInstance, + SERVICE_WORKER_ENVIRONMENT_NAME, + createBuilder, +} from '@modern-js/builder'; +import type { CLIPluginAPI } from '@modern-js/plugin'; +import { lodash as _, fs as fse } from '@modern-js/utils'; +import { applyBuilderPlugins } from '../../../builder/generator'; +import { createBuilderProviderConfig } from '../../../builder/generator/createBuilderProviderConfig'; +import type { AppTools } from '../../../types'; +import { ESM_RESOLVE_CONDITIONS } from './constant'; + +export const generateNodeExternals = ( + getExternal: (api: string) => string, + list: string[] = [], +) => [ + ...list.map(api => [api, getExternal(api)]), + ...list.map(api => [`node:${api}`, getExternal(api)]), +]; + +export interface BundleSSROptions { + config?: BuilderConfig; + modifyBuilder?: (builder: BuilderInstance) => Promise; + forceESM?: boolean; +} + +export const bundleServer = async ( + handlerCode: string, + api: CLIPluginAPI, + options?: BundleSSROptions, +) => { + const normalizedConfig = api.getNormalizedConfig(); + const appContext = api.getAppContext(); + + const minify = normalizedConfig.output?.minify ?? true; + + const handlerPath = path.join( + appContext.internalDirectory, + 'modern-server-bundle', + 'handler.mjs', + ); + await fse.writeFile(handlerPath, handlerCode); + + // create provider + const providerConfig = createBuilderProviderConfig( + normalizedConfig, + appContext, + ); + + const defaultConfig: BuilderConfig = { + environments: { + [SERVICE_WORKER_ENVIRONMENT_NAME]: { + source: { + entry: { + bundle: { + import: handlerPath, + html: false, + }, + }, + define: { + 'process.env.NODE_ENV': '"production"', + 'process.env.MODERN_SSR_ENV': '"edge"', + }, + }, + }, + }, + resolve: { + conditionNames: ESM_RESOLVE_CONDITIONS, + }, + output: { + target: 'web', + emitAssets: false, + cleanDistPath: true, + polyfill: 'off', + sourceMap: false, + distPath: { + js: '.', + jsAsync: '.', + worker: '.', + server: '.', + }, + filename: { + js: '[name].js', + }, + minify, + }, + performance: { + chunkSplit: { + strategy: 'all-in-one', + }, + }, + tools: { + rspack: { + target: 'es2020', + output: { + asyncChunks: false, + library: { + type: 'module', + }, + pathinfo: !minify, + }, + experiments: { + outputModule: true, + }, + }, + }, + }; + + const finalConfig = _.merge( + {}, + providerConfig, + defaultConfig, + options?.config, + ); + + const builder = await createBuilder({ + bundlerType: 'rspack', + config: finalConfig, + }); + + await applyBuilderPlugins(builder, { + normalizedConfig, + appContext, + }); + + // remove bff server external + builder.modifyRsbuildConfig(config => { + const { output } = config; + if (Array.isArray(output?.externals)) { + output.externals = output.externals.filter( + x => typeof x !== 'object' || !('@modern-js/plugin-bff/server' in x), + ); + } + }); + + if (options?.modifyBuilder) { + await options.modifyBuilder(builder); + } + + await builder.build(); +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts new file mode 100644 index 000000000000..6f80c72c7125 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts @@ -0,0 +1,129 @@ +import path from 'node:path'; +import { lodash as _ } from '@modern-js/utils'; +import type { Rspack } from '@rsbuild/core'; +import type { PluginAPI } from '../../types'; +import { normalizePath } from '../../utils'; +import { generateNodeExternals } from '../builder'; +import { NODE_BUILTIN_MODULES } from '../constant'; +import { appendTo } from '../utils'; +import { generateChunkLoading } from './chunk-loader'; + +export interface ApplyConfigParams { + rsbuild?: Parameters[0]; + rspack?: Parameters[0]; +} + +export const applyConfig = (api: PluginAPI, options?: ApplyConfigParams) => { + let baseDistPath: string; + + api.modifyRsbuildConfig((config, utils) => { + if (!config.environments?.node) { + return; + } + const { appDirectory } = api.getAppContext(); + const userConfig = api.getConfig(); + baseDistPath = path.join( + appDirectory, + userConfig.output?.distPath?.root || 'dist', + ); + options?.rsbuild?.(config, utils); + }); + + const nodeExternals = Object.fromEntries( + generateNodeExternals( + api => `module-import node:${api}`, + NODE_BUILTIN_MODULES, + ), + ); + + api.modifyRspackConfig((config, utils) => { + const outputPath = config.output?.path; + if (config.target !== 'node' || !baseDistPath || !outputPath) { + return; + } + + const isTsProject = Boolean(config.resolve?.tsConfig); + const isEsmProject = Boolean(config.output?.module); + + config.target = 'es2020'; + if (isTsProject || isEsmProject) { + _.set(config, 'output.chunkFormat', 'module'); + _.set(config, 'output.chunkLoading', 'singleBundleChunkLoad'); + _.set(config, 'output.module', true); + _.set(config, 'output.library.type', 'module'); + _.set(config, 'experiments.outputModule', true); + } + + const instance: Rspack.RspackPluginInstance = { + apply(compiler) { + const { RuntimeModule, RuntimeGlobals } = compiler.rspack; + + compiler.rspack.javascript.EnableChunkLoadingPlugin.setEnabled( + compiler, + 'singleBundleChunkLoad', + ); + + class SingleBundleChunkLoad extends RuntimeModule { + constructor() { + super('single bundle chunk load', RuntimeModule.STAGE_ATTACH); + } + + generate() { + const { chunk, compilation } = this; + if (!chunk || !compilation || !outputPath || !chunk.id) { + return ''; + } + const chunkFilename = compilation.options.output + .chunkFilename as string; + const chunkMap: Record = {}; + chunk.getAllReferencedChunks().map(refChunk => { + if (!refChunk.id) { + return; + } + const p = compilation.getPath(chunkFilename, { + chunk: refChunk, + }); + const fullPath = path.join(outputPath, p); + const relativePath = normalizePath( + path.relative(baseDistPath, fullPath), + ); + chunkMap[refChunk.id] = relativePath; + }); + // rspack declared a wrong type of RuntimeGlobals, they fixed in a newer version + // @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/packages/rspack/src/RuntimeGlobals.ts#L679 + return generateChunkLoading( + chunk.id, + chunkMap, + RuntimeGlobals as any, + isTsProject || isEsmProject, + ); + } + } + + compiler.hooks.thisCompilation.tap( + 'SingleBundleChunkLoadPlugin', + compilation => { + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.ensureChunkHandlers) + .tap('SingleBundleChunkLoad', (chunk, set) => { + compilation.addRuntimeModule( + chunk, + new SingleBundleChunkLoad(), + ); + }); + }, + ); + }, + }; + + appendTo(config, 'externals', nodeExternals); + appendTo(config, 'plugins', instance); + + try { + options?.rspack?.(config, utils); + } catch (e) { + console.error(e); + } + // console.log('\n\n\n\n', 'config 222', config, '\n\n\n\n'); + }); +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts new file mode 100644 index 000000000000..1042c82741f7 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts @@ -0,0 +1,75 @@ +// @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/crates/rspack_plugin_esm_library/src/render.rs#L726 +// @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/crates/rspack_plugin_runtime/src/runtime_module/runtime/module_chunk_loading.ejs +const runtimeVariableModules = '__webpack_modules__'; +const esmChunkInstaller = (globals: Record) => ` +${globals.moduleFactories} = ${globals.moduleFactories} || ${runtimeVariableModules}; +var installChunk = (data) => { + var __rspack_esm_ids = data.__rspack_esm_ids; + var ${runtimeVariableModules} = data.${runtimeVariableModules}; + var __rspack_esm_runtime = data.__rspack_esm_runtime; + // add "modules" to the modules object, + // then flag all "ids" as loaded and fire callback + var moduleId, chunkId, i = 0; + for (moduleId in ${runtimeVariableModules}) { + if (${globals.hasOwnProperty}(${runtimeVariableModules}, moduleId)) { + ${globals.moduleFactories}[moduleId] = ${runtimeVariableModules}[moduleId]; + } + } + if (__rspack_esm_runtime) __rspack_esm_runtime(${globals.require}); + for (; i < __rspack_esm_ids.length; i++) { + chunkId = __rspack_esm_ids[i]; + if (${globals.hasOwnProperty}(installedChunks, chunkId) && installedChunks[chunkId]) { + installedChunks[chunkId][0](); + } + installedChunks[__rspack_esm_ids[i]] = 1; + } +};`; + +// @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/crates/rspack_plugin_runtime/src/runtime_module/runtime/require_chunk_loading.ejs +const cjsChunkInstaller = (globals: Record) => ` +var installChunk = (chunk) => { + var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime; + for (var moduleId in moreModules) { + if (${globals.hasOwnProperty}(moreModules, moduleId)) { + ${globals.moduleFactories}[moduleId] = moreModules[moduleId]; + } + } + if (runtime) runtime(${globals.require}); + for (var i = 0; i < chunkIds.length; i++) installedChunks[chunkIds[i]] = 1; +};`; + +export const generateChunkLoading = ( + chunkId: string, + chunkMap: Record, + runtimeGlobals: Record, + isESM?: boolean, +) => { + const installer = isESM + ? esmChunkInstaller(runtimeGlobals) + : cjsChunkInstaller(runtimeGlobals); + return `var installedChunks = {"${chunkId}": 1}; +var loadingChunks = {}; +var chunkMap = ${JSON.stringify(chunkMap)}; +${installer} +${runtimeGlobals.ensureChunkHandlers}.singleBundleChunkLoad = (chunkId, promises) => { + if (installedChunks[chunkId]) { + return; + } + if (!loadingChunks[chunkId]) { + var g = global || globalThis; + loadingChunks[chunkId] = new Promise((resolve, reject) => { + var p = g.__MODERN_DEPS__[chunkMap[chunkId]]; + if (!p) { + reject(new Error('chunk ' + chunkId + ' is not available')); + return; + } + p().then(d => { + installChunk(d.default || d); + delete loadingChunks[chunkId]; + resolve(); + }).catch(reject) + }); + } + promises.push(loadingChunks[chunkId]); +};`; +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/constant.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/constant.ts new file mode 100644 index 000000000000..2ea3110a1dc5 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/constant.ts @@ -0,0 +1,46 @@ +export const ESM_RESOLVE_CONDITIONS = ['node', 'import', 'module', 'default']; + +export const NODE_BUILTIN_MODULES = [ + 'assert', + 'async_hooks', + 'buffer', + 'child_process', + 'cluster', + 'console', + 'crypto', + 'dgram', + 'diagnostics_channel', + 'dns', + 'domain', + 'events', + 'fs', + 'fs/promises', + 'http', + 'http2', + 'https', + 'inspector', + 'module', + 'net', + 'os', + 'path', + 'perf_hooks', + 'process', + 'punycode', + 'querystring', + 'readline', + 'repl', + 'stream', + 'string_decoder', + 'timers', + 'tls', + 'trace_events', + 'tty', + 'url', + 'util', + 'v8', + 'vm', + 'wasi', + 'worker_threads', + 'zlib', + 'constants', +]; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/dep-generator.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/dep-generator.ts new file mode 100644 index 000000000000..ace3255ecb3a --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/dep-generator.ts @@ -0,0 +1,128 @@ +import path from 'node:path'; +import type { Entrypoint } from '@modern-js/plugin'; +import { fs as fse } from '@modern-js/utils'; +import type { AppToolsNormalizedConfig } from '../../../types'; +import { isMainEntry } from '../../../utils/routes'; +import { normalizePath } from '../utils'; + +const isTextFile = (filePath: string) => { + const textExtensions = ['.txt', '.html', '.css', '.svg', '.css']; + + const ext = path.extname(filePath).toLowerCase(); + return textExtensions.includes(ext); +}; + +export const walkDirectory = async ( + sourceDir: string, + cb: (filePath: string) => void | Promise, +) => { + // Read directory contents + const items = await fse.readdir(sourceDir); + + for (const item of items) { + const sourcePath = path.join(sourceDir, item); + + const stat = await fse.stat(sourcePath); + + if (stat.isDirectory()) { + // Recursively process subdirectories + await walkDirectory(sourcePath, cb); + } else if (stat.isFile()) { + // Process files based on extension + await cb(sourcePath); + } + } +}; + +const copyStaticDepFiles = async (sourcePath: string, targetPath: string) => { + const ext = path.extname(sourcePath); + + // If it's a JS-like file, do not copy + if (['.js', '.mjs', '.json'].includes(ext)) { + return { path: sourcePath }; + } + + if (!isTextFile(sourcePath)) { + return; + } + + await fse.ensureDir(path.dirname(targetPath)); + // Handle text files + const content = await fse.readFile(sourcePath, 'utf-8'); + // Escape quotes and backslashes in content + const escapedContent = content + .replace(/\\/g, '\\\\') + .replace(/`/g, '\\`') + .replace(/\$/g, '\\$'); + + const jsContent = `\ +// Automatically generated JS wrapper for ${path.basename(sourcePath)} +export const _DEP_TEXT = \`${escapedContent}\`; +`; + + // Keep the same filename but with .js extension + const jsTargetPath = `${targetPath}.js`; + + await fse.writeFile(jsTargetPath, jsContent); + return { path: jsTargetPath, wrapper: '_DEP_TEXT' }; +}; + +export const scanDeps = async ( + source: string, + tempDirectory: string, + skipPrefix: string[] = [], +) => { + const t = path.join(tempDirectory, 'modern-server-bundle/deps'); + await fse.ensureDir(t); + const codes = ['{']; + await walkDirectory(source, async filePath => { + // skip static files + if (skipPrefix.some(x => filePath.startsWith(x))) { + return; + } + + // Skip map and LICENSE files, they will increase server bundle size + if (filePath.endsWith('.map') || filePath.endsWith('.LICENSE.txt')) { + return; + } + + const relative = normalizePath(path.relative(source, filePath)); + const targetPath = path.join(t, relative); + const copyResult = await copyStaticDepFiles(filePath, targetPath); + if (copyResult) { + const suffix = copyResult.wrapper + ? `.then(x => x.${copyResult.wrapper})` + : ''; + codes.push( + `${JSON.stringify(relative)}: () => import(${JSON.stringify(copyResult.path)})${suffix},`, + ); + } + }); + codes.push('}'); + + return { + code: codes.join('\n'), + }; +}; + +export const copyEntriesHtml = async ( + modernConfig: AppToolsNormalizedConfig, + entrypoints: Entrypoint[], + from: string, + to: string, +) => { + const { + source: { mainEntryName }, + } = modernConfig; + for (const entry of entrypoints) { + const isMain = isMainEntry(entry.entryName, mainEntryName); + const entryFilePath = path.join( + from, + 'html', + entry.entryName, + 'index.html', + ); + const targetHtml = isMain ? 'index.html' : `${entry.entryName}.html`; + await fse.copyFile(entryFilePath, path.join(to, targetHtml)); + } +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts new file mode 100644 index 000000000000..13f3cbf6d8b8 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts @@ -0,0 +1,104 @@ +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { SERVER_ENTRY_POINT_FILE_NAME } from '@modern-js/utils/cli/constants'; +import fse from '@modern-js/utils/fs-extra'; +import { SERVER_BUNDLE_DEP_VARNAME } from '@modern-js/utils/universal/constants'; +import type { AppToolsContext } from '../../../types/plugin'; +import { getServerCombinedModuleFile } from '../../analyze/utils'; +import { normalizePath } from '../utils'; +import { + type GenerateHandlerOptions as BaseGenerateHandlerOptions, + type PluginItem, + generateHandler as baseGenerateHandler, +} from '../utils/generator'; +import { resolveESMDependency } from './utils'; + +export const serverAppContextTemplate = (appContext: AppToolsContext) => { + const { + appDirectory, + sharedDirectory, + apiDirectory, + lambdaDirectory, + metaName, + bffRuntimeFramework, + } = appContext; + return { + sharedDirectory: `"${normalizePath( + path.relative(appDirectory, sharedDirectory), + )}"`, + apiDirectory: `"${normalizePath(path.relative(appDirectory, apiDirectory))}"`, + lambdaDirectory: `"${normalizePath( + path.relative(appDirectory, lambdaDirectory), + )}"`, + metaName, + bffRuntimeFramework: bffRuntimeFramework || 'hono', + }; +}; + +const generatePluginCode = (plugins: PluginItem[]) => { + const pluginCode = plugins.map( + ([name], index) => + `import * as plugin_${index}_ns from '${name}';\nconst plugin_${index} = plugin_${index}_ns.default || plugin_${index}_ns;`, + ); + return pluginCode.join('\n'); +}; + +export interface GenerateHandlerOptions extends BaseGenerateHandlerOptions { + depCode: string; + serverType: string; +} + +export const generateHandler = async (options: GenerateHandlerOptions) => { + const { appContext, depCode, serverType } = options; + const { serverRoutes, internalDirectory } = appContext; + + const routesCode: string[] = []; + for (const route of serverRoutes) { + if (!route.isSSR) { + continue; + } + const bundleEntry = path.join( + internalDirectory, + route.entryName!, + SERVER_ENTRY_POINT_FILE_NAME, + ); + const serverLoadersEntry = getServerCombinedModuleFile( + internalDirectory, + route.entryName!, + ); + const hasServerLoaders = await fse.pathExists(serverLoadersEntry); + const serverLoadersCode = hasServerLoaders + ? `serverLoadersContent: () => import(${JSON.stringify(pathToFileURL(serverLoadersEntry))}).then(x => x.default || x),` + : ''; + const baseRouteCode = JSON.stringify(route); + routesCode.push(`${baseRouteCode.substring(0, baseRouteCode.length - 1)}, + bundleContent: () => import(${JSON.stringify(pathToFileURL(bundleEntry))}).then(x => x.default || x), + ${serverLoadersCode} + }`); + } + + const prodServerEntry = resolveESMDependency( + serverType === 'node' + ? '@modern-js/prod-server' + : `@modern-js/prod-server/${serverType}`, + ); + + if (!prodServerEntry) { + throw new Error(`Can not find ${serverType} server entry.`); + } + + const code = await baseGenerateHandler({ + ...options, + genAppContextTemplate: serverAppContextTemplate, + genPluginImports: generatePluginCode, + routesCode: routesCode.length ? `[${routesCode.join(',\n')}]` : '[]', + }); + + return code + .replace('p_genDepCode', depCode) + .replace('p_bundleDepVarName', JSON.stringify(SERVER_BUNDLE_DEP_VARNAME)) + .replace( + 'p_prodServerEntry', + String(pathToFileURL(normalizePath(prodServerEntry))), + ); +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts new file mode 100644 index 000000000000..f2513967b42d --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts @@ -0,0 +1,6 @@ +export * from './constant'; +export * from './builder'; +export * from './dep-generator'; +export * from './generator'; +export * from './utils'; +export { applyConfig } from './config/apply'; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts new file mode 100644 index 000000000000..e1463e15f8f4 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts @@ -0,0 +1,29 @@ +import { pathToFileURL } from 'node:url'; +import { lodash as _ } from '@modern-js/utils'; +import { moduleResolve } from 'import-meta-resolve'; +import { normalizePath } from '../utils'; + +export const resolveESMDependency = (entry: string) => { + const conditions = new Set(['node', 'import', 'module', 'default']); + try { + return normalizePath( + moduleResolve( + entry, + pathToFileURL(`${__dirname}/`), + conditions, + false, + ).pathname.replace(/^\/(\w)\:/, '$1:'), + ); + } catch (err) { + // ignore + } +}; + +export const appendTo = (target: any, key: string, value: any) => { + const v = _.get(target, key); + if (Array.isArray(v)) { + v.push(value); + } else { + _.set(target, key, [value]); + } +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/types.ts b/packages/solutions/app-tools/src/plugins/deploy/types.ts new file mode 100644 index 000000000000..d0340eb7c874 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/types.ts @@ -0,0 +1,5 @@ +import type { AppTools, CliPlugin } from '../../types'; + +export type Setup = NonNullable['setup']>; + +export type PluginAPI = Parameters[0]; diff --git a/packages/solutions/app-tools/src/plugins/deploy/utils.ts b/packages/solutions/app-tools/src/plugins/deploy/utils.ts deleted file mode 100644 index 0fc40e33c624..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/utils.ts +++ /dev/null @@ -1,99 +0,0 @@ -import path from 'path'; -import type { ServerRoute } from '@modern-js/types'; -import { - ROUTE_SPEC_FILE, - SERVER_DIR, - fs as fse, - getMeta, -} from '@modern-js/utils'; -import type { AppToolsContext } from '../../types/plugin'; - -export type ServerAppContext = { - sharedDirectory: string; - apiDirectory: string; - lambdaDirectory: string; - metaName: string; - bffRuntimeFramework: string; -}; - -export const serverAppContenxtTemplate = (appContext: AppToolsContext) => { - const { - appDirectory, - sharedDirectory, - apiDirectory, - lambdaDirectory, - metaName, - bffRuntimeFramework, - } = appContext; - return { - sharedDirectory: `path.join(__dirname, "${path.relative( - appDirectory, - sharedDirectory, - )}")`, - apiDirectory: `path.join(__dirname, "${path.relative( - appDirectory, - apiDirectory, - )}")`, - lambdaDirectory: `path.join(__dirname, "${path.relative( - appDirectory, - lambdaDirectory, - )}")`, - metaName, - bffRuntimeFramework: bffRuntimeFramework || 'hono', - }; -}; - -export type PluginItem = [string, Record | undefined]; - -export const genPluginImportsCode = (plugins: PluginItem[]) => { - return plugins - .map( - ([name, options], index) => ` - let plugin_${index} = require('${name}') - plugin_${index} = plugin_${index}.default || plugin_${index} - `, - ) - .join(';\n'); -}; - -export const getPluginsCode = (plugins: PluginItem[]) => { - return `[${plugins - .map( - ([, options], index) => - `plugin_${index}(${options ? JSON.stringify(options) : ''})`, - ) - .join(',')}]`; -}; - -export const getProjectUsage = ( - appDirectory: string, - distDirectory: string, - metaName: string, -) => { - const routeJSON = path.join(distDirectory, ROUTE_SPEC_FILE); - const { routes } = fse.readJSONSync(routeJSON); - - let useSSR = false; - let useAPI = false; - routes.forEach((route: ServerRoute) => { - if (route.isSSR) { - useSSR = true; - } - - if (route.isApi) { - useAPI = true; - } - }); - - const meta = getMeta(metaName); - const serverConfigPath = path.resolve( - appDirectory, - SERVER_DIR, - `${meta}.server`, - ); - const isServerConfigExists = ['.ts', '.js'].some(ex => { - return fse.existsSync(`${serverConfigPath}${ex}`); - }); - - return { useSSR, useAPI, useWebServer: isServerConfigExists }; -}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts b/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts new file mode 100644 index 000000000000..c7adf90150bd --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts @@ -0,0 +1,129 @@ +import path from 'node:path'; +import type { ProdServerOptions } from '@modern-js/prod-server'; +import { + ROUTE_SPEC_FILE, + SERVER_DIR, + fs as fse, + getMeta, +} from '@modern-js/utils'; +import { merge } from '@modern-js/utils/lodash'; +import { normalizePath } from '.'; +import type { AppToolsNormalizedConfig } from '../../../types'; +import type { AppToolsContext } from '../../../types/plugin'; + +export const serverAppContextTemplate = (appContext: AppToolsContext) => { + const { + appDirectory, + sharedDirectory, + apiDirectory, + lambdaDirectory, + metaName, + bffRuntimeFramework, + } = appContext; + return { + sharedDirectory: `path.join(__dirname, "${normalizePath( + path.relative(appDirectory, sharedDirectory), + )}")`, + apiDirectory: `path.join(__dirname, "${normalizePath( + path.relative(appDirectory, apiDirectory), + )}")`, + lambdaDirectory: `path.join(__dirname, "${normalizePath( + path.relative(appDirectory, lambdaDirectory), + )}")`, + metaName, + bffRuntimeFramework: bffRuntimeFramework || 'hono', + }; +}; + +export type PluginItem = [string, Record | undefined]; + +export const genPluginImportsCode = (plugins: PluginItem[]) => { + return plugins + .map( + ([name, options], index) => ` + let plugin_${index} = require('${name}') + plugin_${index} = plugin_${index}.default || plugin_${index} + `, + ) + .join(';\n'); +}; + +export const getPluginsCode = (plugins: PluginItem[]) => { + return `[${plugins + .map( + ([, options], index) => + `plugin_${index}(${options ? JSON.stringify(options) : ''})`, + ) + .join(',')}]`; +}; + +export const getServerConfigPath = (meta: string) => + `"${normalizePath(path.join(SERVER_DIR, `${meta}.server`))}"`; + +export interface GenerateHandlerOptions { + template: string; + appContext: AppToolsContext; + config: AppToolsNormalizedConfig; + serverConfig?: Partial; + genAppContextTemplate?: typeof serverAppContextTemplate; + genPluginImports?: typeof genPluginImportsCode; + routesCode?: string; +} +export const generateHandler = async ({ + template, + appContext, + config, + serverConfig: modifyServerConfig, + genAppContextTemplate = serverAppContextTemplate, + genPluginImports = genPluginImportsCode, + routesCode, +}: GenerateHandlerOptions) => { + const { serverPlugins, metaName, serverRoutes } = appContext; + + const plugins: PluginItem[] = serverPlugins.map(plugin => [ + plugin.name, + plugin.options, + ]); + + const serverConfig = merge( + { + bff: { + prefix: config?.bff?.prefix, + }, + output: { + distPath: { + root: '.', + }, + }, + }, + modifyServerConfig || {}, + ); + + const meta = getMeta(metaName); + + const pluginImportCode = genPluginImports(plugins || []); + const dynamicProdOptions = { + config: serverConfig, + }; + + const serverConfigPath = getServerConfigPath(meta); + + const pluginsCode = getPluginsCode(plugins); + + const serverAppContext = genAppContextTemplate(appContext); + + return template + .replace('p_genPluginImportsCode', pluginImportCode) + .replace('p_ROUTE_SPEC_FILE', `"${ROUTE_SPEC_FILE}"`) + .replace('p_ROUTES', routesCode || JSON.stringify(serverRoutes)) + .replace('p_dynamicProdOptions', JSON.stringify(dynamicProdOptions)) + .replace('p_plugins', pluginsCode) + .replace( + 'p_bffRuntimeFramework', + `"${serverAppContext.bffRuntimeFramework}"`, + ) + .replace('p_serverDirectory', serverConfigPath) + .replace('p_sharedDirectory', serverAppContext.sharedDirectory) + .replace('p_apiDirectory', serverAppContext.apiDirectory) + .replace('p_lambdaDirectory', serverAppContext.lambdaDirectory); +}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/utils/index.ts b/packages/solutions/app-tools/src/plugins/deploy/utils/index.ts new file mode 100644 index 000000000000..3c22461320a5 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/utils/index.ts @@ -0,0 +1,56 @@ +import path from 'path'; +import type { ServerRoute } from '@modern-js/types'; +import { + ROUTE_SPEC_FILE, + SERVER_DIR, + fs as fse, + getMeta, +} from '@modern-js/utils'; + +export type ServerAppContext = { + sharedDirectory: string; + apiDirectory: string; + lambdaDirectory: string; + metaName: string; + bffRuntimeFramework: string; +}; + +export const normalizePath = (filePath: string) => filePath.replace(/\\/g, '/'); + +export const getProjectUsage = ( + appDirectory: string, + distDirectory: string, + metaName: string, +) => { + const routeJSON = path.join(distDirectory, ROUTE_SPEC_FILE); + const { routes } = fse.readJSONSync(routeJSON); + + let useSSR = false; + let useAPI = false; + routes.forEach((route: ServerRoute) => { + if (route.isSSR) { + useSSR = true; + } + + if (route.isApi) { + useAPI = true; + } + }); + + const meta = getMeta(metaName); + const serverConfigPath = path.resolve( + appDirectory, + SERVER_DIR, + `${meta}.server`, + ); + const isServerConfigExists = ['.ts', '.js'].some(ex => { + return fse.existsSync(`${serverConfigPath}${ex}`); + }); + + return { useSSR, useAPI, useWebServer: isServerConfigExists }; +}; + +export const getTemplatePath = (file: string) => + path.join(__dirname, '../platforms/templates', file); +export const readTemplate = async (file: string) => + (await fse.readFile(getTemplatePath(file))).toString(); diff --git a/packages/toolkit/runtime-utils/src/node/stream.ts b/packages/toolkit/runtime-utils/src/node/stream.ts index d5dc7951d919..3f9d9c42647a 100644 --- a/packages/toolkit/runtime-utils/src/node/stream.ts +++ b/packages/toolkit/runtime-utils/src/node/stream.ts @@ -1,4 +1,5 @@ -import { type Readable, Stream } from 'stream'; +import { nextTick } from 'node:process'; +import { type Readable, Stream } from 'node:stream'; export const createReadableStreamFromReadable = ( source: Readable & { readableHighWaterMark?: number }, @@ -63,7 +64,7 @@ class StreamPump { this.stream.destroy(reason); } - process.nextTick(() => { + nextTick(() => { this.stream.off('data', this.enqueue); this.stream.off('error', this.error); this.stream.off('end', this.close); diff --git a/packages/toolkit/utils/package.json b/packages/toolkit/utils/package.json index 2cc287568da3..be92b0a73d9c 100644 --- a/packages/toolkit/utils/package.json +++ b/packages/toolkit/utils/package.json @@ -59,6 +59,14 @@ "import": "./dist/esm/universal/pluginDagSort.mjs", "default": "./dist/cjs/universal/pluginDagSort.js" }, + "./cli": { + "import": "./dist/esm/cli.mjs", + "default": "./dist/cjs/cli.js" + }, + "./cli/constants": { + "import": "./dist/esm/cli/constants.mjs", + "default": "./dist/cjs/cli/constants.js" + }, "./commander": { "import": "./dist/compiled/commander/index.mjs", "default": "./dist/compiled/commander/index.js" @@ -113,6 +121,12 @@ "universal/plugin-dag-sort": [ "./dist/types/universal/pluginDagSort.d.ts" ], + "cli": [ + "./dist/types/cli/index.d.ts" + ], + "cli/constants": [ + "./dist/types/cli/constants.d.ts" + ], "execa": [ "./dist/compiled/execa/index.d.ts" ], diff --git a/packages/toolkit/utils/src/cli/constants.ts b/packages/toolkit/utils/src/cli/constants.ts index ff55552c47d7..7a83cbba8b20 100644 --- a/packages/toolkit/utils/src/cli/constants.ts +++ b/packages/toolkit/utils/src/cli/constants.ts @@ -76,3 +76,23 @@ export const DEFAULT_DEV_HOST = '0.0.0.0'; export const INTERNAL_RUNTIME_PLUGINS: InternalPlugins = { '@modern-js/runtime': '@modern-js/runtime/cli', }; + +// internal generated files, main use in plugin-runtime +export const APP_FILE_NAME = 'App'; + +export const ENTRY_POINT_FILE_NAME = 'index.jsx'; + +export const SERVER_ENTRY_POINT_FILE_NAME = 'index.server.jsx'; + +export const INDEX_FILE_NAME = 'index'; + +export const ENTRY_BOOTSTRAP_FILE_NAME = 'bootstrap.jsx'; + +export const ENTRY_SERVER_BOOTSTRAP_FILE_NAME = 'bootstrap.server.jsx'; + +export const ENTRY_POINT_RUNTIME_REGISTER_FILE_NAME = 'runtime-register.js'; + +export const ENTRY_POINT_RUNTIME_GLOBAL_CONTEXT_FILE_NAME = + 'runtime-global-context'; + +export const ENTRY_POINT_REGISTER_FILE_NAME = 'register.js'; diff --git a/packages/toolkit/utils/src/universal/constants.ts b/packages/toolkit/utils/src/universal/constants.ts index e637137d15bd..0db66da92cd1 100644 --- a/packages/toolkit/utils/src/universal/constants.ts +++ b/packages/toolkit/utils/src/universal/constants.ts @@ -50,3 +50,8 @@ export const SERVER_RENDER_FUNCTION_NAME = 'serverRender'; export const SERVER_PLUGIN_BFF = '@modern-js/plugin-bff'; export const SERVER_PLUGIN_POLYFILL = '@modern-js/plugin-polyfill'; + +/** + * In server bundle mode, dependencies will be mounted to this variable + */ +export const SERVER_BUNDLE_DEP_VARNAME = '__MODERN_DEPS__'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6471c0f6c3ec..ffa9831bc54c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -359,9 +359,6 @@ importers: '@types/supertest': specifier: ^2.0.16 version: 2.0.16 - isomorphic-fetch: - specifier: ^3.0.0 - version: 3.0.0(encoding@0.1.13) memfs: specifier: ^3.5.3 version: 3.6.0 @@ -976,12 +973,9 @@ importers: '@types/qs': specifier: ^6.14.0 version: 6.14.0 - isomorphic-fetch: - specifier: ^3.0.0 - version: 3.0.0(encoding@0.1.13) nock: - specifier: ^13.5.6 - version: 13.5.6 + specifier: ^14.0.10 + version: 14.0.10 typescript: specifier: ^5 version: 5.9.3 @@ -1275,6 +1269,9 @@ importers: flatted: specifier: ^3.3.3 version: 3.3.3 + import-meta-resolve: + specifier: ^4.2.0 + version: 4.2.0 mlly: specifier: ^1.8.0 version: 1.8.0 @@ -3602,9 +3599,6 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 - isomorphic-fetch: - specifier: ^3.0.0 - version: 3.0.0(encoding@0.1.13) typescript: specifier: ^5 version: 5.9.3 @@ -6093,6 +6087,7 @@ packages: '@module-federation/data-prefetch@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-knLlwi93KEK9S/VDjZO8UbJxLp6s6rpnl8IXTJ5ELhljD5s6gN1VqtfOXxYYChB2DaUu4EMf/rCApcDoTekuCg==} + deprecated: Pre-release version deprecated peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -6108,6 +6103,7 @@ packages: '@module-federation/enhanced@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-s0nQ7295n30dIQwhBHjUEcPvdgjl5e82r7aH9oOe8g/XUePI3blsedVVinrCGaQEW1y5MzrpQY6OBQwsmcjYrQ==} + deprecated: Pre-release version deprecated hasBin: true peerDependencies: typescript: ^4.9.0 || ^5.0.0 @@ -6132,6 +6128,7 @@ packages: '@module-federation/inject-external-runtime-core-plugin@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-EwxEnSKm5vegoBXf4QOKdvhbtHhSMAGK0KEIe8Dn1s3prlAabXVYICrhZmkLx7rm7KBZJeQKcSgeJR9jdX+fmQ==} + deprecated: Pre-release version deprecated peerDependencies: '@module-federation/runtime-tools': 0.0.0-feat-modern-3-0-20251120074204 @@ -6140,6 +6137,7 @@ packages: '@module-federation/manifest@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-7S/PikFR7sy3yh5PUZELNsupujsLXNheADU1O1T73lCKRUSlJEHNsakCAOrf6v/znTYC8BIf3pkrr6xauDn5zg==} + deprecated: Pre-release version deprecated '@module-federation/modern-js@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-RbS0GymeY63c9rgqESPn2iTa+YHAps5cgUlKWA67IvFTHOpluKtdOsYdCJOjyKQgcPmO6jjBxpZElA+KZPWg5w==} @@ -6178,6 +6176,7 @@ packages: '@module-federation/rsbuild-plugin@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-XZsYL/PvmRgxjxFgEEoi+gtTOjzImLX/dlZEOzbxmwg4DLXoaUYbKNshF3+zNaC2K2VWWnHFCs+aws1Dw3pjzw==} engines: {node: '>=16.0.0'} + deprecated: Pre-release version deprecated peerDependencies: '@rsbuild/core': ^1.6.7 peerDependenciesMeta: @@ -6198,6 +6197,7 @@ packages: '@module-federation/runtime-core@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-MfWQE41lutPqbcY9pPk2CSLMU2mT/kXlGNQirm4Y6QhKB/0KRWQ+7FD9yCHIeIqM0fbLJVtA/RDihw/kS2qRyQ==} + deprecated: Pre-release version deprecated '@module-federation/runtime-core@0.21.6': resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} @@ -6216,6 +6216,7 @@ packages: '@module-federation/runtime@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-LVoGjJQyN+UIoc7hdrKNSzJEpQ9xEFjYytnkKiXUAPrIwXw8zLNkktKJVyJI0hb3aO1Gy0/Su1L6qTWZ4pq5kw==} + deprecated: Pre-release version deprecated '@module-federation/runtime@0.21.6': resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} @@ -6237,6 +6238,7 @@ packages: '@module-federation/webpack-bundler-runtime@0.0.0-feat-modern-3-0-20251120074204': resolution: {integrity: sha512-ADgapHbMfyGnfM8DuFJjgGtGu5xEXIiGXz+igel0cMuHcSwzvLL4WW0Z3N99LvmJjObt4Lebpgidw8jyjmwxmg==} + deprecated: Pre-release version deprecated '@module-federation/webpack-bundler-runtime@0.21.6': resolution: {integrity: sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ==} @@ -6244,6 +6246,10 @@ packages: '@module-federation/webpack-bundler-runtime@0.22.0': resolution: {integrity: sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==} + '@mswjs/interceptors@0.39.8': + resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==} + engines: {node: '>=18'} + '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} @@ -6319,6 +6325,12 @@ packages: '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -10633,6 +10645,9 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -10738,9 +10753,6 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - isomorphic-fetch@3.0.0: - resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} - isomorphic-ws@5.0.0: resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: @@ -11766,9 +11778,9 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - nock@13.5.6: - resolution: {integrity: sha512-o2zOYiCpzRqSzPj0Zt/dQ/DqZeYoaQ7TUonc/xUPjCGl9WeHpNbxgVvOquXYAaJzI0M9BXV3HTzG0p8IUAbBTQ==} - engines: {node: '>= 10.13'} + nock@14.0.10: + resolution: {integrity: sha512-Q7HjkpyPeLa0ZVZC5qpxBt5EyLczFJ91MEewQiIi9taWuA0KB/MDJlUWtON+7dGouVdADTQsf9RA7TZk6D8VMw==} + engines: {node: '>=18.20.0 <20 || >=20.12.1'} node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -11947,6 +11959,9 @@ packages: outvariant@1.4.0: resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -13137,6 +13152,7 @@ packages: react-server-dom-webpack@19.2.3: resolution: {integrity: sha512-ifo7aqqdNJyV6U2zuvvWX4rRQ51pbleuUFNG7ZYhIuSuWZzQPbfmYv11GNsyJm/3uGNbt8buJ9wmoISn/uOAfw==} engines: {node: '>=0.10.0'} + deprecated: High Security Vulnerability in React Server Components peerDependencies: react: ^19.2.3 react-dom: ^19.2.3 @@ -13817,6 +13833,9 @@ packages: strict-event-emitter@0.4.6: resolution: {integrity: sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -15130,22 +15149,22 @@ snapshots: '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.28.6)': dependencies: @@ -15155,17 +15174,17 @@ snapshots: '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.6)': dependencies: @@ -15175,42 +15194,42 @@ snapshots: '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.6)': dependencies: @@ -17197,6 +17216,15 @@ snapshots: '@module-federation/runtime': 0.22.0 '@module-federation/sdk': 0.22.0 + '@mswjs/interceptors@0.39.8': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/wasm-runtime@0.2.4': dependencies: '@emnapi/core': 1.7.1 @@ -17256,6 +17284,13 @@ snapshots: '@open-draft/deferred-promise@2.2.0': {} + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 @@ -22273,6 +22308,8 @@ snapshots: is-interactive@1.0.0: {} + is-node-process@1.2.0: {} + is-number@7.0.0: {} is-obj@2.0.0: {} @@ -22354,13 +22391,6 @@ snapshots: isobject@3.0.1: {} - isomorphic-fetch@3.0.0(encoding@0.1.13): - dependencies: - node-fetch: 2.7.0(encoding@0.1.13) - whatwg-fetch: 3.6.20 - transitivePeerDependencies: - - encoding - isomorphic-ws@5.0.0(ws@8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): dependencies: ws: 8.18.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) @@ -23993,13 +24023,11 @@ snapshots: lower-case: 2.0.2 tslib: 2.8.1 - nock@13.5.6: + nock@14.0.10: dependencies: - debug: 4.4.3(supports-color@5.5.0) + '@mswjs/interceptors': 0.39.8 json-stringify-safe: 5.0.1 propagate: 2.0.1 - transitivePeerDependencies: - - supports-color node-addon-api@7.1.1: {} @@ -24214,6 +24242,8 @@ snapshots: outvariant@1.4.0: {} + outvariant@1.4.3: {} + p-cancelable@2.1.1: {} p-filter@2.1.0: @@ -26242,6 +26272,8 @@ snapshots: strict-event-emitter@0.4.6: {} + strict-event-emitter@0.5.1: {} + string-argv@0.3.2: {} string-convert@0.2.1: {} diff --git a/tests/integration/bff-corss-project/tests/index.test.ts b/tests/integration/bff-corss-project/tests/index.test.ts index 117834d0ffd4..8906c1fa3033 100644 --- a/tests/integration/bff-corss-project/tests/index.test.ts +++ b/tests/integration/bff-corss-project/tests/index.test.ts @@ -9,7 +9,6 @@ import { modernBuild, modernServe, } from '../../../utils/modernTestUtils'; -import 'isomorphic-fetch'; // Skip flaky tests on CI, but run them locally const conditionalTest = process.env.LOCAL_TEST === 'true' ? test : test.skip; diff --git a/tests/integration/bff-hono/tests/index.test.ts b/tests/integration/bff-hono/tests/index.test.ts index fb4e0a113a87..a5d471c879ba 100644 --- a/tests/integration/bff-hono/tests/index.test.ts +++ b/tests/integration/bff-hono/tests/index.test.ts @@ -9,7 +9,6 @@ import { modernBuild, modernServe, } from '../../../utils/modernTestUtils'; -import 'isomorphic-fetch'; dns.setDefaultResultOrder('ipv4first'); diff --git a/tests/integration/deploy-server/package.json b/tests/integration/deploy-server/package.json index 2e7d638922e4..a2d6010c1a0f 100644 --- a/tests/integration/deploy-server/package.json +++ b/tests/integration/deploy-server/package.json @@ -7,6 +7,7 @@ "dev:bff": "modern dev --api-only", "build": "modern build", "serve": "modern serve", + "deploy": "modern deploy", "start:bff": "modern serve --api-only", "new": "modern new" }, diff --git a/tests/integration/pure-esm-project/tests/index.test.ts b/tests/integration/pure-esm-project/tests/index.test.ts index 11aed6632e6b..521a3fde1ee0 100644 --- a/tests/integration/pure-esm-project/tests/index.test.ts +++ b/tests/integration/pure-esm-project/tests/index.test.ts @@ -1,5 +1,6 @@ import dns from 'node:dns'; import path from 'path'; +import { isVersionAtLeast1819 } from '@modern-js/utils'; import puppeteer, { type Browser, type Page } from 'puppeteer'; import { getPort, @@ -9,8 +10,6 @@ import { modernBuild, modernServe, } from '../../../utils/modernTestUtils'; -import 'isomorphic-fetch'; -import { isVersionAtLeast1819 } from '@modern-js/utils'; const appDir = path.resolve(__dirname, '../'); dns.setDefaultResultOrder('ipv4first'); diff --git a/tests/integration/rsc-ssr-app/package.json b/tests/integration/rsc-ssr-app/package.json index 9f6e08e7740f..6f0ba997f1c9 100644 --- a/tests/integration/rsc-ssr-app/package.json +++ b/tests/integration/rsc-ssr-app/package.json @@ -25,7 +25,6 @@ "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "cross-env": "^7.0.3", - "isomorphic-fetch": "^3.0.0", "typescript": "^5" } } diff --git a/tests/integration/server-config/tests/index.test.ts b/tests/integration/server-config/tests/index.test.ts index c3c46f711499..631b404741f7 100644 --- a/tests/integration/server-config/tests/index.test.ts +++ b/tests/integration/server-config/tests/index.test.ts @@ -7,7 +7,6 @@ import { modernBuild, modernServe, } from '../../../utils/modernTestUtils'; -import 'isomorphic-fetch'; dns.setDefaultResultOrder('ipv4first'); From 7fdb7d337d4c8d1e1c6947be50a1b9a729cf247c Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Thu, 29 Jan 2026 20:00:43 +0800 Subject: [PATCH 02/27] feat: server plugins --- .../src/adapters/node/helper/getBundledDep.ts | 38 ++++++ .../core/src/adapters/node/helper/index.ts | 10 +- .../src/adapters/node/helper/loadCache.ts | 29 +++- .../src/adapters/node/helper/loadConfig.ts | 68 ++++++---- .../server/core/src/adapters/node/index.ts | 4 + .../src/adapters/node/plugins/resource.ts | 124 +++++++++++++++--- packages/server/prod-server/src/apply.ts | 38 ++++-- .../server/prod-server/src/base-server.ts | 64 +++++++++ packages/server/prod-server/src/index.ts | 49 ++----- packages/server/prod-server/src/netlify.ts | 37 +----- packages/server/server/src/createDevServer.ts | 2 +- packages/server/server/src/types.ts | 7 +- .../shared/builderPlugins/adapterHtml.ts | 12 +- .../src/plugins/deploy/platforms/node.ts | 4 +- ...ingle-bundle.mjs => node-entry-bundle.mjs} | 3 +- .../plugins/deploy/server-bundle/builder.ts | 13 +- .../deploy/server-bundle/config/apply.ts | 79 +---------- .../server-bundle/config/chunk-loader.ts | 75 ----------- .../plugins/deploy/server-bundle/generator.ts | 12 +- .../src/plugins/deploy/server-bundle/utils.ts | 6 +- .../toolkit/plugin/src/server/run/create.ts | 2 + .../toolkit/plugin/src/server/run/types.ts | 1 + .../plugin/src/types/server/context.ts | 1 + packages/toolkit/types/server/route.d.ts | 4 + .../toolkit/utils/src/universal/constants.ts | 5 - .../deploy-server/modern.config.ts | 9 +- 26 files changed, 389 insertions(+), 307 deletions(-) create mode 100644 packages/server/core/src/adapters/node/helper/getBundledDep.ts create mode 100644 packages/server/prod-server/src/base-server.ts rename packages/solutions/app-tools/src/plugins/deploy/platforms/templates/{node-entry-single-bundle.mjs => node-entry-bundle.mjs} (94%) delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts diff --git a/packages/server/core/src/adapters/node/helper/getBundledDep.ts b/packages/server/core/src/adapters/node/helper/getBundledDep.ts new file mode 100644 index 000000000000..92c0ab2552ee --- /dev/null +++ b/packages/server/core/src/adapters/node/helper/getBundledDep.ts @@ -0,0 +1,38 @@ +export const getBundledDep = async ( + keyParam: string, + deps?: Record>, + interop = true, +): Promise => { + if (!deps || typeof deps !== 'object') { + return; + } + + let key = keyParam; + if (key.startsWith('/')) { + key = key.substring(1); + } + + let value: any; + if (deps.hasOwnProperty(key)) { + value = deps[key]; + } else { + const s = ['.js', '.json', '.mjs'].find(x => deps.hasOwnProperty(key + x)); + if (s) { + value = deps[s]; + } + } + + if (typeof value !== 'function') { + return; + } + + try { + const res = await value(); + if (interop) { + return res.default || res; + } + return res; + } catch (e) { + console.error(e); + } +}; diff --git a/packages/server/core/src/adapters/node/helper/index.ts b/packages/server/core/src/adapters/node/helper/index.ts index 544ff3d693f1..f26105bf6d8d 100644 --- a/packages/server/core/src/adapters/node/helper/index.ts +++ b/packages/server/core/src/adapters/node/helper/index.ts @@ -1,6 +1,12 @@ export { loadServerEnv } from './loadEnv'; export { loadServerPlugins } from './loadPlugin'; -export { loadServerRuntimeConfig, loadServerCliConfig } from './loadConfig'; -export { loadCacheConfig } from './loadCache'; +export { + loadServerRuntimeConfig, + loadBundledServerRuntimeConfig, + loadServerCliConfig, + loadBundledServerCliConfig, +} from './loadConfig'; +export { loadCacheConfig, loadBundledCacheConfig } from './loadCache'; export { isResFinalized } from './utils'; export type { NodeBindings } from './utils'; +export { getBundledDep } from './getBundledDep'; diff --git a/packages/server/core/src/adapters/node/helper/loadCache.ts b/packages/server/core/src/adapters/node/helper/loadCache.ts index a11d44f779b6..ad67b6a0c4d2 100644 --- a/packages/server/core/src/adapters/node/helper/loadCache.ts +++ b/packages/server/core/src/adapters/node/helper/loadCache.ts @@ -1,7 +1,12 @@ import path from 'path'; import type { CacheOption, Container } from '@modern-js/types'; -import { SERVER_DIR, requireExistModule } from '@modern-js/utils'; +import { + SERVER_DIR, + normalizeToPosixPath, + requireExistModule, +} from '@modern-js/utils'; import type { CacheConfig } from '../../../types'; +import { getBundledDep } from './getBundledDep'; const CACHE_FILENAME = 'cache'; @@ -30,3 +35,25 @@ export async function loadCacheConfig( return undefined; } + +export async function loadBundledCacheConfig( + deps?: Record>, +): Promise { + const serverCacheFilepath = path + .join(SERVER_DIR, CACHE_FILENAME) + .replace(/\\/g, '/'); + const mod: CacheMod | undefined = await getBundledDep( + serverCacheFilepath, + deps, + false, + ); + + if (mod?.cacheOption) { + return { + strategy: mod.cacheOption, + container: mod.customContainer, + }; + } + + return undefined; +} diff --git a/packages/server/core/src/adapters/node/helper/loadConfig.ts b/packages/server/core/src/adapters/node/helper/loadConfig.ts index 4a2ec4274014..5a6a25f6dfc1 100644 --- a/packages/server/core/src/adapters/node/helper/loadConfig.ts +++ b/packages/server/core/src/adapters/node/helper/loadConfig.ts @@ -7,21 +7,11 @@ import { ensureAbsolutePath, requireExistModule, } from '@modern-js/utils'; -import { parse } from 'flatted'; +import { fromJSON, parse } from 'flatted'; import type { CliConfig, ServerConfig, UserConfig } from '../../../types'; +import { getBundledDep } from './getBundledDep'; -const requireConfig = async ( - serverConfigPath: string, -): Promise => { - if (fs.pathExistsSync(serverConfigPath)) { - return compatibleRequire(serverConfigPath); - } - return undefined; -}; - -async function loadServerConfigNew( - serverConfigPath: string, -): Promise { +export async function loadServerRuntimeConfig(serverConfigPath: string) { const mod: ServerConfig | null = await requireExistModule(serverConfigPath); if (mod) { @@ -30,24 +20,21 @@ async function loadServerConfigNew( return undefined; } -async function loadServerConfigOld( - pwd: string, - configFile: string, +export async function loadBundledServerRuntimeConfig( + serverConfigPath: string, + deps?: Record>, ): Promise { - const serverConfigPath = path.join(pwd, `${configFile}.cjs`); - const serverConfig = await requireConfig(serverConfigPath); - return serverConfig; -} - -export async function loadServerRuntimeConfig(serverConfigPath: string) { - const newServerConfig = await loadServerConfigNew(serverConfigPath); - return newServerConfig; + const mod = await getBundledDep(serverConfigPath, deps); + if (mod) { + return mod; + } + return undefined; } -export function loadServerCliConfig( +export async function loadServerCliConfig( pwd: string, defaultConfig: UserConfig = {}, -): CliConfig { +): Promise { const cliConfigPath = ensureAbsolutePath( pwd, path.join( @@ -68,7 +55,7 @@ export function loadServerCliConfig( }; try { - const content = fs.readFileSync(cliConfigPath, 'utf-8'); + const content = await fs.readFile(cliConfigPath, 'utf-8'); cliConfig = parse(content); } catch (_) { @@ -79,3 +66,30 @@ export function loadServerCliConfig( return mergedCliConfig; } + +export async function loadBundledServerCliConfig( + defaultConfig: UserConfig = {}, + deps?: Record>, +): Promise { + let cliConfig: CliConfig = { + output: {}, + source: {}, + tools: {}, + server: {}, + security: {}, + bff: {}, + html: {}, + dev: {}, + }; + + try { + const inputConfig = await getBundledDep(OUTPUT_CONFIG_FILE, deps); + cliConfig = fromJSON(inputConfig); + } catch (_) { + // ignore + } + + const mergedCliConfig = _.merge(defaultConfig, cliConfig); + + return mergedCliConfig; +} diff --git a/packages/server/core/src/adapters/node/index.ts b/packages/server/core/src/adapters/node/index.ts index 3f63e2e3a1d8..005c2b665a5f 100644 --- a/packages/server/core/src/adapters/node/index.ts +++ b/packages/server/core/src/adapters/node/index.ts @@ -24,6 +24,10 @@ export { loadServerPlugins, loadServerEnv, loadServerRuntimeConfig, + loadBundledServerRuntimeConfig, loadServerCliConfig, + loadBundledServerCliConfig, loadCacheConfig, + loadBundledCacheConfig, + getBundledDep, } from './helper'; diff --git a/packages/server/core/src/adapters/node/plugins/resource.ts b/packages/server/core/src/adapters/node/plugins/resource.ts index bbc405d594b0..7abd9ccb9b32 100644 --- a/packages/server/core/src/adapters/node/plugins/resource.ts +++ b/packages/server/core/src/adapters/node/plugins/resource.ts @@ -19,6 +19,7 @@ import type { ServerPlugin, } from '../../../types'; import { uniqueKeyByRoute } from '../../../utils'; +import { getBundledDep } from '../helper'; export async function getHtmlTemplates(pwd: string, routes: ServerRoute[]) { // Only process routes with entryName, which are HTML template routes. @@ -43,15 +44,31 @@ export async function getHtmlTemplates(pwd: string, routes: ServerRoute[]) { return templates; } +export async function getBundledHtmlTemplates( + deps: Record>, + routes: ServerRoute[], +) { + const htmlRoutes = routes.filter(route => route.entryName); + + const htmls = await Promise.all( + htmlRoutes.map(async route => { + const html = await getBundledDep(route.entryPath, deps); + return [uniqueKeyByRoute(route), html]; + }) || [], + ); + + const templates: Record = Object.fromEntries(htmls); + + return templates; +} + export function injectTemplates( - pwd: string, + getHtmlTemplatesFn: () => ReturnType, routes?: ServerRoute[], - htmlTemplatePromise?: ReturnType, ): Middleware { return async (c, next) => { if (routes && !c.get('templates')) { - const templates = await (htmlTemplatePromise || - getHtmlTemplates(pwd, routes)); + const templates = await getHtmlTemplatesFn(); c.set('templates', templates); } @@ -132,16 +149,65 @@ export async function getServerManifest( }; } +export async function getBundledServerManifest( + deps: Record>, + routes: ServerRoute[], +): Promise { + const loaderBundles: Record = {}; + const renderBundles: Record = {}; + + await Promise.all( + routes + .filter(route => Boolean(route.bundle)) + .map(async route => { + const entryName = route.entryName || MAIN_ENTRY_NAME; + if (!route.bundleContent) { + throw new Error( + `Bundle content is not defined for route ${route.entryName}`, + ); + } + + const renderBundle = await route.bundleContent(); + const loaderBundle = route.serverLoadersContent + ? await route.serverLoadersContent() + : undefined; + + renderBundle && (renderBundles[entryName] = renderBundle); + loaderBundle && + (loaderBundles[entryName] = loaderBundle?.loadModules + ? await loaderBundle?.loadModules() + : loaderBundle); + }), + ); + + const loadableStats = await getBundledDep(LOADABLE_STATS_FILE, deps).catch( + _ => ({}), + ); + const routeManifest = await getBundledDep(ROUTE_MANIFEST_FILE, deps).catch( + _ => ({}), + ); + const nestedRoutesJson = await getBundledDep( + NESTED_ROUTE_SPEC_FILE, + deps, + ).catch(_ => ({})); + + return { + loaderBundles, + renderBundles, + loadableStats, + routeManifest, + nestedRoutesJson, + }; +} + export function injectServerManifest( - pwd: string, + getManifest: (monitors: Monitors) => Promise, routes?: ServerRoute[], - manifestPromise?: Promise, ): Middleware { return async (c, next) => { if (routes && !c.get('serverManifest')) { const monitors = c.get('monitors'); - const serverManifest = await (manifestPromise || - getServerManifest(pwd, routes, monitors)); + const serverManifest = await getManifest(monitors); c.set('serverManifest', serverManifest); } @@ -216,31 +282,49 @@ export const injectResourcePlugin = (): ServerPlugin => ({ middlewares, routes, distDirectory: pwd, + dependencies, } = api.getServerContext(); // In Production, should warmup server bundles on prepare. - let htmlTemplatePromise: ReturnType | undefined; - let manifestPromise: Promise | undefined; + // let htmlTemplatePromise: ReturnType | undefined; + let getManifest: (c: Monitors) => Promise; + let getHtmlTemplatesFn: () => ReturnType; if (isProd()) { - manifestPromise = getServerManifest( - pwd!, - routes || [], - console as unknown as Monitors, - ); - htmlTemplatePromise = getHtmlTemplates(pwd!, routes || []); + if (process.env.MODERN_SERVER_BUNDLE && dependencies) { + const manifestPromise = getBundledServerManifest( + dependencies, + routes || [], + ); + getManifest = () => manifestPromise; + const htmlTemplatePromise = getBundledHtmlTemplates( + dependencies, + routes || [], + ); + getHtmlTemplatesFn = () => htmlTemplatePromise; + } else { + const manifestPromise = getServerManifest( + pwd!, + routes || [], + console as unknown as Monitors, + ); + getManifest = () => manifestPromise; + const htmlTemplatePromise = getHtmlTemplates(pwd!, routes || []); + getHtmlTemplatesFn = () => htmlTemplatePromise; + } + } else { + getManifest = c => getServerManifest(pwd!, routes || [], c); + getHtmlTemplatesFn = () => getHtmlTemplates(pwd!, routes || []); } middlewares.push({ name: 'inject-server-manifest', - - handler: injectServerManifest(pwd!, routes, manifestPromise), + handler: injectServerManifest(getManifest, routes), }); middlewares.push({ name: 'inject-html', - - handler: injectTemplates(pwd!, routes, htmlTemplatePromise), + handler: injectTemplates(getHtmlTemplatesFn), }); }); }, diff --git a/packages/server/prod-server/src/apply.ts b/packages/server/prod-server/src/apply.ts index 656b7fd424e4..1e1f61918a7e 100644 --- a/packages/server/prod-server/src/apply.ts +++ b/packages/server/prod-server/src/apply.ts @@ -14,6 +14,7 @@ import { injectNodeSeverPlugin, injectResourcePlugin, injectRscManifestPlugin, + loadBundledCacheConfig, loadCacheConfig, serverStaticPlugin, } from '@modern-js/server-core/node'; @@ -33,18 +34,30 @@ function getLogger(_?: boolean | Record) { export type ApplyPlugins = typeof applyPlugins; +export type ExtraApplyConfig = Partial<{ + nodeServer: NodeServer | Http2SecureServer; + noStaticServer: boolean; +}>; + export async function applyPlugins( serverBase: ServerBase, - options: ProdServerOptions, - nodeServer?: NodeServer | Http2SecureServer, + serverOptions: ProdServerOptions, + extra: ExtraApplyConfig = {}, ) { - const { pwd, appContext, config, logger: optLogger, serverConfig } = options; + const { + pwd, + appContext, + config, + logger: optLogger, + serverConfig, + } = serverOptions; const enableRsc = config.server?.rsc ?? serverConfig?.server?.rsc ?? false; - const serverErrorHandler = options.serverConfig?.onError; - const loadCachePwd = isProd() ? pwd : appContext.appDirectory || pwd; - const cacheConfig = await loadCacheConfig(loadCachePwd); + const serverErrorHandler = serverOptions.serverConfig?.onError; + const cacheConfig = await (process.env.MODERN_SERVER_BUNDLE + ? loadBundledCacheConfig(serverOptions.appContext?.dependencies) + : loadCacheConfig(isProd() ? pwd : appContext.appDirectory || pwd)); serverBase.notFound(c => { const monitors = c.get('monitors'); @@ -82,23 +95,26 @@ export async function applyPlugins( }); const loggerOptions = config.server.logger; - const { middlewares, renderMiddlewares } = options.serverConfig || {}; + const { middlewares, renderMiddlewares } = serverOptions.serverConfig || {}; const plugins = [ - ...(nodeServer ? [injectNodeSeverPlugin({ nodeServer })] : []), + ...(extra.nodeServer + ? [injectNodeSeverPlugin({ nodeServer: extra.nodeServer })] + : []), ...createDefaultPlugins({ cacheConfig, - staticGenerate: options.staticGenerate, + staticGenerate: serverOptions.staticGenerate, logger: loggerOptions === false ? false : optLogger || getLogger(loggerOptions), }), injectConfigMiddlewarePlugin(middlewares, renderMiddlewares), - ...(options.plugins || []), + ...(serverOptions.plugins || []), injectResourcePlugin(), injectRscManifestPlugin(enableRsc), - serverStaticPlugin(), + ...(extra.noStaticServer ? [] : [serverStaticPlugin()]), faviconPlugin(), renderPlugin(), ]; + serverBase.addPlugins(plugins); } diff --git a/packages/server/prod-server/src/base-server.ts b/packages/server/prod-server/src/base-server.ts new file mode 100644 index 000000000000..b8f6098f0ad3 --- /dev/null +++ b/packages/server/prod-server/src/base-server.ts @@ -0,0 +1,64 @@ +import { createServerBase } from '@modern-js/server-core'; +import { + loadBundledServerCliConfig, + loadBundledServerRuntimeConfig, + loadServerCliConfig, + loadServerEnv, + loadServerRuntimeConfig, +} from '@modern-js/server-core/node'; +import { type ExtraApplyConfig, applyPlugins } from './apply'; +import type { BaseEnv, ProdServerOptions } from './types'; + +export const createBaseProdServer = async (options: ProdServerOptions) => { + // load env file. + if (!process.env.MODERN_SERVER_BUNDLE) { + await loadServerEnv(options); + } + + const serverBaseOptions = options; + + let serverCliConfig = options.config; + if (process.env.NODE_ENV === 'production') { + if (process.env.MODERN_SERVER_BUNDLE) { + serverCliConfig = await loadBundledServerCliConfig( + options.config, + options.appContext.dependencies, + ); + } else { + serverCliConfig = await loadServerCliConfig(options.pwd, options.config); + } + } + + if (serverCliConfig) { + serverBaseOptions.config = serverCliConfig; + } + + let serverRuntimeConfig; + if (process.env.MODERN_SERVER_BUNDLE) { + serverRuntimeConfig = await loadBundledServerRuntimeConfig( + options.serverConfigPath, + ); + } else { + serverRuntimeConfig = await loadServerRuntimeConfig( + options.serverConfigPath, + ); + } + + if (serverRuntimeConfig) { + serverBaseOptions.serverConfig = serverRuntimeConfig; + serverBaseOptions.plugins = [ + ...(serverRuntimeConfig.plugins || []), + ...(options.plugins || []), + ]; + } + + const server = createServerBase(serverBaseOptions); + + return { + server, + init: async (extra?: ExtraApplyConfig) => { + await applyPlugins(server, options, extra); + await server.init(); + }, + }; +}; diff --git a/packages/server/prod-server/src/index.ts b/packages/server/prod-server/src/index.ts index 35ce62bde683..5add4a65d991 100644 --- a/packages/server/prod-server/src/index.ts +++ b/packages/server/prod-server/src/index.ts @@ -1,12 +1,6 @@ -import { createServerBase } from '@modern-js/server-core'; -import { - createNodeServer, - loadServerCliConfig, - loadServerEnv, - loadServerRuntimeConfig, -} from '@modern-js/server-core/node'; -import { applyPlugins } from './apply'; -import type { BaseEnv, ProdServerOptions } from './types'; +import { createNodeServer } from '@modern-js/server-core/node'; +import { createBaseProdServer } from './base-server'; +import type { ProdServerOptions } from './types'; export { applyPlugins, type ApplyPlugins } from './apply'; @@ -17,42 +11,17 @@ export { export type { ServerPlugin } from '@modern-js/server-core'; -export type { ProdServerOptions, BaseEnv } from './types'; +export type { BaseEnv, ProdServerOptions } from './types'; export const createProdServer = async (options: ProdServerOptions) => { - await loadServerEnv(options); - - const serverBaseOptions = options; - - const serverCliConfig = - process.env.NODE_ENV === 'production' - ? loadServerCliConfig(options.pwd, options.config) - : options.config; - - if (serverCliConfig) { - serverBaseOptions.config = serverCliConfig; - } + const { server, init } = await createBaseProdServer(options); - const serverRuntimeConfig = await loadServerRuntimeConfig( - options.serverConfigPath, - ); - - if (serverRuntimeConfig) { - serverBaseOptions.serverConfig = serverRuntimeConfig; - serverBaseOptions.plugins = [ - ...(serverRuntimeConfig.plugins || []), - ...(options.plugins || []), - ]; - } - - const server = createServerBase(serverBaseOptions); - - // load env file. const nodeServer = await createNodeServer(server.handle.bind(server)); - await applyPlugins(server, options, nodeServer); - - await server.init(); + await init({ + nodeServer, + noStaticServer: Boolean(process.env.MODERN_SERVER_BUNDLE), + }); return nodeServer; }; diff --git a/packages/server/prod-server/src/netlify.ts b/packages/server/prod-server/src/netlify.ts index f39d6270e65c..3b925f9cc0fd 100644 --- a/packages/server/prod-server/src/netlify.ts +++ b/packages/server/prod-server/src/netlify.ts @@ -1,40 +1,13 @@ -import { createServerBase } from '@modern-js/server-core'; -import { - loadServerCliConfig, - loadServerEnv, - loadServerRuntimeConfig, -} from '@modern-js/server-core/node'; -import { applyPlugins } from './apply'; -import type { BaseEnv, ProdServerOptions } from './types'; +import { createBaseProdServer } from './base-server'; +import type { ProdServerOptions } from './types'; -export type { ProdServerOptions, BaseEnv } from './types'; +export type { BaseEnv, ProdServerOptions } from './types'; export const createNetlifyFunction = async (options: ProdServerOptions) => { - await loadServerEnv(options); + const { server, init } = await createBaseProdServer(options); - const serverBaseOptions = options; + await init(); - const serverCliConfig = loadServerCliConfig(options.pwd, options.config); - - if (serverCliConfig) { - options.config = serverCliConfig; - } - - const serverRuntimeConfig = await loadServerRuntimeConfig( - options.serverConfigPath, - ); - - if (serverRuntimeConfig) { - serverBaseOptions.serverConfig = serverRuntimeConfig; - serverBaseOptions.plugins = [ - ...(serverRuntimeConfig.plugins || []), - ...(options.plugins || []), - ]; - } - const server = createServerBase(serverBaseOptions); - - await applyPlugins(server, options); - await server.init(); return (request: Request, context: unknown) => { return server.handle(request, context); }; diff --git a/packages/server/server/src/createDevServer.ts b/packages/server/server/src/createDevServer.ts index 31bcb3098178..740aaf31907c 100644 --- a/packages/server/server/src/createDevServer.ts +++ b/packages/server/server/src/createDevServer.ts @@ -80,7 +80,7 @@ export async function createDevServer( prodServerOptions.config.output.assetPrefix = assetPrefix; } - await applyPlugins(server, prodServerOptions, nodeServer); + await applyPlugins(server, prodServerOptions, { nodeServer }); await server.init(); diff --git a/packages/server/server/src/types.ts b/packages/server/server/src/types.ts index 01ce34917ddc..907dbc00fbf2 100644 --- a/packages/server/server/src/types.ts +++ b/packages/server/server/src/types.ts @@ -88,8 +88,13 @@ export type ModernDevServerOptions< O extends ServerBaseOptions = ServerBaseOptions, > = O & ExtraOptions; +export type ExtraApplyConfig = Partial<{ + nodeServer: NodeServer | Http2SecureServer; + noStaticServer: boolean; +}>; + export type ApplyPlugins = ( server: ServerBase, options: ModernDevServerOptions, - nodeServer?: NodeServer | Http2SecureServer, + extra?: ExtraApplyConfig, ) => Promise; diff --git a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts index 7611f87de096..8737636f03b5 100644 --- a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts +++ b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts @@ -1,4 +1,7 @@ -import { isHtmlDisabled } from '@modern-js/builder'; +import { + SERVICE_WORKER_ENVIRONMENT_NAME, + isHtmlDisabled, +} from '@modern-js/builder'; import { removeTailSlash } from '@modern-js/utils'; import { template as lodashTemplate } from '@modern-js/utils/lodash'; import type { @@ -24,6 +27,13 @@ export const builderPluginAdapterHtml = ( ) => { const builderConfig = environment.config; + const isServiceWorker = + environment.name === SERVICE_WORKER_ENVIRONMENT_NAME; + + if (isServiceWorker) { + return; + } + if (!isHtmlDisabled(builderConfig, target)) { applyBottomHtmlPlugin({ options, diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 1750724fb71c..3a0e2ccff07a 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -55,9 +55,7 @@ export const createNodePreset: CreatePreset = ({ return; } - const handlerTemplate = await readTemplate( - 'node-entry-single-bundle.mjs', - ); + const handlerTemplate = await readTemplate('node-entry-bundle.mjs'); const { code: depCode } = await scanDeps( distDirectory, diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-bundle.mjs similarity index 94% rename from packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs rename to packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-bundle.mjs index c976d0d563b5..d629c54e2caf 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-single-bundle.mjs +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry-bundle.mjs @@ -1,6 +1,6 @@ import { createProdServer } from 'p_prodServerEntry'; -globalThis[p_bundleDepVarName] = p_genDepCode; +const dependencies = p_genDepCode; p_genPluginImportsCode; @@ -21,6 +21,7 @@ async function main() { apiDirectory: p_apiDirectory, lambdaDirectory: p_lambdaDirectory, bffRuntimeFramework: p_bffRuntimeFramework, + dependencies, }, plugins: p_plugins, serverConfigPath: p_serverDirectory, diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index fb7e2b7a61bc..e5ec3fe06ea7 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -60,6 +60,7 @@ export const bundleServer = async ( }, }, define: { + 'process.env.MODERN_SERVER_BUNDLE': 'true', 'process.env.NODE_ENV': '"production"', 'process.env.MODERN_SSR_ENV': '"edge"', }, @@ -104,6 +105,9 @@ export const bundleServer = async ( experiments: { outputModule: true, }, + stats: { + preset: 'verbose', + }, }, }, }; @@ -129,12 +133,19 @@ export const bundleServer = async ( builder.modifyRsbuildConfig(config => { const { output } = config; if (Array.isArray(output?.externals)) { - output.externals = output.externals.filter( + output!.externals = output!.externals.filter( x => typeof x !== 'object' || !('@modern-js/plugin-bff/server' in x), ); } }); + builder.onAfterBuild(async ({ stats }) => { + await fse.writeFile( + path.join(finalConfig.output.distPath!.root!, 'stats.json'), + JSON.stringify(stats?.toJson({}), null, 2), + ); + }); + if (options?.modifyBuilder) { await options.modifyBuilder(builder); } diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts index 6f80c72c7125..b7368b10819b 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts @@ -1,12 +1,9 @@ import path from 'node:path'; -import { lodash as _ } from '@modern-js/utils'; -import type { Rspack } from '@rsbuild/core'; +import { set } from '@modern-js/utils/lodash'; import type { PluginAPI } from '../../types'; -import { normalizePath } from '../../utils'; import { generateNodeExternals } from '../builder'; import { NODE_BUILTIN_MODULES } from '../constant'; import { appendTo } from '../utils'; -import { generateChunkLoading } from './chunk-loader'; export interface ApplyConfigParams { rsbuild?: Parameters[0]; @@ -47,83 +44,19 @@ export const applyConfig = (api: PluginAPI, options?: ApplyConfigParams) => { config.target = 'es2020'; if (isTsProject || isEsmProject) { - _.set(config, 'output.chunkFormat', 'module'); - _.set(config, 'output.chunkLoading', 'singleBundleChunkLoad'); - _.set(config, 'output.module', true); - _.set(config, 'output.library.type', 'module'); - _.set(config, 'experiments.outputModule', true); + set(config, 'output.chunkFormat', 'module'); + set(config, 'output.chunkLoading', 'singleBundleChunkLoad'); + set(config, 'output.module', true); + set(config, 'output.library.type', 'module'); + set(config, 'experiments.outputModule', true); } - const instance: Rspack.RspackPluginInstance = { - apply(compiler) { - const { RuntimeModule, RuntimeGlobals } = compiler.rspack; - - compiler.rspack.javascript.EnableChunkLoadingPlugin.setEnabled( - compiler, - 'singleBundleChunkLoad', - ); - - class SingleBundleChunkLoad extends RuntimeModule { - constructor() { - super('single bundle chunk load', RuntimeModule.STAGE_ATTACH); - } - - generate() { - const { chunk, compilation } = this; - if (!chunk || !compilation || !outputPath || !chunk.id) { - return ''; - } - const chunkFilename = compilation.options.output - .chunkFilename as string; - const chunkMap: Record = {}; - chunk.getAllReferencedChunks().map(refChunk => { - if (!refChunk.id) { - return; - } - const p = compilation.getPath(chunkFilename, { - chunk: refChunk, - }); - const fullPath = path.join(outputPath, p); - const relativePath = normalizePath( - path.relative(baseDistPath, fullPath), - ); - chunkMap[refChunk.id] = relativePath; - }); - // rspack declared a wrong type of RuntimeGlobals, they fixed in a newer version - // @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/packages/rspack/src/RuntimeGlobals.ts#L679 - return generateChunkLoading( - chunk.id, - chunkMap, - RuntimeGlobals as any, - isTsProject || isEsmProject, - ); - } - } - - compiler.hooks.thisCompilation.tap( - 'SingleBundleChunkLoadPlugin', - compilation => { - compilation.hooks.runtimeRequirementInTree - .for(RuntimeGlobals.ensureChunkHandlers) - .tap('SingleBundleChunkLoad', (chunk, set) => { - compilation.addRuntimeModule( - chunk, - new SingleBundleChunkLoad(), - ); - }); - }, - ); - }, - }; - appendTo(config, 'externals', nodeExternals); - appendTo(config, 'plugins', instance); try { options?.rspack?.(config, utils); } catch (e) { console.error(e); } - // console.log('\n\n\n\n', 'config 222', config, '\n\n\n\n'); }); }; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts deleted file mode 100644 index 1042c82741f7..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/chunk-loader.ts +++ /dev/null @@ -1,75 +0,0 @@ -// @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/crates/rspack_plugin_esm_library/src/render.rs#L726 -// @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/crates/rspack_plugin_runtime/src/runtime_module/runtime/module_chunk_loading.ejs -const runtimeVariableModules = '__webpack_modules__'; -const esmChunkInstaller = (globals: Record) => ` -${globals.moduleFactories} = ${globals.moduleFactories} || ${runtimeVariableModules}; -var installChunk = (data) => { - var __rspack_esm_ids = data.__rspack_esm_ids; - var ${runtimeVariableModules} = data.${runtimeVariableModules}; - var __rspack_esm_runtime = data.__rspack_esm_runtime; - // add "modules" to the modules object, - // then flag all "ids" as loaded and fire callback - var moduleId, chunkId, i = 0; - for (moduleId in ${runtimeVariableModules}) { - if (${globals.hasOwnProperty}(${runtimeVariableModules}, moduleId)) { - ${globals.moduleFactories}[moduleId] = ${runtimeVariableModules}[moduleId]; - } - } - if (__rspack_esm_runtime) __rspack_esm_runtime(${globals.require}); - for (; i < __rspack_esm_ids.length; i++) { - chunkId = __rspack_esm_ids[i]; - if (${globals.hasOwnProperty}(installedChunks, chunkId) && installedChunks[chunkId]) { - installedChunks[chunkId][0](); - } - installedChunks[__rspack_esm_ids[i]] = 1; - } -};`; - -// @see https://github.com/web-infra-dev/rspack/blob/v1.6.8/crates/rspack_plugin_runtime/src/runtime_module/runtime/require_chunk_loading.ejs -const cjsChunkInstaller = (globals: Record) => ` -var installChunk = (chunk) => { - var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime; - for (var moduleId in moreModules) { - if (${globals.hasOwnProperty}(moreModules, moduleId)) { - ${globals.moduleFactories}[moduleId] = moreModules[moduleId]; - } - } - if (runtime) runtime(${globals.require}); - for (var i = 0; i < chunkIds.length; i++) installedChunks[chunkIds[i]] = 1; -};`; - -export const generateChunkLoading = ( - chunkId: string, - chunkMap: Record, - runtimeGlobals: Record, - isESM?: boolean, -) => { - const installer = isESM - ? esmChunkInstaller(runtimeGlobals) - : cjsChunkInstaller(runtimeGlobals); - return `var installedChunks = {"${chunkId}": 1}; -var loadingChunks = {}; -var chunkMap = ${JSON.stringify(chunkMap)}; -${installer} -${runtimeGlobals.ensureChunkHandlers}.singleBundleChunkLoad = (chunkId, promises) => { - if (installedChunks[chunkId]) { - return; - } - if (!loadingChunks[chunkId]) { - var g = global || globalThis; - loadingChunks[chunkId] = new Promise((resolve, reject) => { - var p = g.__MODERN_DEPS__[chunkMap[chunkId]]; - if (!p) { - reject(new Error('chunk ' + chunkId + ' is not available')); - return; - } - p().then(d => { - installChunk(d.default || d); - delete loadingChunks[chunkId]; - resolve(); - }).catch(reject) - }); - } - promises.push(loadingChunks[chunkId]); -};`; -}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts index 13f3cbf6d8b8..f71d60d0f149 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts @@ -1,8 +1,6 @@ import path from 'node:path'; -import { pathToFileURL } from 'node:url'; import { SERVER_ENTRY_POINT_FILE_NAME } from '@modern-js/utils/cli/constants'; import fse from '@modern-js/utils/fs-extra'; -import { SERVER_BUNDLE_DEP_VARNAME } from '@modern-js/utils/universal/constants'; import type { AppToolsContext } from '../../../types/plugin'; import { getServerCombinedModuleFile } from '../../analyze/utils'; import { normalizePath } from '../utils'; @@ -68,11 +66,11 @@ export const generateHandler = async (options: GenerateHandlerOptions) => { ); const hasServerLoaders = await fse.pathExists(serverLoadersEntry); const serverLoadersCode = hasServerLoaders - ? `serverLoadersContent: () => import(${JSON.stringify(pathToFileURL(serverLoadersEntry))}).then(x => x.default || x),` + ? `serverLoadersContent: () => import(${JSON.stringify(serverLoadersEntry)}).then(x => x.default || x),` : ''; const baseRouteCode = JSON.stringify(route); routesCode.push(`${baseRouteCode.substring(0, baseRouteCode.length - 1)}, - bundleContent: () => import(${JSON.stringify(pathToFileURL(bundleEntry))}).then(x => x.default || x), + bundleContent: () => import(${JSON.stringify(bundleEntry)}).then(x => x.default || x), ${serverLoadersCode} }`); } @@ -96,9 +94,5 @@ export const generateHandler = async (options: GenerateHandlerOptions) => { return code .replace('p_genDepCode', depCode) - .replace('p_bundleDepVarName', JSON.stringify(SERVER_BUNDLE_DEP_VARNAME)) - .replace( - 'p_prodServerEntry', - String(pathToFileURL(normalizePath(prodServerEntry))), - ); + .replace('p_prodServerEntry', String(normalizePath(prodServerEntry))); }; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts index e1463e15f8f4..26b02129e745 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts @@ -1,5 +1,5 @@ import { pathToFileURL } from 'node:url'; -import { lodash as _ } from '@modern-js/utils'; +import { get, set } from '@modern-js/utils/lodash'; import { moduleResolve } from 'import-meta-resolve'; import { normalizePath } from '../utils'; @@ -20,10 +20,10 @@ export const resolveESMDependency = (entry: string) => { }; export const appendTo = (target: any, key: string, value: any) => { - const v = _.get(target, key); + const v = get(target, key); if (Array.isArray(v)) { v.push(value); } else { - _.set(target, key, [value]); + set(target, key, [value]); } }; diff --git a/packages/toolkit/plugin/src/server/run/create.ts b/packages/toolkit/plugin/src/server/run/create.ts index 5f8edfdfd236..edfa2043d74b 100644 --- a/packages/toolkit/plugin/src/server/run/create.ts +++ b/packages/toolkit/plugin/src/server/run/create.ts @@ -30,6 +30,8 @@ export const createServer = () => { config: initOptions.config, }); + context.dependencies = options.options.appContext.dependencies; + const pluginAPI = initPluginAPI({ context, pluginManager, diff --git a/packages/toolkit/plugin/src/server/run/types.ts b/packages/toolkit/plugin/src/server/run/types.ts index 46a520d38ccf..0d7f12ebe569 100644 --- a/packages/toolkit/plugin/src/server/run/types.ts +++ b/packages/toolkit/plugin/src/server/run/types.ts @@ -13,6 +13,7 @@ export type ServerCreateOptions = { apiDirectory?: string; lambdaDirectory?: string; bffRuntimeFramework?: string; + dependencies?: Record>; }; }; diff --git a/packages/toolkit/plugin/src/types/server/context.ts b/packages/toolkit/plugin/src/types/server/context.ts index 4e8ff320f2f5..54a9499281d6 100644 --- a/packages/toolkit/plugin/src/types/server/context.ts +++ b/packages/toolkit/plugin/src/types/server/context.ts @@ -18,6 +18,7 @@ export type ServerContext = { distDirectory?: string; metaName: string; plugins: ServerPlugin[]; + dependencies?: Record>; }; export type InternalServerContext = diff --git a/packages/toolkit/types/server/route.d.ts b/packages/toolkit/types/server/route.d.ts index 982022bd376e..4bc09e819a4b 100644 --- a/packages/toolkit/types/server/route.d.ts +++ b/packages/toolkit/types/server/route.d.ts @@ -21,4 +21,8 @@ export interface ServerRoute { bundle?: string; // response header for routes responseHeaders?: Record; + + // in server-bundle mode, the bundle content will inject to entry + bundleContent?: () => Promise; + serverLoadersContent?: () => Promise; } diff --git a/packages/toolkit/utils/src/universal/constants.ts b/packages/toolkit/utils/src/universal/constants.ts index 0db66da92cd1..e637137d15bd 100644 --- a/packages/toolkit/utils/src/universal/constants.ts +++ b/packages/toolkit/utils/src/universal/constants.ts @@ -50,8 +50,3 @@ export const SERVER_RENDER_FUNCTION_NAME = 'serverRender'; export const SERVER_PLUGIN_BFF = '@modern-js/plugin-bff'; export const SERVER_PLUGIN_POLYFILL = '@modern-js/plugin-polyfill'; - -/** - * In server bundle mode, dependencies will be mounted to this variable - */ -export const SERVER_BUNDLE_DEP_VARNAME = '__MODERN_DEPS__'; diff --git a/tests/integration/deploy-server/modern.config.ts b/tests/integration/deploy-server/modern.config.ts index 65f1c399e32d..50e83a317f99 100644 --- a/tests/integration/deploy-server/modern.config.ts +++ b/tests/integration/deploy-server/modern.config.ts @@ -1,3 +1,5 @@ +import { writeFileSync } from 'fs'; +import { join } from 'path'; import AppToolsPlugin, { defineConfig } from '@modern-js/app-tools'; import bff from '@modern-js/plugin-bff'; @@ -8,6 +10,11 @@ export default defineConfig({ buildCache: false, }, server: { - ssr: true, + ssr: { + bundleServer: true, + }, + }, + output: { + minify: false, }, }); From 22a9a2fa08c955baf88d5e1724b54fbbccdbe729 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Thu, 29 Jan 2026 20:47:37 +0800 Subject: [PATCH 03/27] fix: fs-extra in esm --- .../src/plugins/deploy/server-bundle/builder.ts | 11 +++++++---- packages/toolkit/utils/compiled/fs-extra/index.js | 2 +- packages/toolkit/utils/compiled/fs-extra/index.mjs | 1 + packages/toolkit/utils/compiled/fs-extra/license | 2 +- .../toolkit/utils/compiled/fs-extra/package.json | 2 +- packages/toolkit/utils/package.json | 5 ++++- packages/toolkit/utils/rslib.config.mts | 5 ++++- pnpm-lock.yaml | 14 +++++++++++--- scripts/prebundle/package.json | 2 +- scripts/prebundle/src/constant.ts | 8 +++++++- scripts/prebundle/src/helper.ts | 3 ++- scripts/prebundle/src/index.ts | 11 ++++++++++- scripts/prebundle/src/types.ts | 1 + 13 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 packages/toolkit/utils/compiled/fs-extra/index.mjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index e5ec3fe06ea7..6f97fcf54e41 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -105,9 +105,6 @@ export const bundleServer = async ( experiments: { outputModule: true, }, - stats: { - preset: 'verbose', - }, }, }, }; @@ -142,7 +139,13 @@ export const bundleServer = async ( builder.onAfterBuild(async ({ stats }) => { await fse.writeFile( path.join(finalConfig.output.distPath!.root!, 'stats.json'), - JSON.stringify(stats?.toJson({}), null, 2), + JSON.stringify( + stats?.toJson({ + preset: 'verbose', + }), + null, + 2, + ), ); }); diff --git a/packages/toolkit/utils/compiled/fs-extra/index.js b/packages/toolkit/utils/compiled/fs-extra/index.js index 97904eeeec60..c434f9497bf4 100644 --- a/packages/toolkit/utils/compiled/fs-extra/index.js +++ b/packages/toolkit/utils/compiled/fs-extra/index.js @@ -1 +1 @@ -(()=>{var e={571:(e,t,r)=>{"use strict";const n=r(127);const i=r(17);const o=r(971).mkdirsSync;const c=r(309).utimesMillisSync;const s=r(883);function copySync(e,t,r){if(typeof r==="function"){r={filter:r}}r=r||{};r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n\n see https://github.com/jprichardson/node-fs-extra/issues/269`)}const{srcStat:n,destStat:i}=s.checkPathsSync(e,t,"copy",r);s.checkParentPathsSync(e,n,t,"copy");return handleFilterAndCopy(i,e,t,r)}function handleFilterAndCopy(e,t,r,c){if(c.filter&&!c.filter(t,r))return;const s=i.dirname(r);if(!n.existsSync(s))o(s);return getStats(e,t,r,c)}function startCopy(e,t,r,n){if(n.filter&&!n.filter(t,r))return;return getStats(e,t,r,n)}function getStats(e,t,r,i){const o=i.dereference?n.statSync:n.lstatSync;const c=o(t);if(c.isDirectory())return onDir(c,e,t,r,i);else if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,e,t,r,i);else if(c.isSymbolicLink())return onLink(e,t,r,i);else if(c.isSocket())throw new Error(`Cannot copy a socket file: ${t}`);else if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${t}`);throw new Error(`Unknown file: ${t}`)}function onFile(e,t,r,n,i){if(!t)return copyFile(e,r,n,i);return mayCopyFile(e,r,n,i)}function mayCopyFile(e,t,r,i){if(i.overwrite){n.unlinkSync(r);return copyFile(e,t,r,i)}else if(i.errorOnExist){throw new Error(`'${r}' already exists`)}}function copyFile(e,t,r,i){n.copyFileSync(t,r);if(i.preserveTimestamps)handleTimestamps(e.mode,t,r);return setDestMode(r,e.mode)}function handleTimestamps(e,t,r){if(fileIsNotWritable(e))makeFileWritable(r,e);return setDestTimestamps(t,r)}function fileIsNotWritable(e){return(e&128)===0}function makeFileWritable(e,t){return setDestMode(e,t|128)}function setDestMode(e,t){return n.chmodSync(e,t)}function setDestTimestamps(e,t){const r=n.statSync(e);return c(t,r.atime,r.mtime)}function onDir(e,t,r,n,i){if(!t)return mkDirAndCopy(e.mode,r,n,i);return copyDir(r,n,i)}function mkDirAndCopy(e,t,r,i){n.mkdirSync(r);copyDir(t,r,i);return setDestMode(r,e)}function copyDir(e,t,r){n.readdirSync(e).forEach((n=>copyDirItem(n,e,t,r)))}function copyDirItem(e,t,r,n){const o=i.join(t,e);const c=i.join(r,e);const{destStat:a}=s.checkPathsSync(o,c,"copy",n);return startCopy(a,o,c,n)}function onLink(e,t,r,o){let c=n.readlinkSync(t);if(o.dereference){c=i.resolve(process.cwd(),c)}if(!e){return n.symlinkSync(c,r)}else{let e;try{e=n.readlinkSync(r)}catch(e){if(e.code==="EINVAL"||e.code==="UNKNOWN")return n.symlinkSync(c,r);throw e}if(o.dereference){e=i.resolve(process.cwd(),e)}if(s.isSrcSubdir(c,e)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${e}'.`)}if(n.statSync(r).isDirectory()&&s.isSrcSubdir(e,c)){throw new Error(`Cannot overwrite '${e}' with '${c}'.`)}return copyLink(c,r)}}function copyLink(e,t){n.unlinkSync(t);return n.symlinkSync(e,t)}e.exports=copySync},987:(e,t,r)=>{"use strict";const n=r(127);const i=r(17);const o=r(971).mkdirs;const c=r(725).pathExists;const s=r(309).utimesMillis;const a=r(883);function copy(e,t,r,n){if(typeof r==="function"&&!n){n=r;r={}}else if(typeof r==="function"){r={filter:r}}n=n||function(){};r=r||{};r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n\n see https://github.com/jprichardson/node-fs-extra/issues/269`)}a.checkPaths(e,t,"copy",r,((i,o)=>{if(i)return n(i);const{srcStat:c,destStat:s}=o;a.checkParentPaths(e,c,t,"copy",(i=>{if(i)return n(i);if(r.filter)return handleFilter(checkParentDir,s,e,t,r,n);return checkParentDir(s,e,t,r,n)}))}))}function checkParentDir(e,t,r,n,s){const a=i.dirname(r);c(a,((i,c)=>{if(i)return s(i);if(c)return getStats(e,t,r,n,s);o(a,(i=>{if(i)return s(i);return getStats(e,t,r,n,s)}))}))}function handleFilter(e,t,r,n,i,o){Promise.resolve(i.filter(r,n)).then((c=>{if(c)return e(t,r,n,i,o);return o()}),(e=>o(e)))}function startCopy(e,t,r,n,i){if(n.filter)return handleFilter(getStats,e,t,r,n,i);return getStats(e,t,r,n,i)}function getStats(e,t,r,i,o){const c=i.dereference?n.stat:n.lstat;c(t,((n,c)=>{if(n)return o(n);if(c.isDirectory())return onDir(c,e,t,r,i,o);else if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,e,t,r,i,o);else if(c.isSymbolicLink())return onLink(e,t,r,i,o);else if(c.isSocket())return o(new Error(`Cannot copy a socket file: ${t}`));else if(c.isFIFO())return o(new Error(`Cannot copy a FIFO pipe: ${t}`));return o(new Error(`Unknown file: ${t}`))}))}function onFile(e,t,r,n,i,o){if(!t)return copyFile(e,r,n,i,o);return mayCopyFile(e,r,n,i,o)}function mayCopyFile(e,t,r,i,o){if(i.overwrite){n.unlink(r,(n=>{if(n)return o(n);return copyFile(e,t,r,i,o)}))}else if(i.errorOnExist){return o(new Error(`'${r}' already exists`))}else return o()}function copyFile(e,t,r,i,o){n.copyFile(t,r,(n=>{if(n)return o(n);if(i.preserveTimestamps)return handleTimestampsAndMode(e.mode,t,r,o);return setDestMode(r,e.mode,o)}))}function handleTimestampsAndMode(e,t,r,n){if(fileIsNotWritable(e)){return makeFileWritable(r,e,(i=>{if(i)return n(i);return setDestTimestampsAndMode(e,t,r,n)}))}return setDestTimestampsAndMode(e,t,r,n)}function fileIsNotWritable(e){return(e&128)===0}function makeFileWritable(e,t,r){return setDestMode(e,t|128,r)}function setDestTimestampsAndMode(e,t,r,n){setDestTimestamps(t,r,(t=>{if(t)return n(t);return setDestMode(r,e,n)}))}function setDestMode(e,t,r){return n.chmod(e,t,r)}function setDestTimestamps(e,t,r){n.stat(e,((e,n)=>{if(e)return r(e);return s(t,n.atime,n.mtime,r)}))}function onDir(e,t,r,n,i,o){if(!t)return mkDirAndCopy(e.mode,r,n,i,o);return copyDir(r,n,i,o)}function mkDirAndCopy(e,t,r,i,o){n.mkdir(r,(n=>{if(n)return o(n);copyDir(t,r,i,(t=>{if(t)return o(t);return setDestMode(r,e,o)}))}))}function copyDir(e,t,r,i){n.readdir(e,((n,o)=>{if(n)return i(n);return copyDirItems(o,e,t,r,i)}))}function copyDirItems(e,t,r,n,i){const o=e.pop();if(!o)return i();return copyDirItem(e,o,t,r,n,i)}function copyDirItem(e,t,r,n,o,c){const s=i.join(r,t);const u=i.join(n,t);a.checkPaths(s,u,"copy",o,((t,i)=>{if(t)return c(t);const{destStat:a}=i;startCopy(a,s,u,o,(t=>{if(t)return c(t);return copyDirItems(e,r,n,o,c)}))}))}function onLink(e,t,r,o,c){n.readlink(t,((t,s)=>{if(t)return c(t);if(o.dereference){s=i.resolve(process.cwd(),s)}if(!e){return n.symlink(s,r,c)}else{n.readlink(r,((t,u)=>{if(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlink(s,r,c);return c(t)}if(o.dereference){u=i.resolve(process.cwd(),u)}if(a.isSrcSubdir(s,u)){return c(new Error(`Cannot copy '${s}' to a subdirectory of itself, '${u}'.`))}if(e.isDirectory()&&a.isSrcSubdir(u,s)){return c(new Error(`Cannot overwrite '${u}' with '${s}'.`))}return copyLink(s,r,c)}))}}))}function copyLink(e,t,r){n.unlink(t,(i=>{if(i)return r(i);return n.symlink(e,t,r)}))}e.exports=copy},2:(e,t,r)=>{"use strict";const n=r(5).fromCallback;e.exports={copy:n(r(987)),copySync:r(571)}},708:(e,t,r)=>{"use strict";const n=r(5).fromPromise;const i=r(812);const o=r(17);const c=r(971);const s=r(95);const a=n((async function emptyDir(e){let t;try{t=await i.readdir(e)}catch{return c.mkdirs(e)}return Promise.all(t.map((t=>s.remove(o.join(e,t)))))}));function emptyDirSync(e){let t;try{t=i.readdirSync(e)}catch{return c.mkdirsSync(e)}t.forEach((t=>{t=o.join(e,t);s.removeSync(t)}))}e.exports={emptyDirSync:emptyDirSync,emptydirSync:emptyDirSync,emptyDir:a,emptydir:a}},102:(e,t,r)=>{"use strict";const n=r(5).fromCallback;const i=r(17);const o=r(127);const c=r(971);function createFile(e,t){function makeFile(){o.writeFile(e,"",(e=>{if(e)return t(e);t()}))}o.stat(e,((r,n)=>{if(!r&&n.isFile())return t();const s=i.dirname(e);o.stat(s,((e,r)=>{if(e){if(e.code==="ENOENT"){return c.mkdirs(s,(e=>{if(e)return t(e);makeFile()}))}return t(e)}if(r.isDirectory())makeFile();else{o.readdir(s,(e=>{if(e)return t(e)}))}}))}))}function createFileSync(e){let t;try{t=o.statSync(e)}catch{}if(t&&t.isFile())return;const r=i.dirname(e);try{if(!o.statSync(r).isDirectory()){o.readdirSync(r)}}catch(e){if(e&&e.code==="ENOENT")c.mkdirsSync(r);else throw e}o.writeFileSync(e,"")}e.exports={createFile:n(createFile),createFileSync:createFileSync}},726:(e,t,r)=>{"use strict";const{createFile:n,createFileSync:i}=r(102);const{createLink:o,createLinkSync:c}=r(161);const{createSymlink:s,createSymlinkSync:a}=r(294);e.exports={createFile:n,createFileSync:i,ensureFile:n,ensureFileSync:i,createLink:o,createLinkSync:c,ensureLink:o,ensureLinkSync:c,createSymlink:s,createSymlinkSync:a,ensureSymlink:s,ensureSymlinkSync:a}},161:(e,t,r)=>{"use strict";const n=r(5).fromCallback;const i=r(17);const o=r(127);const c=r(971);const s=r(725).pathExists;const{areIdentical:a}=r(883);function createLink(e,t,r){function makeLink(e,t){o.link(e,t,(e=>{if(e)return r(e);r(null)}))}o.lstat(t,((n,u)=>{o.lstat(e,((n,o)=>{if(n){n.message=n.message.replace("lstat","ensureLink");return r(n)}if(u&&a(o,u))return r(null);const f=i.dirname(t);s(f,((n,i)=>{if(n)return r(n);if(i)return makeLink(e,t);c.mkdirs(f,(n=>{if(n)return r(n);makeLink(e,t)}))}))}))}))}function createLinkSync(e,t){let r;try{r=o.lstatSync(t)}catch{}try{const t=o.lstatSync(e);if(r&&a(t,r))return}catch(e){e.message=e.message.replace("lstat","ensureLink");throw e}const n=i.dirname(t);const s=o.existsSync(n);if(s)return o.linkSync(e,t);c.mkdirsSync(n);return o.linkSync(e,t)}e.exports={createLink:n(createLink),createLinkSync:createLinkSync}},332:(e,t,r)=>{"use strict";const n=r(17);const i=r(127);const o=r(725).pathExists;function symlinkPaths(e,t,r){if(n.isAbsolute(e)){return i.lstat(e,(t=>{if(t){t.message=t.message.replace("lstat","ensureSymlink");return r(t)}return r(null,{toCwd:e,toDst:e})}))}else{const c=n.dirname(t);const s=n.join(c,e);return o(s,((t,o)=>{if(t)return r(t);if(o){return r(null,{toCwd:s,toDst:e})}else{return i.lstat(e,(t=>{if(t){t.message=t.message.replace("lstat","ensureSymlink");return r(t)}return r(null,{toCwd:e,toDst:n.relative(c,e)})}))}}))}}function symlinkPathsSync(e,t){let r;if(n.isAbsolute(e)){r=i.existsSync(e);if(!r)throw new Error("absolute srcpath does not exist");return{toCwd:e,toDst:e}}else{const o=n.dirname(t);const c=n.join(o,e);r=i.existsSync(c);if(r){return{toCwd:c,toDst:e}}else{r=i.existsSync(e);if(!r)throw new Error("relative srcpath does not exist");return{toCwd:e,toDst:n.relative(o,e)}}}}e.exports={symlinkPaths:symlinkPaths,symlinkPathsSync:symlinkPathsSync}},894:(e,t,r)=>{"use strict";const n=r(127);function symlinkType(e,t,r){r=typeof t==="function"?t:r;t=typeof t==="function"?false:t;if(t)return r(null,t);n.lstat(e,((e,n)=>{if(e)return r(null,"file");t=n&&n.isDirectory()?"dir":"file";r(null,t)}))}function symlinkTypeSync(e,t){let r;if(t)return t;try{r=n.lstatSync(e)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}e.exports={symlinkType:symlinkType,symlinkTypeSync:symlinkTypeSync}},294:(e,t,r)=>{"use strict";const n=r(5).fromCallback;const i=r(17);const o=r(812);const c=r(971);const s=c.mkdirs;const a=c.mkdirsSync;const u=r(332);const f=u.symlinkPaths;const l=u.symlinkPathsSync;const y=r(894);const d=y.symlinkType;const m=y.symlinkTypeSync;const p=r(725).pathExists;const{areIdentical:h}=r(883);function createSymlink(e,t,r,n){n=typeof r==="function"?r:n;r=typeof r==="function"?false:r;o.lstat(t,((i,c)=>{if(!i&&c.isSymbolicLink()){Promise.all([o.stat(e),o.stat(t)]).then((([i,o])=>{if(h(i,o))return n(null);_createSymlink(e,t,r,n)}))}else _createSymlink(e,t,r,n)}))}function _createSymlink(e,t,r,n){f(e,t,((c,a)=>{if(c)return n(c);e=a.toDst;d(a.toCwd,r,((r,c)=>{if(r)return n(r);const a=i.dirname(t);p(a,((r,i)=>{if(r)return n(r);if(i)return o.symlink(e,t,c,n);s(a,(r=>{if(r)return n(r);o.symlink(e,t,c,n)}))}))}))}))}function createSymlinkSync(e,t,r){let n;try{n=o.lstatSync(t)}catch{}if(n&&n.isSymbolicLink()){const r=o.statSync(e);const n=o.statSync(t);if(h(r,n))return}const c=l(e,t);e=c.toDst;r=m(c.toCwd,r);const s=i.dirname(t);const u=o.existsSync(s);if(u)return o.symlinkSync(e,t,r);a(s);return o.symlinkSync(e,t,r)}e.exports={createSymlink:n(createSymlink),createSymlinkSync:createSymlinkSync}},812:(e,t,r)=>{"use strict";const n=r(5).fromCallback;const i=r(127);const o=["access","appendFile","chmod","chown","close","copyFile","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchmod","lchown","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","symlink","truncate","unlink","utimes","writeFile"].filter((e=>typeof i[e]==="function"));Object.assign(t,i);o.forEach((e=>{t[e]=n(i[e])}));t.realpath.native=n(i.realpath.native);t.exists=function(e,t){if(typeof t==="function"){return i.exists(e,t)}return new Promise((t=>i.exists(e,t)))};t.read=function(e,t,r,n,o,c){if(typeof c==="function"){return i.read(e,t,r,n,o,c)}return new Promise(((c,s)=>{i.read(e,t,r,n,o,((e,t,r)=>{if(e)return s(e);c({bytesRead:t,buffer:r})}))}))};t.write=function(e,t,...r){if(typeof r[r.length-1]==="function"){return i.write(e,t,...r)}return new Promise(((n,o)=>{i.write(e,t,...r,((e,t,r)=>{if(e)return o(e);n({bytesWritten:t,buffer:r})}))}))};if(typeof i.writev==="function"){t.writev=function(e,t,...r){if(typeof r[r.length-1]==="function"){return i.writev(e,t,...r)}return new Promise(((n,o)=>{i.writev(e,t,...r,((e,t,r)=>{if(e)return o(e);n({bytesWritten:t,buffers:r})}))}))}}},81:(e,t,r)=>{"use strict";e.exports={...r(812),...r(2),...r(708),...r(726),...r(779),...r(971),...r(511),...r(701),...r(725),...r(95)}},779:(e,t,r)=>{"use strict";const n=r(5).fromPromise;const i=r(901);i.outputJson=n(r(410));i.outputJsonSync=r(925);i.outputJSON=i.outputJson;i.outputJSONSync=i.outputJsonSync;i.writeJSON=i.writeJson;i.writeJSONSync=i.writeJsonSync;i.readJSON=i.readJson;i.readJSONSync=i.readJsonSync;e.exports=i},901:(e,t,r)=>{"use strict";const n=r(654);e.exports={readJson:n.readFile,readJsonSync:n.readFileSync,writeJson:n.writeFile,writeJsonSync:n.writeFileSync}},925:(e,t,r)=>{"use strict";const{stringify:n}=r(208);const{outputFileSync:i}=r(701);function outputJsonSync(e,t,r){const o=n(t,r);i(e,o,r)}e.exports=outputJsonSync},410:(e,t,r)=>{"use strict";const{stringify:n}=r(208);const{outputFile:i}=r(701);async function outputJson(e,t,r={}){const o=n(t,r);await i(e,o,r)}e.exports=outputJson},971:(e,t,r)=>{"use strict";const n=r(5).fromPromise;const{makeDir:i,makeDirSync:o}=r(284);const c=n(i);e.exports={mkdirs:c,mkdirsSync:o,mkdirp:c,mkdirpSync:o,ensureDir:c,ensureDirSync:o}},284:(e,t,r)=>{"use strict";const n=r(812);const{checkPath:i}=r(216);const getMode=e=>{const t={mode:511};if(typeof e==="number")return e;return{...t,...e}.mode};e.exports.makeDir=async(e,t)=>{i(e);return n.mkdir(e,{mode:getMode(t),recursive:true})};e.exports.makeDirSync=(e,t)=>{i(e);return n.mkdirSync(e,{mode:getMode(t),recursive:true})}},216:(e,t,r)=>{"use strict";const n=r(17);e.exports.checkPath=function checkPath(e){if(process.platform==="win32"){const t=/[<>:"|?*]/.test(e.replace(n.parse(e).root,""));if(t){const t=new Error(`Path contains invalid characters: ${e}`);t.code="EINVAL";throw t}}}},511:(e,t,r)=>{"use strict";const n=r(5).fromCallback;e.exports={move:n(r(795)),moveSync:r(429)}},429:(e,t,r)=>{"use strict";const n=r(127);const i=r(17);const o=r(2).copySync;const c=r(95).removeSync;const s=r(971).mkdirpSync;const a=r(883);function moveSync(e,t,r){r=r||{};const n=r.overwrite||r.clobber||false;const{srcStat:o,isChangingCase:c=false}=a.checkPathsSync(e,t,"move",r);a.checkParentPathsSync(e,o,t,"move");if(!isParentRoot(t))s(i.dirname(t));return doRename(e,t,n,c)}function isParentRoot(e){const t=i.dirname(e);const r=i.parse(t);return r.root===t}function doRename(e,t,r,i){if(i)return rename(e,t,r);if(r){c(t);return rename(e,t,r)}if(n.existsSync(t))throw new Error("dest already exists.");return rename(e,t,r)}function rename(e,t,r){try{n.renameSync(e,t)}catch(n){if(n.code!=="EXDEV")throw n;return moveAcrossDevice(e,t,r)}}function moveAcrossDevice(e,t,r){const n={overwrite:r,errorOnExist:true};o(e,t,n);return c(e)}e.exports=moveSync},795:(e,t,r)=>{"use strict";const n=r(127);const i=r(17);const o=r(2).copy;const c=r(95).remove;const s=r(971).mkdirp;const a=r(725).pathExists;const u=r(883);function move(e,t,r,n){if(typeof r==="function"){n=r;r={}}const o=r.overwrite||r.clobber||false;u.checkPaths(e,t,"move",r,((r,c)=>{if(r)return n(r);const{srcStat:a,isChangingCase:f=false}=c;u.checkParentPaths(e,a,t,"move",(r=>{if(r)return n(r);if(isParentRoot(t))return doRename(e,t,o,f,n);s(i.dirname(t),(r=>{if(r)return n(r);return doRename(e,t,o,f,n)}))}))}))}function isParentRoot(e){const t=i.dirname(e);const r=i.parse(t);return r.root===t}function doRename(e,t,r,n,i){if(n)return rename(e,t,r,i);if(r){return c(t,(n=>{if(n)return i(n);return rename(e,t,r,i)}))}a(t,((n,o)=>{if(n)return i(n);if(o)return i(new Error("dest already exists."));return rename(e,t,r,i)}))}function rename(e,t,r,i){n.rename(e,t,(n=>{if(!n)return i();if(n.code!=="EXDEV")return i(n);return moveAcrossDevice(e,t,r,i)}))}function moveAcrossDevice(e,t,r,n){const i={overwrite:r,errorOnExist:true};o(e,t,i,(t=>{if(t)return n(t);return c(e,n)}))}e.exports=move},701:(e,t,r)=>{"use strict";const n=r(5).fromCallback;const i=r(127);const o=r(17);const c=r(971);const s=r(725).pathExists;function outputFile(e,t,r,n){if(typeof r==="function"){n=r;r="utf8"}const a=o.dirname(e);s(a,((o,s)=>{if(o)return n(o);if(s)return i.writeFile(e,t,r,n);c.mkdirs(a,(o=>{if(o)return n(o);i.writeFile(e,t,r,n)}))}))}function outputFileSync(e,...t){const r=o.dirname(e);if(i.existsSync(r)){return i.writeFileSync(e,...t)}c.mkdirsSync(r);i.writeFileSync(e,...t)}e.exports={outputFile:n(outputFile),outputFileSync:outputFileSync}},725:(e,t,r)=>{"use strict";const n=r(5).fromPromise;const i=r(812);function pathExists(e){return i.access(e).then((()=>true)).catch((()=>false))}e.exports={pathExists:n(pathExists),pathExistsSync:i.existsSync}},95:(e,t,r)=>{"use strict";const n=r(127);const i=r(5).fromCallback;const o=r(193);function remove(e,t){if(n.rm)return n.rm(e,{recursive:true,force:true},t);o(e,t)}function removeSync(e){if(n.rmSync)return n.rmSync(e,{recursive:true,force:true});o.sync(e)}e.exports={remove:i(remove),removeSync:removeSync}},193:(e,t,r)=>{"use strict";const n=r(127);const i=r(17);const o=r(491);const c=process.platform==="win32";function defaults(e){const t=["unlink","chmod","stat","lstat","rmdir","readdir"];t.forEach((t=>{e[t]=e[t]||n[t];t=t+"Sync";e[t]=e[t]||n[t]}));e.maxBusyTries=e.maxBusyTries||3}function rimraf(e,t,r){let n=0;if(typeof t==="function"){r=t;t={}}o(e,"rimraf: missing path");o.strictEqual(typeof e,"string","rimraf: path should be a string");o.strictEqual(typeof r,"function","rimraf: callback function required");o(t,"rimraf: invalid options argument provided");o.strictEqual(typeof t,"object","rimraf: options should be object");defaults(t);rimraf_(e,t,(function CB(i){if(i){if((i.code==="EBUSY"||i.code==="ENOTEMPTY"||i.code==="EPERM")&&nrimraf_(e,t,CB)),r)}if(i.code==="ENOENT")i=null}r(i)}))}function rimraf_(e,t,r){o(e);o(t);o(typeof r==="function");t.lstat(e,((n,i)=>{if(n&&n.code==="ENOENT"){return r(null)}if(n&&n.code==="EPERM"&&c){return fixWinEPERM(e,t,n,r)}if(i&&i.isDirectory()){return rmdir(e,t,n,r)}t.unlink(e,(n=>{if(n){if(n.code==="ENOENT"){return r(null)}if(n.code==="EPERM"){return c?fixWinEPERM(e,t,n,r):rmdir(e,t,n,r)}if(n.code==="EISDIR"){return rmdir(e,t,n,r)}}return r(n)}))}))}function fixWinEPERM(e,t,r,n){o(e);o(t);o(typeof n==="function");t.chmod(e,438,(i=>{if(i){n(i.code==="ENOENT"?null:r)}else{t.stat(e,((i,o)=>{if(i){n(i.code==="ENOENT"?null:r)}else if(o.isDirectory()){rmdir(e,t,r,n)}else{t.unlink(e,n)}}))}}))}function fixWinEPERMSync(e,t,r){let n;o(e);o(t);try{t.chmodSync(e,438)}catch(e){if(e.code==="ENOENT"){return}else{throw r}}try{n=t.statSync(e)}catch(e){if(e.code==="ENOENT"){return}else{throw r}}if(n.isDirectory()){rmdirSync(e,t,r)}else{t.unlinkSync(e)}}function rmdir(e,t,r,n){o(e);o(t);o(typeof n==="function");t.rmdir(e,(i=>{if(i&&(i.code==="ENOTEMPTY"||i.code==="EEXIST"||i.code==="EPERM")){rmkids(e,t,n)}else if(i&&i.code==="ENOTDIR"){n(r)}else{n(i)}}))}function rmkids(e,t,r){o(e);o(t);o(typeof r==="function");t.readdir(e,((n,o)=>{if(n)return r(n);let c=o.length;let s;if(c===0)return t.rmdir(e,r);o.forEach((n=>{rimraf(i.join(e,n),t,(n=>{if(s){return}if(n)return r(s=n);if(--c===0){t.rmdir(e,r)}}))}))}))}function rimrafSync(e,t){let r;t=t||{};defaults(t);o(e,"rimraf: missing path");o.strictEqual(typeof e,"string","rimraf: path should be a string");o(t,"rimraf: missing options");o.strictEqual(typeof t,"object","rimraf: options should be object");try{r=t.lstatSync(e)}catch(r){if(r.code==="ENOENT"){return}if(r.code==="EPERM"&&c){fixWinEPERMSync(e,t,r)}}try{if(r&&r.isDirectory()){rmdirSync(e,t,null)}else{t.unlinkSync(e)}}catch(r){if(r.code==="ENOENT"){return}else if(r.code==="EPERM"){return c?fixWinEPERMSync(e,t,r):rmdirSync(e,t,r)}else if(r.code!=="EISDIR"){throw r}rmdirSync(e,t,r)}}function rmdirSync(e,t,r){o(e);o(t);try{t.rmdirSync(e)}catch(n){if(n.code==="ENOTDIR"){throw r}else if(n.code==="ENOTEMPTY"||n.code==="EEXIST"||n.code==="EPERM"){rmkidsSync(e,t)}else if(n.code!=="ENOENT"){throw n}}}function rmkidsSync(e,t){o(e);o(t);t.readdirSync(e).forEach((r=>rimrafSync(i.join(e,r),t)));if(c){const r=Date.now();do{try{const r=t.rmdirSync(e,t);return r}catch{}}while(Date.now()-r<500)}else{const r=t.rmdirSync(e,t);return r}}e.exports=rimraf;rimraf.sync=rimrafSync},883:(e,t,r)=>{"use strict";const n=r(812);const i=r(17);const o=r(837);function getStats(e,t,r){const i=r.dereference?e=>n.stat(e,{bigint:true}):e=>n.lstat(e,{bigint:true});return Promise.all([i(e),i(t).catch((e=>{if(e.code==="ENOENT")return null;throw e}))]).then((([e,t])=>({srcStat:e,destStat:t})))}function getStatsSync(e,t,r){let i;const o=r.dereference?e=>n.statSync(e,{bigint:true}):e=>n.lstatSync(e,{bigint:true});const c=o(e);try{i=o(t)}catch(e){if(e.code==="ENOENT")return{srcStat:c,destStat:null};throw e}return{srcStat:c,destStat:i}}function checkPaths(e,t,r,n,c){o.callbackify(getStats)(e,t,n,((n,o)=>{if(n)return c(n);const{srcStat:s,destStat:a}=o;if(a){if(areIdentical(s,a)){const n=i.basename(e);const o=i.basename(t);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return c(null,{srcStat:s,destStat:a,isChangingCase:true})}return c(new Error("Source and destination must not be the same."))}if(s.isDirectory()&&!a.isDirectory()){return c(new Error(`Cannot overwrite non-directory '${t}' with directory '${e}'.`))}if(!s.isDirectory()&&a.isDirectory()){return c(new Error(`Cannot overwrite directory '${t}' with non-directory '${e}'.`))}}if(s.isDirectory()&&isSrcSubdir(e,t)){return c(new Error(errMsg(e,t,r)))}return c(null,{srcStat:s,destStat:a})}))}function checkPathsSync(e,t,r,n){const{srcStat:o,destStat:c}=getStatsSync(e,t,n);if(c){if(areIdentical(o,c)){const n=i.basename(e);const s=i.basename(t);if(r==="move"&&n!==s&&n.toLowerCase()===s.toLowerCase()){return{srcStat:o,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(o.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${t}' with directory '${e}'.`)}if(!o.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${t}' with non-directory '${e}'.`)}}if(o.isDirectory()&&isSrcSubdir(e,t)){throw new Error(errMsg(e,t,r))}return{srcStat:o,destStat:c}}function checkParentPaths(e,t,r,o,c){const s=i.resolve(i.dirname(e));const a=i.resolve(i.dirname(r));if(a===s||a===i.parse(a).root)return c();n.stat(a,{bigint:true},((n,i)=>{if(n){if(n.code==="ENOENT")return c();return c(n)}if(areIdentical(t,i)){return c(new Error(errMsg(e,r,o)))}return checkParentPaths(e,t,a,o,c)}))}function checkParentPathsSync(e,t,r,o){const c=i.resolve(i.dirname(e));const s=i.resolve(i.dirname(r));if(s===c||s===i.parse(s).root)return;let a;try{a=n.statSync(s,{bigint:true})}catch(e){if(e.code==="ENOENT")return;throw e}if(areIdentical(t,a)){throw new Error(errMsg(e,r,o))}return checkParentPathsSync(e,t,s,o)}function areIdentical(e,t){return t.ino&&t.dev&&t.ino===e.ino&&t.dev===e.dev}function isSrcSubdir(e,t){const r=i.resolve(e).split(i.sep).filter((e=>e));const n=i.resolve(t).split(i.sep).filter((e=>e));return r.reduce(((e,t,r)=>e&&n[r]===t),true)}function errMsg(e,t,r){return`Cannot ${r} '${e}' to a subdirectory of itself, '${t}'.`}e.exports={checkPaths:checkPaths,checkPathsSync:checkPathsSync,checkParentPaths:checkParentPaths,checkParentPathsSync:checkParentPathsSync,isSrcSubdir:isSrcSubdir,areIdentical:areIdentical}},309:(e,t,r)=>{"use strict";const n=r(127);function utimesMillis(e,t,r,i){n.open(e,"r+",((e,o)=>{if(e)return i(e);n.futimes(o,t,r,(e=>{n.close(o,(t=>{if(i)i(e||t)}))}))}))}function utimesMillisSync(e,t,r){const i=n.openSync(e,"r+");n.futimesSync(i,t,r);return n.closeSync(i)}e.exports={utimesMillis:utimesMillis,utimesMillisSync:utimesMillisSync}},132:e=>{"use strict";e.exports=clone;var t=Object.getPrototypeOf||function(e){return e.__proto__};function clone(e){if(e===null||typeof e!=="object")return e;if(e instanceof Object)var r={__proto__:t(e)};else var r=Object.create(null);Object.getOwnPropertyNames(e).forEach((function(t){Object.defineProperty(r,t,Object.getOwnPropertyDescriptor(e,t))}));return r}},127:(e,t,r)=>{var n=r(147);var i=r(367);var o=r(876);var c=r(132);var s=r(837);var a;var u;if(typeof Symbol==="function"&&typeof Symbol.for==="function"){a=Symbol.for("graceful-fs.queue");u=Symbol.for("graceful-fs.previous")}else{a="___graceful-fs.queue";u="___graceful-fs.previous"}function noop(){}function publishQueue(e,t){Object.defineProperty(e,a,{get:function(){return t}})}var f=noop;if(s.debuglog)f=s.debuglog("gfs4");else if(/\bgfs4\b/i.test(process.env.NODE_DEBUG||""))f=function(){var e=s.format.apply(s,arguments);e="GFS4: "+e.split(/\n/).join("\nGFS4: ");console.error(e)};if(!n[a]){var l=global[a]||[];publishQueue(n,l);n.close=function(e){function close(t,r){return e.call(n,t,(function(e){if(!e){resetQueue()}if(typeof r==="function")r.apply(this,arguments)}))}Object.defineProperty(close,u,{value:e});return close}(n.close);n.closeSync=function(e){function closeSync(t){e.apply(n,arguments);resetQueue()}Object.defineProperty(closeSync,u,{value:e});return closeSync}(n.closeSync);if(/\bgfs4\b/i.test(process.env.NODE_DEBUG||"")){process.on("exit",(function(){f(n[a]);r(491).equal(n[a].length,0)}))}}if(!global[a]){publishQueue(global,n[a])}e.exports=patch(c(n));if(process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH&&!n.__patched){e.exports=patch(n);n.__patched=true}function patch(e){i(e);e.gracefulify=patch;e.createReadStream=createReadStream;e.createWriteStream=createWriteStream;var t=e.readFile;e.readFile=readFile;function readFile(e,r,n){if(typeof r==="function")n=r,r=null;return go$readFile(e,r,n);function go$readFile(e,r,n,i){return t(e,r,(function(t){if(t&&(t.code==="EMFILE"||t.code==="ENFILE"))enqueue([go$readFile,[e,r,n],t,i||Date.now(),Date.now()]);else{if(typeof n==="function")n.apply(this,arguments)}}))}}var r=e.writeFile;e.writeFile=writeFile;function writeFile(e,t,n,i){if(typeof n==="function")i=n,n=null;return go$writeFile(e,t,n,i);function go$writeFile(e,t,n,i,o){return r(e,t,n,(function(r){if(r&&(r.code==="EMFILE"||r.code==="ENFILE"))enqueue([go$writeFile,[e,t,n,i],r,o||Date.now(),Date.now()]);else{if(typeof i==="function")i.apply(this,arguments)}}))}}var n=e.appendFile;if(n)e.appendFile=appendFile;function appendFile(e,t,r,i){if(typeof r==="function")i=r,r=null;return go$appendFile(e,t,r,i);function go$appendFile(e,t,r,i,o){return n(e,t,r,(function(n){if(n&&(n.code==="EMFILE"||n.code==="ENFILE"))enqueue([go$appendFile,[e,t,r,i],n,o||Date.now(),Date.now()]);else{if(typeof i==="function")i.apply(this,arguments)}}))}}var c=e.copyFile;if(c)e.copyFile=copyFile;function copyFile(e,t,r,n){if(typeof r==="function"){n=r;r=0}return go$copyFile(e,t,r,n);function go$copyFile(e,t,r,n,i){return c(e,t,r,(function(o){if(o&&(o.code==="EMFILE"||o.code==="ENFILE"))enqueue([go$copyFile,[e,t,r,n],o,i||Date.now(),Date.now()]);else{if(typeof n==="function")n.apply(this,arguments)}}))}}var s=e.readdir;e.readdir=readdir;var a=/^v[0-5]\./;function readdir(e,t,r){if(typeof t==="function")r=t,t=null;var n=a.test(process.version)?function go$readdir(e,t,r,n){return s(e,fs$readdirCallback(e,t,r,n))}:function go$readdir(e,t,r,n){return s(e,t,fs$readdirCallback(e,t,r,n))};return n(e,t,r);function fs$readdirCallback(e,t,r,i){return function(o,c){if(o&&(o.code==="EMFILE"||o.code==="ENFILE"))enqueue([n,[e,t,r],o,i||Date.now(),Date.now()]);else{if(c&&c.sort)c.sort();if(typeof r==="function")r.call(this,o,c)}}}}if(process.version.substr(0,4)==="v0.8"){var u=o(e);ReadStream=u.ReadStream;WriteStream=u.WriteStream}var f=e.ReadStream;if(f){ReadStream.prototype=Object.create(f.prototype);ReadStream.prototype.open=ReadStream$open}var l=e.WriteStream;if(l){WriteStream.prototype=Object.create(l.prototype);WriteStream.prototype.open=WriteStream$open}Object.defineProperty(e,"ReadStream",{get:function(){return ReadStream},set:function(e){ReadStream=e},enumerable:true,configurable:true});Object.defineProperty(e,"WriteStream",{get:function(){return WriteStream},set:function(e){WriteStream=e},enumerable:true,configurable:true});var y=ReadStream;Object.defineProperty(e,"FileReadStream",{get:function(){return y},set:function(e){y=e},enumerable:true,configurable:true});var d=WriteStream;Object.defineProperty(e,"FileWriteStream",{get:function(){return d},set:function(e){d=e},enumerable:true,configurable:true});function ReadStream(e,t){if(this instanceof ReadStream)return f.apply(this,arguments),this;else return ReadStream.apply(Object.create(ReadStream.prototype),arguments)}function ReadStream$open(){var e=this;open(e.path,e.flags,e.mode,(function(t,r){if(t){if(e.autoClose)e.destroy();e.emit("error",t)}else{e.fd=r;e.emit("open",r);e.read()}}))}function WriteStream(e,t){if(this instanceof WriteStream)return l.apply(this,arguments),this;else return WriteStream.apply(Object.create(WriteStream.prototype),arguments)}function WriteStream$open(){var e=this;open(e.path,e.flags,e.mode,(function(t,r){if(t){e.destroy();e.emit("error",t)}else{e.fd=r;e.emit("open",r)}}))}function createReadStream(t,r){return new e.ReadStream(t,r)}function createWriteStream(t,r){return new e.WriteStream(t,r)}var m=e.open;e.open=open;function open(e,t,r,n){if(typeof r==="function")n=r,r=null;return go$open(e,t,r,n);function go$open(e,t,r,n,i){return m(e,t,r,(function(o,c){if(o&&(o.code==="EMFILE"||o.code==="ENFILE"))enqueue([go$open,[e,t,r,n],o,i||Date.now(),Date.now()]);else{if(typeof n==="function")n.apply(this,arguments)}}))}}return e}function enqueue(e){f("ENQUEUE",e[0].name,e[1]);n[a].push(e);retry()}var y;function resetQueue(){var e=Date.now();for(var t=0;t2){n[a][t][3]=e;n[a][t][4]=e}}retry()}function retry(){clearTimeout(y);y=undefined;if(n[a].length===0)return;var e=n[a].shift();var t=e[0];var r=e[1];var i=e[2];var o=e[3];var c=e[4];if(o===undefined){f("RETRY",t.name,r);t.apply(null,r)}else if(Date.now()-o>=6e4){f("TIMEOUT",t.name,r);var s=r.pop();if(typeof s==="function")s.call(null,i)}else{var u=Date.now()-c;var l=Math.max(c-o,1);var d=Math.min(l*1.2,100);if(u>=d){f("RETRY",t.name,r);t.apply(null,r.concat([o]))}else{n[a].push(e)}}if(y===undefined){y=setTimeout(retry,0)}}},876:(e,t,r)=>{var n=r(781).Stream;e.exports=legacy;function legacy(e){return{ReadStream:ReadStream,WriteStream:WriteStream};function ReadStream(t,r){if(!(this instanceof ReadStream))return new ReadStream(t,r);n.call(this);var i=this;this.path=t;this.fd=null;this.readable=true;this.paused=false;this.flags="r";this.mode=438;this.bufferSize=64*1024;r=r||{};var o=Object.keys(r);for(var c=0,s=o.length;cthis.end){throw new Error("start must be <= end")}this.pos=this.start}if(this.fd!==null){process.nextTick((function(){i._read()}));return}e.open(this.path,this.flags,this.mode,(function(e,t){if(e){i.emit("error",e);i.readable=false;return}i.fd=t;i.emit("open",t);i._read()}))}function WriteStream(t,r){if(!(this instanceof WriteStream))return new WriteStream(t,r);n.call(this);this.path=t;this.fd=null;this.writable=true;this.flags="w";this.encoding="binary";this.mode=438;this.bytesWritten=0;r=r||{};var i=Object.keys(r);for(var o=0,c=i.length;o= zero")}this.pos=this.start}this.busy=false;this._queue=[];if(this.fd===null){this._open=e.open;this._queue.push([this._open,this.path,this.flags,this.mode,undefined]);this.flush()}}}},367:(e,t,r)=>{var n=r(57);var i=process.cwd;var o=null;var c=process.env.GRACEFUL_FS_PLATFORM||process.platform;process.cwd=function(){if(!o)o=i.call(process);return o};try{process.cwd()}catch(e){}if(typeof process.chdir==="function"){var s=process.chdir;process.chdir=function(e){o=null;s.call(process,e)};if(Object.setPrototypeOf)Object.setPrototypeOf(process.chdir,s)}e.exports=patch;function patch(e){if(n.hasOwnProperty("O_SYMLINK")&&process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)){patchLchmod(e)}if(!e.lutimes){patchLutimes(e)}e.chown=chownFix(e.chown);e.fchown=chownFix(e.fchown);e.lchown=chownFix(e.lchown);e.chmod=chmodFix(e.chmod);e.fchmod=chmodFix(e.fchmod);e.lchmod=chmodFix(e.lchmod);e.chownSync=chownFixSync(e.chownSync);e.fchownSync=chownFixSync(e.fchownSync);e.lchownSync=chownFixSync(e.lchownSync);e.chmodSync=chmodFixSync(e.chmodSync);e.fchmodSync=chmodFixSync(e.fchmodSync);e.lchmodSync=chmodFixSync(e.lchmodSync);e.stat=statFix(e.stat);e.fstat=statFix(e.fstat);e.lstat=statFix(e.lstat);e.statSync=statFixSync(e.statSync);e.fstatSync=statFixSync(e.fstatSync);e.lstatSync=statFixSync(e.lstatSync);if(e.chmod&&!e.lchmod){e.lchmod=function(e,t,r){if(r)process.nextTick(r)};e.lchmodSync=function(){}}if(e.chown&&!e.lchown){e.lchown=function(e,t,r,n){if(n)process.nextTick(n)};e.lchownSync=function(){}}if(c==="win32"){e.rename=typeof e.rename!=="function"?e.rename:function(t){function rename(r,n,i){var o=Date.now();var c=0;t(r,n,(function CB(s){if(s&&(s.code==="EACCES"||s.code==="EPERM")&&Date.now()-o<6e4){setTimeout((function(){e.stat(n,(function(e,o){if(e&&e.code==="ENOENT")t(r,n,CB);else i(s)}))}),c);if(c<100)c+=10;return}if(i)i(s)}))}if(Object.setPrototypeOf)Object.setPrototypeOf(rename,t);return rename}(e.rename)}e.read=typeof e.read!=="function"?e.read:function(t){function read(r,n,i,o,c,s){var a;if(s&&typeof s==="function"){var u=0;a=function(f,l,y){if(f&&f.code==="EAGAIN"&&u<10){u++;return t.call(e,r,n,i,o,c,a)}s.apply(this,arguments)}}return t.call(e,r,n,i,o,c,a)}if(Object.setPrototypeOf)Object.setPrototypeOf(read,t);return read}(e.read);e.readSync=typeof e.readSync!=="function"?e.readSync:function(t){return function(r,n,i,o,c){var s=0;while(true){try{return t.call(e,r,n,i,o,c)}catch(e){if(e.code==="EAGAIN"&&s<10){s++;continue}throw e}}}}(e.readSync);function patchLchmod(e){e.lchmod=function(t,r,i){e.open(t,n.O_WRONLY|n.O_SYMLINK,r,(function(t,n){if(t){if(i)i(t);return}e.fchmod(n,r,(function(t){e.close(n,(function(e){if(i)i(t||e)}))}))}))};e.lchmodSync=function(t,r){var i=e.openSync(t,n.O_WRONLY|n.O_SYMLINK,r);var o=true;var c;try{c=e.fchmodSync(i,r);o=false}finally{if(o){try{e.closeSync(i)}catch(e){}}else{e.closeSync(i)}}return c}}function patchLutimes(e){if(n.hasOwnProperty("O_SYMLINK")&&e.futimes){e.lutimes=function(t,r,i,o){e.open(t,n.O_SYMLINK,(function(t,n){if(t){if(o)o(t);return}e.futimes(n,r,i,(function(t){e.close(n,(function(e){if(o)o(t||e)}))}))}))};e.lutimesSync=function(t,r,i){var o=e.openSync(t,n.O_SYMLINK);var c;var s=true;try{c=e.futimesSync(o,r,i);s=false}finally{if(s){try{e.closeSync(o)}catch(e){}}else{e.closeSync(o)}}return c}}else if(e.futimes){e.lutimes=function(e,t,r,n){if(n)process.nextTick(n)};e.lutimesSync=function(){}}}function chmodFix(t){if(!t)return t;return function(r,n,i){return t.call(e,r,n,(function(e){if(chownErOk(e))e=null;if(i)i.apply(this,arguments)}))}}function chmodFixSync(t){if(!t)return t;return function(r,n){try{return t.call(e,r,n)}catch(e){if(!chownErOk(e))throw e}}}function chownFix(t){if(!t)return t;return function(r,n,i,o){return t.call(e,r,n,i,(function(e){if(chownErOk(e))e=null;if(o)o.apply(this,arguments)}))}}function chownFixSync(t){if(!t)return t;return function(r,n,i){try{return t.call(e,r,n,i)}catch(e){if(!chownErOk(e))throw e}}}function statFix(t){if(!t)return t;return function(r,n,i){if(typeof n==="function"){i=n;n=null}function callback(e,t){if(t){if(t.uid<0)t.uid+=4294967296;if(t.gid<0)t.gid+=4294967296}if(i)i.apply(this,arguments)}return n?t.call(e,r,n,callback):t.call(e,r,callback)}}function statFixSync(t){if(!t)return t;return function(r,n){var i=n?t.call(e,r,n):t.call(e,r);if(i){if(i.uid<0)i.uid+=4294967296;if(i.gid<0)i.gid+=4294967296}return i}}function chownErOk(e){if(!e)return true;if(e.code==="ENOSYS")return true;var t=!process.getuid||process.getuid()!==0;if(t){if(e.code==="EINVAL"||e.code==="EPERM")return true}return false}}},654:(e,t,r)=>{let n;try{n=r(127)}catch(e){n=r(147)}const i=r(5);const{stringify:o,stripBom:c}=r(208);async function _readFile(e,t={}){if(typeof t==="string"){t={encoding:t}}const r=t.fs||n;const o="throws"in t?t.throws:true;let s=await i.fromCallback(r.readFile)(e,t);s=c(s);let a;try{a=JSON.parse(s,t?t.reviver:null)}catch(t){if(o){t.message=`${e}: ${t.message}`;throw t}else{return null}}return a}const s=i.fromPromise(_readFile);function readFileSync(e,t={}){if(typeof t==="string"){t={encoding:t}}const r=t.fs||n;const i="throws"in t?t.throws:true;try{let n=r.readFileSync(e,t);n=c(n);return JSON.parse(n,t.reviver)}catch(t){if(i){t.message=`${e}: ${t.message}`;throw t}else{return null}}}async function _writeFile(e,t,r={}){const c=r.fs||n;const s=o(t,r);await i.fromCallback(c.writeFile)(e,s,r)}const a=i.fromPromise(_writeFile);function writeFileSync(e,t,r={}){const i=r.fs||n;const c=o(t,r);return i.writeFileSync(e,c,r)}const u={readFile:s,readFileSync:readFileSync,writeFile:a,writeFileSync:writeFileSync};e.exports=u},208:e=>{function stringify(e,{EOL:t="\n",finalEOL:r=true,replacer:n=null,spaces:i}={}){const o=r?t:"";const c=JSON.stringify(e,n,i);return c.replace(/\n/g,t)+o}function stripBom(e){if(Buffer.isBuffer(e))e=e.toString("utf8");return e.replace(/^\uFEFF/,"")}e.exports={stringify:stringify,stripBom:stripBom}},5:(e,t)=>{"use strict";t.fromCallback=function(e){return Object.defineProperty((function(...t){if(typeof t[t.length-1]==="function")e.apply(this,t);else{return new Promise(((r,n)=>{e.call(this,...t,((e,t)=>e!=null?n(e):r(t)))}))}}),"name",{value:e.name})};t.fromPromise=function(e){return Object.defineProperty((function(...t){const r=t[t.length-1];if(typeof r!=="function")return e.apply(this,t);else e.apply(this,t.slice(0,-1)).then((e=>r(null,e)),r)}),"name",{value:e.name})}},491:e=>{"use strict";e.exports=require("assert")},57:e=>{"use strict";e.exports=require("constants")},147:e=>{"use strict";e.exports=require("fs")},17:e=>{"use strict";e.exports=require("path")},781:e=>{"use strict";e.exports=require("stream")},837:e=>{"use strict";e.exports=require("util")}};var t={};function __nccwpck_require__(r){var n=t[r];if(n!==undefined){return n.exports}var i=t[r]={exports:{}};var o=true;try{e[r](i,i.exports,__nccwpck_require__);o=false}finally{if(o)delete t[r]}return i.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(81);module.exports=r})(); \ No newline at end of file +(()=>{var t={901:(t,e,r)=>{"use strict";const n=r(24);const i=r(928);const s=r(552).mkdirsSync;const c=r(213).utimesMillisSync;const o=r(0);function copySync(t,e,r){if(typeof r==="function"){r={filter:r}}r=r||{};r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0002")}const{srcStat:c,destStat:a}=o.checkPathsSync(t,e,"copy",r);o.checkParentPathsSync(t,c,e,"copy");if(r.filter&&!r.filter(t,e))return;const u=i.dirname(e);if(!n.existsSync(u))s(u);return getStats(a,t,e,r)}function getStats(t,e,r,i){const s=i.dereference?n.statSync:n.lstatSync;const c=s(e);if(c.isDirectory())return onDir(c,t,e,r,i);else if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);else if(c.isSymbolicLink())return onLink(t,e,r,i);else if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);else if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}function onFile(t,e,r,n,i){if(!e)return copyFile(t,r,n,i);return mayCopyFile(t,r,n,i)}function mayCopyFile(t,e,r,i){if(i.overwrite){n.unlinkSync(r);return copyFile(t,e,r,i)}else if(i.errorOnExist){throw new Error(`'${r}' already exists`)}}function copyFile(t,e,r,i){n.copyFileSync(e,r);if(i.preserveTimestamps)handleTimestamps(t.mode,e,r);return setDestMode(r,t.mode)}function handleTimestamps(t,e,r){if(fileIsNotWritable(t))makeFileWritable(r,t);return setDestTimestamps(e,r)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return setDestMode(t,e|128)}function setDestMode(t,e){return n.chmodSync(t,e)}function setDestTimestamps(t,e){const r=n.statSync(t);return c(e,r.atime,r.mtime)}function onDir(t,e,r,n,i){if(!e)return mkDirAndCopy(t.mode,r,n,i);return copyDir(r,n,i)}function mkDirAndCopy(t,e,r,i){n.mkdirSync(r);copyDir(e,r,i);return setDestMode(r,t)}function copyDir(t,e,r){const i=n.opendirSync(t);try{let n;while((n=i.readSync())!==null){copyDirItem(n.name,t,e,r)}}finally{i.closeSync()}}function copyDirItem(t,e,r,n){const s=i.join(e,t);const c=i.join(r,t);if(n.filter&&!n.filter(s,c))return;const{destStat:a}=o.checkPathsSync(s,c,"copy",n);return getStats(a,s,c,n)}function onLink(t,e,r,s){let c=n.readlinkSync(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlinkSync(c,r)}else{let t;try{t=n.readlinkSync(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlinkSync(c,r);throw t}if(s.dereference){t=i.resolve(process.cwd(),t)}if(c!==t){if(o.isSrcSubdir(c,t)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${t}'.`)}if(o.isSrcSubdir(t,c)){throw new Error(`Cannot overwrite '${t}' with '${c}'.`)}}return copyLink(c,r)}}function copyLink(t,e){n.unlinkSync(e);return n.symlinkSync(t,e)}t.exports=copySync},600:(t,e,r)=>{"use strict";const n=r(423);const i=r(928);const{mkdirs:s}=r(552);const{pathExists:c}=r(170);const{utimesMillis:o}=r(213);const a=r(0);const{asyncIteratorConcurrentProcess:u}=r(768);async function copy(t,e,r={}){if(typeof r==="function"){r={filter:r}}r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0001")}const{srcStat:n,destStat:o}=await a.checkPaths(t,e,"copy",r);await a.checkParentPaths(t,n,e,"copy");const u=await runFilter(t,e,r);if(!u)return;const y=i.dirname(e);const l=await c(y);if(!l){await s(y)}await getStatsAndPerformCopy(o,t,e,r)}async function runFilter(t,e,r){if(!r.filter)return true;return r.filter(t,e)}async function getStatsAndPerformCopy(t,e,r,i){const s=i.dereference?n.stat:n.lstat;const c=await s(e);if(c.isDirectory())return onDir(c,t,e,r,i);if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);if(c.isSymbolicLink())return onLink(t,e,r,i);if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}async function onFile(t,e,r,i,s){if(!e)return copyFile(t,r,i,s);if(s.overwrite){await n.unlink(i);return copyFile(t,r,i,s)}if(s.errorOnExist){throw new Error(`'${i}' already exists`)}}async function copyFile(t,e,r,i){await n.copyFile(e,r);if(i.preserveTimestamps){if(fileIsNotWritable(t.mode)){await makeFileWritable(r,t.mode)}const i=await n.stat(e);await o(r,i.atime,i.mtime)}return n.chmod(r,t.mode)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return n.chmod(t,e|128)}async function onDir(t,e,r,s,c){if(!e){await n.mkdir(s)}await u(await n.opendir(r),(async t=>{const e=i.join(r,t.name);const n=i.join(s,t.name);const o=await runFilter(e,n,c);if(o){const{destStat:t}=await a.checkPaths(e,n,"copy",c);await getStatsAndPerformCopy(t,e,n,c)}}));if(!e){await n.chmod(s,t.mode)}}async function onLink(t,e,r,s){let c=await n.readlink(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlink(c,r)}let o=null;try{o=await n.readlink(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlink(c,r);throw t}if(s.dereference){o=i.resolve(process.cwd(),o)}if(c!==o){if(a.isSrcSubdir(c,o)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${o}'.`)}if(a.isSrcSubdir(o,c)){throw new Error(`Cannot overwrite '${o}' with '${c}'.`)}}await n.unlink(r);return n.symlink(c,r)}t.exports=copy},509:(t,e,r)=>{"use strict";const n=r(282).fromPromise;t.exports={copy:n(r(600)),copySync:r(901)}},817:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(720);const a=n((async function emptyDir(t){let e;try{e=await i.readdir(t)}catch{return c.mkdirs(t)}return Promise.all(e.map((e=>o.remove(s.join(t,e)))))}));function emptyDirSync(t){let e;try{e=i.readdirSync(t)}catch{return c.mkdirsSync(t)}e.forEach((e=>{e=s.join(t,e);o.removeSync(e)}))}t.exports={emptyDirSync:emptyDirSync,emptydirSync:emptyDirSync,emptyDir:a,emptydir:a}},46:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);async function createFile(t){let e;try{e=await s.stat(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);let n=null;try{n=await s.stat(r)}catch(e){if(e.code==="ENOENT"){await c.mkdirs(r);await s.writeFile(t,"");return}else{throw e}}if(n.isDirectory()){await s.writeFile(t,"")}else{await s.readdir(r)}}function createFileSync(t){let e;try{e=s.statSync(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);try{if(!s.statSync(r).isDirectory()){s.readdirSync(r)}}catch(t){if(t&&t.code==="ENOENT")c.mkdirsSync(r);else throw t}s.writeFileSync(t,"")}t.exports={createFile:n(createFile),createFileSync:createFileSync}},58:(t,e,r)=>{"use strict";const{createFile:n,createFileSync:i}=r(46);const{createLink:s,createLinkSync:c}=r(196);const{createSymlink:o,createSymlinkSync:a}=r(933);t.exports={createFile:n,createFileSync:i,ensureFile:n,ensureFileSync:i,createLink:s,createLinkSync:c,ensureLink:s,ensureLinkSync:c,createSymlink:o,createSymlinkSync:a,ensureSymlink:o,ensureSymlinkSync:a}},196:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);const{pathExists:o}=r(170);const{areIdentical:a}=r(0);async function createLink(t,e){let r;try{r=await s.lstat(e)}catch{}let n;try{n=await s.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}if(r&&a(n,r))return;const u=i.dirname(e);const y=await o(u);if(!y){await c.mkdirs(u)}await s.link(t,e)}function createLinkSync(t,e){let r;try{r=s.lstatSync(e)}catch{}try{const e=s.lstatSync(t);if(r&&a(e,r))return}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}const n=i.dirname(e);const o=s.existsSync(n);if(o)return s.linkSync(t,e);c.mkdirsSync(n);return s.linkSync(t,e)}t.exports={createLink:n(createLink),createLinkSync:createLinkSync}},492:(t,e,r)=>{"use strict";const n=r(928);const i=r(423);const{pathExists:s}=r(170);const c=r(282).fromPromise;async function symlinkPaths(t,e){if(n.isAbsolute(t)){try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:t}}const r=n.dirname(e);const c=n.join(r,t);const o=await s(c);if(o){return{toCwd:c,toDst:t}}try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:n.relative(r,t)}}function symlinkPathsSync(t,e){if(n.isAbsolute(t)){const e=i.existsSync(t);if(!e)throw new Error("absolute srcpath does not exist");return{toCwd:t,toDst:t}}const r=n.dirname(e);const s=n.join(r,t);const c=i.existsSync(s);if(c){return{toCwd:s,toDst:t}}const o=i.existsSync(t);if(!o)throw new Error("relative srcpath does not exist");return{toCwd:t,toDst:n.relative(r,t)}}t.exports={symlinkPaths:c(symlinkPaths),symlinkPathsSync:symlinkPathsSync}},126:(t,e,r)=>{"use strict";const n=r(423);const i=r(282).fromPromise;async function symlinkType(t,e){if(e)return e;let r;try{r=await n.lstat(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}function symlinkTypeSync(t,e){if(e)return e;let r;try{r=n.lstatSync(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}t.exports={symlinkType:i(symlinkType),symlinkTypeSync:symlinkTypeSync}},933:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(928);const s=r(423);const{mkdirs:c,mkdirsSync:o}=r(552);const{symlinkPaths:a,symlinkPathsSync:u}=r(492);const{symlinkType:y,symlinkTypeSync:l}=r(126);const{pathExists:f}=r(170);const{areIdentical:m}=r(0);async function createSymlink(t,e,r){let n;try{n=await s.lstat(e)}catch{}if(n&&n.isSymbolicLink()){const[r,n]=await Promise.all([s.stat(t),s.stat(e)]);if(m(r,n))return}const o=await a(t,e);t=o.toDst;const u=await y(o.toCwd,r);const l=i.dirname(e);if(!await f(l)){await c(l)}return s.symlink(t,e,u)}function createSymlinkSync(t,e,r){let n;try{n=s.lstatSync(e)}catch{}if(n&&n.isSymbolicLink()){const r=s.statSync(t);const n=s.statSync(e);if(m(r,n))return}const c=u(t,e);t=c.toDst;r=l(c.toCwd,r);const a=i.dirname(e);const y=s.existsSync(a);if(y)return s.symlinkSync(t,e,r);o(a);return s.symlinkSync(t,e,r)}t.exports={createSymlink:n(createSymlink),createSymlinkSync:createSymlinkSync}},423:(t,e,r)=>{"use strict";const n=r(282).fromCallback;const i=r(24);const s=["access","appendFile","chmod","chown","close","copyFile","cp","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","glob","lchmod","lchown","lutimes","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","statfs","symlink","truncate","unlink","utimes","writeFile"].filter((t=>typeof i[t]==="function"));Object.assign(e,i);s.forEach((t=>{e[t]=n(i[t])}));e.exists=function(t,e){if(typeof e==="function"){return i.exists(t,e)}return new Promise((e=>i.exists(t,e)))};e.read=function(t,e,r,n,s,c){if(typeof c==="function"){return i.read(t,e,r,n,s,c)}return new Promise(((c,o)=>{i.read(t,e,r,n,s,((t,e,r)=>{if(t)return o(t);c({bytesRead:e,buffer:r})}))}))};e.write=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.write(t,e,...r)}return new Promise(((n,s)=>{i.write(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffer:r})}))}))};e.readv=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.readv(t,e,...r)}return new Promise(((n,s)=>{i.readv(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesRead:e,buffers:r})}))}))};e.writev=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.writev(t,e,...r)}return new Promise(((n,s)=>{i.writev(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffers:r})}))}))};if(typeof i.realpath.native==="function"){e.realpath.native=n(i.realpath.native)}else{process.emitWarning("fs.realpath.native is not a function. Is fs being monkey-patched?","Warning","fs-extra-WARN0003")}},643:(t,e,r)=>{"use strict";t.exports={...r(423),...r(509),...r(817),...r(58),...r(342),...r(552),...r(29),...r(34),...r(170),...r(720)}},342:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(424);i.outputJson=n(r(472));i.outputJsonSync=r(618);i.outputJSON=i.outputJson;i.outputJSONSync=i.outputJsonSync;i.writeJSON=i.writeJson;i.writeJSONSync=i.writeJsonSync;i.readJSON=i.readJson;i.readJSONSync=i.readJsonSync;t.exports=i},424:(t,e,r)=>{"use strict";const n=r(395);t.exports={readJson:n.readFile,readJsonSync:n.readFileSync,writeJson:n.writeFile,writeJsonSync:n.writeFileSync}},618:(t,e,r)=>{"use strict";const{stringify:n}=r(366);const{outputFileSync:i}=r(34);function outputJsonSync(t,e,r){const s=n(e,r);i(t,s,r)}t.exports=outputJsonSync},472:(t,e,r)=>{"use strict";const{stringify:n}=r(366);const{outputFile:i}=r(34);async function outputJson(t,e,r={}){const s=n(e,r);await i(t,s,r)}t.exports=outputJson},552:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const{makeDir:i,makeDirSync:s}=r(974);const c=n(i);t.exports={mkdirs:c,mkdirsSync:s,mkdirp:c,mkdirpSync:s,ensureDir:c,ensureDirSync:s}},974:(t,e,r)=>{"use strict";const n=r(423);const{checkPath:i}=r(9);const getMode=t=>{const e={mode:511};if(typeof t==="number")return t;return{...e,...t}.mode};t.exports.makeDir=async(t,e)=>{i(t);return n.mkdir(t,{mode:getMode(e),recursive:true})};t.exports.makeDirSync=(t,e)=>{i(t);return n.mkdirSync(t,{mode:getMode(e),recursive:true})}},9:(t,e,r)=>{"use strict";const n=r(928);t.exports.checkPath=function checkPath(t){if(process.platform==="win32"){const e=/[<>:"|?*]/.test(t.replace(n.parse(t).root,""));if(e){const e=new Error(`Path contains invalid characters: ${t}`);e.code="EINVAL";throw e}}}},29:(t,e,r)=>{"use strict";const n=r(282).fromPromise;t.exports={move:n(r(816)),moveSync:r(610)}},610:(t,e,r)=>{"use strict";const n=r(24);const i=r(928);const s=r(509).copySync;const c=r(720).removeSync;const o=r(552).mkdirpSync;const a=r(0);function moveSync(t,e,r){r=r||{};const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=a.checkPathsSync(t,e,"move",r);a.checkParentPathsSync(t,s,e,"move");if(!isParentRoot(e))o(i.dirname(e));return doRename(t,e,n,c)}function isParentRoot(t){const e=i.dirname(t);const r=i.parse(e);return r.root===e}function doRename(t,e,r,i){if(i)return rename(t,e,r);if(r){c(e);return rename(t,e,r)}if(n.existsSync(e))throw new Error("dest already exists.");return rename(t,e,r)}function rename(t,e,r){try{n.renameSync(t,e)}catch(n){if(n.code!=="EXDEV")throw n;return moveAcrossDevice(t,e,r)}}function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};s(t,e,n);return c(t)}t.exports=moveSync},816:(t,e,r)=>{"use strict";const n=r(423);const i=r(928);const{copy:s}=r(509);const{remove:c}=r(720);const{mkdirp:o}=r(552);const{pathExists:a}=r(170);const u=r(0);async function move(t,e,r={}){const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=await u.checkPaths(t,e,"move",r);await u.checkParentPaths(t,s,e,"move");const a=i.dirname(e);const y=i.parse(a);if(y.root!==a){await o(a)}return doRename(t,e,n,c)}async function doRename(t,e,r,i){if(!i){if(r){await c(e)}else if(await a(e)){throw new Error("dest already exists.")}}try{await n.rename(t,e)}catch(n){if(n.code!=="EXDEV"){throw n}await moveAcrossDevice(t,e,r)}}async function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};await s(t,e,n);return c(t)}t.exports=move},34:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(170).pathExists;async function outputFile(t,e,r="utf-8"){const n=s.dirname(t);if(!await o(n)){await c.mkdirs(n)}return i.writeFile(t,e,r)}function outputFileSync(t,...e){const r=s.dirname(t);if(!i.existsSync(r)){c.mkdirsSync(r)}i.writeFileSync(t,...e)}t.exports={outputFile:n(outputFile),outputFileSync:outputFileSync}},170:(t,e,r)=>{"use strict";const n=r(282).fromPromise;const i=r(423);function pathExists(t){return i.access(t).then((()=>true)).catch((()=>false))}t.exports={pathExists:n(pathExists),pathExistsSync:i.existsSync}},720:(t,e,r)=>{"use strict";const n=r(24);const i=r(282).fromCallback;function remove(t,e){n.rm(t,{recursive:true,force:true},e)}function removeSync(t){n.rmSync(t,{recursive:true,force:true})}t.exports={remove:i(remove),removeSync:removeSync}},768:t=>{"use strict";async function asyncIteratorConcurrentProcess(t,e){const r=[];for await(const n of t){r.push(e(n).then((()=>null),(t=>t??new Error("unknown error"))))}await Promise.all(r.map((t=>t.then((t=>{if(t!==null)throw t})))))}t.exports={asyncIteratorConcurrentProcess:asyncIteratorConcurrentProcess}},0:(t,e,r)=>{"use strict";const n=r(423);const i=r(928);const s=r(282).fromPromise;function getStats(t,e,r){const i=r.dereference?t=>n.stat(t,{bigint:true}):t=>n.lstat(t,{bigint:true});return Promise.all([i(t),i(e).catch((t=>{if(t.code==="ENOENT")return null;throw t}))]).then((([t,e])=>({srcStat:t,destStat:e})))}function getStatsSync(t,e,r){let i;const s=r.dereference?t=>n.statSync(t,{bigint:true}):t=>n.lstatSync(t,{bigint:true});const c=s(t);try{i=s(e)}catch(t){if(t.code==="ENOENT")return{srcStat:c,destStat:null};throw t}return{srcStat:c,destStat:i}}async function checkPaths(t,e,r,n){const{srcStat:s,destStat:c}=await getStats(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}function checkPathsSync(t,e,r,n){const{srcStat:s,destStat:c}=getStatsSync(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}async function checkParentPaths(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=await n.stat(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPaths(t,e,o,s)}function checkParentPathsSync(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=n.statSync(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPathsSync(t,e,o,s)}function areIdentical(t,e){return e.ino!==undefined&&e.dev!==undefined&&e.ino===t.ino&&e.dev===t.dev}function isSrcSubdir(t,e){const r=i.resolve(t).split(i.sep).filter((t=>t));const n=i.resolve(e).split(i.sep).filter((t=>t));return r.every(((t,e)=>n[e]===t))}function errMsg(t,e,r){return`Cannot ${r} '${t}' to a subdirectory of itself, '${e}'.`}t.exports={checkPaths:s(checkPaths),checkPathsSync:checkPathsSync,checkParentPaths:s(checkParentPaths),checkParentPathsSync:checkParentPathsSync,isSrcSubdir:isSrcSubdir,areIdentical:areIdentical}},213:(t,e,r)=>{"use strict";const n=r(423);const i=r(282).fromPromise;async function utimesMillis(t,e,r){const i=await n.open(t,"r+");let s=null;try{await n.futimes(i,e,r)}finally{try{await n.close(i)}catch(t){s=t}}if(s){throw s}}function utimesMillisSync(t,e,r){const i=n.openSync(t,"r+");n.futimesSync(i,e,r);return n.closeSync(i)}t.exports={utimesMillis:i(utimesMillis),utimesMillisSync:utimesMillisSync}},395:(t,e,r)=>{let n;try{n=r(24)}catch(t){n=r(896)}const i=r(282);const{stringify:s,stripBom:c}=r(366);async function _readFile(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const s="throws"in e?e.throws:true;let o=await i.fromCallback(r.readFile)(t,e);o=c(o);let a;try{a=JSON.parse(o,e?e.reviver:null)}catch(e){if(s){e.message=`${t}: ${e.message}`;throw e}else{return null}}return a}const o=i.fromPromise(_readFile);function readFileSync(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const i="throws"in e?e.throws:true;try{let n=r.readFileSync(t,e);n=c(n);return JSON.parse(n,e.reviver)}catch(e){if(i){e.message=`${t}: ${e.message}`;throw e}else{return null}}}async function _writeFile(t,e,r={}){const c=r.fs||n;const o=s(e,r);await i.fromCallback(c.writeFile)(t,o,r)}const a=i.fromPromise(_writeFile);function writeFileSync(t,e,r={}){const i=r.fs||n;const c=s(e,r);return i.writeFileSync(t,c,r)}t.exports={readFile:o,readFileSync:readFileSync,writeFile:a,writeFileSync:writeFileSync}},366:t=>{function stringify(t,{EOL:e="\n",finalEOL:r=true,replacer:n=null,spaces:i}={}){const s=r?e:"";const c=JSON.stringify(t,n,i);return c.replace(/\n/g,e)+s}function stripBom(t){if(Buffer.isBuffer(t))t=t.toString("utf8");return t.replace(/^\uFEFF/,"")}t.exports={stringify:stringify,stripBom:stripBom}},282:(t,e)=>{"use strict";e.fromCallback=function(t){return Object.defineProperty((function(...e){if(typeof e[e.length-1]==="function")t.apply(this,e);else{return new Promise(((r,n)=>{e.push(((t,e)=>t!=null?n(t):r(e)));t.apply(this,e)}))}}),"name",{value:t.name})};e.fromPromise=function(t){return Object.defineProperty((function(...e){const r=e[e.length-1];if(typeof r!=="function")return t.apply(this,e);else{e.pop();t.apply(this,e).then((t=>r(null,t)),r)}}),"name",{value:t.name})}},896:t=>{"use strict";t.exports=require("fs")},24:t=>{"use strict";t.exports=require("node:fs")},928:t=>{"use strict";t.exports=require("path")}};var e={};function __nccwpck_require__(r){var n=e[r];if(n!==undefined){return n.exports}var i=e[r]={exports:{}};var s=true;try{t[r](i,i.exports,__nccwpck_require__);s=false}finally{if(s)delete e[r]}return i.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(643);module.exports=r})(); \ No newline at end of file diff --git a/packages/toolkit/utils/compiled/fs-extra/index.mjs b/packages/toolkit/utils/compiled/fs-extra/index.mjs new file mode 100644 index 000000000000..ac0f43c17abc --- /dev/null +++ b/packages/toolkit/utils/compiled/fs-extra/index.mjs @@ -0,0 +1 @@ +import{createRequire as t}from"module";var e={901:(t,e,r)=>{const n=r(24);const i=r(928);const s=r(552).mkdirsSync;const c=r(213).utimesMillisSync;const o=r(0);function copySync(t,e,r){if(typeof r==="function"){r={filter:r}}r=r||{};r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0002")}const{srcStat:c,destStat:a}=o.checkPathsSync(t,e,"copy",r);o.checkParentPathsSync(t,c,e,"copy");if(r.filter&&!r.filter(t,e))return;const y=i.dirname(e);if(!n.existsSync(y))s(y);return getStats(a,t,e,r)}function getStats(t,e,r,i){const s=i.dereference?n.statSync:n.lstatSync;const c=s(e);if(c.isDirectory())return onDir(c,t,e,r,i);else if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);else if(c.isSymbolicLink())return onLink(t,e,r,i);else if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);else if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}function onFile(t,e,r,n,i){if(!e)return copyFile(t,r,n,i);return mayCopyFile(t,r,n,i)}function mayCopyFile(t,e,r,i){if(i.overwrite){n.unlinkSync(r);return copyFile(t,e,r,i)}else if(i.errorOnExist){throw new Error(`'${r}' already exists`)}}function copyFile(t,e,r,i){n.copyFileSync(e,r);if(i.preserveTimestamps)handleTimestamps(t.mode,e,r);return setDestMode(r,t.mode)}function handleTimestamps(t,e,r){if(fileIsNotWritable(t))makeFileWritable(r,t);return setDestTimestamps(e,r)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return setDestMode(t,e|128)}function setDestMode(t,e){return n.chmodSync(t,e)}function setDestTimestamps(t,e){const r=n.statSync(t);return c(e,r.atime,r.mtime)}function onDir(t,e,r,n,i){if(!e)return mkDirAndCopy(t.mode,r,n,i);return copyDir(r,n,i)}function mkDirAndCopy(t,e,r,i){n.mkdirSync(r);copyDir(e,r,i);return setDestMode(r,t)}function copyDir(t,e,r){const i=n.opendirSync(t);try{let n;while((n=i.readSync())!==null){copyDirItem(n.name,t,e,r)}}finally{i.closeSync()}}function copyDirItem(t,e,r,n){const s=i.join(e,t);const c=i.join(r,t);if(n.filter&&!n.filter(s,c))return;const{destStat:a}=o.checkPathsSync(s,c,"copy",n);return getStats(a,s,c,n)}function onLink(t,e,r,s){let c=n.readlinkSync(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlinkSync(c,r)}else{let t;try{t=n.readlinkSync(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlinkSync(c,r);throw t}if(s.dereference){t=i.resolve(process.cwd(),t)}if(c!==t){if(o.isSrcSubdir(c,t)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${t}'.`)}if(o.isSrcSubdir(t,c)){throw new Error(`Cannot overwrite '${t}' with '${c}'.`)}}return copyLink(c,r)}}function copyLink(t,e){n.unlinkSync(e);return n.symlinkSync(t,e)}t.exports=copySync},600:(t,e,r)=>{const n=r(423);const i=r(928);const{mkdirs:s}=r(552);const{pathExists:c}=r(170);const{utimesMillis:o}=r(213);const a=r(0);const{asyncIteratorConcurrentProcess:y}=r(768);async function copy(t,e,r={}){if(typeof r==="function"){r={filter:r}}r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0001")}const{srcStat:n,destStat:o}=await a.checkPaths(t,e,"copy",r);await a.checkParentPaths(t,n,e,"copy");const y=await runFilter(t,e,r);if(!y)return;const u=i.dirname(e);const l=await c(u);if(!l){await s(u)}await getStatsAndPerformCopy(o,t,e,r)}async function runFilter(t,e,r){if(!r.filter)return true;return r.filter(t,e)}async function getStatsAndPerformCopy(t,e,r,i){const s=i.dereference?n.stat:n.lstat;const c=await s(e);if(c.isDirectory())return onDir(c,t,e,r,i);if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);if(c.isSymbolicLink())return onLink(t,e,r,i);if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}async function onFile(t,e,r,i,s){if(!e)return copyFile(t,r,i,s);if(s.overwrite){await n.unlink(i);return copyFile(t,r,i,s)}if(s.errorOnExist){throw new Error(`'${i}' already exists`)}}async function copyFile(t,e,r,i){await n.copyFile(e,r);if(i.preserveTimestamps){if(fileIsNotWritable(t.mode)){await makeFileWritable(r,t.mode)}const i=await n.stat(e);await o(r,i.atime,i.mtime)}return n.chmod(r,t.mode)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return n.chmod(t,e|128)}async function onDir(t,e,r,s,c){if(!e){await n.mkdir(s)}await y(await n.opendir(r),(async t=>{const e=i.join(r,t.name);const n=i.join(s,t.name);const o=await runFilter(e,n,c);if(o){const{destStat:t}=await a.checkPaths(e,n,"copy",c);await getStatsAndPerformCopy(t,e,n,c)}}));if(!e){await n.chmod(s,t.mode)}}async function onLink(t,e,r,s){let c=await n.readlink(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlink(c,r)}let o=null;try{o=await n.readlink(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlink(c,r);throw t}if(s.dereference){o=i.resolve(process.cwd(),o)}if(c!==o){if(a.isSrcSubdir(c,o)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${o}'.`)}if(a.isSrcSubdir(o,c)){throw new Error(`Cannot overwrite '${o}' with '${c}'.`)}}await n.unlink(r);return n.symlink(c,r)}t.exports=copy},509:(t,e,r)=>{const n=r(282).fromPromise;t.exports={copy:n(r(600)),copySync:r(901)}},817:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(720);const a=n((async function emptyDir(t){let e;try{e=await i.readdir(t)}catch{return c.mkdirs(t)}return Promise.all(e.map((e=>o.remove(s.join(t,e)))))}));function emptyDirSync(t){let e;try{e=i.readdirSync(t)}catch{return c.mkdirsSync(t)}e.forEach((e=>{e=s.join(t,e);o.removeSync(e)}))}t.exports={emptyDirSync:emptyDirSync,emptydirSync:emptyDirSync,emptyDir:a,emptydir:a}},46:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);async function createFile(t){let e;try{e=await s.stat(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);let n=null;try{n=await s.stat(r)}catch(e){if(e.code==="ENOENT"){await c.mkdirs(r);await s.writeFile(t,"");return}else{throw e}}if(n.isDirectory()){await s.writeFile(t,"")}else{await s.readdir(r)}}function createFileSync(t){let e;try{e=s.statSync(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);try{if(!s.statSync(r).isDirectory()){s.readdirSync(r)}}catch(t){if(t&&t.code==="ENOENT")c.mkdirsSync(r);else throw t}s.writeFileSync(t,"")}t.exports={createFile:n(createFile),createFileSync:createFileSync}},58:(t,e,r)=>{const{createFile:n,createFileSync:i}=r(46);const{createLink:s,createLinkSync:c}=r(196);const{createSymlink:o,createSymlinkSync:a}=r(933);t.exports={createFile:n,createFileSync:i,ensureFile:n,ensureFileSync:i,createLink:s,createLinkSync:c,ensureLink:s,ensureLinkSync:c,createSymlink:o,createSymlinkSync:a,ensureSymlink:o,ensureSymlinkSync:a}},196:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);const{pathExists:o}=r(170);const{areIdentical:a}=r(0);async function createLink(t,e){let r;try{r=await s.lstat(e)}catch{}let n;try{n=await s.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}if(r&&a(n,r))return;const y=i.dirname(e);const u=await o(y);if(!u){await c.mkdirs(y)}await s.link(t,e)}function createLinkSync(t,e){let r;try{r=s.lstatSync(e)}catch{}try{const e=s.lstatSync(t);if(r&&a(e,r))return}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}const n=i.dirname(e);const o=s.existsSync(n);if(o)return s.linkSync(t,e);c.mkdirsSync(n);return s.linkSync(t,e)}t.exports={createLink:n(createLink),createLinkSync:createLinkSync}},492:(t,e,r)=>{const n=r(928);const i=r(423);const{pathExists:s}=r(170);const c=r(282).fromPromise;async function symlinkPaths(t,e){if(n.isAbsolute(t)){try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:t}}const r=n.dirname(e);const c=n.join(r,t);const o=await s(c);if(o){return{toCwd:c,toDst:t}}try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:n.relative(r,t)}}function symlinkPathsSync(t,e){if(n.isAbsolute(t)){const e=i.existsSync(t);if(!e)throw new Error("absolute srcpath does not exist");return{toCwd:t,toDst:t}}const r=n.dirname(e);const s=n.join(r,t);const c=i.existsSync(s);if(c){return{toCwd:s,toDst:t}}const o=i.existsSync(t);if(!o)throw new Error("relative srcpath does not exist");return{toCwd:t,toDst:n.relative(r,t)}}t.exports={symlinkPaths:c(symlinkPaths),symlinkPathsSync:symlinkPathsSync}},126:(t,e,r)=>{const n=r(423);const i=r(282).fromPromise;async function symlinkType(t,e){if(e)return e;let r;try{r=await n.lstat(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}function symlinkTypeSync(t,e){if(e)return e;let r;try{r=n.lstatSync(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}t.exports={symlinkType:i(symlinkType),symlinkTypeSync:symlinkTypeSync}},933:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const{mkdirs:c,mkdirsSync:o}=r(552);const{symlinkPaths:a,symlinkPathsSync:y}=r(492);const{symlinkType:u,symlinkTypeSync:l}=r(126);const{pathExists:f}=r(170);const{areIdentical:m}=r(0);async function createSymlink(t,e,r){let n;try{n=await s.lstat(e)}catch{}if(n&&n.isSymbolicLink()){const[r,n]=await Promise.all([s.stat(t),s.stat(e)]);if(m(r,n))return}const o=await a(t,e);t=o.toDst;const y=await u(o.toCwd,r);const l=i.dirname(e);if(!await f(l)){await c(l)}return s.symlink(t,e,y)}function createSymlinkSync(t,e,r){let n;try{n=s.lstatSync(e)}catch{}if(n&&n.isSymbolicLink()){const r=s.statSync(t);const n=s.statSync(e);if(m(r,n))return}const c=y(t,e);t=c.toDst;r=l(c.toCwd,r);const a=i.dirname(e);const u=s.existsSync(a);if(u)return s.symlinkSync(t,e,r);o(a);return s.symlinkSync(t,e,r)}t.exports={createSymlink:n(createSymlink),createSymlinkSync:createSymlinkSync}},423:(t,e,r)=>{const n=r(282).fromCallback;const i=r(24);const s=["access","appendFile","chmod","chown","close","copyFile","cp","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","glob","lchmod","lchown","lutimes","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","statfs","symlink","truncate","unlink","utimes","writeFile"].filter((t=>typeof i[t]==="function"));Object.assign(e,i);s.forEach((t=>{e[t]=n(i[t])}));e.exists=function(t,e){if(typeof e==="function"){return i.exists(t,e)}return new Promise((e=>i.exists(t,e)))};e.read=function(t,e,r,n,s,c){if(typeof c==="function"){return i.read(t,e,r,n,s,c)}return new Promise(((c,o)=>{i.read(t,e,r,n,s,((t,e,r)=>{if(t)return o(t);c({bytesRead:e,buffer:r})}))}))};e.write=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.write(t,e,...r)}return new Promise(((n,s)=>{i.write(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffer:r})}))}))};e.readv=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.readv(t,e,...r)}return new Promise(((n,s)=>{i.readv(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesRead:e,buffers:r})}))}))};e.writev=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.writev(t,e,...r)}return new Promise(((n,s)=>{i.writev(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffers:r})}))}))};if(typeof i.realpath.native==="function"){e.realpath.native=n(i.realpath.native)}else{process.emitWarning("fs.realpath.native is not a function. Is fs being monkey-patched?","Warning","fs-extra-WARN0003")}},342:(t,e,r)=>{const n=r(282).fromPromise;const i=r(424);i.outputJson=n(r(472));i.outputJsonSync=r(618);i.outputJSON=i.outputJson;i.outputJSONSync=i.outputJsonSync;i.writeJSON=i.writeJson;i.writeJSONSync=i.writeJsonSync;i.readJSON=i.readJson;i.readJSONSync=i.readJsonSync;t.exports=i},424:(t,e,r)=>{const n=r(395);t.exports={readJson:n.readFile,readJsonSync:n.readFileSync,writeJson:n.writeFile,writeJsonSync:n.writeFileSync}},618:(t,e,r)=>{const{stringify:n}=r(366);const{outputFileSync:i}=r(34);function outputJsonSync(t,e,r){const s=n(e,r);i(t,s,r)}t.exports=outputJsonSync},472:(t,e,r)=>{const{stringify:n}=r(366);const{outputFile:i}=r(34);async function outputJson(t,e,r={}){const s=n(e,r);await i(t,s,r)}t.exports=outputJson},552:(t,e,r)=>{const n=r(282).fromPromise;const{makeDir:i,makeDirSync:s}=r(974);const c=n(i);t.exports={mkdirs:c,mkdirsSync:s,mkdirp:c,mkdirpSync:s,ensureDir:c,ensureDirSync:s}},974:(t,e,r)=>{const n=r(423);const{checkPath:i}=r(9);const getMode=t=>{const e={mode:511};if(typeof t==="number")return t;return{...e,...t}.mode};t.exports.makeDir=async(t,e)=>{i(t);return n.mkdir(t,{mode:getMode(e),recursive:true})};t.exports.makeDirSync=(t,e)=>{i(t);return n.mkdirSync(t,{mode:getMode(e),recursive:true})}},9:(t,e,r)=>{const n=r(928);t.exports.checkPath=function checkPath(t){if(process.platform==="win32"){const e=/[<>:"|?*]/.test(t.replace(n.parse(t).root,""));if(e){const e=new Error(`Path contains invalid characters: ${t}`);e.code="EINVAL";throw e}}}},29:(t,e,r)=>{const n=r(282).fromPromise;t.exports={move:n(r(816)),moveSync:r(610)}},610:(t,e,r)=>{const n=r(24);const i=r(928);const s=r(509).copySync;const c=r(720).removeSync;const o=r(552).mkdirpSync;const a=r(0);function moveSync(t,e,r){r=r||{};const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=a.checkPathsSync(t,e,"move",r);a.checkParentPathsSync(t,s,e,"move");if(!isParentRoot(e))o(i.dirname(e));return doRename(t,e,n,c)}function isParentRoot(t){const e=i.dirname(t);const r=i.parse(e);return r.root===e}function doRename(t,e,r,i){if(i)return rename(t,e,r);if(r){c(e);return rename(t,e,r)}if(n.existsSync(e))throw new Error("dest already exists.");return rename(t,e,r)}function rename(t,e,r){try{n.renameSync(t,e)}catch(n){if(n.code!=="EXDEV")throw n;return moveAcrossDevice(t,e,r)}}function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};s(t,e,n);return c(t)}t.exports=moveSync},816:(t,e,r)=>{const n=r(423);const i=r(928);const{copy:s}=r(509);const{remove:c}=r(720);const{mkdirp:o}=r(552);const{pathExists:a}=r(170);const y=r(0);async function move(t,e,r={}){const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=await y.checkPaths(t,e,"move",r);await y.checkParentPaths(t,s,e,"move");const a=i.dirname(e);const u=i.parse(a);if(u.root!==a){await o(a)}return doRename(t,e,n,c)}async function doRename(t,e,r,i){if(!i){if(r){await c(e)}else if(await a(e)){throw new Error("dest already exists.")}}try{await n.rename(t,e)}catch(n){if(n.code!=="EXDEV"){throw n}await moveAcrossDevice(t,e,r)}}async function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};await s(t,e,n);return c(t)}t.exports=move},34:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(170).pathExists;async function outputFile(t,e,r="utf-8"){const n=s.dirname(t);if(!await o(n)){await c.mkdirs(n)}return i.writeFile(t,e,r)}function outputFileSync(t,...e){const r=s.dirname(t);if(!i.existsSync(r)){c.mkdirsSync(r)}i.writeFileSync(t,...e)}t.exports={outputFile:n(outputFile),outputFileSync:outputFileSync}},170:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);function pathExists(t){return i.access(t).then((()=>true)).catch((()=>false))}t.exports={pathExists:n(pathExists),pathExistsSync:i.existsSync}},720:(t,e,r)=>{const n=r(24);const i=r(282).fromCallback;function remove(t,e){n.rm(t,{recursive:true,force:true},e)}function removeSync(t){n.rmSync(t,{recursive:true,force:true})}t.exports={remove:i(remove),removeSync:removeSync}},768:t=>{async function asyncIteratorConcurrentProcess(t,e){const r=[];for await(const n of t){r.push(e(n).then((()=>null),(t=>t??new Error("unknown error"))))}await Promise.all(r.map((t=>t.then((t=>{if(t!==null)throw t})))))}t.exports={asyncIteratorConcurrentProcess:asyncIteratorConcurrentProcess}},0:(t,e,r)=>{const n=r(423);const i=r(928);const s=r(282).fromPromise;function getStats(t,e,r){const i=r.dereference?t=>n.stat(t,{bigint:true}):t=>n.lstat(t,{bigint:true});return Promise.all([i(t),i(e).catch((t=>{if(t.code==="ENOENT")return null;throw t}))]).then((([t,e])=>({srcStat:t,destStat:e})))}function getStatsSync(t,e,r){let i;const s=r.dereference?t=>n.statSync(t,{bigint:true}):t=>n.lstatSync(t,{bigint:true});const c=s(t);try{i=s(e)}catch(t){if(t.code==="ENOENT")return{srcStat:c,destStat:null};throw t}return{srcStat:c,destStat:i}}async function checkPaths(t,e,r,n){const{srcStat:s,destStat:c}=await getStats(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}function checkPathsSync(t,e,r,n){const{srcStat:s,destStat:c}=getStatsSync(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}async function checkParentPaths(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=await n.stat(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPaths(t,e,o,s)}function checkParentPathsSync(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=n.statSync(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPathsSync(t,e,o,s)}function areIdentical(t,e){return e.ino!==undefined&&e.dev!==undefined&&e.ino===t.ino&&e.dev===t.dev}function isSrcSubdir(t,e){const r=i.resolve(t).split(i.sep).filter((t=>t));const n=i.resolve(e).split(i.sep).filter((t=>t));return r.every(((t,e)=>n[e]===t))}function errMsg(t,e,r){return`Cannot ${r} '${t}' to a subdirectory of itself, '${e}'.`}t.exports={checkPaths:s(checkPaths),checkPathsSync:checkPathsSync,checkParentPaths:s(checkParentPaths),checkParentPathsSync:checkParentPathsSync,isSrcSubdir:isSrcSubdir,areIdentical:areIdentical}},213:(t,e,r)=>{const n=r(423);const i=r(282).fromPromise;async function utimesMillis(t,e,r){const i=await n.open(t,"r+");let s=null;try{await n.futimes(i,e,r)}finally{try{await n.close(i)}catch(t){s=t}}if(s){throw s}}function utimesMillisSync(t,e,r){const i=n.openSync(t,"r+");n.futimesSync(i,e,r);return n.closeSync(i)}t.exports={utimesMillis:i(utimesMillis),utimesMillisSync:utimesMillisSync}},395:(t,e,r)=>{let n;try{n=r(24)}catch(t){n=r(896)}const i=r(282);const{stringify:s,stripBom:c}=r(366);async function _readFile(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const s="throws"in e?e.throws:true;let o=await i.fromCallback(r.readFile)(t,e);o=c(o);let a;try{a=JSON.parse(o,e?e.reviver:null)}catch(e){if(s){e.message=`${t}: ${e.message}`;throw e}else{return null}}return a}const o=i.fromPromise(_readFile);function readFileSync(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const i="throws"in e?e.throws:true;try{let n=r.readFileSync(t,e);n=c(n);return JSON.parse(n,e.reviver)}catch(e){if(i){e.message=`${t}: ${e.message}`;throw e}else{return null}}}async function _writeFile(t,e,r={}){const c=r.fs||n;const o=s(e,r);await i.fromCallback(c.writeFile)(t,o,r)}const a=i.fromPromise(_writeFile);function writeFileSync(t,e,r={}){const i=r.fs||n;const c=s(e,r);return i.writeFileSync(t,c,r)}t.exports={readFile:o,readFileSync:readFileSync,writeFile:a,writeFileSync:writeFileSync}},366:t=>{function stringify(t,{EOL:e="\n",finalEOL:r=true,replacer:n=null,spaces:i}={}){const s=r?e:"";const c=JSON.stringify(t,n,i);return c.replace(/\n/g,e)+s}function stripBom(t){if(Buffer.isBuffer(t))t=t.toString("utf8");return t.replace(/^\uFEFF/,"")}t.exports={stringify:stringify,stripBom:stripBom}},282:(t,e)=>{e.fromCallback=function(t){return Object.defineProperty((function(...e){if(typeof e[e.length-1]==="function")t.apply(this,e);else{return new Promise(((r,n)=>{e.push(((t,e)=>t!=null?n(t):r(e)));t.apply(this,e)}))}}),"name",{value:t.name})};e.fromPromise=function(t){return Object.defineProperty((function(...e){const r=e[e.length-1];if(typeof r!=="function")return t.apply(this,e);else{e.pop();t.apply(this,e).then((t=>r(null,t)),r)}}),"name",{value:t.name})}},896:e=>{e.exports=t(import.meta.url)("fs")},24:e=>{e.exports=t(import.meta.url)("node:fs")},928:e=>{e.exports=t(import.meta.url)("path")}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var i=r[t]={exports:{}};var s=true;try{e[t](i,i.exports,__nccwpck_require__);s=false}finally{if(s)delete r[t]}return i.exports}(()=>{__nccwpck_require__.d=(t,e)=>{for(var r in e){if(__nccwpck_require__.o(e,r)&&!__nccwpck_require__.o(t,r)){Object.defineProperty(t,r,{enumerable:true,get:e[r]})}}}})();(()=>{__nccwpck_require__.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=new URL(".",import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/)?1:0,-1)+"/";var n={};__nccwpck_require__.d(n,{A0:()=>X,Ay:()=>nt,C:()=>m,CJ:()=>d,CO:()=>T,Cy:()=>K,EC:()=>rt,EX:()=>v,F3:()=>V,FG:()=>H,GF:()=>$,GT:()=>S,Gu:()=>G,HX:()=>tt,I4:()=>M,JQ:()=>R,Jh:()=>D,L6:()=>x,Nc:()=>U,TF:()=>et,TK:()=>Q,TQ:()=>O,U6:()=>P,Vh:()=>N,W6:()=>L,Wd:()=>q,Wl:()=>F,Z6:()=>h,ah:()=>B,bH:()=>A,bh:()=>b,cJ:()=>E,d:()=>_,f$:()=>w,gg:()=>C,h4:()=>W,hi:()=>J,i9:()=>Y,k:()=>I,nf:()=>Z,pP:()=>p,py:()=>j,s0:()=>z,x3:()=>k,yY:()=>g});var i=__nccwpck_require__(509);var s=__nccwpck_require__(817);var c=__nccwpck_require__(58);var o=__nccwpck_require__(342);var a=__nccwpck_require__(552);var y=__nccwpck_require__(29);var u=__nccwpck_require__(34);var l=__nccwpck_require__(170);var f=__nccwpck_require__(720);const m=i.copy;const p=i.copySync;const S=s.emptyDirSync;const d=s.emptydirSync;const w=s.emptyDir;const h=s.emptydir;const k=c.createFile;const v=c.createFileSync;const b=c.ensureFile;const F=c.ensureFileSync;const _=c.createLink;const P=c.createLinkSync;const x=c.ensureLink;const g=c.ensureLinkSync;const E=c.createSymlink;const D=c.createSymlinkSync;const C=c.ensureSymlink;const J=c.ensureSymlinkSync;const N=o.readJson;const O=o.readJSON;const L=o.readJsonSync;const T=o.readJSONSync;const $=o.writeJson;const I=o.writeJSON;const W=o.writeJsonSync;const A=o.writeJSONSync;const q=o.outputJson;const M=o.outputJSON;const j=o.outputJsonSync;const R=o.outputJSONSync;const U=a.mkdirs;const B=a.mkdirsSync;const G=a.mkdirp;const V=a.mkdirpSync;const X=a.ensureDir;const H=a.ensureDirSync;const K=y.move;const Q=y.moveSync;const Y=u.outputFile;const Z=u.outputFileSync;const z=l.pathExists;const tt=l.pathExistsSync;const et=f.remove;const rt=f.removeSync;const nt={...i,...s,...c,...o,...a,...y,...u,...l,...f};var it=n.C;var st=n.pP;var ct=n.x3;var ot=n.EX;var at=n.d;var yt=n.U6;var ut=n.cJ;var lt=n.Jh;var ft=n.Ay;var mt=n.f$;var pt=n.GT;var St=n.Z6;var dt=n.CJ;var wt=n.A0;var ht=n.FG;var kt=n.bh;var vt=n.Wl;var bt=n.L6;var Ft=n.yY;var _t=n.gg;var Pt=n.hi;var xt=n.Gu;var gt=n.F3;var Et=n.Nc;var Dt=n.ah;var Ct=n.Cy;var Jt=n.TK;var Nt=n.i9;var Ot=n.nf;var Lt=n.I4;var Tt=n.JQ;var $t=n.Wd;var It=n.py;var Wt=n.s0;var At=n.HX;var qt=n.TQ;var Mt=n.CO;var jt=n.Vh;var Rt=n.W6;var Ut=n.TF;var Bt=n.EC;var Gt=n.k;var Vt=n.bH;var Xt=n.GF;var Ht=n.h4;export{it as copy,st as copySync,ct as createFile,ot as createFileSync,at as createLink,yt as createLinkSync,ut as createSymlink,lt as createSymlinkSync,ft as default,mt as emptyDir,pt as emptyDirSync,St as emptydir,dt as emptydirSync,wt as ensureDir,ht as ensureDirSync,kt as ensureFile,vt as ensureFileSync,bt as ensureLink,Ft as ensureLinkSync,_t as ensureSymlink,Pt as ensureSymlinkSync,xt as mkdirp,gt as mkdirpSync,Et as mkdirs,Dt as mkdirsSync,Ct as move,Jt as moveSync,Nt as outputFile,Ot as outputFileSync,Lt as outputJSON,Tt as outputJSONSync,$t as outputJson,It as outputJsonSync,Wt as pathExists,At as pathExistsSync,qt as readJSON,Mt as readJSONSync,jt as readJson,Rt as readJsonSync,Ut as remove,Bt as removeSync,Gt as writeJSON,Vt as writeJSONSync,Xt as writeJson,Ht as writeJsonSync}; \ No newline at end of file diff --git a/packages/toolkit/utils/compiled/fs-extra/license b/packages/toolkit/utils/compiled/fs-extra/license index 93546dfb7655..050c1aa99aba 100644 --- a/packages/toolkit/utils/compiled/fs-extra/license +++ b/packages/toolkit/utils/compiled/fs-extra/license @@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2011-2017 JP Richardson +Copyright (c) 2011-2024 JP Richardson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, diff --git a/packages/toolkit/utils/compiled/fs-extra/package.json b/packages/toolkit/utils/compiled/fs-extra/package.json index c7bad81bdc18..f6fdaa3268e5 100644 --- a/packages/toolkit/utils/compiled/fs-extra/package.json +++ b/packages/toolkit/utils/compiled/fs-extra/package.json @@ -1 +1 @@ -{"name":"fs-extra","author":"JP Richardson ","version":"10.0.1","license":"MIT"} +{"name":"fs-extra","author":"JP Richardson ","version":"11.3.3","license":"MIT"} diff --git a/packages/toolkit/utils/package.json b/packages/toolkit/utils/package.json index be92b0a73d9c..cfa71a74ca57 100644 --- a/packages/toolkit/utils/package.json +++ b/packages/toolkit/utils/package.json @@ -82,7 +82,10 @@ "default": "./dist/compiled/lodash/index.js" }, "./globby": "./dist/compiled/globby/index.js", - "./fs-extra": "./dist/compiled/fs-extra/index.js", + "./fs-extra": { + "import": "./dist/compiled/fs-extra/index.mjs", + "default": "./dist/compiled/fs-extra/index.js" + }, "./fast-glob": "./dist/compiled/fast-glob/index.js", "./gzip-size": "./dist/compiled/gzip-size/index.js", "./mime-types": "./dist/compiled/mime-types/index.js", diff --git a/packages/toolkit/utils/rslib.config.mts b/packages/toolkit/utils/rslib.config.mts index 416acf6e9bf7..36d935b20b0d 100644 --- a/packages/toolkit/utils/rslib.config.mts +++ b/packages/toolkit/utils/rslib.config.mts @@ -52,7 +52,10 @@ const dependencies = [ packageJsonField: ['options'], }, 'execa', - 'fs-extra', + { + name: 'fs-extra', + esm: true, + }, 'browserslist', 'chokidar', 'fast-glob', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ffa9831bc54c..9a198ad3b3a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1740,8 +1740,8 @@ importers: specifier: 5.0.0 version: 5.0.0 fs-extra: - specifier: 10.1.0 - version: 10.1.0 + specifier: 11.3.3 + version: 11.3.3 glob: specifier: 7.2.3 version: 7.2.3 @@ -1905,7 +1905,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 1.4.3 - version: 1.4.3(@rsbuild/core@2.0.0-alpha.4(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) + version: 1.4.3(@rsbuild/core@1.7.2) '@rslib/core': specifier: 0.19.3 version: 0.19.3(typescript@5.9.3) @@ -17635,6 +17635,14 @@ snapshots: transitivePeerDependencies: - webpack-hot-middleware + '@rsbuild/plugin-react@1.4.3(@rsbuild/core@1.7.2)': + dependencies: + '@rsbuild/core': 1.7.2 + '@rspack/plugin-react-refresh': 1.6.0(react-refresh@0.18.0) + react-refresh: 0.18.0 + transitivePeerDependencies: + - webpack-hot-middleware + '@rsbuild/plugin-react@1.4.3(@rsbuild/core@2.0.0-alpha.4(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: '@rsbuild/core': 2.0.0-alpha.4(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) diff --git a/scripts/prebundle/package.json b/scripts/prebundle/package.json index a5899da1506c..271d974011f9 100644 --- a/scripts/prebundle/package.json +++ b/scripts/prebundle/package.json @@ -49,7 +49,7 @@ "fast-glob": "3.3.3", "filesize": "8.0.7", "find-up": "5.0.0", - "fs-extra": "10.1.0", + "fs-extra": "11.3.3", "glob": "7.2.3", "globby": "11.1.0", "gzip-size": "6.0.0", diff --git a/scripts/prebundle/src/constant.ts b/scripts/prebundle/src/constant.ts index 1c28e6c03607..23e4f36d6b57 100644 --- a/scripts/prebundle/src/constant.ts +++ b/scripts/prebundle/src/constant.ts @@ -85,7 +85,13 @@ export const TASKS: TaskConfig[] = [ packageJsonField: ['options'], }, 'execa', - 'fs-extra', + { + name: 'fs-extra', + esmAlias: 'fs-extra/esm', + externals: { + 'graceful-fs': 'node:fs', + }, + }, 'browserslist', 'chokidar', 'fast-glob', diff --git a/scripts/prebundle/src/helper.ts b/scripts/prebundle/src/helper.ts index 8a581f8d93d4..939fd2da1cce 100644 --- a/scripts/prebundle/src/helper.ts +++ b/scripts/prebundle/src/helper.ts @@ -45,7 +45,8 @@ export async function parseTasks() { const distPath = join(packagePath, DIST_DIR, depName); const depPath = findDepPath(depName); const depEntry = require.resolve(depName); - const resolvedEsmEntry = resolveESMDependency(depName); + const esmEntry = typeof dep === 'string' ? dep : dep.esmAlias || dep.name; + const resolvedEsmEntry = resolveESMDependency(esmEntry); let depEsmEntry = ''; if (resolvedEsmEntry) { diff --git a/scripts/prebundle/src/index.ts b/scripts/prebundle/src/index.ts index 593a63e69af2..dbf9f13e0384 100644 --- a/scripts/prebundle/src/index.ts +++ b/scripts/prebundle/src/index.ts @@ -1,8 +1,17 @@ +import { argv } from 'process'; import { parseTasks } from './helper'; import { prebundle } from './prebundle'; async function run() { - const parsedTasks = await parseTasks(); + let parsedTasks = await parseTasks(); + + const startIndex = argv.findIndex(x => + parsedTasks.some(y => y.packageName === x), + ); + if (startIndex !== -1) { + const pkgs = argv.slice(startIndex); + parsedTasks = parsedTasks.filter(x => pkgs.includes(x.packageName)); + } for (const task of parsedTasks) { await prebundle(task); diff --git a/scripts/prebundle/src/types.ts b/scripts/prebundle/src/types.ts index 7602e9f0b039..ddc94a04b2aa 100644 --- a/scripts/prebundle/src/types.ts +++ b/scripts/prebundle/src/types.ts @@ -6,6 +6,7 @@ export type ImportMap = { export type DependencyConfig = { /** Name of dependency */ name: string; + esmAlias?: string; /** Whether to minify the code. */ minify?: boolean; /** Externals to leave as requires of the build. */ From c7459877bb6783657bb5ef0c1f76a384408ff1d3 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 14:12:05 +0800 Subject: [PATCH 04/27] chore: remove unused third party libs --- packages/toolkit/utils/package.json | 4 ---- packages/toolkit/utils/rslib.config.mts | 7 ------- packages/toolkit/utils/src/compiled.ts | 24 ++++++------------------ scripts/prebundle/package.json | 2 -- scripts/prebundle/src/constant.ts | 7 ------- 5 files changed, 6 insertions(+), 38 deletions(-) diff --git a/packages/toolkit/utils/package.json b/packages/toolkit/utils/package.json index cfa71a74ca57..cd795eeee1e0 100644 --- a/packages/toolkit/utils/package.json +++ b/packages/toolkit/utils/package.json @@ -71,7 +71,6 @@ "import": "./dist/compiled/commander/index.mjs", "default": "./dist/compiled/commander/index.js" }, - "./ora": "./dist/compiled/ora/index.js", "./glob": "./dist/compiled/glob/index.js", "./chalk": "./dist/compiled/chalk/index.js", "./execa": "./dist/compiled/execa/index.js", @@ -174,9 +173,6 @@ ], "commander": [ "./dist/compiled/commander/typings/index.d.ts" - ], - "ora": [ - "./dist/compiled/ora/index.d.ts" ] } }, diff --git a/packages/toolkit/utils/rslib.config.mts b/packages/toolkit/utils/rslib.config.mts index 36d935b20b0d..14188452df25 100644 --- a/packages/toolkit/utils/rslib.config.mts +++ b/packages/toolkit/utils/rslib.config.mts @@ -44,13 +44,6 @@ const dependencies = [ 'glob', 'chalk', 'webpack-chain', - { - name: 'signale', - externals: { - chalk: '../chalk', - }, - packageJsonField: ['options'], - }, 'execa', { name: 'fs-extra', diff --git a/packages/toolkit/utils/src/compiled.ts b/packages/toolkit/utils/src/compiled.ts index 2a4e2aa0daa3..d85673077bb1 100644 --- a/packages/toolkit/utils/src/compiled.ts +++ b/packages/toolkit/utils/src/compiled.ts @@ -2,7 +2,6 @@ import { createRequire } from 'node:module'; import { Import } from './import'; export { default as fs } from '../compiled/fs-extra'; -export { default as ora } from '../compiled/ora'; export { default as glob } from '../compiled/glob'; export { default as yaml } from '../compiled/js-yaml'; export { default as chalk } from '../compiled/chalk'; @@ -18,7 +17,6 @@ export { default as dotenv } from '../compiled/dotenv'; export { default as lodash } from '../compiled/lodash'; export { default as globby } from '../compiled/globby'; export { default as address } from '../compiled/address'; -export { default as signale } from '../compiled/signale'; export { default as urlJoin } from '../compiled/url-join'; export { default as minimist } from '../compiled/minimist'; export { default as fastGlob } from '../compiled/fast-glob'; @@ -30,10 +28,6 @@ export { default as browserslist } from '../compiled/browserslist'; export { program, Command } from '../compiled/commander'; -import _signale from '../compiled/signale'; -export const { Signale } = _signale; - -export type { SignaleOptions } from '../compiled/signale'; export type { IOptions as GlobOptions } from '../compiled/glob'; export type { GlobbyOptions } from '../compiled/globby'; export type { FSWatcher, WatchOptions } from '../compiled/chokidar'; @@ -61,15 +55,9 @@ const getNodeRequire = () => { // @ts-ignore - import.meta is only valid in ESM, but we only execute this in ESM return /*#__PURE__*/ createRequire(import.meta.url); }; -export const mime: typeof import('../compiled/mime-types') = Import.lazy( - '../compiled/mime-types', - getNodeRequire, -); -export const chokidar: typeof import('../compiled/chokidar') = Import.lazy( - '../compiled/chokidar', - getNodeRequire, -); -export const inquirer: typeof import('../compiled/inquirer') = Import.lazy( - '../compiled/inquirer', - getNodeRequire, -); +export const mime: typeof import('../compiled/mime-types') = + /*#__PURE__*/ Import.lazy('../compiled/mime-types', getNodeRequire); +export const chokidar: typeof import('../compiled/chokidar') = + /*#__PURE__*/ Import.lazy('../compiled/chokidar', getNodeRequire); +export const inquirer: typeof import('../compiled/inquirer') = + /*#__PURE__*/ Import.lazy('../compiled/inquirer', getNodeRequire); diff --git a/scripts/prebundle/package.json b/scripts/prebundle/package.json index 271d974011f9..084dd5f56322 100644 --- a/scripts/prebundle/package.json +++ b/scripts/prebundle/package.json @@ -35,7 +35,6 @@ "@types/normalize-path": "3.0.2", "@types/semver": "7.7.1", "@types/signal-exit": "3.0.4", - "@types/signale": "1.4.7", "@types/url-join": "4.0.3", "address": "1.2.2", "browserslist": "4.28.1", @@ -82,7 +81,6 @@ "sass": "1.97.3", "semver": "7.7.3", "signal-exit": "3.0.7", - "signale": "1.4.0", "slash": "3.0.0", "strip-ansi": "6.0.1", "styled-components": "^5.3.1", diff --git a/scripts/prebundle/src/constant.ts b/scripts/prebundle/src/constant.ts index 23e4f36d6b57..8d3395a33844 100644 --- a/scripts/prebundle/src/constant.ts +++ b/scripts/prebundle/src/constant.ts @@ -77,13 +77,6 @@ export const TASKS: TaskConfig[] = [ // some dependencies 'glob', 'chalk', - { - name: 'signale', - externals: { - chalk: '../chalk', - }, - packageJsonField: ['options'], - }, 'execa', { name: 'fs-extra', From b86c0bd64727b2842b498402f3020d7ac3007abc Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 14:34:14 +0800 Subject: [PATCH 05/27] fix: fs-extra --- .../src/plugins/deploy/server-bundle/builder.ts | 2 +- packages/toolkit/utils/compiled/fs-extra/esm.mjs | 1 + packages/toolkit/utils/compiled/fs-extra/index.mjs | 5 ++++- scripts/prebundle/src/constant.ts | 2 ++ scripts/prebundle/src/helper.ts | 9 ++++++++- scripts/prebundle/src/prebundle.ts | 6 +++--- scripts/prebundle/src/types.ts | 3 +++ 7 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 packages/toolkit/utils/compiled/fs-extra/esm.mjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 6f97fcf54e41..749d241f4ec7 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -83,7 +83,7 @@ export const bundleServer = async ( server: '.', }, filename: { - js: '[name].js', + js: '[name].mjs', }, minify, }, diff --git a/packages/toolkit/utils/compiled/fs-extra/esm.mjs b/packages/toolkit/utils/compiled/fs-extra/esm.mjs new file mode 100644 index 000000000000..ac0f43c17abc --- /dev/null +++ b/packages/toolkit/utils/compiled/fs-extra/esm.mjs @@ -0,0 +1 @@ +import{createRequire as t}from"module";var e={901:(t,e,r)=>{const n=r(24);const i=r(928);const s=r(552).mkdirsSync;const c=r(213).utimesMillisSync;const o=r(0);function copySync(t,e,r){if(typeof r==="function"){r={filter:r}}r=r||{};r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0002")}const{srcStat:c,destStat:a}=o.checkPathsSync(t,e,"copy",r);o.checkParentPathsSync(t,c,e,"copy");if(r.filter&&!r.filter(t,e))return;const y=i.dirname(e);if(!n.existsSync(y))s(y);return getStats(a,t,e,r)}function getStats(t,e,r,i){const s=i.dereference?n.statSync:n.lstatSync;const c=s(e);if(c.isDirectory())return onDir(c,t,e,r,i);else if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);else if(c.isSymbolicLink())return onLink(t,e,r,i);else if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);else if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}function onFile(t,e,r,n,i){if(!e)return copyFile(t,r,n,i);return mayCopyFile(t,r,n,i)}function mayCopyFile(t,e,r,i){if(i.overwrite){n.unlinkSync(r);return copyFile(t,e,r,i)}else if(i.errorOnExist){throw new Error(`'${r}' already exists`)}}function copyFile(t,e,r,i){n.copyFileSync(e,r);if(i.preserveTimestamps)handleTimestamps(t.mode,e,r);return setDestMode(r,t.mode)}function handleTimestamps(t,e,r){if(fileIsNotWritable(t))makeFileWritable(r,t);return setDestTimestamps(e,r)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return setDestMode(t,e|128)}function setDestMode(t,e){return n.chmodSync(t,e)}function setDestTimestamps(t,e){const r=n.statSync(t);return c(e,r.atime,r.mtime)}function onDir(t,e,r,n,i){if(!e)return mkDirAndCopy(t.mode,r,n,i);return copyDir(r,n,i)}function mkDirAndCopy(t,e,r,i){n.mkdirSync(r);copyDir(e,r,i);return setDestMode(r,t)}function copyDir(t,e,r){const i=n.opendirSync(t);try{let n;while((n=i.readSync())!==null){copyDirItem(n.name,t,e,r)}}finally{i.closeSync()}}function copyDirItem(t,e,r,n){const s=i.join(e,t);const c=i.join(r,t);if(n.filter&&!n.filter(s,c))return;const{destStat:a}=o.checkPathsSync(s,c,"copy",n);return getStats(a,s,c,n)}function onLink(t,e,r,s){let c=n.readlinkSync(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlinkSync(c,r)}else{let t;try{t=n.readlinkSync(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlinkSync(c,r);throw t}if(s.dereference){t=i.resolve(process.cwd(),t)}if(c!==t){if(o.isSrcSubdir(c,t)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${t}'.`)}if(o.isSrcSubdir(t,c)){throw new Error(`Cannot overwrite '${t}' with '${c}'.`)}}return copyLink(c,r)}}function copyLink(t,e){n.unlinkSync(e);return n.symlinkSync(t,e)}t.exports=copySync},600:(t,e,r)=>{const n=r(423);const i=r(928);const{mkdirs:s}=r(552);const{pathExists:c}=r(170);const{utimesMillis:o}=r(213);const a=r(0);const{asyncIteratorConcurrentProcess:y}=r(768);async function copy(t,e,r={}){if(typeof r==="function"){r={filter:r}}r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0001")}const{srcStat:n,destStat:o}=await a.checkPaths(t,e,"copy",r);await a.checkParentPaths(t,n,e,"copy");const y=await runFilter(t,e,r);if(!y)return;const u=i.dirname(e);const l=await c(u);if(!l){await s(u)}await getStatsAndPerformCopy(o,t,e,r)}async function runFilter(t,e,r){if(!r.filter)return true;return r.filter(t,e)}async function getStatsAndPerformCopy(t,e,r,i){const s=i.dereference?n.stat:n.lstat;const c=await s(e);if(c.isDirectory())return onDir(c,t,e,r,i);if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);if(c.isSymbolicLink())return onLink(t,e,r,i);if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}async function onFile(t,e,r,i,s){if(!e)return copyFile(t,r,i,s);if(s.overwrite){await n.unlink(i);return copyFile(t,r,i,s)}if(s.errorOnExist){throw new Error(`'${i}' already exists`)}}async function copyFile(t,e,r,i){await n.copyFile(e,r);if(i.preserveTimestamps){if(fileIsNotWritable(t.mode)){await makeFileWritable(r,t.mode)}const i=await n.stat(e);await o(r,i.atime,i.mtime)}return n.chmod(r,t.mode)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return n.chmod(t,e|128)}async function onDir(t,e,r,s,c){if(!e){await n.mkdir(s)}await y(await n.opendir(r),(async t=>{const e=i.join(r,t.name);const n=i.join(s,t.name);const o=await runFilter(e,n,c);if(o){const{destStat:t}=await a.checkPaths(e,n,"copy",c);await getStatsAndPerformCopy(t,e,n,c)}}));if(!e){await n.chmod(s,t.mode)}}async function onLink(t,e,r,s){let c=await n.readlink(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlink(c,r)}let o=null;try{o=await n.readlink(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlink(c,r);throw t}if(s.dereference){o=i.resolve(process.cwd(),o)}if(c!==o){if(a.isSrcSubdir(c,o)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${o}'.`)}if(a.isSrcSubdir(o,c)){throw new Error(`Cannot overwrite '${o}' with '${c}'.`)}}await n.unlink(r);return n.symlink(c,r)}t.exports=copy},509:(t,e,r)=>{const n=r(282).fromPromise;t.exports={copy:n(r(600)),copySync:r(901)}},817:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(720);const a=n((async function emptyDir(t){let e;try{e=await i.readdir(t)}catch{return c.mkdirs(t)}return Promise.all(e.map((e=>o.remove(s.join(t,e)))))}));function emptyDirSync(t){let e;try{e=i.readdirSync(t)}catch{return c.mkdirsSync(t)}e.forEach((e=>{e=s.join(t,e);o.removeSync(e)}))}t.exports={emptyDirSync:emptyDirSync,emptydirSync:emptyDirSync,emptyDir:a,emptydir:a}},46:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);async function createFile(t){let e;try{e=await s.stat(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);let n=null;try{n=await s.stat(r)}catch(e){if(e.code==="ENOENT"){await c.mkdirs(r);await s.writeFile(t,"");return}else{throw e}}if(n.isDirectory()){await s.writeFile(t,"")}else{await s.readdir(r)}}function createFileSync(t){let e;try{e=s.statSync(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);try{if(!s.statSync(r).isDirectory()){s.readdirSync(r)}}catch(t){if(t&&t.code==="ENOENT")c.mkdirsSync(r);else throw t}s.writeFileSync(t,"")}t.exports={createFile:n(createFile),createFileSync:createFileSync}},58:(t,e,r)=>{const{createFile:n,createFileSync:i}=r(46);const{createLink:s,createLinkSync:c}=r(196);const{createSymlink:o,createSymlinkSync:a}=r(933);t.exports={createFile:n,createFileSync:i,ensureFile:n,ensureFileSync:i,createLink:s,createLinkSync:c,ensureLink:s,ensureLinkSync:c,createSymlink:o,createSymlinkSync:a,ensureSymlink:o,ensureSymlinkSync:a}},196:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);const{pathExists:o}=r(170);const{areIdentical:a}=r(0);async function createLink(t,e){let r;try{r=await s.lstat(e)}catch{}let n;try{n=await s.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}if(r&&a(n,r))return;const y=i.dirname(e);const u=await o(y);if(!u){await c.mkdirs(y)}await s.link(t,e)}function createLinkSync(t,e){let r;try{r=s.lstatSync(e)}catch{}try{const e=s.lstatSync(t);if(r&&a(e,r))return}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}const n=i.dirname(e);const o=s.existsSync(n);if(o)return s.linkSync(t,e);c.mkdirsSync(n);return s.linkSync(t,e)}t.exports={createLink:n(createLink),createLinkSync:createLinkSync}},492:(t,e,r)=>{const n=r(928);const i=r(423);const{pathExists:s}=r(170);const c=r(282).fromPromise;async function symlinkPaths(t,e){if(n.isAbsolute(t)){try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:t}}const r=n.dirname(e);const c=n.join(r,t);const o=await s(c);if(o){return{toCwd:c,toDst:t}}try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:n.relative(r,t)}}function symlinkPathsSync(t,e){if(n.isAbsolute(t)){const e=i.existsSync(t);if(!e)throw new Error("absolute srcpath does not exist");return{toCwd:t,toDst:t}}const r=n.dirname(e);const s=n.join(r,t);const c=i.existsSync(s);if(c){return{toCwd:s,toDst:t}}const o=i.existsSync(t);if(!o)throw new Error("relative srcpath does not exist");return{toCwd:t,toDst:n.relative(r,t)}}t.exports={symlinkPaths:c(symlinkPaths),symlinkPathsSync:symlinkPathsSync}},126:(t,e,r)=>{const n=r(423);const i=r(282).fromPromise;async function symlinkType(t,e){if(e)return e;let r;try{r=await n.lstat(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}function symlinkTypeSync(t,e){if(e)return e;let r;try{r=n.lstatSync(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}t.exports={symlinkType:i(symlinkType),symlinkTypeSync:symlinkTypeSync}},933:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const{mkdirs:c,mkdirsSync:o}=r(552);const{symlinkPaths:a,symlinkPathsSync:y}=r(492);const{symlinkType:u,symlinkTypeSync:l}=r(126);const{pathExists:f}=r(170);const{areIdentical:m}=r(0);async function createSymlink(t,e,r){let n;try{n=await s.lstat(e)}catch{}if(n&&n.isSymbolicLink()){const[r,n]=await Promise.all([s.stat(t),s.stat(e)]);if(m(r,n))return}const o=await a(t,e);t=o.toDst;const y=await u(o.toCwd,r);const l=i.dirname(e);if(!await f(l)){await c(l)}return s.symlink(t,e,y)}function createSymlinkSync(t,e,r){let n;try{n=s.lstatSync(e)}catch{}if(n&&n.isSymbolicLink()){const r=s.statSync(t);const n=s.statSync(e);if(m(r,n))return}const c=y(t,e);t=c.toDst;r=l(c.toCwd,r);const a=i.dirname(e);const u=s.existsSync(a);if(u)return s.symlinkSync(t,e,r);o(a);return s.symlinkSync(t,e,r)}t.exports={createSymlink:n(createSymlink),createSymlinkSync:createSymlinkSync}},423:(t,e,r)=>{const n=r(282).fromCallback;const i=r(24);const s=["access","appendFile","chmod","chown","close","copyFile","cp","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","glob","lchmod","lchown","lutimes","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","statfs","symlink","truncate","unlink","utimes","writeFile"].filter((t=>typeof i[t]==="function"));Object.assign(e,i);s.forEach((t=>{e[t]=n(i[t])}));e.exists=function(t,e){if(typeof e==="function"){return i.exists(t,e)}return new Promise((e=>i.exists(t,e)))};e.read=function(t,e,r,n,s,c){if(typeof c==="function"){return i.read(t,e,r,n,s,c)}return new Promise(((c,o)=>{i.read(t,e,r,n,s,((t,e,r)=>{if(t)return o(t);c({bytesRead:e,buffer:r})}))}))};e.write=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.write(t,e,...r)}return new Promise(((n,s)=>{i.write(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffer:r})}))}))};e.readv=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.readv(t,e,...r)}return new Promise(((n,s)=>{i.readv(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesRead:e,buffers:r})}))}))};e.writev=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.writev(t,e,...r)}return new Promise(((n,s)=>{i.writev(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffers:r})}))}))};if(typeof i.realpath.native==="function"){e.realpath.native=n(i.realpath.native)}else{process.emitWarning("fs.realpath.native is not a function. Is fs being monkey-patched?","Warning","fs-extra-WARN0003")}},342:(t,e,r)=>{const n=r(282).fromPromise;const i=r(424);i.outputJson=n(r(472));i.outputJsonSync=r(618);i.outputJSON=i.outputJson;i.outputJSONSync=i.outputJsonSync;i.writeJSON=i.writeJson;i.writeJSONSync=i.writeJsonSync;i.readJSON=i.readJson;i.readJSONSync=i.readJsonSync;t.exports=i},424:(t,e,r)=>{const n=r(395);t.exports={readJson:n.readFile,readJsonSync:n.readFileSync,writeJson:n.writeFile,writeJsonSync:n.writeFileSync}},618:(t,e,r)=>{const{stringify:n}=r(366);const{outputFileSync:i}=r(34);function outputJsonSync(t,e,r){const s=n(e,r);i(t,s,r)}t.exports=outputJsonSync},472:(t,e,r)=>{const{stringify:n}=r(366);const{outputFile:i}=r(34);async function outputJson(t,e,r={}){const s=n(e,r);await i(t,s,r)}t.exports=outputJson},552:(t,e,r)=>{const n=r(282).fromPromise;const{makeDir:i,makeDirSync:s}=r(974);const c=n(i);t.exports={mkdirs:c,mkdirsSync:s,mkdirp:c,mkdirpSync:s,ensureDir:c,ensureDirSync:s}},974:(t,e,r)=>{const n=r(423);const{checkPath:i}=r(9);const getMode=t=>{const e={mode:511};if(typeof t==="number")return t;return{...e,...t}.mode};t.exports.makeDir=async(t,e)=>{i(t);return n.mkdir(t,{mode:getMode(e),recursive:true})};t.exports.makeDirSync=(t,e)=>{i(t);return n.mkdirSync(t,{mode:getMode(e),recursive:true})}},9:(t,e,r)=>{const n=r(928);t.exports.checkPath=function checkPath(t){if(process.platform==="win32"){const e=/[<>:"|?*]/.test(t.replace(n.parse(t).root,""));if(e){const e=new Error(`Path contains invalid characters: ${t}`);e.code="EINVAL";throw e}}}},29:(t,e,r)=>{const n=r(282).fromPromise;t.exports={move:n(r(816)),moveSync:r(610)}},610:(t,e,r)=>{const n=r(24);const i=r(928);const s=r(509).copySync;const c=r(720).removeSync;const o=r(552).mkdirpSync;const a=r(0);function moveSync(t,e,r){r=r||{};const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=a.checkPathsSync(t,e,"move",r);a.checkParentPathsSync(t,s,e,"move");if(!isParentRoot(e))o(i.dirname(e));return doRename(t,e,n,c)}function isParentRoot(t){const e=i.dirname(t);const r=i.parse(e);return r.root===e}function doRename(t,e,r,i){if(i)return rename(t,e,r);if(r){c(e);return rename(t,e,r)}if(n.existsSync(e))throw new Error("dest already exists.");return rename(t,e,r)}function rename(t,e,r){try{n.renameSync(t,e)}catch(n){if(n.code!=="EXDEV")throw n;return moveAcrossDevice(t,e,r)}}function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};s(t,e,n);return c(t)}t.exports=moveSync},816:(t,e,r)=>{const n=r(423);const i=r(928);const{copy:s}=r(509);const{remove:c}=r(720);const{mkdirp:o}=r(552);const{pathExists:a}=r(170);const y=r(0);async function move(t,e,r={}){const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=await y.checkPaths(t,e,"move",r);await y.checkParentPaths(t,s,e,"move");const a=i.dirname(e);const u=i.parse(a);if(u.root!==a){await o(a)}return doRename(t,e,n,c)}async function doRename(t,e,r,i){if(!i){if(r){await c(e)}else if(await a(e)){throw new Error("dest already exists.")}}try{await n.rename(t,e)}catch(n){if(n.code!=="EXDEV"){throw n}await moveAcrossDevice(t,e,r)}}async function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};await s(t,e,n);return c(t)}t.exports=move},34:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(170).pathExists;async function outputFile(t,e,r="utf-8"){const n=s.dirname(t);if(!await o(n)){await c.mkdirs(n)}return i.writeFile(t,e,r)}function outputFileSync(t,...e){const r=s.dirname(t);if(!i.existsSync(r)){c.mkdirsSync(r)}i.writeFileSync(t,...e)}t.exports={outputFile:n(outputFile),outputFileSync:outputFileSync}},170:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);function pathExists(t){return i.access(t).then((()=>true)).catch((()=>false))}t.exports={pathExists:n(pathExists),pathExistsSync:i.existsSync}},720:(t,e,r)=>{const n=r(24);const i=r(282).fromCallback;function remove(t,e){n.rm(t,{recursive:true,force:true},e)}function removeSync(t){n.rmSync(t,{recursive:true,force:true})}t.exports={remove:i(remove),removeSync:removeSync}},768:t=>{async function asyncIteratorConcurrentProcess(t,e){const r=[];for await(const n of t){r.push(e(n).then((()=>null),(t=>t??new Error("unknown error"))))}await Promise.all(r.map((t=>t.then((t=>{if(t!==null)throw t})))))}t.exports={asyncIteratorConcurrentProcess:asyncIteratorConcurrentProcess}},0:(t,e,r)=>{const n=r(423);const i=r(928);const s=r(282).fromPromise;function getStats(t,e,r){const i=r.dereference?t=>n.stat(t,{bigint:true}):t=>n.lstat(t,{bigint:true});return Promise.all([i(t),i(e).catch((t=>{if(t.code==="ENOENT")return null;throw t}))]).then((([t,e])=>({srcStat:t,destStat:e})))}function getStatsSync(t,e,r){let i;const s=r.dereference?t=>n.statSync(t,{bigint:true}):t=>n.lstatSync(t,{bigint:true});const c=s(t);try{i=s(e)}catch(t){if(t.code==="ENOENT")return{srcStat:c,destStat:null};throw t}return{srcStat:c,destStat:i}}async function checkPaths(t,e,r,n){const{srcStat:s,destStat:c}=await getStats(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}function checkPathsSync(t,e,r,n){const{srcStat:s,destStat:c}=getStatsSync(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}async function checkParentPaths(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=await n.stat(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPaths(t,e,o,s)}function checkParentPathsSync(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=n.statSync(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPathsSync(t,e,o,s)}function areIdentical(t,e){return e.ino!==undefined&&e.dev!==undefined&&e.ino===t.ino&&e.dev===t.dev}function isSrcSubdir(t,e){const r=i.resolve(t).split(i.sep).filter((t=>t));const n=i.resolve(e).split(i.sep).filter((t=>t));return r.every(((t,e)=>n[e]===t))}function errMsg(t,e,r){return`Cannot ${r} '${t}' to a subdirectory of itself, '${e}'.`}t.exports={checkPaths:s(checkPaths),checkPathsSync:checkPathsSync,checkParentPaths:s(checkParentPaths),checkParentPathsSync:checkParentPathsSync,isSrcSubdir:isSrcSubdir,areIdentical:areIdentical}},213:(t,e,r)=>{const n=r(423);const i=r(282).fromPromise;async function utimesMillis(t,e,r){const i=await n.open(t,"r+");let s=null;try{await n.futimes(i,e,r)}finally{try{await n.close(i)}catch(t){s=t}}if(s){throw s}}function utimesMillisSync(t,e,r){const i=n.openSync(t,"r+");n.futimesSync(i,e,r);return n.closeSync(i)}t.exports={utimesMillis:i(utimesMillis),utimesMillisSync:utimesMillisSync}},395:(t,e,r)=>{let n;try{n=r(24)}catch(t){n=r(896)}const i=r(282);const{stringify:s,stripBom:c}=r(366);async function _readFile(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const s="throws"in e?e.throws:true;let o=await i.fromCallback(r.readFile)(t,e);o=c(o);let a;try{a=JSON.parse(o,e?e.reviver:null)}catch(e){if(s){e.message=`${t}: ${e.message}`;throw e}else{return null}}return a}const o=i.fromPromise(_readFile);function readFileSync(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const i="throws"in e?e.throws:true;try{let n=r.readFileSync(t,e);n=c(n);return JSON.parse(n,e.reviver)}catch(e){if(i){e.message=`${t}: ${e.message}`;throw e}else{return null}}}async function _writeFile(t,e,r={}){const c=r.fs||n;const o=s(e,r);await i.fromCallback(c.writeFile)(t,o,r)}const a=i.fromPromise(_writeFile);function writeFileSync(t,e,r={}){const i=r.fs||n;const c=s(e,r);return i.writeFileSync(t,c,r)}t.exports={readFile:o,readFileSync:readFileSync,writeFile:a,writeFileSync:writeFileSync}},366:t=>{function stringify(t,{EOL:e="\n",finalEOL:r=true,replacer:n=null,spaces:i}={}){const s=r?e:"";const c=JSON.stringify(t,n,i);return c.replace(/\n/g,e)+s}function stripBom(t){if(Buffer.isBuffer(t))t=t.toString("utf8");return t.replace(/^\uFEFF/,"")}t.exports={stringify:stringify,stripBom:stripBom}},282:(t,e)=>{e.fromCallback=function(t){return Object.defineProperty((function(...e){if(typeof e[e.length-1]==="function")t.apply(this,e);else{return new Promise(((r,n)=>{e.push(((t,e)=>t!=null?n(t):r(e)));t.apply(this,e)}))}}),"name",{value:t.name})};e.fromPromise=function(t){return Object.defineProperty((function(...e){const r=e[e.length-1];if(typeof r!=="function")return t.apply(this,e);else{e.pop();t.apply(this,e).then((t=>r(null,t)),r)}}),"name",{value:t.name})}},896:e=>{e.exports=t(import.meta.url)("fs")},24:e=>{e.exports=t(import.meta.url)("node:fs")},928:e=>{e.exports=t(import.meta.url)("path")}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var i=r[t]={exports:{}};var s=true;try{e[t](i,i.exports,__nccwpck_require__);s=false}finally{if(s)delete r[t]}return i.exports}(()=>{__nccwpck_require__.d=(t,e)=>{for(var r in e){if(__nccwpck_require__.o(e,r)&&!__nccwpck_require__.o(t,r)){Object.defineProperty(t,r,{enumerable:true,get:e[r]})}}}})();(()=>{__nccwpck_require__.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=new URL(".",import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/)?1:0,-1)+"/";var n={};__nccwpck_require__.d(n,{A0:()=>X,Ay:()=>nt,C:()=>m,CJ:()=>d,CO:()=>T,Cy:()=>K,EC:()=>rt,EX:()=>v,F3:()=>V,FG:()=>H,GF:()=>$,GT:()=>S,Gu:()=>G,HX:()=>tt,I4:()=>M,JQ:()=>R,Jh:()=>D,L6:()=>x,Nc:()=>U,TF:()=>et,TK:()=>Q,TQ:()=>O,U6:()=>P,Vh:()=>N,W6:()=>L,Wd:()=>q,Wl:()=>F,Z6:()=>h,ah:()=>B,bH:()=>A,bh:()=>b,cJ:()=>E,d:()=>_,f$:()=>w,gg:()=>C,h4:()=>W,hi:()=>J,i9:()=>Y,k:()=>I,nf:()=>Z,pP:()=>p,py:()=>j,s0:()=>z,x3:()=>k,yY:()=>g});var i=__nccwpck_require__(509);var s=__nccwpck_require__(817);var c=__nccwpck_require__(58);var o=__nccwpck_require__(342);var a=__nccwpck_require__(552);var y=__nccwpck_require__(29);var u=__nccwpck_require__(34);var l=__nccwpck_require__(170);var f=__nccwpck_require__(720);const m=i.copy;const p=i.copySync;const S=s.emptyDirSync;const d=s.emptydirSync;const w=s.emptyDir;const h=s.emptydir;const k=c.createFile;const v=c.createFileSync;const b=c.ensureFile;const F=c.ensureFileSync;const _=c.createLink;const P=c.createLinkSync;const x=c.ensureLink;const g=c.ensureLinkSync;const E=c.createSymlink;const D=c.createSymlinkSync;const C=c.ensureSymlink;const J=c.ensureSymlinkSync;const N=o.readJson;const O=o.readJSON;const L=o.readJsonSync;const T=o.readJSONSync;const $=o.writeJson;const I=o.writeJSON;const W=o.writeJsonSync;const A=o.writeJSONSync;const q=o.outputJson;const M=o.outputJSON;const j=o.outputJsonSync;const R=o.outputJSONSync;const U=a.mkdirs;const B=a.mkdirsSync;const G=a.mkdirp;const V=a.mkdirpSync;const X=a.ensureDir;const H=a.ensureDirSync;const K=y.move;const Q=y.moveSync;const Y=u.outputFile;const Z=u.outputFileSync;const z=l.pathExists;const tt=l.pathExistsSync;const et=f.remove;const rt=f.removeSync;const nt={...i,...s,...c,...o,...a,...y,...u,...l,...f};var it=n.C;var st=n.pP;var ct=n.x3;var ot=n.EX;var at=n.d;var yt=n.U6;var ut=n.cJ;var lt=n.Jh;var ft=n.Ay;var mt=n.f$;var pt=n.GT;var St=n.Z6;var dt=n.CJ;var wt=n.A0;var ht=n.FG;var kt=n.bh;var vt=n.Wl;var bt=n.L6;var Ft=n.yY;var _t=n.gg;var Pt=n.hi;var xt=n.Gu;var gt=n.F3;var Et=n.Nc;var Dt=n.ah;var Ct=n.Cy;var Jt=n.TK;var Nt=n.i9;var Ot=n.nf;var Lt=n.I4;var Tt=n.JQ;var $t=n.Wd;var It=n.py;var Wt=n.s0;var At=n.HX;var qt=n.TQ;var Mt=n.CO;var jt=n.Vh;var Rt=n.W6;var Ut=n.TF;var Bt=n.EC;var Gt=n.k;var Vt=n.bH;var Xt=n.GF;var Ht=n.h4;export{it as copy,st as copySync,ct as createFile,ot as createFileSync,at as createLink,yt as createLinkSync,ut as createSymlink,lt as createSymlinkSync,ft as default,mt as emptyDir,pt as emptyDirSync,St as emptydir,dt as emptydirSync,wt as ensureDir,ht as ensureDirSync,kt as ensureFile,vt as ensureFileSync,bt as ensureLink,Ft as ensureLinkSync,_t as ensureSymlink,Pt as ensureSymlinkSync,xt as mkdirp,gt as mkdirpSync,Et as mkdirs,Dt as mkdirsSync,Ct as move,Jt as moveSync,Nt as outputFile,Ot as outputFileSync,Lt as outputJSON,Tt as outputJSONSync,$t as outputJson,It as outputJsonSync,Wt as pathExists,At as pathExistsSync,qt as readJSON,Mt as readJSONSync,jt as readJson,Rt as readJsonSync,Ut as remove,Bt as removeSync,Gt as writeJSON,Vt as writeJSONSync,Xt as writeJson,Ht as writeJsonSync}; \ No newline at end of file diff --git a/packages/toolkit/utils/compiled/fs-extra/index.mjs b/packages/toolkit/utils/compiled/fs-extra/index.mjs index ac0f43c17abc..70d42d7922ff 100644 --- a/packages/toolkit/utils/compiled/fs-extra/index.mjs +++ b/packages/toolkit/utils/compiled/fs-extra/index.mjs @@ -1 +1,4 @@ -import{createRequire as t}from"module";var e={901:(t,e,r)=>{const n=r(24);const i=r(928);const s=r(552).mkdirsSync;const c=r(213).utimesMillisSync;const o=r(0);function copySync(t,e,r){if(typeof r==="function"){r={filter:r}}r=r||{};r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0002")}const{srcStat:c,destStat:a}=o.checkPathsSync(t,e,"copy",r);o.checkParentPathsSync(t,c,e,"copy");if(r.filter&&!r.filter(t,e))return;const y=i.dirname(e);if(!n.existsSync(y))s(y);return getStats(a,t,e,r)}function getStats(t,e,r,i){const s=i.dereference?n.statSync:n.lstatSync;const c=s(e);if(c.isDirectory())return onDir(c,t,e,r,i);else if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);else if(c.isSymbolicLink())return onLink(t,e,r,i);else if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);else if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}function onFile(t,e,r,n,i){if(!e)return copyFile(t,r,n,i);return mayCopyFile(t,r,n,i)}function mayCopyFile(t,e,r,i){if(i.overwrite){n.unlinkSync(r);return copyFile(t,e,r,i)}else if(i.errorOnExist){throw new Error(`'${r}' already exists`)}}function copyFile(t,e,r,i){n.copyFileSync(e,r);if(i.preserveTimestamps)handleTimestamps(t.mode,e,r);return setDestMode(r,t.mode)}function handleTimestamps(t,e,r){if(fileIsNotWritable(t))makeFileWritable(r,t);return setDestTimestamps(e,r)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return setDestMode(t,e|128)}function setDestMode(t,e){return n.chmodSync(t,e)}function setDestTimestamps(t,e){const r=n.statSync(t);return c(e,r.atime,r.mtime)}function onDir(t,e,r,n,i){if(!e)return mkDirAndCopy(t.mode,r,n,i);return copyDir(r,n,i)}function mkDirAndCopy(t,e,r,i){n.mkdirSync(r);copyDir(e,r,i);return setDestMode(r,t)}function copyDir(t,e,r){const i=n.opendirSync(t);try{let n;while((n=i.readSync())!==null){copyDirItem(n.name,t,e,r)}}finally{i.closeSync()}}function copyDirItem(t,e,r,n){const s=i.join(e,t);const c=i.join(r,t);if(n.filter&&!n.filter(s,c))return;const{destStat:a}=o.checkPathsSync(s,c,"copy",n);return getStats(a,s,c,n)}function onLink(t,e,r,s){let c=n.readlinkSync(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlinkSync(c,r)}else{let t;try{t=n.readlinkSync(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlinkSync(c,r);throw t}if(s.dereference){t=i.resolve(process.cwd(),t)}if(c!==t){if(o.isSrcSubdir(c,t)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${t}'.`)}if(o.isSrcSubdir(t,c)){throw new Error(`Cannot overwrite '${t}' with '${c}'.`)}}return copyLink(c,r)}}function copyLink(t,e){n.unlinkSync(e);return n.symlinkSync(t,e)}t.exports=copySync},600:(t,e,r)=>{const n=r(423);const i=r(928);const{mkdirs:s}=r(552);const{pathExists:c}=r(170);const{utimesMillis:o}=r(213);const a=r(0);const{asyncIteratorConcurrentProcess:y}=r(768);async function copy(t,e,r={}){if(typeof r==="function"){r={filter:r}}r.clobber="clobber"in r?!!r.clobber:true;r.overwrite="overwrite"in r?!!r.overwrite:r.clobber;if(r.preserveTimestamps&&process.arch==="ia32"){process.emitWarning("Using the preserveTimestamps option in 32-bit node is not recommended;\n\n"+"\tsee https://github.com/jprichardson/node-fs-extra/issues/269","Warning","fs-extra-WARN0001")}const{srcStat:n,destStat:o}=await a.checkPaths(t,e,"copy",r);await a.checkParentPaths(t,n,e,"copy");const y=await runFilter(t,e,r);if(!y)return;const u=i.dirname(e);const l=await c(u);if(!l){await s(u)}await getStatsAndPerformCopy(o,t,e,r)}async function runFilter(t,e,r){if(!r.filter)return true;return r.filter(t,e)}async function getStatsAndPerformCopy(t,e,r,i){const s=i.dereference?n.stat:n.lstat;const c=await s(e);if(c.isDirectory())return onDir(c,t,e,r,i);if(c.isFile()||c.isCharacterDevice()||c.isBlockDevice())return onFile(c,t,e,r,i);if(c.isSymbolicLink())return onLink(t,e,r,i);if(c.isSocket())throw new Error(`Cannot copy a socket file: ${e}`);if(c.isFIFO())throw new Error(`Cannot copy a FIFO pipe: ${e}`);throw new Error(`Unknown file: ${e}`)}async function onFile(t,e,r,i,s){if(!e)return copyFile(t,r,i,s);if(s.overwrite){await n.unlink(i);return copyFile(t,r,i,s)}if(s.errorOnExist){throw new Error(`'${i}' already exists`)}}async function copyFile(t,e,r,i){await n.copyFile(e,r);if(i.preserveTimestamps){if(fileIsNotWritable(t.mode)){await makeFileWritable(r,t.mode)}const i=await n.stat(e);await o(r,i.atime,i.mtime)}return n.chmod(r,t.mode)}function fileIsNotWritable(t){return(t&128)===0}function makeFileWritable(t,e){return n.chmod(t,e|128)}async function onDir(t,e,r,s,c){if(!e){await n.mkdir(s)}await y(await n.opendir(r),(async t=>{const e=i.join(r,t.name);const n=i.join(s,t.name);const o=await runFilter(e,n,c);if(o){const{destStat:t}=await a.checkPaths(e,n,"copy",c);await getStatsAndPerformCopy(t,e,n,c)}}));if(!e){await n.chmod(s,t.mode)}}async function onLink(t,e,r,s){let c=await n.readlink(e);if(s.dereference){c=i.resolve(process.cwd(),c)}if(!t){return n.symlink(c,r)}let o=null;try{o=await n.readlink(r)}catch(t){if(t.code==="EINVAL"||t.code==="UNKNOWN")return n.symlink(c,r);throw t}if(s.dereference){o=i.resolve(process.cwd(),o)}if(c!==o){if(a.isSrcSubdir(c,o)){throw new Error(`Cannot copy '${c}' to a subdirectory of itself, '${o}'.`)}if(a.isSrcSubdir(o,c)){throw new Error(`Cannot overwrite '${o}' with '${c}'.`)}}await n.unlink(r);return n.symlink(c,r)}t.exports=copy},509:(t,e,r)=>{const n=r(282).fromPromise;t.exports={copy:n(r(600)),copySync:r(901)}},817:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(720);const a=n((async function emptyDir(t){let e;try{e=await i.readdir(t)}catch{return c.mkdirs(t)}return Promise.all(e.map((e=>o.remove(s.join(t,e)))))}));function emptyDirSync(t){let e;try{e=i.readdirSync(t)}catch{return c.mkdirsSync(t)}e.forEach((e=>{e=s.join(t,e);o.removeSync(e)}))}t.exports={emptyDirSync:emptyDirSync,emptydirSync:emptyDirSync,emptyDir:a,emptydir:a}},46:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);async function createFile(t){let e;try{e=await s.stat(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);let n=null;try{n=await s.stat(r)}catch(e){if(e.code==="ENOENT"){await c.mkdirs(r);await s.writeFile(t,"");return}else{throw e}}if(n.isDirectory()){await s.writeFile(t,"")}else{await s.readdir(r)}}function createFileSync(t){let e;try{e=s.statSync(t)}catch{}if(e&&e.isFile())return;const r=i.dirname(t);try{if(!s.statSync(r).isDirectory()){s.readdirSync(r)}}catch(t){if(t&&t.code==="ENOENT")c.mkdirsSync(r);else throw t}s.writeFileSync(t,"")}t.exports={createFile:n(createFile),createFileSync:createFileSync}},58:(t,e,r)=>{const{createFile:n,createFileSync:i}=r(46);const{createLink:s,createLinkSync:c}=r(196);const{createSymlink:o,createSymlinkSync:a}=r(933);t.exports={createFile:n,createFileSync:i,ensureFile:n,ensureFileSync:i,createLink:s,createLinkSync:c,ensureLink:s,ensureLinkSync:c,createSymlink:o,createSymlinkSync:a,ensureSymlink:o,ensureSymlinkSync:a}},196:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const c=r(552);const{pathExists:o}=r(170);const{areIdentical:a}=r(0);async function createLink(t,e){let r;try{r=await s.lstat(e)}catch{}let n;try{n=await s.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}if(r&&a(n,r))return;const y=i.dirname(e);const u=await o(y);if(!u){await c.mkdirs(y)}await s.link(t,e)}function createLinkSync(t,e){let r;try{r=s.lstatSync(e)}catch{}try{const e=s.lstatSync(t);if(r&&a(e,r))return}catch(t){t.message=t.message.replace("lstat","ensureLink");throw t}const n=i.dirname(e);const o=s.existsSync(n);if(o)return s.linkSync(t,e);c.mkdirsSync(n);return s.linkSync(t,e)}t.exports={createLink:n(createLink),createLinkSync:createLinkSync}},492:(t,e,r)=>{const n=r(928);const i=r(423);const{pathExists:s}=r(170);const c=r(282).fromPromise;async function symlinkPaths(t,e){if(n.isAbsolute(t)){try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:t}}const r=n.dirname(e);const c=n.join(r,t);const o=await s(c);if(o){return{toCwd:c,toDst:t}}try{await i.lstat(t)}catch(t){t.message=t.message.replace("lstat","ensureSymlink");throw t}return{toCwd:t,toDst:n.relative(r,t)}}function symlinkPathsSync(t,e){if(n.isAbsolute(t)){const e=i.existsSync(t);if(!e)throw new Error("absolute srcpath does not exist");return{toCwd:t,toDst:t}}const r=n.dirname(e);const s=n.join(r,t);const c=i.existsSync(s);if(c){return{toCwd:s,toDst:t}}const o=i.existsSync(t);if(!o)throw new Error("relative srcpath does not exist");return{toCwd:t,toDst:n.relative(r,t)}}t.exports={symlinkPaths:c(symlinkPaths),symlinkPathsSync:symlinkPathsSync}},126:(t,e,r)=>{const n=r(423);const i=r(282).fromPromise;async function symlinkType(t,e){if(e)return e;let r;try{r=await n.lstat(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}function symlinkTypeSync(t,e){if(e)return e;let r;try{r=n.lstatSync(t)}catch{return"file"}return r&&r.isDirectory()?"dir":"file"}t.exports={symlinkType:i(symlinkType),symlinkTypeSync:symlinkTypeSync}},933:(t,e,r)=>{const n=r(282).fromPromise;const i=r(928);const s=r(423);const{mkdirs:c,mkdirsSync:o}=r(552);const{symlinkPaths:a,symlinkPathsSync:y}=r(492);const{symlinkType:u,symlinkTypeSync:l}=r(126);const{pathExists:f}=r(170);const{areIdentical:m}=r(0);async function createSymlink(t,e,r){let n;try{n=await s.lstat(e)}catch{}if(n&&n.isSymbolicLink()){const[r,n]=await Promise.all([s.stat(t),s.stat(e)]);if(m(r,n))return}const o=await a(t,e);t=o.toDst;const y=await u(o.toCwd,r);const l=i.dirname(e);if(!await f(l)){await c(l)}return s.symlink(t,e,y)}function createSymlinkSync(t,e,r){let n;try{n=s.lstatSync(e)}catch{}if(n&&n.isSymbolicLink()){const r=s.statSync(t);const n=s.statSync(e);if(m(r,n))return}const c=y(t,e);t=c.toDst;r=l(c.toCwd,r);const a=i.dirname(e);const u=s.existsSync(a);if(u)return s.symlinkSync(t,e,r);o(a);return s.symlinkSync(t,e,r)}t.exports={createSymlink:n(createSymlink),createSymlinkSync:createSymlinkSync}},423:(t,e,r)=>{const n=r(282).fromCallback;const i=r(24);const s=["access","appendFile","chmod","chown","close","copyFile","cp","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","glob","lchmod","lchown","lutimes","link","lstat","mkdir","mkdtemp","open","opendir","readdir","readFile","readlink","realpath","rename","rm","rmdir","stat","statfs","symlink","truncate","unlink","utimes","writeFile"].filter((t=>typeof i[t]==="function"));Object.assign(e,i);s.forEach((t=>{e[t]=n(i[t])}));e.exists=function(t,e){if(typeof e==="function"){return i.exists(t,e)}return new Promise((e=>i.exists(t,e)))};e.read=function(t,e,r,n,s,c){if(typeof c==="function"){return i.read(t,e,r,n,s,c)}return new Promise(((c,o)=>{i.read(t,e,r,n,s,((t,e,r)=>{if(t)return o(t);c({bytesRead:e,buffer:r})}))}))};e.write=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.write(t,e,...r)}return new Promise(((n,s)=>{i.write(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffer:r})}))}))};e.readv=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.readv(t,e,...r)}return new Promise(((n,s)=>{i.readv(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesRead:e,buffers:r})}))}))};e.writev=function(t,e,...r){if(typeof r[r.length-1]==="function"){return i.writev(t,e,...r)}return new Promise(((n,s)=>{i.writev(t,e,...r,((t,e,r)=>{if(t)return s(t);n({bytesWritten:e,buffers:r})}))}))};if(typeof i.realpath.native==="function"){e.realpath.native=n(i.realpath.native)}else{process.emitWarning("fs.realpath.native is not a function. Is fs being monkey-patched?","Warning","fs-extra-WARN0003")}},342:(t,e,r)=>{const n=r(282).fromPromise;const i=r(424);i.outputJson=n(r(472));i.outputJsonSync=r(618);i.outputJSON=i.outputJson;i.outputJSONSync=i.outputJsonSync;i.writeJSON=i.writeJson;i.writeJSONSync=i.writeJsonSync;i.readJSON=i.readJson;i.readJSONSync=i.readJsonSync;t.exports=i},424:(t,e,r)=>{const n=r(395);t.exports={readJson:n.readFile,readJsonSync:n.readFileSync,writeJson:n.writeFile,writeJsonSync:n.writeFileSync}},618:(t,e,r)=>{const{stringify:n}=r(366);const{outputFileSync:i}=r(34);function outputJsonSync(t,e,r){const s=n(e,r);i(t,s,r)}t.exports=outputJsonSync},472:(t,e,r)=>{const{stringify:n}=r(366);const{outputFile:i}=r(34);async function outputJson(t,e,r={}){const s=n(e,r);await i(t,s,r)}t.exports=outputJson},552:(t,e,r)=>{const n=r(282).fromPromise;const{makeDir:i,makeDirSync:s}=r(974);const c=n(i);t.exports={mkdirs:c,mkdirsSync:s,mkdirp:c,mkdirpSync:s,ensureDir:c,ensureDirSync:s}},974:(t,e,r)=>{const n=r(423);const{checkPath:i}=r(9);const getMode=t=>{const e={mode:511};if(typeof t==="number")return t;return{...e,...t}.mode};t.exports.makeDir=async(t,e)=>{i(t);return n.mkdir(t,{mode:getMode(e),recursive:true})};t.exports.makeDirSync=(t,e)=>{i(t);return n.mkdirSync(t,{mode:getMode(e),recursive:true})}},9:(t,e,r)=>{const n=r(928);t.exports.checkPath=function checkPath(t){if(process.platform==="win32"){const e=/[<>:"|?*]/.test(t.replace(n.parse(t).root,""));if(e){const e=new Error(`Path contains invalid characters: ${t}`);e.code="EINVAL";throw e}}}},29:(t,e,r)=>{const n=r(282).fromPromise;t.exports={move:n(r(816)),moveSync:r(610)}},610:(t,e,r)=>{const n=r(24);const i=r(928);const s=r(509).copySync;const c=r(720).removeSync;const o=r(552).mkdirpSync;const a=r(0);function moveSync(t,e,r){r=r||{};const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=a.checkPathsSync(t,e,"move",r);a.checkParentPathsSync(t,s,e,"move");if(!isParentRoot(e))o(i.dirname(e));return doRename(t,e,n,c)}function isParentRoot(t){const e=i.dirname(t);const r=i.parse(e);return r.root===e}function doRename(t,e,r,i){if(i)return rename(t,e,r);if(r){c(e);return rename(t,e,r)}if(n.existsSync(e))throw new Error("dest already exists.");return rename(t,e,r)}function rename(t,e,r){try{n.renameSync(t,e)}catch(n){if(n.code!=="EXDEV")throw n;return moveAcrossDevice(t,e,r)}}function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};s(t,e,n);return c(t)}t.exports=moveSync},816:(t,e,r)=>{const n=r(423);const i=r(928);const{copy:s}=r(509);const{remove:c}=r(720);const{mkdirp:o}=r(552);const{pathExists:a}=r(170);const y=r(0);async function move(t,e,r={}){const n=r.overwrite||r.clobber||false;const{srcStat:s,isChangingCase:c=false}=await y.checkPaths(t,e,"move",r);await y.checkParentPaths(t,s,e,"move");const a=i.dirname(e);const u=i.parse(a);if(u.root!==a){await o(a)}return doRename(t,e,n,c)}async function doRename(t,e,r,i){if(!i){if(r){await c(e)}else if(await a(e)){throw new Error("dest already exists.")}}try{await n.rename(t,e)}catch(n){if(n.code!=="EXDEV"){throw n}await moveAcrossDevice(t,e,r)}}async function moveAcrossDevice(t,e,r){const n={overwrite:r,errorOnExist:true,preserveTimestamps:true};await s(t,e,n);return c(t)}t.exports=move},34:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);const s=r(928);const c=r(552);const o=r(170).pathExists;async function outputFile(t,e,r="utf-8"){const n=s.dirname(t);if(!await o(n)){await c.mkdirs(n)}return i.writeFile(t,e,r)}function outputFileSync(t,...e){const r=s.dirname(t);if(!i.existsSync(r)){c.mkdirsSync(r)}i.writeFileSync(t,...e)}t.exports={outputFile:n(outputFile),outputFileSync:outputFileSync}},170:(t,e,r)=>{const n=r(282).fromPromise;const i=r(423);function pathExists(t){return i.access(t).then((()=>true)).catch((()=>false))}t.exports={pathExists:n(pathExists),pathExistsSync:i.existsSync}},720:(t,e,r)=>{const n=r(24);const i=r(282).fromCallback;function remove(t,e){n.rm(t,{recursive:true,force:true},e)}function removeSync(t){n.rmSync(t,{recursive:true,force:true})}t.exports={remove:i(remove),removeSync:removeSync}},768:t=>{async function asyncIteratorConcurrentProcess(t,e){const r=[];for await(const n of t){r.push(e(n).then((()=>null),(t=>t??new Error("unknown error"))))}await Promise.all(r.map((t=>t.then((t=>{if(t!==null)throw t})))))}t.exports={asyncIteratorConcurrentProcess:asyncIteratorConcurrentProcess}},0:(t,e,r)=>{const n=r(423);const i=r(928);const s=r(282).fromPromise;function getStats(t,e,r){const i=r.dereference?t=>n.stat(t,{bigint:true}):t=>n.lstat(t,{bigint:true});return Promise.all([i(t),i(e).catch((t=>{if(t.code==="ENOENT")return null;throw t}))]).then((([t,e])=>({srcStat:t,destStat:e})))}function getStatsSync(t,e,r){let i;const s=r.dereference?t=>n.statSync(t,{bigint:true}):t=>n.lstatSync(t,{bigint:true});const c=s(t);try{i=s(e)}catch(t){if(t.code==="ENOENT")return{srcStat:c,destStat:null};throw t}return{srcStat:c,destStat:i}}async function checkPaths(t,e,r,n){const{srcStat:s,destStat:c}=await getStats(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}function checkPathsSync(t,e,r,n){const{srcStat:s,destStat:c}=getStatsSync(t,e,n);if(c){if(areIdentical(s,c)){const n=i.basename(t);const o=i.basename(e);if(r==="move"&&n!==o&&n.toLowerCase()===o.toLowerCase()){return{srcStat:s,destStat:c,isChangingCase:true}}throw new Error("Source and destination must not be the same.")}if(s.isDirectory()&&!c.isDirectory()){throw new Error(`Cannot overwrite non-directory '${e}' with directory '${t}'.`)}if(!s.isDirectory()&&c.isDirectory()){throw new Error(`Cannot overwrite directory '${e}' with non-directory '${t}'.`)}}if(s.isDirectory()&&isSrcSubdir(t,e)){throw new Error(errMsg(t,e,r))}return{srcStat:s,destStat:c}}async function checkParentPaths(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=await n.stat(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPaths(t,e,o,s)}function checkParentPathsSync(t,e,r,s){const c=i.resolve(i.dirname(t));const o=i.resolve(i.dirname(r));if(o===c||o===i.parse(o).root)return;let a;try{a=n.statSync(o,{bigint:true})}catch(t){if(t.code==="ENOENT")return;throw t}if(areIdentical(e,a)){throw new Error(errMsg(t,r,s))}return checkParentPathsSync(t,e,o,s)}function areIdentical(t,e){return e.ino!==undefined&&e.dev!==undefined&&e.ino===t.ino&&e.dev===t.dev}function isSrcSubdir(t,e){const r=i.resolve(t).split(i.sep).filter((t=>t));const n=i.resolve(e).split(i.sep).filter((t=>t));return r.every(((t,e)=>n[e]===t))}function errMsg(t,e,r){return`Cannot ${r} '${t}' to a subdirectory of itself, '${e}'.`}t.exports={checkPaths:s(checkPaths),checkPathsSync:checkPathsSync,checkParentPaths:s(checkParentPaths),checkParentPathsSync:checkParentPathsSync,isSrcSubdir:isSrcSubdir,areIdentical:areIdentical}},213:(t,e,r)=>{const n=r(423);const i=r(282).fromPromise;async function utimesMillis(t,e,r){const i=await n.open(t,"r+");let s=null;try{await n.futimes(i,e,r)}finally{try{await n.close(i)}catch(t){s=t}}if(s){throw s}}function utimesMillisSync(t,e,r){const i=n.openSync(t,"r+");n.futimesSync(i,e,r);return n.closeSync(i)}t.exports={utimesMillis:i(utimesMillis),utimesMillisSync:utimesMillisSync}},395:(t,e,r)=>{let n;try{n=r(24)}catch(t){n=r(896)}const i=r(282);const{stringify:s,stripBom:c}=r(366);async function _readFile(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const s="throws"in e?e.throws:true;let o=await i.fromCallback(r.readFile)(t,e);o=c(o);let a;try{a=JSON.parse(o,e?e.reviver:null)}catch(e){if(s){e.message=`${t}: ${e.message}`;throw e}else{return null}}return a}const o=i.fromPromise(_readFile);function readFileSync(t,e={}){if(typeof e==="string"){e={encoding:e}}const r=e.fs||n;const i="throws"in e?e.throws:true;try{let n=r.readFileSync(t,e);n=c(n);return JSON.parse(n,e.reviver)}catch(e){if(i){e.message=`${t}: ${e.message}`;throw e}else{return null}}}async function _writeFile(t,e,r={}){const c=r.fs||n;const o=s(e,r);await i.fromCallback(c.writeFile)(t,o,r)}const a=i.fromPromise(_writeFile);function writeFileSync(t,e,r={}){const i=r.fs||n;const c=s(e,r);return i.writeFileSync(t,c,r)}t.exports={readFile:o,readFileSync:readFileSync,writeFile:a,writeFileSync:writeFileSync}},366:t=>{function stringify(t,{EOL:e="\n",finalEOL:r=true,replacer:n=null,spaces:i}={}){const s=r?e:"";const c=JSON.stringify(t,n,i);return c.replace(/\n/g,e)+s}function stripBom(t){if(Buffer.isBuffer(t))t=t.toString("utf8");return t.replace(/^\uFEFF/,"")}t.exports={stringify:stringify,stripBom:stripBom}},282:(t,e)=>{e.fromCallback=function(t){return Object.defineProperty((function(...e){if(typeof e[e.length-1]==="function")t.apply(this,e);else{return new Promise(((r,n)=>{e.push(((t,e)=>t!=null?n(t):r(e)));t.apply(this,e)}))}}),"name",{value:t.name})};e.fromPromise=function(t){return Object.defineProperty((function(...e){const r=e[e.length-1];if(typeof r!=="function")return t.apply(this,e);else{e.pop();t.apply(this,e).then((t=>r(null,t)),r)}}),"name",{value:t.name})}},896:e=>{e.exports=t(import.meta.url)("fs")},24:e=>{e.exports=t(import.meta.url)("node:fs")},928:e=>{e.exports=t(import.meta.url)("path")}};var r={};function __nccwpck_require__(t){var n=r[t];if(n!==undefined){return n.exports}var i=r[t]={exports:{}};var s=true;try{e[t](i,i.exports,__nccwpck_require__);s=false}finally{if(s)delete r[t]}return i.exports}(()=>{__nccwpck_require__.d=(t,e)=>{for(var r in e){if(__nccwpck_require__.o(e,r)&&!__nccwpck_require__.o(t,r)){Object.defineProperty(t,r,{enumerable:true,get:e[r]})}}}})();(()=>{__nccwpck_require__.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e)})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=new URL(".",import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/)?1:0,-1)+"/";var n={};__nccwpck_require__.d(n,{A0:()=>X,Ay:()=>nt,C:()=>m,CJ:()=>d,CO:()=>T,Cy:()=>K,EC:()=>rt,EX:()=>v,F3:()=>V,FG:()=>H,GF:()=>$,GT:()=>S,Gu:()=>G,HX:()=>tt,I4:()=>M,JQ:()=>R,Jh:()=>D,L6:()=>x,Nc:()=>U,TF:()=>et,TK:()=>Q,TQ:()=>O,U6:()=>P,Vh:()=>N,W6:()=>L,Wd:()=>q,Wl:()=>F,Z6:()=>h,ah:()=>B,bH:()=>A,bh:()=>b,cJ:()=>E,d:()=>_,f$:()=>w,gg:()=>C,h4:()=>W,hi:()=>J,i9:()=>Y,k:()=>I,nf:()=>Z,pP:()=>p,py:()=>j,s0:()=>z,x3:()=>k,yY:()=>g});var i=__nccwpck_require__(509);var s=__nccwpck_require__(817);var c=__nccwpck_require__(58);var o=__nccwpck_require__(342);var a=__nccwpck_require__(552);var y=__nccwpck_require__(29);var u=__nccwpck_require__(34);var l=__nccwpck_require__(170);var f=__nccwpck_require__(720);const m=i.copy;const p=i.copySync;const S=s.emptyDirSync;const d=s.emptydirSync;const w=s.emptyDir;const h=s.emptydir;const k=c.createFile;const v=c.createFileSync;const b=c.ensureFile;const F=c.ensureFileSync;const _=c.createLink;const P=c.createLinkSync;const x=c.ensureLink;const g=c.ensureLinkSync;const E=c.createSymlink;const D=c.createSymlinkSync;const C=c.ensureSymlink;const J=c.ensureSymlinkSync;const N=o.readJson;const O=o.readJSON;const L=o.readJsonSync;const T=o.readJSONSync;const $=o.writeJson;const I=o.writeJSON;const W=o.writeJsonSync;const A=o.writeJSONSync;const q=o.outputJson;const M=o.outputJSON;const j=o.outputJsonSync;const R=o.outputJSONSync;const U=a.mkdirs;const B=a.mkdirsSync;const G=a.mkdirp;const V=a.mkdirpSync;const X=a.ensureDir;const H=a.ensureDirSync;const K=y.move;const Q=y.moveSync;const Y=u.outputFile;const Z=u.outputFileSync;const z=l.pathExists;const tt=l.pathExistsSync;const et=f.remove;const rt=f.removeSync;const nt={...i,...s,...c,...o,...a,...y,...u,...l,...f};var it=n.C;var st=n.pP;var ct=n.x3;var ot=n.EX;var at=n.d;var yt=n.U6;var ut=n.cJ;var lt=n.Jh;var ft=n.Ay;var mt=n.f$;var pt=n.GT;var St=n.Z6;var dt=n.CJ;var wt=n.A0;var ht=n.FG;var kt=n.bh;var vt=n.Wl;var bt=n.L6;var Ft=n.yY;var _t=n.gg;var Pt=n.hi;var xt=n.Gu;var gt=n.F3;var Et=n.Nc;var Dt=n.ah;var Ct=n.Cy;var Jt=n.TK;var Nt=n.i9;var Ot=n.nf;var Lt=n.I4;var Tt=n.JQ;var $t=n.Wd;var It=n.py;var Wt=n.s0;var At=n.HX;var qt=n.TQ;var Mt=n.CO;var jt=n.Vh;var Rt=n.W6;var Ut=n.TF;var Bt=n.EC;var Gt=n.k;var Vt=n.bH;var Xt=n.GF;var Ht=n.h4;export{it as copy,st as copySync,ct as createFile,ot as createFileSync,at as createLink,yt as createLinkSync,ut as createSymlink,lt as createSymlinkSync,ft as default,mt as emptyDir,pt as emptyDirSync,St as emptydir,dt as emptydirSync,wt as ensureDir,ht as ensureDirSync,kt as ensureFile,vt as ensureFileSync,bt as ensureLink,Ft as ensureLinkSync,_t as ensureSymlink,Pt as ensureSymlinkSync,xt as mkdirp,gt as mkdirpSync,Et as mkdirs,Dt as mkdirsSync,Ct as move,Jt as moveSync,Nt as outputFile,Ot as outputFileSync,Lt as outputJSON,Tt as outputJSONSync,$t as outputJson,It as outputJsonSync,Wt as pathExists,At as pathExistsSync,qt as readJSON,Mt as readJSONSync,jt as readJson,Rt as readJsonSync,Ut as remove,Bt as removeSync,Gt as writeJSON,Vt as writeJSONSync,Xt as writeJson,Ht as writeJsonSync}; \ No newline at end of file +import fse from './index.js'; +/* fs-extra esm only exports fs-extra's functions */ +export * from './esm.mjs'; +export default fse; diff --git a/scripts/prebundle/src/constant.ts b/scripts/prebundle/src/constant.ts index 8d3395a33844..6d2e89cc96ef 100644 --- a/scripts/prebundle/src/constant.ts +++ b/scripts/prebundle/src/constant.ts @@ -81,6 +81,8 @@ export const TASKS: TaskConfig[] = [ { name: 'fs-extra', esmAlias: 'fs-extra/esm', + esmOutput: 'esm.mjs', + clear: false, externals: { 'graceful-fs': 'node:fs', }, diff --git a/scripts/prebundle/src/helper.ts b/scripts/prebundle/src/helper.ts index 939fd2da1cce..f385ecfea664 100644 --- a/scripts/prebundle/src/helper.ts +++ b/scripts/prebundle/src/helper.ts @@ -64,7 +64,10 @@ export async function parseTasks() { } } - const info = { + const info: Omit< + ParsedTask, + 'minify' | 'externals' | 'emitFiles' | 'packageJsonField' + > = { depName, depPath, depEntry, @@ -76,6 +79,10 @@ export async function parseTasks() { packageName, }; + if (typeof dep === 'object') { + info.depConfig = dep; + } + if (typeof dep === 'string') { result.push({ minify: true, diff --git a/scripts/prebundle/src/prebundle.ts b/scripts/prebundle/src/prebundle.ts index 406523d4ae11..b872050bbff0 100644 --- a/scripts/prebundle/src/prebundle.ts +++ b/scripts/prebundle/src/prebundle.ts @@ -22,8 +22,8 @@ function emitIndex(code: string, distPath: string) { fs.outputFileSync(distIndex, code); } -function emitESMIndex(code: string, distPath: string) { - const distIndex = join(distPath, 'index.mjs'); +function emitESMIndex(code: string, distPath: string, fileName?: string) { + const distIndex = join(distPath, fileName || 'index.mjs'); fs.outputFileSync(distIndex, code); } @@ -185,7 +185,7 @@ export async function prebundle(task: ParsedTask) { minify: task.minify, esm: true, }); - emitESMIndex(esmCode, task.distPath); + emitESMIndex(esmCode, task.distPath, task.depConfig?.esmOutput); } emitIndex(code, task.distPath); diff --git a/scripts/prebundle/src/types.ts b/scripts/prebundle/src/types.ts index ddc94a04b2aa..8a19e3ea21c9 100644 --- a/scripts/prebundle/src/types.ts +++ b/scripts/prebundle/src/types.ts @@ -7,6 +7,8 @@ export type DependencyConfig = { /** Name of dependency */ name: string; esmAlias?: string; + /** Write esm output path */ + esmOutput?: string; /** Whether to minify the code. */ minify?: boolean; /** Externals to leave as requires of the build. */ @@ -45,6 +47,7 @@ export type ParsedTask = { clear?: boolean; packagePath: string; packageName: string; + depConfig?: DependencyConfig; minify: NonNullable; depName: NonNullable; externals: NonNullable; From 81cfedc533732f353186181f0a1f8e3d7f72073c Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 15:09:23 +0800 Subject: [PATCH 06/27] feat: bff in bundle mode --- packages/cli/plugin-bff/src/server.ts | 2 +- packages/server/bff-core/package.json | 1 + packages/server/bff-core/src/router/index.ts | 51 +++++++- packages/server/bff-core/src/router/utils.ts | 11 +- .../src/adapters/node/plugins/resource.ts | 2 +- pnpm-lock.yaml | 123 +----------------- 6 files changed, 58 insertions(+), 132 deletions(-) diff --git a/packages/cli/plugin-bff/src/server.ts b/packages/cli/plugin-bff/src/server.ts index aa14e95a8dd9..f8836ece4d0c 100644 --- a/packages/cli/plugin-bff/src/server.ts +++ b/packages/cli/plugin-bff/src/server.ts @@ -112,7 +112,7 @@ export default (): ServerPlugin => ({ const { pwd, prefix, httpMethodDecider } = input; const apiDir = path.resolve(pwd, API_DIR); const appContext = api.getServerContext(); - const { apiDirectory, lambdaDirectory } = appContext; + const { apiDirectory, lambdaDirectory, dependencies } = appContext; apiRouter = new ApiRouter({ appDir: pwd, apiDir: (apiDirectory as string) || apiDir, diff --git a/packages/server/bff-core/package.json b/packages/server/bff-core/package.json index a71885ba6dcc..5e03db017604 100644 --- a/packages/server/bff-core/package.json +++ b/packages/server/bff-core/package.json @@ -37,6 +37,7 @@ "test": "rstest --passWithNoTests" }, "dependencies": { + "@modern-js/server-core": "workspace:*", "@modern-js/utils": "workspace:*", "@swc/helpers": "^0.5.17", "koa-compose": "^4.1.0", diff --git a/packages/server/bff-core/src/router/index.ts b/packages/server/bff-core/src/router/index.ts index dc304b87527d..1b7349d1eb4e 100644 --- a/packages/server/bff-core/src/router/index.ts +++ b/packages/server/bff-core/src/router/index.ts @@ -1,6 +1,7 @@ import path from 'path'; import { fs, logger } from '@modern-js/utils'; import 'reflect-metadata'; +import { getBundledDep } from '@modern-js/server-core/node'; import type { HttpMethodDecider } from '@modern-js/types'; import { HttpMethod, OperatorType, TriggerType, httpMethods } from '../types'; import { INPUT_PARAMS_DECIDER, debug } from '../utils'; @@ -13,6 +14,7 @@ import type { APIHandlerInfo, ApiHandler, ModuleInfo } from './types'; import { getFiles, getPathFromFilename, + interopHandlerModule, requireHandlerModule, sortRoutes, } from './utils'; @@ -38,6 +40,8 @@ export class ApiRouter { private isBuild?: boolean; + private dependencies?: Record>; + constructor({ appDir, apiDir, @@ -45,6 +49,7 @@ export class ApiRouter { prefix, isBuild, httpMethodDecider = 'functionName', + dependencies, }: { appDir?: string; apiDir: string; @@ -52,17 +57,29 @@ export class ApiRouter { prefix?: string; isBuild?: boolean; httpMethodDecider?: HttpMethodDecider; + dependencies?: Record>; }) { - this.validateAbsolute(apiDir, 'apiDir'); - this.validateAbsolute(lambdaDir, 'lambdaDir'); - this.prefix = this.initPrefix(prefix); this.appDir = appDir; this.apiDir = apiDir; this.httpMethodDecider = httpMethodDecider; this.isBuild = isBuild; this.lambdaDir = this.getExactLambdaDir(this.apiDir, lambdaDir); - this.existLambdaDir = fs.existsSync(this.lambdaDir); + + if (process.env.MODERN_SERVER_BUNDLE) { + if (lambdaDir && dependencies) { + this.existLambdaDir = Object.keys(dependencies).some(x => + x.startsWith(lambdaDir), + ); + } else { + this.existLambdaDir = false; + } + } else { + this.validateAbsolute(apiDir, 'apiDir'); + this.validateAbsolute(lambdaDir, 'lambdaDir'); + this.existLambdaDir = fs.existsSync(this.lambdaDir); + } + debug(`apiDir:`, this.apiDir, `lambdaDir:`, this.lambdaDir); } @@ -214,8 +231,20 @@ export class ApiRouter { if (!this.existLambdaDir) { return []; } - const apiFiles = (this.apiFiles = getFiles(this.lambdaDir, API_FILE_RULES)); - return apiFiles; + if (process.env.MODERN_SERVER_BUNDLE) { + if (!this.dependencies) { + return []; + } + return Object.keys(this.dependencies).filter(x => + x.startsWith(this.lambdaDir), + ); + } else { + const apiFiles = (this.apiFiles = getFiles( + this.lambdaDir, + API_FILE_RULES, + )); + return apiFiles; + } } public getApiFiles() { @@ -269,6 +298,16 @@ export class ApiRouter { } private async getModuleInfo(filename: string) { + if (process.env.MODERN_SERVER_BUNDLE) { + if (!this.dependencies) { + return null; + } + const mod = await getBundledDep(filename, this.dependencies); + if (mod) { + return interopHandlerModule(mod); + } + return null; + } try { const module = await requireHandlerModule(filename); return { diff --git a/packages/server/bff-core/src/router/utils.ts b/packages/server/bff-core/src/router/utils.ts index 14a978c6bad6..5f48550991ec 100644 --- a/packages/server/bff-core/src/router/utils.ts +++ b/packages/server/bff-core/src/router/utils.ts @@ -64,16 +64,17 @@ export const isHandler = (input: any): input is Handler => const isFunction = (input: any): input is (...args: any) => any => input && {}.toString.call(input) === '[object Function]'; +export const interopHandlerModule = (mod: any) => + isFunction(mod) ? { default: module } : mod; + export const requireHandlerModule = async (modulePath: string) => { // 测试环境不走缓存,因为缓存的 handler 文件,会被 mockAPI 函数进行 mock,升级 jest28,setupFilesAfterEnv 能做异步操作的话,可解此问题 const originRequire = process.env.NODE_ENV === 'test' ? require : compatibleRequire; - const module = await originRequire(modulePath, false); - if (isFunction(module)) { - return { default: module }; - } - return module; + const mod = await originRequire(modulePath, false); + + return interopHandlerModule(mod); }; const routeValue = (routePath: string) => { diff --git a/packages/server/core/src/adapters/node/plugins/resource.ts b/packages/server/core/src/adapters/node/plugins/resource.ts index 7abd9ccb9b32..5c20c310fd89 100644 --- a/packages/server/core/src/adapters/node/plugins/resource.ts +++ b/packages/server/core/src/adapters/node/plugins/resource.ts @@ -324,7 +324,7 @@ export const injectResourcePlugin = (): ServerPlugin => ({ middlewares.push({ name: 'inject-html', - handler: injectTemplates(getHtmlTemplatesFn), + handler: injectTemplates(getHtmlTemplatesFn, routes), }); }); }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a198ad3b3a8..867873aaa3a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -789,6 +789,9 @@ importers: packages/server/bff-core: dependencies: + '@modern-js/server-core': + specifier: workspace:* + version: link:../core '@modern-js/utils': specifier: workspace:* version: link:../../toolkit/utils @@ -1697,9 +1700,6 @@ importers: '@types/signal-exit': specifier: 3.0.4 version: 3.0.4 - '@types/signale': - specifier: 1.4.7 - version: 1.4.7 '@types/url-join': specifier: 4.0.3 version: 4.0.3 @@ -1838,9 +1838,6 @@ importers: signal-exit: specifier: 3.0.7 version: 3.0.7 - signale: - specifier: 1.4.0 - version: 1.4.0 slash: specifier: 3.0.0 version: 3.0.0 @@ -1905,7 +1902,7 @@ importers: devDependencies: '@rsbuild/plugin-react': specifier: 1.4.3 - version: 1.4.3(@rsbuild/core@1.7.2) + version: 1.4.3(@rsbuild/core@2.0.0-alpha.4(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0)) '@rslib/core': specifier: 0.19.3 version: 0.19.3(typescript@5.9.3) @@ -7843,9 +7840,6 @@ packages: '@types/signal-exit@3.0.4': resolution: {integrity: sha512-e7EUPfU9afHyWc5CXtlqbvVHEshrb05uPlDCenWIbMgtWoFrTuTDVYNLKk6o4X2/4oHTfNqrJX/vaJ3uBhtXTg==} - '@types/signale@1.4.7': - resolution: {integrity: sha512-nc0j37QupTT7OcYeH3gRE1ZfzUalEUsDKJsJ3IsJr0pjjFZTjtrX1Bsn6Kv56YXI/H9rNSwAkIPRxNlZI8GyQw==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -9837,10 +9831,6 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - figures@2.0.0: - resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} - engines: {node: '>=4'} - figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -9888,10 +9878,6 @@ packages: resolution: {integrity: sha512-mAOh9gGk9WZ4ip5UjV0o6Vb4SrfnAmtsFNzkMRH9HQiFXVQnDyQFrSHTK5UoG6E+KV+s+cIznbtwpfN41l2nFA==} hasBin: true - find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} - find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -11000,9 +10986,6 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -11225,10 +11208,6 @@ packages: enquirer: optional: true - load-json-file@4.0.0: - resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} - engines: {node: '>=4'} - loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} @@ -11241,10 +11220,6 @@ packages: resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} engines: {node: '>= 12.13.0'} - locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} - locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -11970,10 +11945,6 @@ packages: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} - p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -11986,10 +11957,6 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} - p-locate@3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} @@ -12014,10 +11981,6 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} - p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -12049,10 +12012,6 @@ packages: parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} - parse-json@4.0.0: - resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} - engines: {node: '>=4'} - parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -12172,10 +12131,6 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -12184,10 +12139,6 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - pkg-conf@2.1.0: - resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} - engines: {node: '>=4'} - pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -13682,10 +13633,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - signale@1.4.0: - resolution: {integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==} - engines: {node: '>=6'} - simple-swizzle@0.2.4: resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} @@ -17635,14 +17582,6 @@ snapshots: transitivePeerDependencies: - webpack-hot-middleware - '@rsbuild/plugin-react@1.4.3(@rsbuild/core@1.7.2)': - dependencies: - '@rsbuild/core': 1.7.2 - '@rspack/plugin-react-refresh': 1.6.0(react-refresh@0.18.0) - react-refresh: 0.18.0 - transitivePeerDependencies: - - webpack-hot-middleware - '@rsbuild/plugin-react@1.4.3(@rsbuild/core@2.0.0-alpha.4(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0))': dependencies: '@rsbuild/core': 2.0.0-alpha.4(@module-federation/runtime-tools@0.22.0)(core-js@3.48.0) @@ -19034,10 +18973,6 @@ snapshots: '@types/signal-exit@3.0.4': {} - '@types/signale@1.4.7': - dependencies: - '@types/node': 20.19.27 - '@types/stack-utils@2.0.3': {} '@types/styled-components@5.1.36': @@ -21311,10 +21246,6 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 - figures@2.0.0: - dependencies: - escape-string-regexp: 1.0.5 - figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -21376,10 +21307,6 @@ snapshots: commander: 12.1.0 loglevel: 1.9.2 - find-up@2.1.0: - dependencies: - locate-path: 2.0.0 - find-up@3.0.0: dependencies: locate-path: 3.0.0 @@ -22982,8 +22909,6 @@ snapshots: json-buffer@3.0.1: {} - json-parse-better-errors@1.0.2: {} - json-parse-even-better-errors@2.3.1: {} json-schema-traverse@1.0.0: {} @@ -23242,13 +23167,6 @@ snapshots: optionalDependencies: enquirer: 2.4.1 - load-json-file@4.0.0: - dependencies: - graceful-fs: 4.2.11 - parse-json: 4.0.0 - pify: 3.0.0 - strip-bom: 3.0.0 - loader-runner@4.3.1: {} loader-utils@2.0.4: @@ -23259,11 +23177,6 @@ snapshots: loader-utils@3.3.1: {} - locate-path@2.0.0: - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - locate-path@3.0.0: dependencies: p-locate: 3.0.0 @@ -24258,10 +24171,6 @@ snapshots: dependencies: p-map: 2.1.0 - p-limit@1.3.0: - dependencies: - p-try: 1.0.0 - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -24274,10 +24183,6 @@ snapshots: dependencies: yocto-queue: 1.2.2 - p-locate@2.0.0: - dependencies: - p-limit: 1.3.0 - p-locate@3.0.0: dependencies: p-limit: 2.3.0 @@ -24300,8 +24205,6 @@ snapshots: dependencies: aggregate-error: 3.1.0 - p-try@1.0.0: {} - p-try@2.2.0: {} pac-proxy-agent@7.2.0: @@ -24349,11 +24252,6 @@ snapshots: is-decimal: 2.0.1 is-hexadecimal: 2.0.1 - parse-json@4.0.0: - dependencies: - error-ex: 1.3.4 - json-parse-better-errors: 1.0.2 - parse-json@5.2.0: dependencies: '@babel/code-frame': 7.27.1 @@ -24442,17 +24340,10 @@ snapshots: pify@2.3.0: {} - pify@3.0.0: {} - pify@4.0.1: {} pirates@4.0.7: {} - pkg-conf@2.1.0: - dependencies: - find-up: 2.1.0 - load-json-file: 4.0.0 - pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -26103,12 +25994,6 @@ snapshots: signal-exit@4.1.0: {} - signale@1.4.0: - dependencies: - chalk: 2.4.2 - figures: 2.0.0 - pkg-conf: 2.1.0 - simple-swizzle@0.2.4: dependencies: is-arrayish: 0.3.4 From 1ad6ac1165ed5bdaa56ee6c5353d75dec2f551ea Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 18:15:23 +0800 Subject: [PATCH 07/27] fix: server-module-loader --- .../app-tools/src/builder/shared/builderPlugins/adapterBasic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts index d9e500fa2297..65f6d650eeeb 100644 --- a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts +++ b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts @@ -18,7 +18,7 @@ export const builderPluginAdapterBasic = ( applyNodeCompat(isServiceWorker, chain); } - if (target === 'web') { + if (target === 'web' && !isServiceWorker) { const bareServerModuleReg = /\.(server|node)\.[tj]sx?$/; const depExt = process.env.MODERN_LIB_FORMAT === 'esm' ? 'mjs' : 'js'; chain.module.rule(CHAIN_ID.RULE.JS).exclude.add(bareServerModuleReg); From f368fd67a5b806158b1cdca058b52a82f1419111 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 21:52:14 +0800 Subject: [PATCH 08/27] fix: server bundle build --- packages/cli/plugin-bff/src/loader.ts | 2 +- .../cli/plugin-data-loader/src/cli/loader.ts | 3 + .../plugin-runtime/src/cli/ssr/index.ts | 5 +- .../shared/builderPlugins/adapterBasic.ts | 9 ++- .../shared/builderPlugins/adapterHtml.ts | 4 +- .../shared/builderPlugins/adapterSSR.ts | 6 +- .../shared/bundlerPlugins/RouterPlugin.ts | 9 ++- .../src/plugins/deploy/platforms/node.ts | 9 +-- .../plugins/deploy/server-bundle/builder.ts | 56 +++++++++++------ .../deploy/server-bundle/config/apply.ts | 62 ------------------- .../src/plugins/deploy/server-bundle/index.ts | 1 - .../server-bundle/node-external-plugin.ts | 26 ++++++++ .../toolkit/utils/src/universal/constants.ts | 5 ++ 13 files changed, 96 insertions(+), 101 deletions(-) delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts create mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts diff --git a/packages/cli/plugin-bff/src/loader.ts b/packages/cli/plugin-bff/src/loader.ts index 0d288da0783a..b2df8c5e1cd6 100644 --- a/packages/cli/plugin-bff/src/loader.ts +++ b/packages/cli/plugin-bff/src/loader.ts @@ -30,7 +30,7 @@ async function loader( const draftOptions = this.getOptions(); - const warning = `The file ${resourcePath} is not allowd to be imported in src directory, only API definition files are allowed.`; + const warning = `The file ${resourcePath} is not allowed to be imported in src directory, only API definition files are allowed.`; if (!draftOptions.existLambda) { logger.warn(warning); diff --git a/packages/cli/plugin-data-loader/src/cli/loader.ts b/packages/cli/plugin-data-loader/src/cli/loader.ts index 0cd2d05d1339..2f8122ed3d8b 100644 --- a/packages/cli/plugin-data-loader/src/cli/loader.ts +++ b/packages/cli/plugin-data-loader/src/cli/loader.ts @@ -1,5 +1,6 @@ import { promisify } from 'util'; import { logger } from '@modern-js/utils/logger'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import type { Rspack } from '@rsbuild/core'; import { generateClient } from './generateClient'; @@ -19,6 +20,7 @@ export default async function loader( ) { this.cacheable(); const target = this._compiler?.options.target; + const name = this._compiler?.options.name; const shouldSkip = (compileTarget: string) => { return ( @@ -28,6 +30,7 @@ export default async function loader( }; if ( + name === SERVER_BUNDLE_NAME || shouldSkip('node') || shouldSkip('webworker') || shouldSkip('async-node') diff --git a/packages/runtime/plugin-runtime/src/cli/ssr/index.ts b/packages/runtime/plugin-runtime/src/cli/ssr/index.ts index 567f2a9666ce..08ca8f2633cc 100644 --- a/packages/runtime/plugin-runtime/src/cli/ssr/index.ts +++ b/packages/runtime/plugin-runtime/src/cli/ssr/index.ts @@ -8,6 +8,7 @@ import type { import type { CLIPluginAPI } from '@modern-js/plugin'; import type { Entrypoint } from '@modern-js/types'; import { LOADABLE_STATS_FILE, isUseSSRBundle } from '@modern-js/utils'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import type { RsbuildPlugin } from '@rsbuild/core'; import LoadableBundlerPlugin from './loadable-bundler-plugin'; import { resolveSSRMode } from './mode'; @@ -82,7 +83,9 @@ const ssrBuilderPlugin = ( setup(api) { api.modifyEnvironmentConfig((config, { name, mergeEnvironmentConfig }) => { const isServerEnvironment = - config.output.target === 'node' || name === 'workerSSR'; + config.output.target === 'node' || + name === 'workerSSR' || + name === SERVER_BUNDLE_NAME; const userConfig = modernAPI.getNormalizedConfig(); // Maybe we can enable it for node 18 and above, but we can't ensure it in the compilation. diff --git a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts index 65f6d650eeeb..4ff5e47cce68 100644 --- a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts +++ b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterBasic.ts @@ -1,5 +1,6 @@ import path from 'node:path'; import { SERVICE_WORKER_ENVIRONMENT_NAME } from '@modern-js/builder'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import type { RsbuildPlugin, RspackChain } from '@rsbuild/core'; import type { BuilderOptions } from '../types'; @@ -12,13 +13,14 @@ export const builderPluginAdapterBasic = ( api.modifyBundlerChain((chain, { target, CHAIN_ID, environment }) => { const isServiceWorker = environment.name === SERVICE_WORKER_ENVIRONMENT_NAME; + const isServerBundle = environment.name === SERVER_BUNDLE_NAME; // apply node compat - if (target === 'node' || isServiceWorker) { + if (target === 'node' || isServerBundle || isServiceWorker) { applyNodeCompat(isServiceWorker, chain); } - if (target === 'web' && !isServiceWorker) { + if (target === 'web' && !isServerBundle) { const bareServerModuleReg = /\.(server|node)\.[tj]sx?$/; const depExt = process.env.MODERN_LIB_FORMAT === 'esm' ? 'mjs' : 'js'; chain.module.rule(CHAIN_ID.RULE.JS).exclude.add(bareServerModuleReg); @@ -45,8 +47,9 @@ export const builderPluginAdapterBasic = ( api.modifyRspackConfig((config, { target, environment }) => { const isServiceWorker = environment.name === SERVICE_WORKER_ENVIRONMENT_NAME; + const isServerBundle = environment.name === SERVER_BUNDLE_NAME; - if (target === 'node' || isServiceWorker) { + if (target === 'node' || isServerBundle || isServiceWorker) { // Define extensionAlias for server and node files // a .mjs file will resolve in order of .node.mjs, .server.mjs, .mjs const extensionAlias: Record = { diff --git a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts index 8737636f03b5..fa4044d372e5 100644 --- a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts +++ b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterHtml.ts @@ -4,6 +4,7 @@ import { } from '@modern-js/builder'; import { removeTailSlash } from '@modern-js/utils'; import { template as lodashTemplate } from '@modern-js/utils/lodash'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import type { ChainIdentifier, RsbuildPlugin, @@ -29,8 +30,9 @@ export const builderPluginAdapterHtml = ( const isServiceWorker = environment.name === SERVICE_WORKER_ENVIRONMENT_NAME; + const isServerBundle = environment.name === SERVER_BUNDLE_NAME; - if (isServiceWorker) { + if (isServiceWorker || isServerBundle) { return; } diff --git a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts index bdd849cad6f5..7a5761594e27 100644 --- a/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts +++ b/packages/solutions/app-tools/src/builder/shared/builderPlugins/adapterSSR.ts @@ -5,6 +5,7 @@ import { isHtmlDisabled, } from '@modern-js/builder'; import { fs, isUseRsc, isUseSSRBundle } from '@modern-js/utils'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import { type RsbuildPlugin, type RspackChain, @@ -65,8 +66,9 @@ export const builderPluginAdapterSSR = ( const isServiceWorker = environment.name === SERVICE_WORKER_ENVIRONMENT_NAME; + const isServerBundle = environment.name === SERVER_BUNDLE_NAME; - if (target === 'node' || isServiceWorker) { + if (target === 'node' || isServiceWorker || isServerBundle) { applyFilterEntriesBySSRConfig({ isProd, chain, @@ -79,7 +81,7 @@ export const builderPluginAdapterSSR = ( applySSRDataLoader(chain, options); } - if (!isHtmlDisabled(builderConfig, target)) { + if (!isHtmlDisabled(builderConfig, target) && !isServerBundle) { applyAsyncChunkHtmlPlugin({ chain, modernConfig: options.normalizedConfig, diff --git a/packages/solutions/app-tools/src/builder/shared/bundlerPlugins/RouterPlugin.ts b/packages/solutions/app-tools/src/builder/shared/bundlerPlugins/RouterPlugin.ts index 79f52eb578ad..055e02ecac0c 100644 --- a/packages/solutions/app-tools/src/builder/shared/bundlerPlugins/RouterPlugin.ts +++ b/packages/solutions/app-tools/src/builder/shared/bundlerPlugins/RouterPlugin.ts @@ -1,7 +1,10 @@ import { createHash } from 'crypto'; import { ROUTE_MANIFEST_FILE } from '@modern-js/utils'; import { merge, mergeWith } from '@modern-js/utils/lodash'; -import { ROUTE_MANIFEST } from '@modern-js/utils/universal/constants'; +import { + ROUTE_MANIFEST, + SERVER_BUNDLE_NAME, +} from '@modern-js/utils/universal/constants'; import type { Rspack, ScriptLoading } from '@rsbuild/core'; const PLUGIN_NAME = 'ModernjsRoutePlugin'; @@ -97,8 +100,8 @@ export class RouterPlugin { } apply(compiler: Compiler) { - const { target } = compiler.options; - if (this.isTargetNodeOrWebWorker(target)) { + const { target, name } = compiler.options; + if (this.isTargetNodeOrWebWorker(target) || name === SERVER_BUNDLE_NAME) { return; } diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 3a0e2ccff07a..ef27833d18b9 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -8,7 +8,6 @@ import { nodeDepEmit as handleDependencies } from 'ndepe'; import { NODE_BUILTIN_MODULES, bundleServer, - generateNodeExternals, generateHandler as generateSingleBundleHandler, } from '../server-bundle'; import { scanDeps } from '../server-bundle/dep-generator'; @@ -72,16 +71,10 @@ export const createNodePreset: CreatePreset = ({ depCode, serverType: 'node', }); - const nodeExternals = Object.fromEntries( - generateNodeExternals( - api => `module-import node:${api}`, - NODE_BUILTIN_MODULES, - ), - ); await bundleServer(code, api, { + nodeExternal: NODE_BUILTIN_MODULES, config: { output: { - externals: [nodeExternals], distPath: { root: join(outputDirectory, 'server-bundle'), js: '.', diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 749d241f4ec7..98a470a893be 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -2,15 +2,14 @@ import path from 'node:path'; import { type BuilderConfig, type BuilderInstance, - SERVICE_WORKER_ENVIRONMENT_NAME, createBuilder, } from '@modern-js/builder'; import type { CLIPluginAPI } from '@modern-js/plugin'; import { lodash as _, fs as fse } from '@modern-js/utils'; -import { applyBuilderPlugins } from '../../../builder/generator'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import { createBuilderProviderConfig } from '../../../builder/generator/createBuilderProviderConfig'; import type { AppTools } from '../../../types'; -import { ESM_RESOLVE_CONDITIONS } from './constant'; +import { ESM_RESOLVE_CONDITIONS, NODE_BUILTIN_MODULES } from './constant'; export const generateNodeExternals = ( getExternal: (api: string) => string, @@ -24,6 +23,7 @@ export interface BundleSSROptions { config?: BuilderConfig; modifyBuilder?: (builder: BuilderInstance) => Promise; forceESM?: boolean; + nodeExternal?: string[]; } export const bundleServer = async ( @@ -49,9 +49,18 @@ export const bundleServer = async ( appContext, ); + const nodeExternal = options?.nodeExternal + ? Object.fromEntries( + generateNodeExternals( + api => `module-import node:${api}`, + NODE_BUILTIN_MODULES, + ), + ) + : undefined; + const defaultConfig: BuilderConfig = { environments: { - [SERVICE_WORKER_ENVIRONMENT_NAME]: { + [SERVER_BUNDLE_NAME]: { source: { entry: { bundle: { @@ -72,6 +81,7 @@ export const bundleServer = async ( }, output: { target: 'web', + module: true, emitAssets: false, cleanDistPath: true, polyfill: 'off', @@ -86,6 +96,7 @@ export const bundleServer = async ( js: '[name].mjs', }, minify, + externals: nodeExternal ? [nodeExternal] : undefined, }, performance: { chunkSplit: { @@ -93,19 +104,26 @@ export const bundleServer = async ( }, }, tools: { - rspack: { - target: 'es2020', - output: { - asyncChunks: false, - library: { - type: 'module', + rspack: [ + { + name: SERVER_BUNDLE_NAME, + target: 'es2021', + output: { + chunkFormat: 'module', + asyncChunks: false, + pathinfo: !minify, + library: { + type: 'module', + }, + }, + experiments: { + outputModule: true, }, - pathinfo: !minify, }, - experiments: { - outputModule: true, + config => { + console.log(config); }, - }, + ], }, }; @@ -121,13 +139,13 @@ export const bundleServer = async ( config: finalConfig, }); - await applyBuilderPlugins(builder, { - normalizedConfig, - appContext, - }); + const plugins = api.getAppContext().builder?.getPlugins(); + if (plugins) { + builder.addPlugins(plugins); + } - // remove bff server external builder.modifyRsbuildConfig(config => { + // remove bff server external const { output } = config; if (Array.isArray(output?.externals)) { output!.externals = output!.externals.filter( diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts deleted file mode 100644 index b7368b10819b..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/config/apply.ts +++ /dev/null @@ -1,62 +0,0 @@ -import path from 'node:path'; -import { set } from '@modern-js/utils/lodash'; -import type { PluginAPI } from '../../types'; -import { generateNodeExternals } from '../builder'; -import { NODE_BUILTIN_MODULES } from '../constant'; -import { appendTo } from '../utils'; - -export interface ApplyConfigParams { - rsbuild?: Parameters[0]; - rspack?: Parameters[0]; -} - -export const applyConfig = (api: PluginAPI, options?: ApplyConfigParams) => { - let baseDistPath: string; - - api.modifyRsbuildConfig((config, utils) => { - if (!config.environments?.node) { - return; - } - const { appDirectory } = api.getAppContext(); - const userConfig = api.getConfig(); - baseDistPath = path.join( - appDirectory, - userConfig.output?.distPath?.root || 'dist', - ); - options?.rsbuild?.(config, utils); - }); - - const nodeExternals = Object.fromEntries( - generateNodeExternals( - api => `module-import node:${api}`, - NODE_BUILTIN_MODULES, - ), - ); - - api.modifyRspackConfig((config, utils) => { - const outputPath = config.output?.path; - if (config.target !== 'node' || !baseDistPath || !outputPath) { - return; - } - - const isTsProject = Boolean(config.resolve?.tsConfig); - const isEsmProject = Boolean(config.output?.module); - - config.target = 'es2020'; - if (isTsProject || isEsmProject) { - set(config, 'output.chunkFormat', 'module'); - set(config, 'output.chunkLoading', 'singleBundleChunkLoad'); - set(config, 'output.module', true); - set(config, 'output.library.type', 'module'); - set(config, 'experiments.outputModule', true); - } - - appendTo(config, 'externals', nodeExternals); - - try { - options?.rspack?.(config, utils); - } catch (e) { - console.error(e); - } - }); -}; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts index f2513967b42d..8962d3dba407 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/index.ts @@ -3,4 +3,3 @@ export * from './builder'; export * from './dep-generator'; export * from './generator'; export * from './utils'; -export { applyConfig } from './config/apply'; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts new file mode 100644 index 000000000000..449901b70e4d --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts @@ -0,0 +1,26 @@ +import type { Rspack } from '@rsbuild/core'; +import { NODE_BUILTIN_MODULES } from './constant'; + +export const nodeExternalPlugin: Rspack.RspackPluginInstance = { + name: 'node-external', + apply(compiler) { + compiler.hooks.compilation.tap( + 'NodeExternalPlugin', + (_, { normalModuleFactory }) => { + normalModuleFactory.hooks.factorize.tap( + 'NodeExternalPlugin', + resourceData => { + if (NODE_BUILTIN_MODULES.includes(resourceData.request)) { + console.log('factorize', resourceData); + } + }, + ); + normalModuleFactory.hooks.resolveForScheme + .for('node') + .tap('NodeExternalPlugin', resourceData => { + console.log('resolveForScheme', resourceData); + }); + }, + ); + }, +}; diff --git a/packages/toolkit/utils/src/universal/constants.ts b/packages/toolkit/utils/src/universal/constants.ts index e637137d15bd..64f60a38f4d0 100644 --- a/packages/toolkit/utils/src/universal/constants.ts +++ b/packages/toolkit/utils/src/universal/constants.ts @@ -50,3 +50,8 @@ export const SERVER_RENDER_FUNCTION_NAME = 'serverRender'; export const SERVER_PLUGIN_BFF = '@modern-js/plugin-bff'; export const SERVER_PLUGIN_POLYFILL = '@modern-js/plugin-polyfill'; + +/** + * Server bundle mode + */ +export const SERVER_BUNDLE_NAME = 'ServerBundle'; From 8c2f3b1ace4653577af3cbbd62d28f02f730f807 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 22:44:53 +0800 Subject: [PATCH 09/27] chore: remove prebundle browserslist --- packages/toolkit/utils/package.json | 4 --- packages/toolkit/utils/rslib.config.mts | 1 - packages/toolkit/utils/src/cli/get/data.ts | 5 +-- packages/toolkit/utils/src/compiled.ts | 1 - .../utils/tests/getBrowserslist.test.ts | 35 ------------------- pnpm-lock.yaml | 3 -- scripts/prebundle/package.json | 1 - scripts/prebundle/src/constant.ts | 1 - 8 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 packages/toolkit/utils/tests/getBrowserslist.test.ts diff --git a/packages/toolkit/utils/package.json b/packages/toolkit/utils/package.json index cd795eeee1e0..37a27d598e1a 100644 --- a/packages/toolkit/utils/package.json +++ b/packages/toolkit/utils/package.json @@ -89,7 +89,6 @@ "./gzip-size": "./dist/compiled/gzip-size/index.js", "./mime-types": "./dist/compiled/mime-types/index.js", "./strip-ansi": "./dist/compiled/strip-ansi/index.js", - "./browserslist": "./dist/compiled/browserslist/index.js", "./tsconfig-paths": { "import": "./dist/compiled/tsconfig-paths/index.mjs", "default": "./dist/compiled/tsconfig-paths/index.js" @@ -165,9 +164,6 @@ "strip-ansi": [ "./dist/compiled/strip-ansi/index.d.ts" ], - "browserslist": [ - "./dist/compiled/browserslist/index.d.ts" - ], "tsconfig-paths": [ "./dist/compiled/tsconfig-paths/lib/index.d.ts" ], diff --git a/packages/toolkit/utils/rslib.config.mts b/packages/toolkit/utils/rslib.config.mts index 14188452df25..93709ca6581b 100644 --- a/packages/toolkit/utils/rslib.config.mts +++ b/packages/toolkit/utils/rslib.config.mts @@ -49,7 +49,6 @@ const dependencies = [ name: 'fs-extra', esm: true, }, - 'browserslist', 'chokidar', 'fast-glob', { diff --git a/packages/toolkit/utils/src/cli/get/data.ts b/packages/toolkit/utils/src/cli/get/data.ts index ddb053c2387d..75b06b8d2bfb 100644 --- a/packages/toolkit/utils/src/cli/get/data.ts +++ b/packages/toolkit/utils/src/cli/get/data.ts @@ -1,7 +1,7 @@ import os from 'os'; import path from 'path'; import type { InternalPlugins } from '@modern-js/types'; -import { fs, browserslist, json5 } from '../../compiled'; +import { fs, json5 } from '../../compiled'; import { isDepExists } from '../is'; import { canUsePnpm, canUseYarn } from '../package'; @@ -49,9 +49,6 @@ export const defaults = [ 'safari >= 14', ]; -export const getBrowserslist = (appDirectory: string) => - browserslist.loadConfig({ path: appDirectory }) || defaults; - export function getInternalPlugins( appDirectory: string, internalPlugins: InternalPlugins = {}, diff --git a/packages/toolkit/utils/src/compiled.ts b/packages/toolkit/utils/src/compiled.ts index d85673077bb1..d5d08320b693 100644 --- a/packages/toolkit/utils/src/compiled.ts +++ b/packages/toolkit/utils/src/compiled.ts @@ -24,7 +24,6 @@ export { default as filesize } from '../compiled/filesize'; export { default as gzipSize } from '../compiled/gzip-size'; export { default as stripAnsi } from '../compiled/strip-ansi'; export { default as dotenvExpand } from '../compiled/dotenv-expand'; -export { default as browserslist } from '../compiled/browserslist'; export { program, Command } from '../compiled/commander'; diff --git a/packages/toolkit/utils/tests/getBrowserslist.test.ts b/packages/toolkit/utils/tests/getBrowserslist.test.ts deleted file mode 100644 index cb4d7adedbe5..000000000000 --- a/packages/toolkit/utils/tests/getBrowserslist.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import path from 'path'; -import { defaults, getBrowserslist } from '../src'; - -describe('get browserslist', () => { - afterEach(() => { - rstest.unstubAllEnvs(); - }); - const fixture = path.resolve(__dirname, './fixtures/browserlist'); - - test(`should load browserslist from package.json`, () => { - expect(getBrowserslist(path.join(fixture, 'pkg'))).toEqual([ - 'not IE 11', - 'maintained node versions', - ]); - }); - - test(`should load browerslist from .browserslistrc`, () => { - expect(getBrowserslist(path.join(fixture, 'dotfile'))).toEqual([ - 'defaults', - 'not IE 11', - 'maintained node versions', - ]); - }); - - test(`should load browserslist base on environment`, () => { - rstest.stubEnv('NODE_ENV', 'development'); - expect(getBrowserslist(path.join(fixture, 'develop'))).toEqual([ - 'last 1 chrome version', - ]); - }); - - test(`should return default browserslist config`, () => { - expect(getBrowserslist(path.join(fixture))).toEqual(defaults); - }); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 867873aaa3a1..143392e37f62 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1706,9 +1706,6 @@ importers: address: specifier: 1.2.2 version: 1.2.2 - browserslist: - specifier: 4.28.1 - version: 4.28.1 chalk: specifier: 4.1.2 version: 4.1.2 diff --git a/scripts/prebundle/package.json b/scripts/prebundle/package.json index 084dd5f56322..f338bd85c358 100644 --- a/scripts/prebundle/package.json +++ b/scripts/prebundle/package.json @@ -37,7 +37,6 @@ "@types/signal-exit": "3.0.4", "@types/url-join": "4.0.3", "address": "1.2.2", - "browserslist": "4.28.1", "chalk": "4.1.2", "chokidar": "3.6.0", "commander": "10.0.1", diff --git a/scripts/prebundle/src/constant.ts b/scripts/prebundle/src/constant.ts index 6d2e89cc96ef..1e4c6f068566 100644 --- a/scripts/prebundle/src/constant.ts +++ b/scripts/prebundle/src/constant.ts @@ -87,7 +87,6 @@ export const TASKS: TaskConfig[] = [ 'graceful-fs': 'node:fs', }, }, - 'browserslist', 'chokidar', 'fast-glob', { From fcfda24d56fd05d714f2ad1410d0675935d9f6b1 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Fri, 30 Jan 2026 23:08:35 +0800 Subject: [PATCH 10/27] fix: builder plugins --- .../src/plugins/deploy/platforms/node.ts | 2 +- .../plugins/deploy/server-bundle/builder.ts | 32 +++++++++---------- .../server-bundle/node-external-plugin.ts | 26 --------------- 3 files changed, 17 insertions(+), 43 deletions(-) delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index ef27833d18b9..9fcdcda17a9b 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -120,7 +120,7 @@ export const createNodePreset: CreatePreset = ({ if (isBundleServer) { console.log( `You can preview this build by`, - chalk.blue(`node .output/server-bundle/index`), + chalk.blue(`node .output/server-bundle/bundle.mjs`), ); } else { console.log( diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 98a470a893be..898162757a20 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -119,9 +119,7 @@ export const bundleServer = async ( experiments: { outputModule: true, }, - }, - config => { - console.log(config); + ignoreWarnings: [/__dirname/, /dependency is an expression/], }, ], }, @@ -140,8 +138,9 @@ export const bundleServer = async ( }); const plugins = api.getAppContext().builder?.getPlugins(); + const hasPlugins = builder.getPlugins().map(x => x.name); if (plugins) { - builder.addPlugins(plugins); + builder.addPlugins(plugins.filter(x => !hasPlugins.includes(x.name))); } builder.modifyRsbuildConfig(config => { @@ -154,18 +153,19 @@ export const bundleServer = async ( } }); - builder.onAfterBuild(async ({ stats }) => { - await fse.writeFile( - path.join(finalConfig.output.distPath!.root!, 'stats.json'), - JSON.stringify( - stats?.toJson({ - preset: 'verbose', - }), - null, - 2, - ), - ); - }); + // output stats to debug tree shaking + // builder.onAfterBuild(async ({ stats }) => { + // await fse.writeFile( + // path.join(finalConfig.output.distPath!.root!, 'stats.json'), + // JSON.stringify( + // stats?.toJson({ + // preset: 'verbose', + // }), + // null, + // 2, + // ), + // ); + // }); if (options?.modifyBuilder) { await options.modifyBuilder(builder); diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts deleted file mode 100644 index 449901b70e4d..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/node-external-plugin.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Rspack } from '@rsbuild/core'; -import { NODE_BUILTIN_MODULES } from './constant'; - -export const nodeExternalPlugin: Rspack.RspackPluginInstance = { - name: 'node-external', - apply(compiler) { - compiler.hooks.compilation.tap( - 'NodeExternalPlugin', - (_, { normalModuleFactory }) => { - normalModuleFactory.hooks.factorize.tap( - 'NodeExternalPlugin', - resourceData => { - if (NODE_BUILTIN_MODULES.includes(resourceData.request)) { - console.log('factorize', resourceData); - } - }, - ); - normalModuleFactory.hooks.resolveForScheme - .for('node') - .tap('NodeExternalPlugin', resourceData => { - console.log('resolveForScheme', resourceData); - }); - }, - ); - }, -}; From 16f71f4b41117ae5494ef282f27edb7a13eeb4ce Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 14:01:54 +0800 Subject: [PATCH 11/27] test: add server bundle --- .gitignore | 1 + packages/cli/plugin-bff/src/server.ts | 1 + packages/server/bff-core/src/router/index.ts | 6 +- packages/server/bff-core/src/router/utils.ts | 2 +- .../src/plugins/deploy/platforms/node.ts | 4 +- .../utils/compiled/lodash/package.json | 2 +- .../deploy-server/modern.config.ts | 7 +- .../deploy-server/tests/index.test.ts | 79 ++++++++++- tests/utils/modernTestUtils.js | 124 ++++++++++-------- 9 files changed, 159 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index 02930dbb82f7..711738399552 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ playground/ .output/ +.output-server-bundle/ .vercel/ .netlify/ diff --git a/packages/cli/plugin-bff/src/server.ts b/packages/cli/plugin-bff/src/server.ts index f8836ece4d0c..f32dc7406f25 100644 --- a/packages/cli/plugin-bff/src/server.ts +++ b/packages/cli/plugin-bff/src/server.ts @@ -119,6 +119,7 @@ export default (): ServerPlugin => ({ lambdaDir: lambdaDirectory as string, prefix, httpMethodDecider, + dependencies, }); const apiHandlerInfos = await apiRouter.getApiHandlers(); api.updateServerContext({ diff --git a/packages/server/bff-core/src/router/index.ts b/packages/server/bff-core/src/router/index.ts index 1b7349d1eb4e..224ed2f7549d 100644 --- a/packages/server/bff-core/src/router/index.ts +++ b/packages/server/bff-core/src/router/index.ts @@ -68,6 +68,7 @@ export class ApiRouter { if (process.env.MODERN_SERVER_BUNDLE) { if (lambdaDir && dependencies) { + this.dependencies = dependencies; this.existLambdaDir = Object.keys(dependencies).some(x => x.startsWith(lambdaDir), ); @@ -304,7 +305,10 @@ export class ApiRouter { } const mod = await getBundledDep(filename, this.dependencies); if (mod) { - return interopHandlerModule(mod); + return { + filename, + module: interopHandlerModule(mod), + }; } return null; } diff --git a/packages/server/bff-core/src/router/utils.ts b/packages/server/bff-core/src/router/utils.ts index 5f48550991ec..61f1523655e9 100644 --- a/packages/server/bff-core/src/router/utils.ts +++ b/packages/server/bff-core/src/router/utils.ts @@ -65,7 +65,7 @@ const isFunction = (input: any): input is (...args: any) => any => input && {}.toString.call(input) === '[object Function]'; export const interopHandlerModule = (mod: any) => - isFunction(mod) ? { default: module } : mod; + isFunction(mod) ? { default: mod } : mod; export const requireHandlerModule = async (modulePath: string) => { // 测试环境不走缓存,因为缓存的 handler 文件,会被 mockAPI 函数进行 mock,升级 jest28,setupFilesAfterEnv 能做异步操作的话,可解此问题 diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 9fcdcda17a9b..2c06b4aa9feb 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -76,7 +76,7 @@ export const createNodePreset: CreatePreset = ({ config: { output: { distPath: { - root: join(outputDirectory, 'server-bundle'), + root: join(appDirectory, '.output-server-bundle'), js: '.', }, }, @@ -120,7 +120,7 @@ export const createNodePreset: CreatePreset = ({ if (isBundleServer) { console.log( `You can preview this build by`, - chalk.blue(`node .output/server-bundle/bundle.mjs`), + chalk.blue(`node .output-server-bundle/bundle.mjs`), ); } else { console.log( diff --git a/packages/toolkit/utils/compiled/lodash/package.json b/packages/toolkit/utils/compiled/lodash/package.json index 587c6b18dd95..1986445f5eae 100644 --- a/packages/toolkit/utils/compiled/lodash/package.json +++ b/packages/toolkit/utils/compiled/lodash/package.json @@ -1 +1 @@ -{"name":"lodash","author":"John-David Dalton ","version":"4.17.21","license":"MIT"} +{"name":"lodash-prebundled","author":"John-David Dalton ","version":"4.17.21","license":"MIT"} diff --git a/tests/integration/deploy-server/modern.config.ts b/tests/integration/deploy-server/modern.config.ts index 50e83a317f99..b1a31d62e0bd 100644 --- a/tests/integration/deploy-server/modern.config.ts +++ b/tests/integration/deploy-server/modern.config.ts @@ -1,5 +1,3 @@ -import { writeFileSync } from 'fs'; -import { join } from 'path'; import AppToolsPlugin, { defineConfig } from '@modern-js/app-tools'; import bff from '@modern-js/plugin-bff'; @@ -11,10 +9,7 @@ export default defineConfig({ }, server: { ssr: { - bundleServer: true, + bundleServer: process.env.TEST_BUNDLE_SERVER === 'true', }, }, - output: { - minify: false, - }, }); diff --git a/tests/integration/deploy-server/tests/index.test.ts b/tests/integration/deploy-server/tests/index.test.ts index ae1d3280dfbe..a7df20dd9748 100644 --- a/tests/integration/deploy-server/tests/index.test.ts +++ b/tests/integration/deploy-server/tests/index.test.ts @@ -1,19 +1,48 @@ import path from 'path'; import { execa, fs as fse } from '@modern-js/utils'; -import { modernBuild } from '../../../utils/modernTestUtils'; +import { + getPort, + killApp, + modernBuild, + runContinuousTask, +} from '../../../utils/modernTestUtils'; const appDir = path.resolve(__dirname, '../'); +async function checkAppRun(host: string) { + // Page render + const onePage = await fetch(`${host}/one`); + expect(onePage.status).toBe(200); + expect(await onePage.text()).toContain('
'); + + // Loader + const oneLoader = await fetch(`${host}/one?__loader=one_page`); + expect(oneLoader.status).toBe(200); + expect(await oneLoader.text()).toContain('Hello Modern.js'); + + // API + const api = await fetch(`${host}/api/context`); + expect(api.status).toBe(200); + expect(api.headers.get('x-id')).toBe('1'); + expect(await api.json()).toEqual({ + message: 'Hello Modern.js', + }); +} + // bff project's dependencies is more complex, so use bff project to test describe('deploy', () => { + const apps = new Set(); + beforeAll(async () => { await modernBuild(appDir, [], {}); }); afterAll(async () => { + await Promise.all([...apps].map(x => killApp(x))); await fse.remove(path.join(appDir, '.vercel')); await fse.remove(path.join(appDir, '.netlify')); await fse.remove(path.join(appDir, '.output')); + await fse.remove(path.join(appDir, '.output-server-bundle')); }); test('support server when deploy target is node', async () => { @@ -23,6 +52,7 @@ describe('deploy', () => { stdio: 'inherit', env: { ...process.env, + TEST_BUNDLE_SERVER: 'false', MODERNJS_DEPLOY: 'node', }, }); @@ -36,6 +66,53 @@ describe('deploy', () => { expect(await fse.pathExists(htmlDirectory)).toBe(true); expect(await fse.pathExists(apiFile)).toBe(true); expect(await fse.pathExists(bootstrapPath)).toBe(true); + + // check server run + const port = await getPort(); + const app = await runContinuousTask(['./.output/index.js'], undefined, { + cwd: appDir, + env: { + ...process.env, + NODE_ENV: 'production', + PORT: port, + }, + waitMessage: /Server is listening on/i, + }); + apps.add(app); + await checkAppRun(`http://localhost:${port}`); + await killApp(app); + apps.delete(app); + }); + + test('support server bundle when deploy target is node', async () => { + await execa('npx modern deploy', { + shell: true, + cwd: appDir, + stdio: 'inherit', + env: { + ...process.env, + TEST_BUNDLE_SERVER: 'true', + MODERNJS_DEPLOY: 'node', + }, + }); + const outputFile = '.output-server-bundle/bundle.mjs'; + expect(await fse.pathExists(path.join(appDir, outputFile))).toBe(true); + + // check server run + const port = await getPort(); + const app = await runContinuousTask([outputFile], undefined, { + cwd: appDir, + env: { + ...process.env, + NODE_ENV: 'production', + PORT: port, + }, + waitMessage: /Server is listening on/i, + }); + apps.add(app); + await checkAppRun(`http://localhost:${port}`); + await killApp(app); + apps.delete(app); }); test('support server when deploy target is vercel', async () => { diff --git a/tests/utils/modernTestUtils.js b/tests/utils/modernTestUtils.js index b29f6ab3c4ea..746a0d276503 100644 --- a/tests/utils/modernTestUtils.js +++ b/tests/utils/modernTestUtils.js @@ -9,6 +9,63 @@ const kModernAppTools = path.join( '../node_modules/@modern-js/app-tools/bin/modern.js', ); +function runContinuousTask(argv, stdOut, options = {}) { + const { cwd } = options; + const env = { + ...process.env, + ...options.env, + }; + + return new Promise((resolve, reject) => { + const instance = spawn(process.execPath, argv, { + cwd, + env, + }); + + let didResolve = false; + + function handleStdout(data) { + const message = data.toString(); + + if (options.errorMessage?.test(message)) { + if (!didResolve) { + didResolve = true; + reject(new Error(message)); + } + } + + if (options.waitMessage.test(message)) { + if (!didResolve) { + didResolve = true; + resolve(stdOut ? message : instance); + } + } + + if (typeof options.onStdout === 'function') { + options.onStdout(message); + } + + if (stdOut !== false && options.stdout !== false) { + process.stdout.write(message); + } + } + + instance.stdout.on('data', handleStdout); + + instance.on('error', error => { + reject(error); + }); + + instance.on('close', () => { + instance.stdout.removeListener('data', handleStdout); + if (!didResolve) { + didResolve = true; + resolve(); + } + }); + }); +} + function runModernCommand(argv, options = {}) { const { cwd, rejectOnCompileError = true } = options; const cmd = argv[0]; @@ -83,64 +140,20 @@ function runModernCommand(argv, options = {}) { } function runModernCommandDev(argv, stdOut, options = {}) { - const { cwd, rejectOnCompileError = true } = options; - const env = { - ...process.env, - ...options.env, - }; - - return new Promise((resolve, reject) => { - const instance = spawn(process.execPath, [kModernAppTools, ...argv], { - cwd, - env, - }); - - let didResolve = false; + const { rejectOnCompileError = true } = options; - function handleStdout(data) { - const message = data.toString(); - const bootupMarkers = { - dev: /> Local:/i, - serve: /> Local:/i, - }; - const compileErrorMarker = /Compile error/i; - - if (rejectOnCompileError && compileErrorMarker.test(message)) { - if (!didResolve) { - didResolve = true; - reject(new Error(message)); - } - } - - if (bootupMarkers[options.modernServe ? 'serve' : 'dev'].test(message)) { - if (!didResolve) { - didResolve = true; - resolve(stdOut ? message : instance); - } - } - - if (typeof options.onStdout === 'function') { - options.onStdout(message); - } - - if (stdOut !== false && options.stdout !== false) { - process.stdout.write(message); - } - } - - instance.stdout.on('data', handleStdout); + const bootupMarkers = { + dev: /> Local:/i, + serve: /> Local:/i, + }; + const compileErrorMarker = /Compile error/i; - instance.on('error', error => { - reject(error); - }); + const errorMessage = rejectOnCompileError ? compileErrorMarker : undefined; - instance.on('close', () => { - instance.stdout.removeListener('data', handleStdout); - if (!didResolve) { - didResolve = true; - resolve(); - } - }); + return runContinuousTask([kModernAppTools, ...argv], stdOut, { + ...options, + waitMessage: bootupMarkers[options.modernServe ? 'serve' : 'dev'], + errorMessage, }); } @@ -239,6 +252,7 @@ function sleep(t) { } module.exports = { + runContinuousTask, runModernCommand, runModernCommandDev, modernBuild, From 748d06ac00ea8c5bffed65e3b8a4b7043bd9b222 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 14:35:54 +0800 Subject: [PATCH 12/27] revert: loaderContext --- .../runtime/plugin-runtime/src/core/compat/requestContext.ts | 1 - packages/runtime/plugin-runtime/src/core/types.ts | 1 - packages/server/core/src/plugins/render/index.ts | 5 +---- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts b/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts index 74d850c8f97b..a769689291ac 100644 --- a/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts +++ b/packages/runtime/plugin-runtime/src/core/compat/requestContext.ts @@ -10,7 +10,6 @@ export const makeRequestContext = ( const baseSSRContext = context.ssrContext; if (baseSSRContext) { return { - loaderContext: baseSSRContext.loaderContext, request: baseSSRContext.request, response: baseSSRContext.response, }; diff --git a/packages/runtime/plugin-runtime/src/core/types.ts b/packages/runtime/plugin-runtime/src/core/types.ts index 67ab29485c8e..97ca318101ae 100644 --- a/packages/runtime/plugin-runtime/src/core/types.ts +++ b/packages/runtime/plugin-runtime/src/core/types.ts @@ -61,7 +61,6 @@ export type SSRServerContext = Pick< }; export type RequestContext = { - loaderContext?: BaseSSRServerContext['loaderContext']; request: BaseSSRServerContext['request']; response: BaseSSRServerContext['response']; }; diff --git a/packages/server/core/src/plugins/render/index.ts b/packages/server/core/src/plugins/render/index.ts index fd02b9089b06..bf029687f0a4 100644 --- a/packages/server/core/src/plugins/render/index.ts +++ b/packages/server/core/src/plugins/render/index.ts @@ -107,10 +107,7 @@ function createRenderHandler( const contextForceCSR = c.get('forceCSR'); const request = c.req.raw; - const bindings = c.env; - const nodeReq = bindings.node?.req; - - loaderContext.set('bindings', bindings); + const nodeReq = c.env.node?.req; const res = await render(request, { nodeReq, From ae96df793a6b17292f7aa184e72dc40c7609144d Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 14:59:02 +0800 Subject: [PATCH 13/27] chore: changesety --- .changeset/slick-bugs-repair.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .changeset/slick-bugs-repair.md diff --git a/.changeset/slick-bugs-repair.md b/.changeset/slick-bugs-repair.md new file mode 100644 index 000000000000..ce6b58da9017 --- /dev/null +++ b/.changeset/slick-bugs-repair.md @@ -0,0 +1,16 @@ +--- +'@modern-js/plugin-data-loader': minor +'@modern-js/runtime': minor +'@modern-js/app-tools': minor +'@modern-js/prod-server': minor +'@modern-js/bff-core': minor +'@modern-js/plugin-bff': minor +'@modern-js/plugin': minor +'@modern-js/server': minor +'@modern-js/types': minor +'@modern-js/utils': minor +'@modern-js/server-core': minor +--- + +feat: bundle server-side codes into a single file +feat: 打包服务端代码至单一文件 From 8b1234631e8e96802feeacd38d85b432f16bf858 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 15:05:45 +0800 Subject: [PATCH 14/27] chore: add comments --- .../app-tools/src/plugins/deploy/server-bundle/builder.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 898162757a20..7aec8350c5d1 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -80,6 +80,11 @@ export const bundleServer = async ( conditionNames: ESM_RESOLVE_CONDITIONS, }, output: { + /** + * web: worked, but should use SERVER_BUNDLE_NAME in plugins to mark this as a server-side build + * node: generally worked, but can not polyfill node builtin modules + * web-worker: node externals not take effect + */ target: 'web', module: true, emitAssets: false, From 5335dae448329e89ffff42d7de55bfed366efafc Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 21:21:30 +0800 Subject: [PATCH 15/27] revert: node server --- .../src/plugins/deploy/platforms/node.ts | 13 ++-- .../deploy/platforms/templates/node-entry.mjs | 61 ------------------- 2 files changed, 9 insertions(+), 65 deletions(-) delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 2c06b4aa9feb..39c0e8d59915 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -40,9 +40,7 @@ export const createNodePreset: CreatePreset = ({ }, async genEntry() { if (!isBundleServer) { - const handlerTemplate = await readTemplate( - `node-entry.${isEsmProject ? 'mjs' : 'cjs'}`, - ); + const handlerTemplate = await readTemplate('node-entry.cjs'); const code = await generateHandler({ template: handlerTemplate, @@ -50,7 +48,14 @@ export const createNodePreset: CreatePreset = ({ config: modernConfig, }); - await fse.writeFile(entryFilePath, code); + if (isEsmProject) { + // We have not test all the packages in esm mode + const cjsEntryFilePath = path.join(outputDirectory, 'index.cjs'); + await fse.writeFile(cjsEntryFilePath, code); + await fse.writeFile(entryFilePath, `import('./index.cjs');`); + } else { + await fse.writeFile(entryFilePath, code); + } return; } diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs deleted file mode 100644 index 0714c38654f9..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs +++ /dev/null @@ -1,61 +0,0 @@ -import fs from 'node:fs/promises'; -import path from 'node:path'; -import { createProdServer } from '@modern-js/prod-server'; - -p_genPluginImportsCode; - -if (!process.env.NODE_ENV) { - process.env.NODE_ENV = 'production'; -} - -async function loadRoutes(routeFilepath) { - try { - await fs.access(routeFilepath); - const content = await fs.readFile(routeFilepath, 'utf-8'); - const routeSpec = JSON.parse(content); - return routeSpec.routes || []; - } catch (error) { - console.warn( - 'route.json not found or invalid, continuing with empty routes.', - ); - return []; - } -} - -async function main() { - const routeFilepath = path.join(__dirname, p_ROUTE_SPEC_FILE); - const routes = await loadRoutes(routeFilepath); - - const dynamicProdOptions = p_dynamicProdOptions; - const prodServerOptions = { - pwd: __dirname, - routes, - disableCustomHook: true, - appContext: { - sharedDirectory: p_sharedDirectory, - apiDirectory: p_apiDirectory, - lambdaDirectory: p_lambdaDirectory, - bffRuntimeFramework: p_bffRuntimeFramework, - }, - plugins: p_plugins, - serverConfigPath: p_serverDirectory, - ...dynamicProdOptions, - }; - - const app = await createProdServer(prodServerOptions); - const port = process.env.PORT || 8080; - app.listen( - { - host: '::', - port, - }, - () => { - console.log( - `\x1b[32mServer is listening on http://[::]:${port}`, - '\x1b[0m', - ); - }, - ); -} - -main(); From f99eb121c80bc4ba024fd24afa3a7a668119d855 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 21:25:08 +0800 Subject: [PATCH 16/27] chore: remove forceESM --- .../app-tools/src/plugins/deploy/server-bundle/builder.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 7aec8350c5d1..1dba94deacd7 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -19,17 +19,16 @@ export const generateNodeExternals = ( ...list.map(api => [`node:${api}`, getExternal(api)]), ]; -export interface BundleSSROptions { +export interface BundleServerOptions { config?: BuilderConfig; modifyBuilder?: (builder: BuilderInstance) => Promise; - forceESM?: boolean; nodeExternal?: string[]; } export const bundleServer = async ( handlerCode: string, api: CLIPluginAPI, - options?: BundleSSROptions, + options?: BundleServerOptions, ) => { const normalizedConfig = api.getNormalizedConfig(); const appContext = api.getAppContext(); From 165b088d1475867e70c29f5de1440d04a194dcb5 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 21:30:10 +0800 Subject: [PATCH 17/27] test: pure esm deploy --- .../deploy-server/tests/index.test.ts | 2 +- .../pure-esm-project/tests/deploy.test.ts | 118 ++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 tests/integration/pure-esm-project/tests/deploy.test.ts diff --git a/tests/integration/deploy-server/tests/index.test.ts b/tests/integration/deploy-server/tests/index.test.ts index a7df20dd9748..f3e66d381b73 100644 --- a/tests/integration/deploy-server/tests/index.test.ts +++ b/tests/integration/deploy-server/tests/index.test.ts @@ -69,7 +69,7 @@ describe('deploy', () => { // check server run const port = await getPort(); - const app = await runContinuousTask(['./.output/index.js'], undefined, { + const app = await runContinuousTask(['.output/index.js'], undefined, { cwd: appDir, env: { ...process.env, diff --git a/tests/integration/pure-esm-project/tests/deploy.test.ts b/tests/integration/pure-esm-project/tests/deploy.test.ts new file mode 100644 index 000000000000..88fa4ed5c8d2 --- /dev/null +++ b/tests/integration/pure-esm-project/tests/deploy.test.ts @@ -0,0 +1,118 @@ +import path from 'path'; +import { execa, fs as fse } from '@modern-js/utils'; +import { + getPort, + killApp, + modernBuild, + runContinuousTask, +} from '../../../utils/modernTestUtils'; + +const appDir = path.resolve(__dirname, '../'); + +async function checkAppRun(host: string) { + // Page render + const page = await fetch(`${host}/`); + expect(page.status).toBe(200); + expect(await page.text()).toContain('
'); + + // Loader + const loader = await fetch(`${host}/one?__loader=page&name=name`); + expect(loader.status).toBe(200); + expect(await loader.text()).toContain( + JSON.stringify({ name: 'name', age: 18 }), + ); + + // API + const api = await fetch(`${host}/api/info`); + expect(api.status).toBe(200); + expect(await api.json()).toEqual({ + company: 'bytedance', + addRes: 3, + url: '/api/info', + }); +} + +// bff project's dependencies is more complex, so use bff project to test +describe('deploy', () => { + const apps = new Set(); + + beforeAll(async () => { + await modernBuild(appDir, [], {}); + }); + + afterAll(async () => { + await Promise.all([...apps].map(x => killApp(x))); + await fse.remove(path.join(appDir, '.output')); + await fse.remove(path.join(appDir, '.output-server-bundle')); + }); + + test('support server when deploy target is node', async () => { + await execa('npx modern deploy --skip-build', { + shell: true, + cwd: appDir, + stdio: 'inherit', + env: { + ...process.env, + TEST_BUNDLE_SERVER: 'false', + MODERNJS_DEPLOY: 'node', + }, + }); + const outputDirectory = path.join(appDir, '.output'); + const staticDirectory = path.join(outputDirectory, 'static'); + const htmlDirectory = path.join(outputDirectory, 'html'); + const apiFile = path.join(outputDirectory, 'api/lambda/index.js'); + const bootstrapPath = path.join(outputDirectory, 'index.js'); + + expect(await fse.pathExists(staticDirectory)).toBe(true); + expect(await fse.pathExists(htmlDirectory)).toBe(true); + expect(await fse.pathExists(apiFile)).toBe(true); + expect(await fse.pathExists(bootstrapPath)).toBe(true); + + // check server run + const port = await getPort(); + const app = await runContinuousTask(['.output/index.js'], undefined, { + cwd: appDir, + env: { + ...process.env, + NODE_ENV: 'production', + PORT: port, + }, + waitMessage: /Server is listening on/i, + }); + apps.add(app); + await checkAppRun(`http://localhost:${port}`); + await killApp(app); + apps.delete(app); + }); + + test('support server bundle when deploy target is node', async () => { + await execa('npx modern deploy', { + shell: true, + cwd: appDir, + stdio: 'inherit', + env: { + ...process.env, + TEST_BUNDLE_SERVER: 'true', + MODERNJS_DEPLOY: 'node', + }, + }); + const outputFile = '.output-server-bundle/bundle.mjs'; + expect(await fse.pathExists(path.join(appDir, outputFile))).toBe(true); + + // check server run + const port = await getPort(); + const app = await runContinuousTask([outputFile], undefined, { + cwd: appDir, + env: { + ...process.env, + NODE_ENV: 'production', + PORT: port, + }, + waitMessage: /Server is listening on/i, + }); + apps.add(app); + await checkAppRun(`http://localhost:${port}`); + await killApp(app); + apps.delete(app); + }); +}); From bbf837c1af124cead76e5f9d485a1faf5d4b9725 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 21:34:08 +0800 Subject: [PATCH 18/27] test: pure esm bundleServer --- tests/integration/pure-esm-project/modern.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/pure-esm-project/modern.config.js b/tests/integration/pure-esm-project/modern.config.js index 06bf0e7f492d..73129774ae24 100644 --- a/tests/integration/pure-esm-project/modern.config.js +++ b/tests/integration/pure-esm-project/modern.config.js @@ -10,6 +10,7 @@ export default applyBaseConfig({ server: { ssr: { mode: 'stream', + bundleServer: process.env.TEST_BUNDLE_SERVER === 'true', }, }, output: { From 92d0fff3a76fef149a804497898bf1ef1fd93f8c Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 22:07:21 +0800 Subject: [PATCH 19/27] feat: pure esm server --- .../src/plugins/deploy/platforms/node.ts | 27 ++++---- .../deploy/platforms/templates/node-entry.mjs | 64 +++++++++++++++++++ .../plugins/deploy/server-bundle/builder.ts | 6 +- .../plugins/deploy/server-bundle/generator.ts | 2 +- .../src/plugins/deploy/server-bundle/utils.ts | 5 +- .../src/plugins/deploy/utils/generator.ts | 18 +++--- .../integration/pure-esm-project/package.json | 1 + 7 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 39c0e8d59915..726d79a4423f 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -9,6 +9,7 @@ import { NODE_BUILTIN_MODULES, bundleServer, generateHandler as generateSingleBundleHandler, + resolveESMDependency, } from '../server-bundle'; import { scanDeps } from '../server-bundle/dep-generator'; import { readTemplate } from '../utils'; @@ -40,22 +41,18 @@ export const createNodePreset: CreatePreset = ({ }, async genEntry() { if (!isBundleServer) { - const handlerTemplate = await readTemplate('node-entry.cjs'); + const handlerTemplate = await readTemplate( + `node-entry.${isEsmProject ? 'mjs' : 'cjs'}`, + ); const code = await generateHandler({ template: handlerTemplate, appContext, config: modernConfig, + isESM: isEsmProject, }); - if (isEsmProject) { - // We have not test all the packages in esm mode - const cjsEntryFilePath = path.join(outputDirectory, 'index.cjs'); - await fse.writeFile(cjsEntryFilePath, code); - await fse.writeFile(entryFilePath, `import('./index.cjs');`); - } else { - await fse.writeFile(entryFilePath, code); - } + await fse.writeFile(entryFilePath, code); return; } @@ -96,10 +93,16 @@ export const createNodePreset: CreatePreset = ({ ); }; // Because @modern-js/prod-server is an implicit dependency of the entry, so we add it to the include here. + const entry = isEsmProject + ? await resolveESMDependency('@modern-js/prod-server') + : require.resolve('@modern-js/prod-server'); + if (!entry) { + throw new Error('Cannot find @modern-js/prod-server'); + } await handleDependencies({ appDir: appDirectory, sourceDir: outputDirectory, - includeEntries: [require.resolve('@modern-js/prod-server')], + includeEntries: [entry], copyWholePackage(pkgName) { return pkgName === '@modern-js/utils'; }, @@ -120,7 +123,9 @@ export const createNodePreset: CreatePreset = ({ } console.log( 'Static directory:', - chalk.blue(path.relative(appDirectory, staticDirectory)), + chalk.blue( + path.relative(appDirectory, staticDirectory).replace(/\\/g, '/'), + ), ); if (isBundleServer) { console.log( diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs new file mode 100644 index 000000000000..5ddde2d9b082 --- /dev/null +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/node-entry.mjs @@ -0,0 +1,64 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createProdServer } from '@modern-js/prod-server'; + +p_genPluginImportsCode; + +if (!process.env.NODE_ENV) { + process.env.NODE_ENV = 'production'; +} + +async function loadRoutes(routeFilepath) { + try { + await fs.access(routeFilepath); + const content = await fs.readFile(routeFilepath, 'utf-8'); + const routeSpec = JSON.parse(content); + return routeSpec.routes || []; + } catch (error) { + console.warn( + 'route.json not found or invalid, continuing with empty routes.', + ); + return []; + } +} + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +async function main() { + const routeFilepath = path.join(__dirname, p_ROUTE_SPEC_FILE); + const routes = await loadRoutes(routeFilepath); + + const dynamicProdOptions = p_dynamicProdOptions; + const prodServerOptions = { + pwd: __dirname, + routes, + disableCustomHook: true, + appContext: { + sharedDirectory: p_sharedDirectory, + apiDirectory: p_apiDirectory, + lambdaDirectory: p_lambdaDirectory, + bffRuntimeFramework: p_bffRuntimeFramework, + }, + plugins: p_plugins, + serverConfigPath: p_serverDirectory, + ...dynamicProdOptions, + }; + + const app = await createProdServer(prodServerOptions); + const port = process.env.PORT || 8080; + app.listen( + { + host: '::', + port, + }, + () => { + console.log( + `\x1b[32mServer is listening on http://[::]:${port}`, + '\x1b[0m', + ); + }, + ); +} + +main(); diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 1dba94deacd7..32b79e72546a 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -123,7 +123,11 @@ export const bundleServer = async ( experiments: { outputModule: true, }, - ignoreWarnings: [/__dirname/, /dependency is an expression/], + node: { + __dirname: 'mock', + __filename: 'mock', + }, + ignoreWarnings: [/dependency is an expression/], }, ], }, diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts index f71d60d0f149..1cc6d53c8741 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/generator.ts @@ -75,7 +75,7 @@ export const generateHandler = async (options: GenerateHandlerOptions) => { }`); } - const prodServerEntry = resolveESMDependency( + const prodServerEntry = await resolveESMDependency( serverType === 'node' ? '@modern-js/prod-server' : `@modern-js/prod-server/${serverType}`, diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts index 26b02129e745..9bde74586ffe 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/utils.ts @@ -1,11 +1,12 @@ import { pathToFileURL } from 'node:url'; import { get, set } from '@modern-js/utils/lodash'; -import { moduleResolve } from 'import-meta-resolve'; import { normalizePath } from '../utils'; -export const resolveESMDependency = (entry: string) => { +export const resolveESMDependency = async (entry: string) => { const conditions = new Set(['node', 'import', 'module', 'default']); + try { + const { moduleResolve } = await import('import-meta-resolve'); return normalizePath( moduleResolve( entry, diff --git a/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts b/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts index c7adf90150bd..0b9b4109d85f 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/utils/generator.ts @@ -37,14 +37,14 @@ export const serverAppContextTemplate = (appContext: AppToolsContext) => { export type PluginItem = [string, Record | undefined]; -export const genPluginImportsCode = (plugins: PluginItem[]) => { +export const genPluginImportsCode = (plugins: PluginItem[], isESM = false) => { return plugins - .map( - ([name, options], index) => ` - let plugin_${index} = require('${name}') - plugin_${index} = plugin_${index}.default || plugin_${index} - `, - ) + .map(([name, options], index) => { + const im = isESM + ? `import * as plugin_${index}_ns from '${name}'` + : `const plugin_${index}_ns = require('${name}')`; + return `${im};const plugin_${index} = plugin_${index}_ns.default || plugin_${index}_ns`; + }) .join(';\n'); }; @@ -68,6 +68,7 @@ export interface GenerateHandlerOptions { genAppContextTemplate?: typeof serverAppContextTemplate; genPluginImports?: typeof genPluginImportsCode; routesCode?: string; + isESM?: boolean; } export const generateHandler = async ({ template, @@ -77,6 +78,7 @@ export const generateHandler = async ({ genAppContextTemplate = serverAppContextTemplate, genPluginImports = genPluginImportsCode, routesCode, + isESM, }: GenerateHandlerOptions) => { const { serverPlugins, metaName, serverRoutes } = appContext; @@ -101,7 +103,7 @@ export const generateHandler = async ({ const meta = getMeta(metaName); - const pluginImportCode = genPluginImports(plugins || []); + const pluginImportCode = genPluginImports(plugins || [], Boolean(isESM)); const dynamicProdOptions = { config: serverConfig, }; diff --git a/tests/integration/pure-esm-project/package.json b/tests/integration/pure-esm-project/package.json index 13bcd9d06e0e..5d3609bb72d2 100644 --- a/tests/integration/pure-esm-project/package.json +++ b/tests/integration/pure-esm-project/package.json @@ -8,6 +8,7 @@ "dev:bff": "modern dev --api-only", "build": "modern build", "serve": "modern serve", + "deploy": "modern deploy", "start:bff": "modern serve --api-only", "new": "modern new" }, From c548b557710654ab9f8e86448e0017b664dc99ed Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 22:38:51 +0800 Subject: [PATCH 20/27] fix: test --- packages/server/bff-core/src/router/utils.ts | 7 +- .../pure-esm-project/tests/deploy.test.ts | 6 +- .../pure-esm-project/tests/index.test.ts | 179 +++++++++--------- 3 files changed, 91 insertions(+), 101 deletions(-) diff --git a/packages/server/bff-core/src/router/utils.ts b/packages/server/bff-core/src/router/utils.ts index 61f1523655e9..d0031ad30e55 100644 --- a/packages/server/bff-core/src/router/utils.ts +++ b/packages/server/bff-core/src/router/utils.ts @@ -68,12 +68,7 @@ export const interopHandlerModule = (mod: any) => isFunction(mod) ? { default: mod } : mod; export const requireHandlerModule = async (modulePath: string) => { - // 测试环境不走缓存,因为缓存的 handler 文件,会被 mockAPI 函数进行 mock,升级 jest28,setupFilesAfterEnv 能做异步操作的话,可解此问题 - const originRequire = - process.env.NODE_ENV === 'test' ? require : compatibleRequire; - - const mod = await originRequire(modulePath, false); - + const mod = await compatibleRequire(modulePath, false); return interopHandlerModule(mod); }; diff --git a/tests/integration/pure-esm-project/tests/deploy.test.ts b/tests/integration/pure-esm-project/tests/deploy.test.ts index 88fa4ed5c8d2..160f72251329 100644 --- a/tests/integration/pure-esm-project/tests/deploy.test.ts +++ b/tests/integration/pure-esm-project/tests/deploy.test.ts @@ -16,7 +16,7 @@ async function checkAppRun(host: string) { expect(await page.text()).toContain('
'); // Loader - const loader = await fetch(`${host}/one?__loader=page&name=name`); + const loader = await fetch(`${host}/?__loader=page&name=name`); expect(loader.status).toBe(200); expect(await loader.text()).toContain( JSON.stringify({ name: 'name', age: 18 }), @@ -42,8 +42,8 @@ describe('deploy', () => { afterAll(async () => { await Promise.all([...apps].map(x => killApp(x))); - await fse.remove(path.join(appDir, '.output')); - await fse.remove(path.join(appDir, '.output-server-bundle')); + // await fse.remove(path.join(appDir, '.output')); + // await fse.remove(path.join(appDir, '.output-server-bundle')); }); test('support server when deploy target is node', async () => { diff --git a/tests/integration/pure-esm-project/tests/index.test.ts b/tests/integration/pure-esm-project/tests/index.test.ts index 521a3fde1ee0..83ddf93db299 100644 --- a/tests/integration/pure-esm-project/tests/index.test.ts +++ b/tests/integration/pure-esm-project/tests/index.test.ts @@ -14,115 +14,110 @@ import { const appDir = path.resolve(__dirname, '../'); dns.setDefaultResultOrder('ipv4first'); -if (isVersionAtLeast1819()) { - describe('pure-esm-project in dev', () => { - let port = 8080; - const host = `http://localhost`; - let app: any; - let page: Page; - let browser: Browser; +describe('pure-esm-project in dev', () => { + let port = 8080; + const host = `http://localhost`; + let app: any; + let page: Page; + let browser: Browser; - beforeAll(async () => { - jest.setTimeout(1000 * 60 * 2); - port = await getPort(); - app = await launchApp(appDir, port); - browser = await puppeteer.launch(launchOptions as any); - page = await browser.newPage(); - }); - - test('stream ssr with bff handle web', async () => { - await page.goto(`${host}:${port}?name=bytedance`, { - waitUntil: ['networkidle0'], - }); - const text = await page.$eval('#item', el => el?.textContent); - expect(text).toMatch('name: bytedance, age: 18'); - }); + beforeAll(async () => { + jest.setTimeout(1000 * 60 * 2); + port = await getPort(); + app = await launchApp(appDir, port); + browser = await puppeteer.launch(launchOptions as any); + page = await browser.newPage(); + }); - test('stream ssr with bff handle web, client nav', async () => { - await page.goto(`${host}:${port}/user`, { - waitUntil: ['networkidle0'], - }); - await page.click('#home-btn'); - await page.waitForSelector('#data'); - const text = await page.$eval('#data', el => el?.textContent); - expect(text).toMatch('name: modernjs, age: 18'); + test('stream ssr with bff handle web', async () => { + await page.goto(`${host}:${port}?name=bytedance`, { + waitUntil: ['networkidle0'], }); + const text = await page.$eval('#item', el => el?.textContent); + expect(text).toMatch('name: bytedance, age: 18'); + }); - test('api service should serve normally', async () => { - try { - const res = await fetch(`${host}:${port}/api/info`); - const data = await res.json(); - expect(data).toEqual({ - company: 'bytedance', - addRes: 3, - url: '/api/info', - }); - } catch (error) { - console.error(error); - throw error; - } + test('stream ssr with bff handle web, client nav', async () => { + await page.goto(`${host}:${port}/user`, { + waitUntil: ['networkidle0'], }); + await page.click('#home-btn'); + await page.waitForSelector('#data'); + const text = await page.$eval('#data', el => el?.textContent); + expect(text).toMatch('name: modernjs, age: 18'); + }); - afterAll(async () => { - await killApp(app); - await page.close(); - await browser.close(); - }); + test('api service should serve normally', async () => { + try { + const res = await fetch(`${host}:${port}/api/info`); + const data = await res.json(); + expect(data).toEqual({ + company: 'bytedance', + addRes: 3, + url: '/api/info', + }); + } catch (error) { + console.error(error); + throw error; + } }); - describe('pure-esm-project in prod', () => { - let port = 8080; - const host = `http://localhost`; - let app: any; - let page: Page; - let browser: Browser; + afterAll(async () => { + await killApp(app); + await page.close(); + await browser.close(); + }); +}); - beforeAll(async () => { - port = await getPort(); +describe('pure-esm-project in prod', () => { + let port = 8080; + const host = `http://localhost`; + let app: any; + let page: Page; + let browser: Browser; - await modernBuild(appDir, [], {}); + beforeAll(async () => { + port = await getPort(); - app = await modernServe(appDir, port, {}); - browser = await puppeteer.launch(launchOptions as any); - page = await browser.newPage(); - }); + await modernBuild(appDir, [], {}); - test('stream ssr with bff handle web', async () => { - await page.goto(`${host}:${port}?name=bytedance`, { - waitUntil: ['networkidle0'], - }); - const text = await page.$eval('#item', el => el?.textContent); - expect(text).toMatch('name: bytedance, age: 18'); - }); + app = await modernServe(appDir, port, {}); + browser = await puppeteer.launch(launchOptions as any); + page = await browser.newPage(); + }); - test('stream ssr with bff handle web, client nav', async () => { - await page.goto(`${host}:${port}/user`, { - waitUntil: ['networkidle0'], - }); - await page.click('#home-btn'); - await page.waitForSelector('#data'); - const text = await page.$eval('#data', el => el?.textContent); - expect(text).toMatch('name: modernjs, age: 18'); + test('stream ssr with bff handle web', async () => { + await page.goto(`${host}:${port}?name=bytedance`, { + waitUntil: ['networkidle0'], }); + const text = await page.$eval('#item', el => el?.textContent); + expect(text).toMatch('name: bytedance, age: 18'); + }); - test('api service should serve normally', async () => { - const res = await fetch(`${host}:${port}/api/info`); - const data = await res.json(); - expect(data).toEqual({ - company: 'bytedance', - addRes: 3, - url: '/api/info', - }); + test('stream ssr with bff handle web, client nav', async () => { + await page.goto(`${host}:${port}/user`, { + waitUntil: ['networkidle0'], }); + await page.waitForSelector('#home-btn'); + await page.click('#home-btn'); + await page.waitForSelector('#data'); + const text = await page.$eval('#data', el => el?.textContent); + expect(text).toMatch('name: modernjs, age: 18'); + }); - afterAll(async () => { - await killApp(app); - await page.close(); - await browser.close(); + test('api service should serve normally', async () => { + const res = await fetch(`${host}:${port}/api/info`); + const data = await res.json(); + expect(data).toEqual({ + company: 'bytedance', + addRes: 3, + url: '/api/info', }); }); -} else { - test('should skip the test cases', () => { - expect(true).toBe(true); + + afterAll(async () => { + await killApp(app); + await page.close(); + await browser.close(); }); -} +}); From be782c7ef77466bda86f3c7c94d972913e1a280a Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 22:41:36 +0800 Subject: [PATCH 21/27] chore: ignore kill error --- tests/integration/deploy-server/tests/index.test.ts | 6 +++--- .../integration/pure-esm-project/tests/deploy.test.ts | 10 +++++----- tests/utils/modernTestUtils.js | 6 ++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/integration/deploy-server/tests/index.test.ts b/tests/integration/deploy-server/tests/index.test.ts index f3e66d381b73..05cd6b5d6b2f 100644 --- a/tests/integration/deploy-server/tests/index.test.ts +++ b/tests/integration/deploy-server/tests/index.test.ts @@ -38,7 +38,7 @@ describe('deploy', () => { }); afterAll(async () => { - await Promise.all([...apps].map(x => killApp(x))); + await Promise.all([...apps].map(x => killApp(x, true))); await fse.remove(path.join(appDir, '.vercel')); await fse.remove(path.join(appDir, '.netlify')); await fse.remove(path.join(appDir, '.output')); @@ -80,7 +80,7 @@ describe('deploy', () => { }); apps.add(app); await checkAppRun(`http://localhost:${port}`); - await killApp(app); + await killApp(app, true); apps.delete(app); }); @@ -111,7 +111,7 @@ describe('deploy', () => { }); apps.add(app); await checkAppRun(`http://localhost:${port}`); - await killApp(app); + await killApp(app, true); apps.delete(app); }); diff --git a/tests/integration/pure-esm-project/tests/deploy.test.ts b/tests/integration/pure-esm-project/tests/deploy.test.ts index 160f72251329..5a2aeb0251ef 100644 --- a/tests/integration/pure-esm-project/tests/deploy.test.ts +++ b/tests/integration/pure-esm-project/tests/deploy.test.ts @@ -41,9 +41,9 @@ describe('deploy', () => { }); afterAll(async () => { - await Promise.all([...apps].map(x => killApp(x))); - // await fse.remove(path.join(appDir, '.output')); - // await fse.remove(path.join(appDir, '.output-server-bundle')); + await Promise.all([...apps].map(x => killApp(x, true))); + await fse.remove(path.join(appDir, '.output')); + await fse.remove(path.join(appDir, '.output-server-bundle')); }); test('support server when deploy target is node', async () => { @@ -81,7 +81,7 @@ describe('deploy', () => { }); apps.add(app); await checkAppRun(`http://localhost:${port}`); - await killApp(app); + await killApp(app, true); apps.delete(app); }); @@ -112,7 +112,7 @@ describe('deploy', () => { }); apps.add(app); await checkAppRun(`http://localhost:${port}`); - await killApp(app); + await killApp(app, true); apps.delete(app); }); }); diff --git a/tests/utils/modernTestUtils.js b/tests/utils/modernTestUtils.js index 746a0d276503..838efec7d68e 100644 --- a/tests/utils/modernTestUtils.js +++ b/tests/utils/modernTestUtils.js @@ -207,7 +207,7 @@ function modernServe(dir, port, opts = {}) { }); } -async function killApp(instance) { +async function killApp(instance, ignoreError = false) { await new Promise((resolve, reject) => { if (!instance) { resolve(); @@ -228,7 +228,9 @@ async function killApp(instance) { // Reason: There is no running instance of the task. return resolve(); } - return reject(err); + if (!ignoreError) { + return reject(err); + } } return resolve(); }); From e3a0afa32bd875529fac168c21913f5bbe8f8370 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sat, 31 Jan 2026 23:52:00 +0800 Subject: [PATCH 22/27] fix: test --- packages/cli/plugin-bff/src/cli.ts | 8 +++++++- .../server/utils/src/compilers/typescript/index.ts | 2 +- tests/integration/deploy-server/.gitignore | 1 + tests/integration/deploy-server/modern.config.ts | 5 +++++ tests/integration/deploy-server/tests/index.test.ts | 2 ++ tests/integration/pure-esm-project/.gitignore | 1 + tests/integration/pure-esm-project/modern.config.js | 3 +++ .../pure-esm-project/tests/deploy.test.ts | 13 ++++++++++++- 8 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/integration/deploy-server/.gitignore create mode 100644 tests/integration/pure-esm-project/.gitignore diff --git a/packages/cli/plugin-bff/src/cli.ts b/packages/cli/plugin-bff/src/cli.ts index 6009bc34161f..a922befa0a81 100644 --- a/packages/cli/plugin-bff/src/cli.ts +++ b/packages/cli/plugin-bff/src/cli.ts @@ -13,6 +13,7 @@ import { SHARED_DIR, normalizeOutputPath, } from '@modern-js/utils'; +import { SERVER_BUNDLE_NAME } from '@modern-js/utils/universal/constants'; import type { ConfigChain } from '@rsbuild/core'; import clientGenerator from './utils/clientGenerator'; import pluginGenerator from './utils/pluginGenerator'; @@ -185,7 +186,10 @@ export const bffPlugin = (): CliPlugin => ({ devServer: { compress, }, - bundlerChain: (chain, { CHAIN_ID, isServer }) => { + bundlerChain: ( + chain, + { CHAIN_ID, isServer: rIsServer, environment }, + ) => { const { port, appDirectory, apiDirectory, lambdaDirectory } = api.getAppContext(); const modernConfig = api.getNormalizedConfig(); @@ -209,6 +213,8 @@ export const bffPlugin = (): CliPlugin => ({ normalizeOutputPath(`${apiDirectory}${path.sep}.*(.[tj]s)$`), ); + const isServer = + rIsServer || environment.name === SERVER_BUNDLE_NAME; const name = isServer ? 'server' : 'client'; const sourceExt = process.env.MODERN_LIB_FORMAT === 'esm' ? 'mjs' : 'js'; diff --git a/packages/server/utils/src/compilers/typescript/index.ts b/packages/server/utils/src/compilers/typescript/index.ts index 7f6bad6570db..d3df9cf14282 100644 --- a/packages/server/utils/src/compilers/typescript/index.ts +++ b/packages/server/utils/src/compilers/typescript/index.ts @@ -73,9 +73,9 @@ export const compileByTs: CompileFunc = async ( rootNames, projectReferences, options: { + ...options, rootDir: appDirectory, outDir: distDir, - ...options, }, }); diff --git a/tests/integration/deploy-server/.gitignore b/tests/integration/deploy-server/.gitignore new file mode 100644 index 000000000000..cfe7d10d198f --- /dev/null +++ b/tests/integration/deploy-server/.gitignore @@ -0,0 +1 @@ +dist-* diff --git a/tests/integration/deploy-server/modern.config.ts b/tests/integration/deploy-server/modern.config.ts index b1a31d62e0bd..d6155b6fd61a 100644 --- a/tests/integration/deploy-server/modern.config.ts +++ b/tests/integration/deploy-server/modern.config.ts @@ -7,6 +7,11 @@ export default defineConfig({ performance: { buildCache: false, }, + output: { + distPath: { + root: process.env.TEST_DIST || 'dist', + }, + }, server: { ssr: { bundleServer: process.env.TEST_BUNDLE_SERVER === 'true', diff --git a/tests/integration/deploy-server/tests/index.test.ts b/tests/integration/deploy-server/tests/index.test.ts index 05cd6b5d6b2f..b17b81340630 100644 --- a/tests/integration/deploy-server/tests/index.test.ts +++ b/tests/integration/deploy-server/tests/index.test.ts @@ -39,6 +39,7 @@ describe('deploy', () => { afterAll(async () => { await Promise.all([...apps].map(x => killApp(x, true))); + await fse.remove(path.join(appDir, 'dist-bundle')); await fse.remove(path.join(appDir, '.vercel')); await fse.remove(path.join(appDir, '.netlify')); await fse.remove(path.join(appDir, '.output')); @@ -91,6 +92,7 @@ describe('deploy', () => { stdio: 'inherit', env: { ...process.env, + TEST_DIST: 'dist-bundle', TEST_BUNDLE_SERVER: 'true', MODERNJS_DEPLOY: 'node', }, diff --git a/tests/integration/pure-esm-project/.gitignore b/tests/integration/pure-esm-project/.gitignore new file mode 100644 index 000000000000..cfe7d10d198f --- /dev/null +++ b/tests/integration/pure-esm-project/.gitignore @@ -0,0 +1 @@ +dist-* diff --git a/tests/integration/pure-esm-project/modern.config.js b/tests/integration/pure-esm-project/modern.config.js index 73129774ae24..f88d0154e820 100644 --- a/tests/integration/pure-esm-project/modern.config.js +++ b/tests/integration/pure-esm-project/modern.config.js @@ -15,6 +15,9 @@ export default applyBaseConfig({ }, output: { disableTsChecker: true, + distPath: { + root: process.env.TEST_DIST || 'dist', + }, }, plugins: [bffPlugin()], }); diff --git a/tests/integration/pure-esm-project/tests/deploy.test.ts b/tests/integration/pure-esm-project/tests/deploy.test.ts index 5a2aeb0251ef..1ed5ac4b0ea4 100644 --- a/tests/integration/pure-esm-project/tests/deploy.test.ts +++ b/tests/integration/pure-esm-project/tests/deploy.test.ts @@ -1,5 +1,6 @@ import path from 'path'; import { execa, fs as fse } from '@modern-js/utils'; +import { setTimeout } from 'timers/promises'; import { getPort, killApp, @@ -37,11 +38,18 @@ describe('deploy', () => { const apps = new Set(); beforeAll(async () => { - await modernBuild(appDir, [], {}); + await modernBuild(appDir, [], { + env: { + TEST_DIST: 'dist-deploy', + TEST_BUNDLE_SERVER: 'false', + }, + }); }); afterAll(async () => { await Promise.all([...apps].map(x => killApp(x, true))); + await fse.remove(path.join(appDir, 'dist-deploy')); + await fse.remove(path.join(appDir, 'dist-deploy-bundle')); await fse.remove(path.join(appDir, '.output')); await fse.remove(path.join(appDir, '.output-server-bundle')); }); @@ -53,6 +61,7 @@ describe('deploy', () => { stdio: 'inherit', env: { ...process.env, + TEST_DIST: 'dist-deploy', TEST_BUNDLE_SERVER: 'false', MODERNJS_DEPLOY: 'node', }, @@ -92,6 +101,7 @@ describe('deploy', () => { stdio: 'inherit', env: { ...process.env, + TEST_DIST: 'dist-deploy-bundle', TEST_BUNDLE_SERVER: 'true', MODERNJS_DEPLOY: 'node', }, @@ -111,6 +121,7 @@ describe('deploy', () => { waitMessage: /Server is listening on/i, }); apps.add(app); + // await setTimeout(3000000); await checkAppRun(`http://localhost:${port}`); await killApp(app, true); apps.delete(app); From 3e35ffb5ab8d571ffb5db23d0b3ccaa5594e41d0 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sun, 1 Feb 2026 00:39:15 +0800 Subject: [PATCH 23/27] fix: ut --- .../runtime/plugin-runtime/src/router/cli/code/nestedRoutes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/plugin-runtime/src/router/cli/code/nestedRoutes.ts b/packages/runtime/plugin-runtime/src/router/cli/code/nestedRoutes.ts index 95f2a21ab558..c8058c46e4b3 100644 --- a/packages/runtime/plugin-runtime/src/router/cli/code/nestedRoutes.ts +++ b/packages/runtime/plugin-runtime/src/router/cli/code/nestedRoutes.ts @@ -164,7 +164,7 @@ export const walk = async (options: { let splatData = ''; let splatAction = ''; - const items = await fs.readdir(dirname); + const items = (await fs.readdir(dirname)).sort(); for (const item of items) { const itemPath = path.join(dirname, item); From 7d625ad455d0691374d3a9fb1607263cbb471f21 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sun, 1 Feb 2026 23:34:41 +0800 Subject: [PATCH 24/27] chore: move bundled --- packages/server/bff-core/src/router/index.ts | 2 +- packages/server/core/package.json | 12 + .../{node => bundled}/helper/getBundledDep.ts | 2 +- .../core/src/adapters/bundled/helper/index.ts | 6 + .../src/adapters/bundled/helper/loadCache.ts | 32 +++ .../src/adapters/bundled/helper/loadConfig.ts | 42 ++++ .../server/core/src/adapters/bundled/index.ts | 11 + .../src/adapters/bundled/plugins/index.ts | 1 + .../src/adapters/bundled/plugins/resource.ts | 210 ++++++++++++++++++ .../core/src/adapters/node/helper/index.ts | 5 +- .../src/adapters/node/helper/loadCache.ts | 29 +-- .../src/adapters/node/helper/loadConfig.ts | 62 ++---- .../server/core/src/adapters/node/index.ts | 4 - .../src/adapters/node/plugins/resource.ts | 124 ++--------- packages/server/prod-server/src/apply.ts | 16 +- .../server/prod-server/src/base-server.ts | 2 + 16 files changed, 376 insertions(+), 184 deletions(-) rename packages/server/core/src/adapters/{node => bundled}/helper/getBundledDep.ts (94%) create mode 100644 packages/server/core/src/adapters/bundled/helper/index.ts create mode 100644 packages/server/core/src/adapters/bundled/helper/loadCache.ts create mode 100644 packages/server/core/src/adapters/bundled/helper/loadConfig.ts create mode 100644 packages/server/core/src/adapters/bundled/index.ts create mode 100644 packages/server/core/src/adapters/bundled/plugins/index.ts create mode 100644 packages/server/core/src/adapters/bundled/plugins/resource.ts diff --git a/packages/server/bff-core/src/router/index.ts b/packages/server/bff-core/src/router/index.ts index 224ed2f7549d..880fe4559ead 100644 --- a/packages/server/bff-core/src/router/index.ts +++ b/packages/server/bff-core/src/router/index.ts @@ -1,7 +1,7 @@ import path from 'path'; import { fs, logger } from '@modern-js/utils'; import 'reflect-metadata'; -import { getBundledDep } from '@modern-js/server-core/node'; +import { getBundledDep } from '@modern-js/server-core/bundled'; import type { HttpMethodDecider } from '@modern-js/types'; import { HttpMethod, OperatorType, TriggerType, httpMethods } from '../types'; import { INPUT_PARAMS_DECIDER, debug } from '../utils'; diff --git a/packages/server/core/package.json b/packages/server/core/package.json index d9470300e83d..bc3c55a890eb 100644 --- a/packages/server/core/package.json +++ b/packages/server/core/package.json @@ -37,6 +37,15 @@ }, "default": "./dist/cjs/adapters/node/index.js" }, + "./bundled": { + "types": "./dist/types/adapters/bundled/index.d.ts", + "modern:source": "./src/adapters/bundled/index.ts", + "node": { + "import": "./dist/esm-node/adapters/bundled/index.mjs", + "require": "./dist/cjs/adapters/bundled/index.js" + }, + "default": "./dist/cjs/adapters/bundled/index.js" + }, "./hono": { "types": "./dist/types/hono.d.ts", "node": { @@ -54,6 +63,9 @@ "node": [ "./dist/types/adapters/node/index.d.ts" ], + "bundled": [ + "./dist/types/adapters/bundled/index.d.ts" + ], "hono": [ "./dist/types/hono.d.ts" ] diff --git a/packages/server/core/src/adapters/node/helper/getBundledDep.ts b/packages/server/core/src/adapters/bundled/helper/getBundledDep.ts similarity index 94% rename from packages/server/core/src/adapters/node/helper/getBundledDep.ts rename to packages/server/core/src/adapters/bundled/helper/getBundledDep.ts index 92c0ab2552ee..1497c50fec5a 100644 --- a/packages/server/core/src/adapters/node/helper/getBundledDep.ts +++ b/packages/server/core/src/adapters/bundled/helper/getBundledDep.ts @@ -7,7 +7,7 @@ export const getBundledDep = async ( return; } - let key = keyParam; + let key = keyParam.replace(/\\/g, '/'); if (key.startsWith('/')) { key = key.substring(1); } diff --git a/packages/server/core/src/adapters/bundled/helper/index.ts b/packages/server/core/src/adapters/bundled/helper/index.ts new file mode 100644 index 000000000000..ebbb0d3a11c6 --- /dev/null +++ b/packages/server/core/src/adapters/bundled/helper/index.ts @@ -0,0 +1,6 @@ +export { + loadBundledServerRuntimeConfig, + loadBundledServerCliConfig, +} from './loadConfig'; +export { loadBundledCacheConfig } from './loadCache'; +export { getBundledDep } from './getBundledDep'; diff --git a/packages/server/core/src/adapters/bundled/helper/loadCache.ts b/packages/server/core/src/adapters/bundled/helper/loadCache.ts new file mode 100644 index 000000000000..d60424d19208 --- /dev/null +++ b/packages/server/core/src/adapters/bundled/helper/loadCache.ts @@ -0,0 +1,32 @@ +import path from 'path'; +import type { CacheOption, Container } from '@modern-js/types'; +import { SERVER_DIR } from '@modern-js/utils'; +import type { CacheConfig } from '../../../types'; +import { getBundledDep } from './getBundledDep'; + +const CACHE_FILENAME = 'cache'; + +interface CacheMod { + customContainer?: Container; + cacheOption?: CacheOption; +} + +export async function loadBundledCacheConfig( + deps?: Record>, +): Promise { + const serverCacheFilepath = path.join(SERVER_DIR, CACHE_FILENAME); + const mod: CacheMod | undefined = await getBundledDep( + serverCacheFilepath, + deps, + false, + ); + + if (mod?.cacheOption) { + return { + strategy: mod.cacheOption, + container: mod.customContainer, + }; + } + + return undefined; +} diff --git a/packages/server/core/src/adapters/bundled/helper/loadConfig.ts b/packages/server/core/src/adapters/bundled/helper/loadConfig.ts new file mode 100644 index 000000000000..efb26f88f90c --- /dev/null +++ b/packages/server/core/src/adapters/bundled/helper/loadConfig.ts @@ -0,0 +1,42 @@ +import { OUTPUT_CONFIG_FILE, lodash as _ } from '@modern-js/utils'; +import { fromJSON } from 'flatted'; +import type { CliConfig, ServerConfig, UserConfig } from '../../../types'; +import { getBundledDep } from './getBundledDep'; + +export async function loadBundledServerRuntimeConfig( + serverConfigPath: string, + deps?: Record>, +): Promise { + const mod = await getBundledDep(serverConfigPath, deps); + if (mod) { + return mod; + } + return undefined; +} + +export async function loadBundledServerCliConfig( + defaultConfig: UserConfig = {}, + deps?: Record>, +): Promise { + let cliConfig: CliConfig = { + output: {}, + source: {}, + tools: {}, + server: {}, + security: {}, + bff: {}, + html: {}, + dev: {}, + }; + + try { + const inputConfig = await getBundledDep(OUTPUT_CONFIG_FILE, deps); + cliConfig = fromJSON(inputConfig); + } catch (_) { + // ignore + } + + const mergedCliConfig = _.merge(defaultConfig, cliConfig); + + return mergedCliConfig; +} diff --git a/packages/server/core/src/adapters/bundled/index.ts b/packages/server/core/src/adapters/bundled/index.ts new file mode 100644 index 000000000000..e4a8d15987d0 --- /dev/null +++ b/packages/server/core/src/adapters/bundled/index.ts @@ -0,0 +1,11 @@ +export { + injectResourcePlugin, + injectRscManifestPlugin, +} from './plugins'; + +export { + loadBundledServerRuntimeConfig, + loadBundledServerCliConfig, + loadBundledCacheConfig, + getBundledDep, +} from './helper'; diff --git a/packages/server/core/src/adapters/bundled/plugins/index.ts b/packages/server/core/src/adapters/bundled/plugins/index.ts new file mode 100644 index 000000000000..c1cb5de6b711 --- /dev/null +++ b/packages/server/core/src/adapters/bundled/plugins/index.ts @@ -0,0 +1 @@ +export * from './resource'; diff --git a/packages/server/core/src/adapters/bundled/plugins/resource.ts b/packages/server/core/src/adapters/bundled/plugins/resource.ts new file mode 100644 index 000000000000..5906aeba5805 --- /dev/null +++ b/packages/server/core/src/adapters/bundled/plugins/resource.ts @@ -0,0 +1,210 @@ +import path from 'path'; +import { fileReader } from '@modern-js/runtime-utils/fileReader'; +import type { Logger, Monitors, ServerRoute } from '@modern-js/types'; +import { + fs, + LOADABLE_STATS_FILE, + MAIN_ENTRY_NAME, + NESTED_ROUTE_SPEC_FILE, + ROUTE_MANIFEST_FILE, + SERVER_BUNDLE_DIRECTORY, + compatibleRequire, + isProd, +} from '@modern-js/utils'; +import type { + Middleware, + MiddlewareHandler, + ServerEnv, + ServerManifest, + ServerPlugin, +} from '../../../types'; +import { uniqueKeyByRoute } from '../../../utils'; +import { getBundledDep } from '../helper'; + +export async function getBundledHtmlTemplates( + deps: Record>, + routes: ServerRoute[], +) { + const htmlRoutes = routes.filter(route => route.entryName); + + const htmls = await Promise.all( + htmlRoutes.map(async route => { + const html = await getBundledDep(route.entryPath, deps); + return [uniqueKeyByRoute(route), html]; + }) || [], + ); + + const templates: Record = Object.fromEntries(htmls); + + return templates; +} + +export function injectTemplates( + htmlTemplatesPromise: ReturnType, + routes?: ServerRoute[], +): Middleware { + return async (c, next) => { + if (routes && !c.get('templates')) { + const templates = await htmlTemplatesPromise; + c.set('templates', templates); + } + + await next(); + }; +} + +export async function getBundledServerManifest( + deps: Record>, + routes: ServerRoute[], +): Promise { + const loaderBundles: Record = {}; + const renderBundles: Record = {}; + + await Promise.all( + routes + .filter(route => Boolean(route.bundle)) + .map(async route => { + const entryName = route.entryName || MAIN_ENTRY_NAME; + if (!route.bundleContent) { + throw new Error( + `Bundle content is not defined for route ${route.entryName}`, + ); + } + + const renderBundle = await route.bundleContent(); + const loaderBundle = route.serverLoadersContent + ? await route.serverLoadersContent() + : undefined; + + renderBundle && (renderBundles[entryName] = renderBundle); + loaderBundle && + (loaderBundles[entryName] = loaderBundle?.loadModules + ? await loaderBundle?.loadModules() + : loaderBundle); + }), + ); + + const loadableStats = await getBundledDep(LOADABLE_STATS_FILE, deps).catch( + _ => ({}), + ); + const routeManifest = await getBundledDep(ROUTE_MANIFEST_FILE, deps).catch( + _ => ({}), + ); + const nestedRoutesJson = await getBundledDep( + NESTED_ROUTE_SPEC_FILE, + deps, + ).catch(_ => ({})); + + return { + loaderBundles, + renderBundles, + loadableStats, + routeManifest, + nestedRoutesJson, + }; +} + +export function injectServerManifest( + manifestPromise: ReturnType, + routes?: ServerRoute[], +): Middleware { + return async (c, next) => { + if (routes && !c.get('serverManifest')) { + const serverManifest = await manifestPromise; + + c.set('serverManifest', serverManifest); + } + + await next(); + }; +} + +export async function getRscServerManifest(deps: Record>) { + const rscServerManifest = await getBundledDep( + path.join('bundles', 'react-server-manifest.json'), + deps, + ).catch(_ => undefined); + return rscServerManifest; +} + +export async function getClientManifest(deps: Record>) { + const rscClientManifest = await getBundledDep( + 'react-client-manifest.json', + deps, + ).catch(_ => undefined); + return rscClientManifest; +} + +export async function getRscSSRManifest(deps: Record>) { + const rscSSRManifest = await getBundledDep( + 'react-ssr-manifest.json', + deps, + ).catch(_ => undefined); + return rscSSRManifest; +} + +export const injectRscManifestPlugin = (enableRsc: boolean): ServerPlugin => ({ + name: '@modern-js/plugin-inject-rsc-manifest', + setup(api) { + api.onPrepare(() => { + const { middlewares, dependencies = {} } = api.getServerContext(); + // only rsc project need inject rsc manifest + if (!enableRsc) { + return; + } + + // TODO: should inject in prepare stage, not first request + middlewares.push({ + name: 'inject-rsc-manifest', + handler: (async (c, next) => { + if (!c.get('rscServerManifest')) { + const rscServerManifest = await getRscServerManifest(dependencies); + c.set('rscServerManifest', rscServerManifest); + } + + if (!c.get('rscClientManifest')) { + const rscClientManifest = await getClientManifest(dependencies); + c.set('rscClientManifest', rscClientManifest); + } + + if (!c.get('rscSSRManifest')) { + const rscSSRManifest = await getRscSSRManifest(dependencies); + c.set('rscSSRManifest', rscSSRManifest); + } + + await next(); + }) as MiddlewareHandler, + }); + }); + }, +}); + +export const injectResourcePlugin = (): ServerPlugin => ({ + name: '@modern-js/plugin-inject-resource', + + setup(api) { + api.onPrepare(() => { + const { middlewares, routes, dependencies = {} } = api.getServerContext(); + + // In Production, should warmup server bundles on prepare. + const htmlTemplatePromise = getBundledHtmlTemplates( + dependencies, + routes || [], + ); + const manifestPromise = getBundledServerManifest( + dependencies, + routes || [], + ); + + middlewares.push({ + name: 'inject-server-manifest', + handler: injectServerManifest(manifestPromise, routes), + }); + + middlewares.push({ + name: 'inject-html', + handler: injectTemplates(htmlTemplatePromise, routes), + }); + }); + }, +}); diff --git a/packages/server/core/src/adapters/node/helper/index.ts b/packages/server/core/src/adapters/node/helper/index.ts index f26105bf6d8d..ac98c1e831a9 100644 --- a/packages/server/core/src/adapters/node/helper/index.ts +++ b/packages/server/core/src/adapters/node/helper/index.ts @@ -2,11 +2,8 @@ export { loadServerEnv } from './loadEnv'; export { loadServerPlugins } from './loadPlugin'; export { loadServerRuntimeConfig, - loadBundledServerRuntimeConfig, loadServerCliConfig, - loadBundledServerCliConfig, } from './loadConfig'; -export { loadCacheConfig, loadBundledCacheConfig } from './loadCache'; +export { loadCacheConfig } from './loadCache'; export { isResFinalized } from './utils'; export type { NodeBindings } from './utils'; -export { getBundledDep } from './getBundledDep'; diff --git a/packages/server/core/src/adapters/node/helper/loadCache.ts b/packages/server/core/src/adapters/node/helper/loadCache.ts index ad67b6a0c4d2..a11d44f779b6 100644 --- a/packages/server/core/src/adapters/node/helper/loadCache.ts +++ b/packages/server/core/src/adapters/node/helper/loadCache.ts @@ -1,12 +1,7 @@ import path from 'path'; import type { CacheOption, Container } from '@modern-js/types'; -import { - SERVER_DIR, - normalizeToPosixPath, - requireExistModule, -} from '@modern-js/utils'; +import { SERVER_DIR, requireExistModule } from '@modern-js/utils'; import type { CacheConfig } from '../../../types'; -import { getBundledDep } from './getBundledDep'; const CACHE_FILENAME = 'cache'; @@ -35,25 +30,3 @@ export async function loadCacheConfig( return undefined; } - -export async function loadBundledCacheConfig( - deps?: Record>, -): Promise { - const serverCacheFilepath = path - .join(SERVER_DIR, CACHE_FILENAME) - .replace(/\\/g, '/'); - const mod: CacheMod | undefined = await getBundledDep( - serverCacheFilepath, - deps, - false, - ); - - if (mod?.cacheOption) { - return { - strategy: mod.cacheOption, - container: mod.customContainer, - }; - } - - return undefined; -} diff --git a/packages/server/core/src/adapters/node/helper/loadConfig.ts b/packages/server/core/src/adapters/node/helper/loadConfig.ts index 5a6a25f6dfc1..bff187ca6c59 100644 --- a/packages/server/core/src/adapters/node/helper/loadConfig.ts +++ b/packages/server/core/src/adapters/node/helper/loadConfig.ts @@ -7,30 +7,43 @@ import { ensureAbsolutePath, requireExistModule, } from '@modern-js/utils'; -import { fromJSON, parse } from 'flatted'; +import { parse } from 'flatted'; import type { CliConfig, ServerConfig, UserConfig } from '../../../types'; -import { getBundledDep } from './getBundledDep'; -export async function loadServerRuntimeConfig(serverConfigPath: string) { - const mod: ServerConfig | null = await requireExistModule(serverConfigPath); - - if (mod) { - return mod; +const requireConfig = async ( + serverConfigPath: string, +): Promise => { + if (fs.pathExistsSync(serverConfigPath)) { + return compatibleRequire(serverConfigPath); } return undefined; -} +}; -export async function loadBundledServerRuntimeConfig( +async function loadServerConfigNew( serverConfigPath: string, - deps?: Record>, ): Promise { - const mod = await getBundledDep(serverConfigPath, deps); + const mod: ServerConfig | null = await requireExistModule(serverConfigPath); + if (mod) { return mod; } return undefined; } +async function loadServerConfigOld( + pwd: string, + configFile: string, +): Promise { + const serverConfigPath = path.join(pwd, `${configFile}.cjs`); + const serverConfig = await requireConfig(serverConfigPath); + return serverConfig; +} + +export async function loadServerRuntimeConfig(serverConfigPath: string) { + const newServerConfig = await loadServerConfigNew(serverConfigPath); + return newServerConfig; +} + export async function loadServerCliConfig( pwd: string, defaultConfig: UserConfig = {}, @@ -66,30 +79,3 @@ export async function loadServerCliConfig( return mergedCliConfig; } - -export async function loadBundledServerCliConfig( - defaultConfig: UserConfig = {}, - deps?: Record>, -): Promise { - let cliConfig: CliConfig = { - output: {}, - source: {}, - tools: {}, - server: {}, - security: {}, - bff: {}, - html: {}, - dev: {}, - }; - - try { - const inputConfig = await getBundledDep(OUTPUT_CONFIG_FILE, deps); - cliConfig = fromJSON(inputConfig); - } catch (_) { - // ignore - } - - const mergedCliConfig = _.merge(defaultConfig, cliConfig); - - return mergedCliConfig; -} diff --git a/packages/server/core/src/adapters/node/index.ts b/packages/server/core/src/adapters/node/index.ts index 005c2b665a5f..3f63e2e3a1d8 100644 --- a/packages/server/core/src/adapters/node/index.ts +++ b/packages/server/core/src/adapters/node/index.ts @@ -24,10 +24,6 @@ export { loadServerPlugins, loadServerEnv, loadServerRuntimeConfig, - loadBundledServerRuntimeConfig, loadServerCliConfig, - loadBundledServerCliConfig, loadCacheConfig, - loadBundledCacheConfig, - getBundledDep, } from './helper'; diff --git a/packages/server/core/src/adapters/node/plugins/resource.ts b/packages/server/core/src/adapters/node/plugins/resource.ts index 5c20c310fd89..bbc405d594b0 100644 --- a/packages/server/core/src/adapters/node/plugins/resource.ts +++ b/packages/server/core/src/adapters/node/plugins/resource.ts @@ -19,7 +19,6 @@ import type { ServerPlugin, } from '../../../types'; import { uniqueKeyByRoute } from '../../../utils'; -import { getBundledDep } from '../helper'; export async function getHtmlTemplates(pwd: string, routes: ServerRoute[]) { // Only process routes with entryName, which are HTML template routes. @@ -44,31 +43,15 @@ export async function getHtmlTemplates(pwd: string, routes: ServerRoute[]) { return templates; } -export async function getBundledHtmlTemplates( - deps: Record>, - routes: ServerRoute[], -) { - const htmlRoutes = routes.filter(route => route.entryName); - - const htmls = await Promise.all( - htmlRoutes.map(async route => { - const html = await getBundledDep(route.entryPath, deps); - return [uniqueKeyByRoute(route), html]; - }) || [], - ); - - const templates: Record = Object.fromEntries(htmls); - - return templates; -} - export function injectTemplates( - getHtmlTemplatesFn: () => ReturnType, + pwd: string, routes?: ServerRoute[], + htmlTemplatePromise?: ReturnType, ): Middleware { return async (c, next) => { if (routes && !c.get('templates')) { - const templates = await getHtmlTemplatesFn(); + const templates = await (htmlTemplatePromise || + getHtmlTemplates(pwd, routes)); c.set('templates', templates); } @@ -149,65 +132,16 @@ export async function getServerManifest( }; } -export async function getBundledServerManifest( - deps: Record>, - routes: ServerRoute[], -): Promise { - const loaderBundles: Record = {}; - const renderBundles: Record = {}; - - await Promise.all( - routes - .filter(route => Boolean(route.bundle)) - .map(async route => { - const entryName = route.entryName || MAIN_ENTRY_NAME; - if (!route.bundleContent) { - throw new Error( - `Bundle content is not defined for route ${route.entryName}`, - ); - } - - const renderBundle = await route.bundleContent(); - const loaderBundle = route.serverLoadersContent - ? await route.serverLoadersContent() - : undefined; - - renderBundle && (renderBundles[entryName] = renderBundle); - loaderBundle && - (loaderBundles[entryName] = loaderBundle?.loadModules - ? await loaderBundle?.loadModules() - : loaderBundle); - }), - ); - - const loadableStats = await getBundledDep(LOADABLE_STATS_FILE, deps).catch( - _ => ({}), - ); - const routeManifest = await getBundledDep(ROUTE_MANIFEST_FILE, deps).catch( - _ => ({}), - ); - const nestedRoutesJson = await getBundledDep( - NESTED_ROUTE_SPEC_FILE, - deps, - ).catch(_ => ({})); - - return { - loaderBundles, - renderBundles, - loadableStats, - routeManifest, - nestedRoutesJson, - }; -} - export function injectServerManifest( - getManifest: (monitors: Monitors) => Promise, + pwd: string, routes?: ServerRoute[], + manifestPromise?: Promise, ): Middleware { return async (c, next) => { if (routes && !c.get('serverManifest')) { const monitors = c.get('monitors'); - const serverManifest = await getManifest(monitors); + const serverManifest = await (manifestPromise || + getServerManifest(pwd, routes, monitors)); c.set('serverManifest', serverManifest); } @@ -282,49 +216,31 @@ export const injectResourcePlugin = (): ServerPlugin => ({ middlewares, routes, distDirectory: pwd, - dependencies, } = api.getServerContext(); // In Production, should warmup server bundles on prepare. - // let htmlTemplatePromise: ReturnType | undefined; - let getManifest: (c: Monitors) => Promise; - let getHtmlTemplatesFn: () => ReturnType; + let htmlTemplatePromise: ReturnType | undefined; + let manifestPromise: Promise | undefined; if (isProd()) { - if (process.env.MODERN_SERVER_BUNDLE && dependencies) { - const manifestPromise = getBundledServerManifest( - dependencies, - routes || [], - ); - getManifest = () => manifestPromise; - const htmlTemplatePromise = getBundledHtmlTemplates( - dependencies, - routes || [], - ); - getHtmlTemplatesFn = () => htmlTemplatePromise; - } else { - const manifestPromise = getServerManifest( - pwd!, - routes || [], - console as unknown as Monitors, - ); - getManifest = () => manifestPromise; - const htmlTemplatePromise = getHtmlTemplates(pwd!, routes || []); - getHtmlTemplatesFn = () => htmlTemplatePromise; - } - } else { - getManifest = c => getServerManifest(pwd!, routes || [], c); - getHtmlTemplatesFn = () => getHtmlTemplates(pwd!, routes || []); + manifestPromise = getServerManifest( + pwd!, + routes || [], + console as unknown as Monitors, + ); + htmlTemplatePromise = getHtmlTemplates(pwd!, routes || []); } middlewares.push({ name: 'inject-server-manifest', - handler: injectServerManifest(getManifest, routes), + + handler: injectServerManifest(pwd!, routes, manifestPromise), }); middlewares.push({ name: 'inject-html', - handler: injectTemplates(getHtmlTemplatesFn, routes), + + handler: injectTemplates(pwd!, routes, htmlTemplatePromise), }); }); }, diff --git a/packages/server/prod-server/src/apply.ts b/packages/server/prod-server/src/apply.ts index 1e1f61918a7e..04cbb8f0a2bd 100644 --- a/packages/server/prod-server/src/apply.ts +++ b/packages/server/prod-server/src/apply.ts @@ -10,11 +10,15 @@ import { onError, renderPlugin, } from '@modern-js/server-core'; +import { + injectResourcePlugin as injectBundledResourcePlugin, + injectRscManifestPlugin as injectBundledRscManifestPlugin, + loadBundledCacheConfig, +} from '@modern-js/server-core/bundled'; import { injectNodeSeverPlugin, injectResourcePlugin, injectRscManifestPlugin, - loadBundledCacheConfig, loadCacheConfig, serverStaticPlugin, } from '@modern-js/server-core/node'; @@ -52,10 +56,12 @@ export async function applyPlugins( serverConfig, } = serverOptions; + const isBundled = Boolean(process.env.MODERN_SERVER_BUNDLE); + const enableRsc = config.server?.rsc ?? serverConfig?.server?.rsc ?? false; const serverErrorHandler = serverOptions.serverConfig?.onError; - const cacheConfig = await (process.env.MODERN_SERVER_BUNDLE + const cacheConfig = await (isBundled ? loadBundledCacheConfig(serverOptions.appContext?.dependencies) : loadCacheConfig(isProd() ? pwd : appContext.appDirectory || pwd)); @@ -109,8 +115,10 @@ export async function applyPlugins( }), injectConfigMiddlewarePlugin(middlewares, renderMiddlewares), ...(serverOptions.plugins || []), - injectResourcePlugin(), - injectRscManifestPlugin(enableRsc), + isBundled ? injectBundledResourcePlugin() : injectResourcePlugin(), + isBundled + ? injectBundledRscManifestPlugin(enableRsc) + : injectRscManifestPlugin(enableRsc), ...(extra.noStaticServer ? [] : [serverStaticPlugin()]), faviconPlugin(), renderPlugin(), diff --git a/packages/server/prod-server/src/base-server.ts b/packages/server/prod-server/src/base-server.ts index b8f6098f0ad3..57ab8ab0989f 100644 --- a/packages/server/prod-server/src/base-server.ts +++ b/packages/server/prod-server/src/base-server.ts @@ -2,6 +2,8 @@ import { createServerBase } from '@modern-js/server-core'; import { loadBundledServerCliConfig, loadBundledServerRuntimeConfig, +} from '@modern-js/server-core/bundled'; +import { loadServerCliConfig, loadServerEnv, loadServerRuntimeConfig, From 791267ae9cc8bcbdeb4e366a02de09090c431d83 Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Sun, 1 Feb 2026 23:43:16 +0800 Subject: [PATCH 25/27] chore: message --- .../app-tools/src/builder/generator/index.ts | 2 +- .../src/plugins/deploy/platforms/node.ts | 18 +++++++----------- .../plugins/deploy/server-bundle/builder.ts | 3 ++- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/solutions/app-tools/src/builder/generator/index.ts b/packages/solutions/app-tools/src/builder/generator/index.ts index 09cfe112eb3b..19abdbea7a02 100644 --- a/packages/solutions/app-tools/src/builder/generator/index.ts +++ b/packages/solutions/app-tools/src/builder/generator/index.ts @@ -74,7 +74,7 @@ export async function generateBuilder( return builder; } -export async function applyBuilderPlugins( +async function applyBuilderPlugins( builder: BuilderInstance, options: BuilderOptions, ) { diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 726d79a4423f..72b76dc6fd9e 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -127,17 +127,13 @@ export const createNodePreset: CreatePreset = ({ path.relative(appDirectory, staticDirectory).replace(/\\/g, '/'), ), ); - if (isBundleServer) { - console.log( - `You can preview this build by`, - chalk.blue(`node .output-server-bundle/bundle.mjs`), - ); - } else { - console.log( - `You can preview this build by`, - chalk.blue(`node .output/index`), - ); - } + const previewPath = isBundleServer + ? '.output-server-bundle/bundle.mjs' + : '.output/index'; + console.log( + `You can preview this build by`, + chalk.blue(`node ${previewPath}`), + ); }, }; }; diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index 32b79e72546a..4c5ff8df1b6d 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -145,9 +145,10 @@ export const bundleServer = async ( config: finalConfig, }); + // copy plugins to make sure build process is same as default const plugins = api.getAppContext().builder?.getPlugins(); - const hasPlugins = builder.getPlugins().map(x => x.name); if (plugins) { + const hasPlugins = builder.getPlugins().map(x => x.name); builder.addPlugins(plugins.filter(x => !hasPlugins.includes(x.name))); } From 333ea5b54b231fc4cb71b60ce275c6201d04e7db Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Tue, 17 Mar 2026 17:33:07 +0800 Subject: [PATCH 26/27] chore: remove handler --- .../platforms/templates/netlify-handler.cjs | 78 ------------------- .../platforms/templates/vercel-handler.cjs | 76 ------------------ 2 files changed, 154 deletions(-) delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-handler.cjs delete mode 100644 packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-handler.cjs diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-handler.cjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-handler.cjs deleted file mode 100644 index 807181495c33..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/netlify-handler.cjs +++ /dev/null @@ -1,78 +0,0 @@ -const fs = require('node:fs/promises'); -const path = require('node:path'); -const { createNetlifyFunction } = require('@modern-js/prod-server/netlify'); - -p_genPluginImportsCode; - -if (!process.env.NODE_ENV) { - process.env.NODE_ENV = 'production'; -} - -let requestHandler = null; -let handlerCreationPromise = null; - -async function loadRoutes(routeFilepath) { - try { - await fs.access(routeFilepath); - const content = await fs.readFile(routeFilepath, 'utf-8'); - const routeSpec = JSON.parse(content); - return routeSpec.routes || []; - } catch (error) { - console.warn( - 'route.json not found or invalid, continuing with empty routes.', - ); - return []; - } -} - -async function initServer() { - const routeFilepath = path.join(__dirname, p_ROUTE_SPEC_FILE); - const routes = await loadRoutes(routeFilepath); - - const dynamicProdOptions = p_dynamicProdOptions; - - const prodServerOptions = { - pwd: __dirname, - routes, - disableCustomHook: true, - appContext: { - sharedDirectory: p_sharedDirectory, - apiDirectory: p_apiDirectory, - lambdaDirectory: p_lambdaDirectory, - bffRuntimeFramework: p_bffRuntimeFramework, - }, - plugins: p_plugins, - serverConfigPath: p_serverDirectory, - ...dynamicProdOptions, - }; - - const requestHandler = await createNetlifyFunction(prodServerOptions); - - return requestHandler; -} - -async function createHandler() { - if (!handlerCreationPromise) { - handlerCreationPromise = (async () => { - try { - requestHandler = await initServer(); - } catch (error) { - console.error('Error creating server:', error); - process.exit(1); - } - })(); - } - await handlerCreationPromise; - return requestHandler; -} - -createHandler(); - -const handler = async (request, context) => { - if (!requestHandler) { - await createHandler(); - } - return requestHandler(request, context); -}; - -exports.handler = handler; diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-handler.cjs b/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-handler.cjs deleted file mode 100644 index 437f98b03ee2..000000000000 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/templates/vercel-handler.cjs +++ /dev/null @@ -1,76 +0,0 @@ -const fs = require('node:fs/promises'); -const path = require('node:path'); -const { createProdServer } = require('@modern-js/prod-server'); - -p_genPluginImportsCode; - -if (!process.env.NODE_ENV) { - process.env.NODE_ENV = 'production'; -} - -let requestHandler = null; -let handlerCreationPromise = null; - -async function loadRoutes(routeFilepath) { - try { - await fs.access(routeFilepath); - const content = await fs.readFile(routeFilepath, 'utf-8'); - const routeSpec = JSON.parse(content); - return routeSpec.routes || []; - } catch (error) { - console.warn( - 'route.json not found or invalid, continuing with empty routes.', - ); - return []; - } -} - -async function initServer() { - const routeFilepath = path.join(__dirname, p_ROUTE_SPEC_FILE); - const routes = await loadRoutes(routeFilepath); - - const dynamicProdOptions = p_dynamicProdOptions; - - const prodServerOptions = { - pwd: __dirname, - routes, - disableCustomHook: true, - appContext: { - sharedDirectory: p_sharedDirectory, - apiDirectory: p_apiDirectory, - lambdaDirectory: p_lambdaDirectory, - }, - plugins: p_plugins, - serverConfigPath: p_serverDirectory, - ...dynamicProdOptions, - }; - const app = await createProdServer(prodServerOptions); - - return app.getRequestListener(); -} - -async function createHandler() { - if (!handlerCreationPromise) { - handlerCreationPromise = (async () => { - try { - requestHandler = await initServer(); - } catch (error) { - console.error('Error creating server:', error); - process.exit(1); - } - })(); - } - await handlerCreationPromise; - return requestHandler; -} - -createHandler(); - -const handler = async (req, res) => { - if (!requestHandler) { - await createHandler(); - } - return requestHandler(req, res); -}; - -module.exports = handler; From d3d0d1e75577383fb3ab085683f0f0f8e085820f Mon Sep 17 00:00:00 2001 From: ShuangYa Date: Tue, 17 Mar 2026 19:09:06 +0800 Subject: [PATCH 27/27] fix: bundle --- .../src/plugins/deploy/platforms/node.ts | 10 ------ .../plugins/deploy/server-bundle/builder.ts | 31 ++++++------------- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts index 2d01b158e243..f5ef73a35fda 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/platforms/node.ts @@ -83,16 +83,6 @@ export const createNodePreset: CreatePreset = ({ }, }, }); - console.log( - 'Static directory:', - chalk.blue( - path.relative(appDirectory, staticDirectory).replace(/\\/g, '/'), - ), - ); - console.log( - `You can preview this build by`, - chalk.blue('node .output/index'), - ); }, async end() { if (!isBundleServer) { diff --git a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts index cb7f009a89d8..9a08694c51bd 100644 --- a/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts +++ b/packages/solutions/app-tools/src/plugins/deploy/server-bundle/builder.ts @@ -52,7 +52,7 @@ export const bundleServer = async ( ? Object.fromEntries( generateNodeExternals( api => `module-import node:${api}`, - NODE_BUILTIN_MODULES, + options.nodeExternal, ), ) : undefined; @@ -116,13 +116,11 @@ export const bundleServer = async ( chunkFormat: 'module', asyncChunks: false, pathinfo: !minify, + module: true, library: { type: 'module', }, }, - // experiments: { - // outputModule: true, - // }, node: { __dirname: 'mock', __filename: 'mock', @@ -156,26 +154,17 @@ export const bundleServer = async ( // remove bff server external const { output } = config; if (Array.isArray(output?.externals)) { - output!.externals = output!.externals.filter( - x => typeof x !== 'object' || !('@modern-js/plugin-bff/server' in x), - ); + output!.externals = output!.externals.map(x => { + if (typeof x === 'object' && '@modern-js/server-runtime' in x) { + const res = { ...x }; + delete res['@modern-js/server-runtime']; + return res; + } + return x; + }); } }); - // output stats to debug tree shaking - // builder.onAfterBuild(async ({ stats }) => { - // await fse.writeFile( - // path.join(finalConfig.output.distPath!.root!, 'stats.json'), - // JSON.stringify( - // stats?.toJson({ - // preset: 'verbose', - // }), - // null, - // 2, - // ), - // ); - // }); - if (options?.modifyBuilder) { await options.modifyBuilder(builder); }