diff --git a/.changeset/fluffy-mayflies-battle.md b/.changeset/fluffy-mayflies-battle.md new file mode 100644 index 000000000000..95ece4fb2031 --- /dev/null +++ b/.changeset/fluffy-mayflies-battle.md @@ -0,0 +1,7 @@ +--- +'@modern-js/app-tools': patch +--- + +feat: migrate app tools to use new cli plugin + +feat: app tools 使用新的 cli 插件 diff --git a/packages/solutions/app-tools/bin/modern.js b/packages/solutions/app-tools/bin/modern.js index edae29b7a74a..ffe115229d5d 100755 --- a/packages/solutions/app-tools/bin/modern.js +++ b/packages/solutions/app-tools/bin/modern.js @@ -10,7 +10,7 @@ if (!process.env.MODERN_JS_VERSION) { process.env.MODERN_JS_VERSION = version; } -require('../dist/cjs/new/run.js').run({ +require('../dist/cjs/run/index.js').run({ internalPlugins: { cli: INTERNAL_APP_TOOLS_PLUGINS, autoLoad: INTERNAL_APP_TOOLS_RUNTIME_PLUGINS, diff --git a/packages/solutions/app-tools/package.json b/packages/solutions/app-tools/package.json index 092ceb295f97..ad349fb1c3f6 100644 --- a/packages/solutions/app-tools/package.json +++ b/packages/solutions/app-tools/package.json @@ -35,9 +35,9 @@ "default": "./dist/cjs/index.js" }, "./cli/run": { - "types": "./dist/types/new/run.d.ts", - "jsnext:source": "./src/new/run.ts", - "default": "./dist/cjs/new/run.js" + "types": "./dist/types/run/index.d.ts", + "jsnext:source": "./src/run/index.ts", + "default": "./dist/cjs/run/index.js" }, "./types": { "types": "./lib/types.d.ts", @@ -64,7 +64,7 @@ "./dist/types/index.d.ts" ], "cli/run": [ - "./dist/types/new/run.d.ts" + "./dist/types/run/index.d.ts" ], "types": [ "./lib/types.d.ts" diff --git a/packages/solutions/app-tools/src/commands/build.ts b/packages/solutions/app-tools/src/commands/build.ts index 541475c2ba1f..ddc8e12b08cf 100644 --- a/packages/solutions/app-tools/src/commands/build.ts +++ b/packages/solutions/app-tools/src/commands/build.ts @@ -1,4 +1,4 @@ -import { type PluginAPI, ResolvedConfigContext } from '@modern-js/core'; +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; import { logger } from '@modern-js/utils'; import type { AppTools } from '../types'; import { buildServerConfig } from '../utils/config'; @@ -8,7 +8,7 @@ import { generateRoutes } from '../utils/routes'; import type { BuildOptions } from '../utils/types'; export const build = async ( - api: PluginAPI>, + api: CLIPluginAPI>, options?: BuildOptions, ) => { if (options?.analyze) { @@ -16,9 +16,9 @@ export const build = async ( process.env.BUNDLE_ANALYZE = 'true'; } - let resolvedConfig = api.useResolvedConfigContext(); - const appContext = api.useAppContext(); - const hookRunners = api.useHookRunners(); + const resolvedConfig = api.getNormalizedConfig(); + const appContext = api.getAppContext(); + const hooks = api.getHooks(); // we need load server plugin to appContext for ssg & deploy commands. await loadServerPlugins(api, appContext.appDirectory, appContext.metaName); @@ -42,9 +42,12 @@ export const build = async ( if (apiOnly) { const { appDirectory, distDirectory, serverConfigFile } = appContext; - await hookRunners.beforeBuild({ + await hooks.onBeforeBuild.call({ + environments: {}, // "null" bundlerConfigs bundlerConfigs: undefined, + isFirstCompile: false, + isWatch: false, }); await buildServerConfig({ @@ -55,16 +58,20 @@ export const build = async ( await generateRoutes(appContext); - await hookRunners.afterBuild({ + await hooks.onAfterBuild.call({ + environments: {}, // "null" stats stats: undefined, + isFirstCompile: false, + isWatch: false, }); return; } - resolvedConfig = { ...resolvedConfig, cliOptions: options }; - ResolvedConfigContext.set(resolvedConfig); + api.modifyResolvedConfig(config => { + return { ...config, cliOptions: options }; + }); const { distDirectory, appDirectory, serverConfigFile } = appContext; diff --git a/packages/solutions/app-tools/src/commands/deploy.ts b/packages/solutions/app-tools/src/commands/deploy.ts index afe786f1a1cc..7fa6279337d5 100644 --- a/packages/solutions/app-tools/src/commands/deploy.ts +++ b/packages/solutions/app-tools/src/commands/deploy.ts @@ -1,19 +1,19 @@ -import type { PluginAPI } from '@modern-js/core'; +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; import type { AppTools } from '../types'; import { getServerPlugins } from '../utils/loadPlugins'; export const deploy = async ( - api: PluginAPI>, + api: CLIPluginAPI>, options: any, ) => { - const hookRunners = api.useHookRunners(); + const hooks = api.getHooks(); - const { metaName } = api.useAppContext(); + const { metaName } = api.getAppContext(); // deploy command need get all plugins await getServerPlugins(api, metaName); - await hookRunners.beforeDeploy(options); - await hookRunners.deploy(options); - await hookRunners.afterDeploy(options); + await hooks.onBeforeDeploy.call(options); + await hooks.deploy.call(); + await hooks.onAfterDeploy.call(options); }; diff --git a/packages/solutions/app-tools/src/commands/dev.ts b/packages/solutions/app-tools/src/commands/dev.ts index cb86bfa486c1..439f842655a1 100644 --- a/packages/solutions/app-tools/src/commands/dev.ts +++ b/packages/solutions/app-tools/src/commands/dev.ts @@ -1,5 +1,5 @@ import path from 'node:path'; -import { type PluginAPI, ResolvedConfigContext } from '@modern-js/core'; +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; import { applyPlugins } from '@modern-js/prod-server'; import { type ApplyPlugins, createDevServer } from '@modern-js/server'; import { @@ -8,11 +8,11 @@ import { getMeta, logger, } from '@modern-js/utils'; -import type { AppTools } from '../types'; +import type { AppNormalizedConfig, AppTools } from '../types'; import { buildServerConfig } from '../utils/config'; import { setServer } from '../utils/createServer'; import { loadServerPlugins } from '../utils/loadPlugins'; -import { printInstructionsCompat } from '../utils/printInstructions'; +import { printInstructions } from '../utils/printInstructions'; import { registerCompiler } from '../utils/register'; import { generateRoutes } from '../utils/routes'; import type { DevOptions } from '../utils/types'; @@ -22,7 +22,7 @@ export interface ExtraServerOptions { } export const dev = async ( - api: PluginAPI>, + api: CLIPluginAPI>, options: DevOptions, devServerOptions?: ExtraServerOptions, ) => { @@ -30,9 +30,9 @@ export const dev = async ( // Builder will read this env var to enable bundle analyzer process.env.BUNDLE_ANALYZE = 'true'; } - let normalizedConfig = api.useResolvedConfigContext(); - const appContext = api.useAppContext(); - const hookRunners = api.useHookRunners(); + const normalizedConfig = api.getNormalizedConfig(); + const appContext = api.getAppContext(); + const hooks = api.getHooks(); if (appContext.moduleType && appContext.moduleType === 'module') { const { registerEsm } = await import('../esm/register-esm.mjs'); @@ -49,8 +49,9 @@ export const dev = async ( normalizedConfig?.source?.alias, ); - normalizedConfig = { ...normalizedConfig, cliOptions: options }; - ResolvedConfigContext.set(normalizedConfig); + api.modifyResolvedConfig(config => { + return { ...config, cliOptions: options }; + }); const { appDirectory, @@ -76,7 +77,7 @@ export const dev = async ( `${meta}.server`, ); - await hookRunners.beforeDev(); + await hooks.onBeforeDev.call(); if (!appContext.builder && !apiOnly) { throw new Error( @@ -129,7 +130,11 @@ export const dev = async ( host, }, () => { - printInstructionsCompat(hookRunners, appContext, normalizedConfig); + printInstructions( + hooks, + appContext, + normalizedConfig as AppNormalizedConfig<'shared'>, + ); }, ); } else { diff --git a/packages/solutions/app-tools/src/commands/index.ts b/packages/solutions/app-tools/src/commands/index.ts index 73424df54229..9d5d9e9d445f 100644 --- a/packages/solutions/app-tools/src/commands/index.ts +++ b/packages/solutions/app-tools/src/commands/index.ts @@ -1,4 +1,4 @@ -import type { PluginAPI } from '@modern-js/core'; +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; import { castArray } from '@modern-js/uni-builder'; import { type Command, newAction, upgradeAction } from '@modern-js/utils'; import { i18n, localeKeys } from '../locale'; @@ -12,10 +12,10 @@ import type { export const devCommand = async ( program: Command, - api: PluginAPI>, + api: CLIPluginAPI>, ) => { - const runner = api.useHookRunners(); - const devToolMetas = await runner.registerDev(); + const hooks = api.getHooks(); + const devToolMetas = await hooks.registerDev.call(); const devProgram = program .command('dev') @@ -39,7 +39,7 @@ export const devCommand = async ( for (const subCmd of meta.subCommands) { devProgram.command(subCmd).action(async (options: DevOptions = {}) => { - const { appDirectory } = api.useAppContext(); + const { appDirectory } = api.getAppContext(); const { isTypescript } = await import('@modern-js/utils'); await meta.action(options, { @@ -52,10 +52,10 @@ export const devCommand = async ( export const buildCommand = async ( program: Command, - api: PluginAPI>, + api: CLIPluginAPI>, ) => { - const runner = api.useHookRunners(); - const platformBuilders = await runner.registerBuildPlatform(); + const hooks = api.getHooks(); + const platformBuilders = await hooks.registerBuildPlatform.call(); const buildProgram = program .command('build') @@ -72,7 +72,7 @@ export const buildCommand = async ( const platforms = castArray(platformBuilder.platform); for (const platform of platforms) { buildProgram.command(platform).action(async () => { - const { appDirectory } = api.useAppContext(); + const { appDirectory } = api.getAppContext(); const { isTypescript } = await import('@modern-js/utils'); await platformBuilder.build(platform, { @@ -85,7 +85,7 @@ export const buildCommand = async ( export const serverCommand = ( program: Command, - api: PluginAPI>, + api: CLIPluginAPI>, ) => { program .command('serve') @@ -101,7 +101,7 @@ export const serverCommand = ( export const deployCommand = ( program: Command, - api: PluginAPI>, + api: CLIPluginAPI>, ) => { program .command('deploy') @@ -152,7 +152,7 @@ export const newCommand = (program: Command, locale: string) => { export const inspectCommand = ( program: Command, - api: PluginAPI>, + api: CLIPluginAPI>, ) => { program .command('inspect') diff --git a/packages/solutions/app-tools/src/commands/inspect.ts b/packages/solutions/app-tools/src/commands/inspect.ts index 97483d874514..917c4474a046 100644 --- a/packages/solutions/app-tools/src/commands/inspect.ts +++ b/packages/solutions/app-tools/src/commands/inspect.ts @@ -1,13 +1,13 @@ -import type { PluginAPI } from '@modern-js/core'; +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; import type { RsbuildMode } from '@rsbuild/core'; import type { AppTools } from '../types'; import type { InspectOptions } from '../utils/types'; export const inspect = async ( - api: PluginAPI>, + api: CLIPluginAPI>, options: InspectOptions, ) => { - const appContext = api.useAppContext(); + const appContext = api.getAppContext(); if (!appContext.builder) { throw new Error( 'Expect the Builder to have been initialized, But the appContext.builder received `undefined`', diff --git a/packages/solutions/app-tools/src/commands/serve.ts b/packages/solutions/app-tools/src/commands/serve.ts index 787e74507b50..11431f278ccc 100644 --- a/packages/solutions/app-tools/src/commands/serve.ts +++ b/packages/solutions/app-tools/src/commands/serve.ts @@ -1,5 +1,5 @@ import path from 'path'; -import type { PluginAPI } from '@modern-js/core'; +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; import { createProdServer } from '@modern-js/prod-server'; import { SERVER_DIR, @@ -8,14 +8,14 @@ import { isApiOnly, logger, } from '@modern-js/utils'; -import type { AppTools } from '../types'; +import type { AppNormalizedConfig, AppTools } from '../types'; import { loadServerPlugins } from '../utils/loadPlugins'; -import { printInstructionsCompat } from '../utils/printInstructions'; +import { printInstructions } from '../utils/printInstructions'; -export const start = async (api: PluginAPI>) => { - const appContext = api.useAppContext(); - const userConfig = api.useResolvedConfigContext(); - const hookRunners = api.useHookRunners(); +export const start = async (api: CLIPluginAPI>) => { + const appContext = api.getAppContext(); + const userConfig = api.getNormalizedConfig(); + const hooks = api.getHooks(); const { distDirectory, @@ -87,6 +87,10 @@ export const start = async (api: PluginAPI>) => { }); app.listen(port, async () => { - await printInstructionsCompat(hookRunners, appContext, userConfig); + await printInstructions( + hooks, + appContext, + userConfig as AppNormalizedConfig<'shared'>, + ); }); }; diff --git a/packages/solutions/app-tools/src/new/compat/hooks.ts b/packages/solutions/app-tools/src/compat/hooks.ts similarity index 89% rename from packages/solutions/app-tools/src/new/compat/hooks.ts rename to packages/solutions/app-tools/src/compat/hooks.ts index 066f86a05be5..283ed49e0234 100644 --- a/packages/solutions/app-tools/src/new/compat/hooks.ts +++ b/packages/solutions/app-tools/src/compat/hooks.ts @@ -8,9 +8,9 @@ import type { ServerRoute, } from '@modern-js/types'; import type { Command } from '@modern-js/utils'; -import { getModifyHtmlPartials } from '../../plugins/analyze/getHtmlTemplate'; -import type { AppTools, AppToolsNormalizedConfig } from '../../types'; -import type { RuntimePlugin } from '../../types/hooks'; +import { getModifyHtmlPartials } from '../plugins/analyze/getHtmlTemplate'; +import type { AppTools, AppToolsNormalizedConfig } from '../types'; +import type { RuntimePlugin } from '../types/hooks'; import { transformHookParams, transformHookResult, @@ -21,7 +21,7 @@ import { * old plugin useHookRunners function result */ export function getHookRunners( - context: InternalContext, + context: InternalContext>, ): Record { const { hooks } = context; return { @@ -162,24 +162,14 @@ export function getHookRunners( /** * @deprecated */ - registerDev: async (params: { - name: string; - entry: string; - type: string; - config: any; - }) => { - return hooks.registerDev.call(params); + registerDev: async () => { + return hooks.registerDev.call(); }, /** * @deprecated */ - registerBuildPlatform: async (params: { - name: string; - entry: string; - type: string; - config: any; - }) => { - return hooks.registerBuildPlatform.call(params); + registerBuildPlatform: async () => { + return hooks.registerBuildPlatform.call(); }, /** * @deprecated diff --git a/packages/solutions/app-tools/src/new/compat/index.ts b/packages/solutions/app-tools/src/compat/index.ts similarity index 82% rename from packages/solutions/app-tools/src/new/compat/index.ts rename to packages/solutions/app-tools/src/compat/index.ts index b30a3aab0b87..3674d229e84f 100644 --- a/packages/solutions/app-tools/src/new/compat/index.ts +++ b/packages/solutions/app-tools/src/compat/index.ts @@ -1,6 +1,6 @@ import { createCollectAsyncHook } from '@modern-js/plugin-v2'; import type { Entrypoint } from '@modern-js/types'; -import type { AppTools, CliPluginFuture } from '../../types'; +import type { AppTools, CliPluginFuture } from '../types'; import { getHookRunners } from './hooks'; type AppendEntryCodeFn = (params: { @@ -8,7 +8,7 @@ type AppendEntryCodeFn = (params: { code: string; }) => string | Promise; -export const compatPlugin = (): CliPluginFuture => ({ +export const compatPlugin = (): CliPluginFuture> => ({ name: '@modern-js/app-tools-compat', _registryApi: (getAppContext, updateAppContext) => { const getInternalContext = () => { @@ -36,5 +36,9 @@ export const compatPlugin = (): CliPluginFuture => ({ registryHooks: { appendEntryCode: createCollectAsyncHook(), }, - setup: _api => {}, + setup: api => { + api.updateAppContext({ + toolsType: 'app-tools', + }); + }, }); diff --git a/packages/solutions/app-tools/src/new/compat/utils.ts b/packages/solutions/app-tools/src/compat/utils.ts similarity index 100% rename from packages/solutions/app-tools/src/new/compat/utils.ts rename to packages/solutions/app-tools/src/compat/utils.ts diff --git a/packages/solutions/app-tools/src/new/constants.ts b/packages/solutions/app-tools/src/constants.ts similarity index 100% rename from packages/solutions/app-tools/src/new/constants.ts rename to packages/solutions/app-tools/src/constants.ts diff --git a/packages/solutions/app-tools/src/hooks.ts b/packages/solutions/app-tools/src/hooks.ts deleted file mode 100644 index af8d6b5e942b..000000000000 --- a/packages/solutions/app-tools/src/hooks.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { DevToolData, RegisterBuildPlatformResult } from '@modern-js/core'; -import { - createAsyncWaterfall, - createAsyncWorkflow, - createParallelWorkflow, -} from '@modern-js/plugin'; -import type { AppToolsHooks } from './types/hooks'; - -export const hooks: AppToolsHooks = { - _internalRuntimePlugins: createAsyncWaterfall(), - modifyFileSystemRoutes: createAsyncWaterfall(), - modifyServerRoutes: createAsyncWaterfall(), - /** add entry point info to entrypoints array */ - modifyEntrypoints: createAsyncWaterfall(), - /** add entry type */ - checkEntryPoint: createAsyncWaterfall(), - generateEntryCode: createAsyncWorkflow(), - htmlPartials: createAsyncWaterfall(), - beforeGenerateRoutes: createAsyncWaterfall(), - _internalServerPlugins: createAsyncWaterfall(), - beforeDev: createAsyncWorkflow(), - afterDev: createAsyncWorkflow(), - beforeCreateCompiler: createAsyncWorkflow(), - afterCreateCompiler: createAsyncWorkflow(), - beforePrintInstructions: createAsyncWaterfall(), - beforeBuild: createAsyncWorkflow(), - afterBuild: createAsyncWorkflow(), - beforeDeploy: createAsyncWorkflow(), - deploy: createAsyncWorkflow(), - afterDeploy: createAsyncWorkflow(), - - beforeRestart: createAsyncWorkflow(), - - /** - * @deprecated - */ - registerDev: createParallelWorkflow(), - /** - * @deprecated - */ - registerBuildPlatform: createParallelWorkflow< - void, - RegisterBuildPlatformResult - >(), -}; diff --git a/packages/solutions/app-tools/src/index.ts b/packages/solutions/app-tools/src/index.ts index 421f8daa0dd8..5be38e12bd05 100644 --- a/packages/solutions/app-tools/src/index.ts +++ b/packages/solutions/app-tools/src/index.ts @@ -1,9 +1,195 @@ -import { appTools } from './new/index'; +import { getLocaleLanguage } from '@modern-js/plugin-i18n/language-detector'; +import { createAsyncHook, createCollectAsyncHook } from '@modern-js/plugin-v2'; +import { castArray } from '@modern-js/uni-builder'; +import { + cleanRequireCache, + deprecatedCommands, + emptyDir, + getArgv, + getCommand, +} from '@modern-js/utils'; +import { + buildCommand, + deployCommand, + devCommand, + inspectCommand, + newCommand, + serverCommand, + upgradeCommand, +} from './commands'; +import { compatPlugin } from './compat'; +import { + DEFAULT_RUNTIME_CONFIG_FILE, + DEFAULT_SERVER_CONFIG_FILE, +} from './constants'; +import { i18n } from './locale'; +import analyzePlugin from './plugins/analyze'; +import deployPlugin from './plugins/deploy'; +import initializePlugin from './plugins/initialize'; +import serverBuildPlugin from './plugins/serverBuild'; +import type { AppTools, AppToolsOptions, CliPluginFuture } from './types'; +import type { + AddRuntimeExportsFn, + AfterPrepareFn, + BeforeConfigFn, + BeforeGenerateRoutesFn, + BeforePrintInstructionsFn, + CheckEntryPointFn, + DeplpoyFn, + GenerateEntryCodeFn, + InternalRuntimePluginsFn, + InternalServerPluginsFn, + ModifyEntrypointsFn, + ModifyFileSystemRoutesFn, + ModifyServerRoutesFn, + RegisterBuildPlatformFn, + RegisterDevFn, +} from './types/new'; +import { generateWatchFiles } from './utils/generateWatchFiles'; +import { initAppContext } from './utils/initAppContext'; +import { restart } from './utils/restart'; -export { appTools }; +export * from './defineConfig'; -// new app tools plugin -export { initAppContext } from './new/index'; +export const appTools = ( + options: AppToolsOptions = { + // default webpack to be compatible with original projects + bundler: 'webpack', + }, +): CliPluginFuture> => ({ + name: '@modern-js/app-tools', + usePlugins: [ + compatPlugin(), + initializePlugin({ + bundler: + options?.bundler && + ['rspack', 'experimental-rspack'].includes(options.bundler) + ? 'rspack' + : 'webpack', + }), + analyzePlugin({ + bundler: + options?.bundler && + ['rspack', 'experimental-rspack'].includes(options.bundler) + ? 'rspack' + : 'webpack', + }), + serverBuildPlugin(), + deployPlugin(), + ], + post: [ + '@modern-js/plugin-initialize', + '@modern-js/plugin-analyze', + '@modern-js/plugin-ssr', + '@modern-js/plugin-document', + '@modern-js/plugin-state', + '@modern-js/plugin-router', + '@modern-js/plugin-router-v5', + '@modern-js/plugin-polyfill', + ], + registryHooks: { + onBeforeConfig: createAsyncHook(), + onAfterPrepare: createAsyncHook(), + deploy: createAsyncHook(), + _internalRuntimePlugins: createAsyncHook(), + _internalServerPlugins: createAsyncHook(), + checkEntryPoint: createAsyncHook(), + modifyEntrypoints: createAsyncHook(), + modifyFileSystemRoutes: createAsyncHook(), + modifyServerRoutes: createAsyncHook(), + generateEntryCode: createAsyncHook(), + onBeforeGenerateRoutes: createAsyncHook(), + onBeforePrintInstructions: createAsyncHook(), + registerDev: createCollectAsyncHook(), + registerBuildPlatform: createCollectAsyncHook(), + addRuntimeExports: createAsyncHook(), + }, + setup: api => { + const context = api.getAppContext(); + const userConfig = api.getConfig(); + const locale = getLocaleLanguage(); + i18n.changeLanguage({ locale }); + api.updateAppContext( + initAppContext({ + appDirectory: context.appDirectory, + options: {}, + serverConfigFile: DEFAULT_SERVER_CONFIG_FILE, + runtimeConfigFile: DEFAULT_RUNTIME_CONFIG_FILE, + tempDir: userConfig.output?.tempDir, + }), + ); + + api.addCommand(async ({ program }) => { + await devCommand(program, api); + await buildCommand(program, api); + serverCommand(program, api); + deployCommand(program, api); + newCommand(program, locale); + inspectCommand(program, api); + upgradeCommand(program); + deprecatedCommands(program); + }); + + api.onPrepare(async () => { + const command = getCommand(); + if (command === 'deploy') { + const isSkipBuild = ['-s', '--skip-build'].some(tag => { + return getArgv().includes(tag); + }); + // if skip build, do not clean dist path + if (isSkipBuild) { + return; + } + } + + // clean dist path before building + if ( + command === 'dev' || + command === 'start' || + command === 'build' || + command === 'deploy' + ) { + const resolvedConfig = api.getNormalizedConfig(); + if (resolvedConfig.output.cleanDistPath) { + const appContext = api.getAppContext(); + await emptyDir(appContext.distDirectory); + } + } + }); + + api.addWatchFiles(async () => { + const appContext = api.getAppContext(); + const config = api.getNormalizedConfig(); + const files = await generateWatchFiles( + appContext, + config.source.configDir, + ); + + const watchFiles = castArray(config.dev.watchFiles); + watchFiles.forEach(({ type, paths }) => { + if (type === 'reload-server') { + files.push(...(Array.isArray(paths) ? paths : [paths])); + } + }); + + return files; + }); + + api.onFileChanged(async e => { + const { filename, eventType, isPrivate } = e; + + if (!isPrivate && (eventType === 'change' || eventType === 'unlink')) { + const { closeServer } = await import('./utils/createServer.js'); + await closeServer(); + await restart(api.getHooks(), filename); + } + }); + + api.onBeforeRestart(() => { + cleanRequireCache([require.resolve('./plugins/analyze')]); + }); + }, +}); export { defineConfig, defineLegacyConfig } from './defineConfig'; export { mergeConfig } from '@modern-js/core'; @@ -14,4 +200,6 @@ export type { DevOptions } from './utils/types'; export * from './types'; +export { initAppContext }; + export default appTools; diff --git a/packages/solutions/app-tools/src/new/index.ts b/packages/solutions/app-tools/src/new/index.ts deleted file mode 100644 index 2d041e315f63..000000000000 --- a/packages/solutions/app-tools/src/new/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { createAsyncHook } from '@modern-js/plugin-v2'; -import { type AppToolsOptions, appTools as oldAppTools } from '../old'; -import type { AppTools, CliPluginFuture } from '../types'; -import type { - AddRuntimeExportsFn, - AfterPrepareFn, - BeforeConfigFn, - BeforeGenerateRoutesFn, - BeforePrintInstructionsFn, - CheckEntryPointFn, - DeplpoyFn, - GenerateEntryCodeFn, - InternalRuntimePluginsFn, - InternalServerPluginsFn, - ModifyEntrypointsFn, - ModifyFileSystemRoutesFn, - ModifyServerRoutesFn, - RegisterBuildPlatformFn, - RegisterDevFn, -} from '../types/new'; -import { compatPlugin } from './compat'; -import { - DEFAULT_RUNTIME_CONFIG_FILE, - DEFAULT_SERVER_CONFIG_FILE, -} from './constants'; -import { initAppContext } from './context'; - -export * from '../defineConfig'; -export { initAppContext }; - -export const appTools = ( - options: AppToolsOptions = { - // default webpack to be compatible with original projects - bundler: 'webpack', - }, -): CliPluginFuture> => ({ - name: '@modern-js/app-tools', - usePlugins: [compatPlugin(), oldAppTools(options) as any], - post: ['@modern-js/app-tools-old'], - registryHooks: { - onBeforeConfig: createAsyncHook(), - onAfterPrepare: createAsyncHook(), - deploy: createAsyncHook(), - _internalRuntimePlugins: createAsyncHook(), - _internalServerPlugins: createAsyncHook(), - checkEntryPoint: createAsyncHook(), - modifyEntrypoints: createAsyncHook(), - modifyFileSystemRoutes: createAsyncHook(), - modifyServerRoutes: createAsyncHook(), - generateEntryCode: createAsyncHook(), - onBeforeGenerateRoutes: createAsyncHook(), - onBeforePrintInstructions: createAsyncHook(), - registerDev: createAsyncHook(), - registerBuildPlatform: createAsyncHook(), - addRuntimeExports: createAsyncHook(), - }, - setup: api => { - const context = api.getAppContext(); - const userConfig = api.getConfig(); - api.updateAppContext( - initAppContext({ - appDirectory: context.appDirectory, - options: {}, - serverConfigFile: DEFAULT_SERVER_CONFIG_FILE, - runtimeConfigFile: DEFAULT_RUNTIME_CONFIG_FILE, - tempDir: userConfig.output?.tempDir, - }), - ); - }, -}); diff --git a/packages/solutions/app-tools/src/new/loadPlugins.ts b/packages/solutions/app-tools/src/new/loadPlugins.ts deleted file mode 100644 index b08e2c231be3..000000000000 --- a/packages/solutions/app-tools/src/new/loadPlugins.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { Plugin } from '@modern-js/plugin-v2'; -import type { InternalPlugins } from '@modern-js/types'; -import { - compatibleRequire, - createDebugger, - dynamicImport, - getInternalPlugins, - tryResolve, -} from '@modern-js/utils'; -const debug = createDebugger('load-plugins'); - -const resolveCliPlugin = async ( - p: string, - appDirectory: string, -): Promise => { - const pkg = typeof p === 'string' ? p : p[0]; - const pluginOptions = typeof p === 'string' ? undefined : p[1]; - const path = tryResolve(pkg, appDirectory); - let module; - try { - module = await compatibleRequire(path); - } catch (e) { - // load esm module - ({ default: module } = await dynamicImport(path)); - } - - // handle string plugin - if (typeof module === 'function') { - const result: Plugin = module(pluginOptions); - return result; - } - - return module; -}; - -/** - * Load internal plugins which in @modern-js scope and user's custom plugins. - * @param appDirectory - Application root directory. - * @param internalPlugins - Internal plugins. - * @returns Plugin Objects has been required. - */ -export const loadInternalPlugins = async ( - appDirectory: string, - internalPlugins?: InternalPlugins, - autoLoad?: InternalPlugins, - autoLoadPlugins?: boolean, // user config auto load plugins -) => { - const plugins = [ - ...(autoLoadPlugins - ? getInternalPlugins(appDirectory, internalPlugins) - : []), - ...(autoLoad ? getInternalPlugins(appDirectory, autoLoad) : []), - ]; - - const loadedPlugins = await Promise.all( - plugins.map(plugin => { - const loadedPlugin = resolveCliPlugin(plugin, appDirectory); - - debug(`resolve plugin %s: %s`, plugin, loadedPlugin); - - return loadedPlugin; - }), - ); - - return loadedPlugins; -}; diff --git a/packages/solutions/app-tools/src/old.ts b/packages/solutions/app-tools/src/old.ts deleted file mode 100644 index d426386db21d..000000000000 --- a/packages/solutions/app-tools/src/old.ts +++ /dev/null @@ -1,186 +0,0 @@ -import path from 'path'; -import type { CliPlugin } from '@modern-js/core'; -import { getLocaleLanguage } from '@modern-js/plugin-i18n/language-detector'; -import { castArray } from '@modern-js/uni-builder'; -import { - cleanRequireCache, - deprecatedCommands, - emptyDir, - getArgv, - getCommand, -} from '@modern-js/utils'; -import { hooks } from './hooks'; -import { i18n } from './locale'; -import analyzePlugin from './plugins/analyze'; -import deployPlugin from './plugins/deploy'; -import initializePlugin from './plugins/initialize'; -import serverBuildPlugin from './plugins/serverBuild'; -import type { AppTools, AppToolsOptions } from './types'; - -import { - buildCommand, - deployCommand, - devCommand, - inspectCommand, - newCommand, - serverCommand, - upgradeCommand, -} from './commands'; -import { generateWatchFiles } from './utils/generateWatchFiles'; -import { restart } from './utils/restart'; - -export { dev } from './commands/dev'; -export type { DevOptions } from './utils/types'; - -export { mergeConfig } from '@modern-js/core'; -export * from './defineConfig'; -export * from './types'; - -export type { RuntimeUserConfig } from './types/config'; - -/** - * The core package of the framework, providing CLI commands, build capabilities, configuration parsing and more. - */ -export const appTools = ( - options: AppToolsOptions = { - // default webpack to be compatible with original projects - bundler: 'webpack', - }, -): CliPlugin> => ({ - name: '@modern-js/app-tools-old', - - post: [ - '@modern-js/plugin-initialize', - '@modern-js/plugin-analyze', - '@modern-js/plugin-ssr', - '@modern-js/plugin-document', - '@modern-js/plugin-state', - '@modern-js/plugin-router', - '@modern-js/plugin-router-v5', - '@modern-js/plugin-polyfill', - ], - - registerHook: hooks, - - usePlugins: [ - initializePlugin({ - bundler: - options?.bundler && - ['rspack', 'experimental-rspack'].includes(options.bundler) - ? 'rspack' - : 'webpack', - }), - analyzePlugin({ - bundler: - options?.bundler && - ['rspack', 'experimental-rspack'].includes(options.bundler) - ? 'rspack' - : 'webpack', - }), - serverBuildPlugin(), - deployPlugin(), - ], - - setup: api => { - const appContext = api.useAppContext(); - api.setAppContext({ - ...appContext, - toolsType: 'app-tools', - }); - - const locale = getLocaleLanguage(); - i18n.changeLanguage({ locale }); - - return { - async beforeConfig() { - const userConfig = api.useConfigContext(); - const appContext = api.useAppContext(); - if (userConfig.output?.tempDir) { - api.setAppContext({ - ...appContext, - internalDirectory: path.resolve( - appContext.appDirectory, - userConfig.output.tempDir, - ), - }); - } - }, - async commands({ program }) { - await devCommand(program, api); - await buildCommand(program, api); - serverCommand(program, api); - deployCommand(program, api); - newCommand(program, locale); - inspectCommand(program, api); - upgradeCommand(program); - deprecatedCommands(program); - }, - - async prepare() { - const command = getCommand(); - if (command === 'deploy') { - const isSkipBuild = ['-s', '--skip-build'].some(tag => { - return getArgv().includes(tag); - }); - // if skip build, do not clean dist path - if (isSkipBuild) { - return; - } - } - - // clean dist path before building - if ( - command === 'dev' || - command === 'start' || - command === 'build' || - command === 'deploy' - ) { - const resolvedConfig = api.useResolvedConfigContext(); - if (resolvedConfig.output.cleanDistPath) { - const appContext = api.useAppContext(); - await emptyDir(appContext.distDirectory); - } - } - }, - - async watchFiles() { - const appContext = api.useAppContext(); - const config = api.useResolvedConfigContext(); - const files = await generateWatchFiles( - appContext, - config.source.configDir, - ); - - const watchFiles = castArray(config.dev.watchFiles); - watchFiles.forEach(({ type, paths }) => { - if (type === 'reload-server') { - files.push(...(Array.isArray(paths) ? paths : [paths])); - } - }); - - return files; - }, - - // 这里会被 core/initWatcher 监听的文件变动触发,如果是 src 目录下的文件变动,则不做 restart - async fileChange(e: { - filename: string; - eventType: string; - isPrivate: boolean; - }) { - const { filename, eventType, isPrivate } = e; - - if (!isPrivate && (eventType === 'change' || eventType === 'unlink')) { - const { closeServer } = await import('./utils/createServer.js'); - await closeServer(); - await restart(api.useHookRunners(), filename); - } - }, - - async beforeRestart() { - cleanRequireCache([require.resolve('./plugins/analyze')]); - }, - }; - }, -}); - -export default appTools; diff --git a/packages/solutions/app-tools/src/plugins/serverBuild.ts b/packages/solutions/app-tools/src/plugins/serverBuild.ts index a03d492bff24..57422f38c9db 100644 --- a/packages/solutions/app-tools/src/plugins/serverBuild.ts +++ b/packages/solutions/app-tools/src/plugins/serverBuild.ts @@ -2,7 +2,7 @@ import fs from 'fs'; import path from 'path'; import { compile } from '@modern-js/server-utils'; import { SERVER_DIR, SHARED_DIR, getMeta } from '@modern-js/utils'; -import type { AppTools, CliPlugin } from '../types'; +import type { AppTools, CliPluginFuture } from '../types'; const TS_CONFIG_FILENAME = 'tsconfig.json'; @@ -22,56 +22,54 @@ function checkHasConfig(appDir: string, metaName = 'modern-js') { return fs.existsSync(tsFilepath) || fs.existsSync(jsfilepath); } -export default (): CliPlugin => ({ +export default (): CliPluginFuture> => ({ name: '@modern-js/server-build', setup(api) { - return { - async afterBuild() { - const { appDirectory, distDirectory, metaName } = api.useAppContext(); - if ( - !checkHasCache(appDirectory) && - !checkHasConfig(appDirectory, metaName) - ) { - return; - } - const modernConfig = api.useResolvedConfigContext(); + api.onAfterBuild(async () => { + const { appDirectory, distDirectory, metaName } = api.getAppContext(); + if ( + !checkHasCache(appDirectory) && + !checkHasConfig(appDirectory, metaName) + ) { + return; + } + const modernConfig = api.getNormalizedConfig(); - const distDir = path.resolve(distDirectory); - const serverDir = path.resolve(appDirectory, SERVER_DIR); - const sharedDir = path.resolve(appDirectory, SHARED_DIR); - const tsconfigPath = path.resolve(appDirectory, TS_CONFIG_FILENAME); + const distDir = path.resolve(distDirectory); + const serverDir = path.resolve(appDirectory, SERVER_DIR); + const sharedDir = path.resolve(appDirectory, SHARED_DIR); + const tsconfigPath = path.resolve(appDirectory, TS_CONFIG_FILENAME); - const sourceDirs = []; - if (fs.existsSync(serverDir)) { - sourceDirs.push(serverDir); + const sourceDirs = []; + if (fs.existsSync(serverDir)) { + sourceDirs.push(serverDir); - // compile the sharedDir only when serverDir exists - if (fs.existsSync(sharedDir)) { - sourceDirs.push(sharedDir); - } + // compile the sharedDir only when serverDir exists + if (fs.existsSync(sharedDir)) { + sourceDirs.push(sharedDir); } + } - const { server } = modernConfig; - const { alias } = modernConfig.source; - const { babel } = modernConfig.tools; + const { server } = modernConfig; + const { alias } = modernConfig.source; + const { babel } = modernConfig.tools; - if (sourceDirs.length > 0) { - await compile( - appDirectory, - { - server, - alias, - babelConfig: babel, - }, - { - sourceDirs, - distDir, - tsconfigPath, - }, - ); - } - }, - }; + if (sourceDirs.length > 0) { + await compile( + appDirectory, + { + server, + alias, + babelConfig: babel, + }, + { + sourceDirs, + distDir, + tsconfigPath, + }, + ); + } + }); }, }); diff --git a/packages/solutions/app-tools/src/new/run.ts b/packages/solutions/app-tools/src/run/index.ts similarity index 84% rename from packages/solutions/app-tools/src/new/run.ts rename to packages/solutions/app-tools/src/run/index.ts index cbee6c4ec4f5..beb3e7ffb06b 100644 --- a/packages/solutions/app-tools/src/new/run.ts +++ b/packages/solutions/app-tools/src/run/index.ts @@ -2,11 +2,11 @@ import { initAppDir } from '@modern-js/plugin-v2/cli'; import { run as CLIPluginRun } from '@modern-js/plugin-v2/run'; import type { InternalPlugins } from '@modern-js/types'; import { minimist } from '@modern-js/utils'; -import { handleSetupResult } from './compat/hooks'; -import { PACKAGE_JSON_CONFIG_NAME } from './constants'; -import { getConfigFile } from './getConfigFile'; -import { loadInternalPlugins } from './loadPlugins'; -import { getIsAutoLoadPlugins } from './utils'; +import { handleSetupResult } from '../compat/hooks'; +import { PACKAGE_JSON_CONFIG_NAME } from '../constants'; +import { getConfigFile } from '../utils/getConfigFile'; +import { isAutoLoadPlugins } from '../utils/isAutoLoadPlugins'; +import { loadInternalPlugins } from '../utils/loadPlugins'; export interface RunOptions { cwd?: string; @@ -59,7 +59,7 @@ export async function run({ const appDirectory = await initAppDir(cwd); const finalConfigFile = customConfigFile || getConfigFile(configFile); - const autoLoadPlugins = await getIsAutoLoadPlugins( + const autoLoadPlugins = await isAutoLoadPlugins( appDirectory, finalConfigFile, ); diff --git a/packages/solutions/app-tools/src/types/index.ts b/packages/solutions/app-tools/src/types/index.ts index 13e9cb19b73d..16a09ba113a8 100644 --- a/packages/solutions/app-tools/src/types/index.ts +++ b/packages/solutions/app-tools/src/types/index.ts @@ -13,6 +13,7 @@ import type { } from './new'; import type { Bundler } from './utils'; +export type { CLIPluginExtends }; export * from './hooks'; export * from './config'; export * from './legacyConfig'; @@ -84,3 +85,11 @@ export type AppToolsOptions = { * */ bundler?: 'rspack' | 'webpack' | 'experimental-rspack'; }; + +export type { + AppToolsExtendAPI, + AppToolsExtendContext, + AppToolsExtendHooks, + AppToolsContext, + AppToolsHooks as AppToolsFeatureHooks, +} from './new'; diff --git a/packages/solutions/app-tools/src/types/new.ts b/packages/solutions/app-tools/src/types/new.ts index 8499f296e2cd..27f7ddea21ee 100644 --- a/packages/solutions/app-tools/src/types/new.ts +++ b/packages/solutions/app-tools/src/types/new.ts @@ -2,6 +2,7 @@ import type { DevToolData, RegisterBuildPlatformResult } from '@modern-js/core'; import type { AppContext, AsyncHook, + CollectAsyncHook, InternalContext, PluginHook, PluginHookTap, @@ -19,7 +20,7 @@ import type { ServerRoute, } from '@modern-js/types'; import type { AppTools } from '.'; -import type { getHookRunners } from '../new/compat/hooks'; +import type { getHookRunners } from '../compat/hooks'; import type { AppToolsNormalizedConfig, AppToolsUserConfig } from './config'; import type { RuntimePlugin } from './hooks'; import type { Bundler } from './utils'; @@ -56,18 +57,10 @@ export type BeforeGenerateRoutesFn = TransformFunction<{ export type BeforePrintInstructionsFn = TransformFunction<{ instructions: string; }>; -export type RegisterDevFn = (params: { - name: string; - entry: string; - type: string; - config: any; -}) => Promise | DevToolData; -export type RegisterBuildPlatformFn = (params: { - name: string; - entry: string; - type: string; - config: any; -}) => Promise | RegisterBuildPlatformResult; +export type RegisterDevFn = () => Promise | DevToolData; +export type RegisterBuildPlatformFn = () => + | Promise + | RegisterBuildPlatformResult; export type AddRuntimeExportsFn = () => Promise | void; export interface AppToolsExtendAPI { @@ -141,11 +134,11 @@ export interface AppToolsExtendHooks /** * @deprecated */ - registerDev: AsyncHook; + registerDev: CollectAsyncHook; /** * @deprecated */ - registerBuildPlatform: AsyncHook; + registerBuildPlatform: CollectAsyncHook; /** * @deprecated */ @@ -160,6 +153,7 @@ export type AppToolsExtendContext = { internalSrcAlias: string; apiDirectory: string; lambdaDirectory: string; + serverConfigFile: string; serverPlugins: ServerPlugin[]; moduleType: 'module' | 'commonjs'; /** Information for entry points */ @@ -181,6 +175,10 @@ export type AppToolsExtendContext = { * @private */ htmlTemplates: HtmlTemplates; + /** + * @deprecated compat old plugin, default is app tools + */ + toolsType?: string; }; export type AppToolsContext = AppContext< diff --git a/packages/solutions/app-tools/src/utils/generateWatchFiles.ts b/packages/solutions/app-tools/src/utils/generateWatchFiles.ts index 4531698e46b9..4474b394ee7c 100644 --- a/packages/solutions/app-tools/src/utils/generateWatchFiles.ts +++ b/packages/solutions/app-tools/src/utils/generateWatchFiles.ts @@ -1,6 +1,6 @@ import path from 'path'; import { fs, getServerConfig } from '@modern-js/utils'; -import type { IAppContext } from '../types'; +import type { AppToolsContext } from '../types/new'; /** * Get user config from package.json. @@ -32,7 +32,7 @@ export const addServerConfigToDeps = async ( }; export async function generateWatchFiles( - appContext: IAppContext, + appContext: AppToolsContext<'shared'>, configDir?: string, ): Promise { const { appDirectory, configFile } = appContext; diff --git a/packages/solutions/app-tools/src/new/getConfigFile.ts b/packages/solutions/app-tools/src/utils/getConfigFile.ts similarity index 86% rename from packages/solutions/app-tools/src/new/getConfigFile.ts rename to packages/solutions/app-tools/src/utils/getConfigFile.ts index 2a7819d09cd7..fd6ee1ec0e84 100644 --- a/packages/solutions/app-tools/src/new/getConfigFile.ts +++ b/packages/solutions/app-tools/src/utils/getConfigFile.ts @@ -1,6 +1,6 @@ import path from 'path'; import { CONFIG_FILE_EXTENSIONS, findExists } from '@modern-js/utils'; -import { DEFAULT_CONFIG_FILE } from './constants'; +import { DEFAULT_CONFIG_FILE } from '../constants'; export const getConfigFile = (configFile?: string) => findExists( diff --git a/packages/solutions/app-tools/src/new/context.ts b/packages/solutions/app-tools/src/utils/initAppContext.ts similarity index 100% rename from packages/solutions/app-tools/src/new/context.ts rename to packages/solutions/app-tools/src/utils/initAppContext.ts diff --git a/packages/solutions/app-tools/src/new/utils/index.ts b/packages/solutions/app-tools/src/utils/isAutoLoadPlugins.ts similarity index 89% rename from packages/solutions/app-tools/src/new/utils/index.ts rename to packages/solutions/app-tools/src/utils/isAutoLoadPlugins.ts index 44fa7f8f6ff4..096130311440 100644 --- a/packages/solutions/app-tools/src/new/utils/index.ts +++ b/packages/solutions/app-tools/src/utils/isAutoLoadPlugins.ts @@ -1,5 +1,5 @@ import { createLoadedConfig } from '@modern-js/plugin-v2/cli'; -export async function getIsAutoLoadPlugins( +export async function isAutoLoadPlugins( appDirectory: string, configFile = 'modern.config.ts', packageJsonConfig = 'ModernConfig', diff --git a/packages/solutions/app-tools/src/utils/loadPlugins.ts b/packages/solutions/app-tools/src/utils/loadPlugins.ts index a812749de1a3..ba62f3475c8b 100644 --- a/packages/solutions/app-tools/src/utils/loadPlugins.ts +++ b/packages/solutions/app-tools/src/utils/loadPlugins.ts @@ -1,22 +1,32 @@ +import type { CLIPluginAPI } from '@modern-js/plugin-v2'; +import type { Plugin } from '@modern-js/plugin-v2'; import { loadServerPlugins as loadServerPluginInstances } from '@modern-js/prod-server'; import type { ServerPlugin as ServerPluginInstance } from '@modern-js/server-core'; import type { ServerPlugin } from '@modern-js/types'; -import type { AppTools, PluginAPI } from '../types'; +import type { InternalPlugins } from '@modern-js/types'; +import { + compatibleRequire, + createDebugger, + dynamicImport, + getInternalPlugins, + tryResolve, +} from '@modern-js/utils'; +import type { AppTools } from '../types'; +const debug = createDebugger('load-plugins'); export async function getServerPlugins( - api: PluginAPI>, + api: CLIPluginAPI>, metaName = 'modern-js', ): Promise { - const runner = api.useHookRunners(); - const { plugins } = await runner._internalServerPlugins({ plugins: [] }); + const hooks = api.getHooks(); + const { plugins } = await hooks._internalServerPlugins.call({ plugins: [] }); // filter plugins by metaName const filtedPlugins = plugins.filter(plugin => plugin.name.includes(metaName), ); - api.setAppContext({ - ...api.useAppContext(), + api.updateAppContext({ serverPlugins: filtedPlugins, }); @@ -24,7 +34,7 @@ export async function getServerPlugins( } export async function loadServerPlugins( - api: PluginAPI>, + api: CLIPluginAPI>, appDirectory: string, metaName: string, ): Promise { @@ -34,3 +44,59 @@ export async function loadServerPlugins( return instances; } + +const resolveCliPlugin = async ( + p: string, + appDirectory: string, +): Promise => { + const pkg = typeof p === 'string' ? p : p[0]; + const pluginOptions = typeof p === 'string' ? undefined : p[1]; + const path = tryResolve(pkg, appDirectory); + let module; + try { + module = await compatibleRequire(path); + } catch (e) { + // load esm module + ({ default: module } = await dynamicImport(path)); + } + + // handle string plugin + if (typeof module === 'function') { + const result: Plugin = module(pluginOptions); + return result; + } + + return module; +}; + +/** + * Load internal plugins which in @modern-js scope and user's custom plugins. + * @param appDirectory - Application root directory. + * @param internalPlugins - Internal plugins. + * @returns Plugin Objects has been required. + */ +export const loadInternalPlugins = async ( + appDirectory: string, + internalPlugins?: InternalPlugins, + autoLoad?: InternalPlugins, + autoLoadPlugins?: boolean, // user config auto load plugins +) => { + const plugins = [ + ...(autoLoadPlugins + ? getInternalPlugins(appDirectory, internalPlugins) + : []), + ...(autoLoad ? getInternalPlugins(appDirectory, autoLoad) : []), + ]; + + const loadedPlugins = await Promise.all( + plugins.map(plugin => { + const loadedPlugin = resolveCliPlugin(plugin, appDirectory); + + debug(`resolve plugin %s: %s`, plugin, loadedPlugin); + + return loadedPlugin; + }), + ); + + return loadedPlugins; +}; diff --git a/packages/solutions/app-tools/src/utils/printInstructions.ts b/packages/solutions/app-tools/src/utils/printInstructions.ts index d01e924575ea..bf3358231cd9 100644 --- a/packages/solutions/app-tools/src/utils/printInstructions.ts +++ b/packages/solutions/app-tools/src/utils/printInstructions.ts @@ -17,18 +17,3 @@ export const printInstructions = async ( logger.log(instructions); }; - -export const printInstructionsCompat = async ( - hookRunners: CliHooksRunner>, - appContext: IAppContext, - config: AppNormalizedConfig<'shared'>, -) => { - const message = prettyInstructions(appContext, config); - - // call beforePrintInstructions hook. - const { instructions } = await hookRunners.beforePrintInstructions({ - instructions: message, - }); - - logger.log(instructions); -}; diff --git a/packages/solutions/app-tools/src/utils/restart.ts b/packages/solutions/app-tools/src/utils/restart.ts index 747936e240ff..e3c3e5d66da6 100644 --- a/packages/solutions/app-tools/src/utils/restart.ts +++ b/packages/solutions/app-tools/src/utils/restart.ts @@ -1,11 +1,10 @@ -import type { ToRunners } from '@modern-js/core'; import { cli } from '@modern-js/plugin-v2/cli'; import { chalk, clearConsole, getFullArgv, logger } from '@modern-js/utils'; import { program } from '@modern-js/utils/commander'; -import type { AppToolsHooks } from '../types/hooks'; +import type { AppToolsHooks } from '../types/new'; export async function restart( - hooksRunner: ToRunners, + hooks: AppToolsHooks<'shared'>, filename: string, ) { clearConsole(); @@ -13,7 +12,7 @@ export async function restart( let hasGetError = false; - await hooksRunner.beforeRestart(); + await hooks.onBeforeRestart.call(); try { await cli.init(cli.getPrevInitOptions()); diff --git a/packages/solutions/app-tools/tests/analyze/getFileSystemEntry.test.ts b/packages/solutions/app-tools/tests/analyze/getFileSystemEntry.test.ts index 9fa7e10347f6..31fc8096a66f 100644 --- a/packages/solutions/app-tools/tests/analyze/getFileSystemEntry.test.ts +++ b/packages/solutions/app-tools/tests/analyze/getFileSystemEntry.test.ts @@ -3,7 +3,7 @@ import { type Plugin, createPluginManager } from '@modern-js/plugin-v2'; import { createContext, initPluginAPI } from '@modern-js/plugin-v2/cli'; import { runtimePlugin } from '../../../../runtime/plugin-runtime/src/cli'; import { appTools } from '../../src'; -import { handleSetupResult } from '../../src/new/compat/hooks'; +import { handleSetupResult } from '../../src/compat/hooks'; import { getFileSystemEntry } from '../../src/plugins/analyze/getFileSystemEntry'; import type { AppNormalizedConfig, AppTools } from '../../src/types'; import type { AppToolsContext } from '../../src/types/new'; diff --git a/packages/solutions/app-tools/tests/commands/build.test.ts b/packages/solutions/app-tools/tests/commands/build.test.ts index 7f882e4924dc..5bc5e108c6d1 100644 --- a/packages/solutions/app-tools/tests/commands/build.test.ts +++ b/packages/solutions/app-tools/tests/commands/build.test.ts @@ -1,4 +1,4 @@ -import { manager } from '@modern-js/core'; +import { type Plugin, createPluginManager } from '@modern-js/plugin-v2'; import { build } from '../../src/commands/build'; const mockGenerateRoutes = jest.fn(); @@ -14,35 +14,43 @@ describe('command build', () => { }); test('hooks should be invoke correctly', async () => { - const mockBeforeBuild = jest.fn(); - const mockAfterBuild = jest.fn(); - const mockInternalServerPlugins = jest.fn(() => ({ plugins: [] })); + const mockBeforeBuild = { call: jest.fn() }; + const mockAfterBuild = { call: jest.fn() }; + const mockInternalServerPlugins = { + call: jest.fn(() => ({ plugins: [] })), + }; const mockAPI = { - useAppContext: jest.fn((): any => ({ + getAppContext: jest.fn((): any => ({ apiOnly: true, distDirectory: '', appDirectory: '', })), - useResolvedConfigContext: jest.fn(), - - useHookRunners: (): any => ({ - afterBuild: mockAfterBuild, - beforeBuild: mockBeforeBuild, + getNormalizedConfig: jest.fn(), + getHooks: (): any => ({ + onAfterBuild: mockAfterBuild, + onBeforeBuild: mockBeforeBuild, _internalServerPlugins: mockInternalServerPlugins, }), + updateAppContext: jest.fn(), }; - const cloned = manager.clone(mockAPI); - cloned.usePlugin({ - async setup(api) { - await build(api as any); - expect(mockBeforeBuild).toBeCalled(); - expect(mockGenerateRoutes).toBeCalled(); - expect(mockAfterBuild).toBeCalled(); - expect(mockInternalServerPlugins).toBeCalled(); - }, - }); - await cloned.init(); + const pluginManager = createPluginManager(); + pluginManager.addPlugins([ + { + name: 'test', + async setup(api) { + await build(api as any); + expect(mockBeforeBuild.call).toBeCalled(); + expect(mockGenerateRoutes).toBeCalled(); + expect(mockAfterBuild.call).toBeCalled(); + expect(mockInternalServerPlugins.call).toBeCalled(); + }, + } as Plugin, + ]); + const plugins = await pluginManager.getPlugins(); + for (const plugin of plugins) { + await plugin.setup(mockAPI); + } }); });