Skip to content

Commit

Permalink
feat: registry hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
caohuilin committed Nov 11, 2024
1 parent 4e28f9f commit bfa95d7
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 104 deletions.
36 changes: 35 additions & 1 deletion packages/solutions/app-tools/src/v3/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import type { Plugin } from '@modern-js/plugin-v2';
import type { AppTools } from './types';
import { createAsyncHook } from '@modern-js/plugin-v2';
import type {
AppTools,
CheckEntryPointFn,
DeplpoyFn,
InternalRuntimePluginsFn,
InternalServerPluginsFn,
ModifyEntrypointsFn,
ModifyFileSystemRoutesFn,
ModifyServerRoutesFn,
} from './types';

export * from '../defineConfig';

Expand All @@ -11,15 +21,39 @@ export type AppToolsOptions = {
bundler?: 'rspack' | 'webpack' | 'experimental-rspack';
};

const testPlugin = (): Plugin<AppTools<'shared'>> => {
return {
name: 'test-plugin',
setup: api => {
api.checkEntryPoint(({ path, entry }) => {
console.log('checkEntryPoint');
return { path, entry };
});
},
};
};

export const appTools = (
options: AppToolsOptions = {
// default webpack to be compatible with original projects
bundler: 'webpack',
},
): Plugin<AppTools<'shared'>> => ({
name: '@modern-js/plugin-app-tools',
usePlugins: [testPlugin()],
registryHooks: {
_internalRuntimePlugins: createAsyncHook<InternalRuntimePluginsFn>(),
_internalServerPlugins: createAsyncHook<InternalServerPluginsFn>(),
checkEntryPoint: createAsyncHook<CheckEntryPointFn>(),
modifyEntrypoints: createAsyncHook<ModifyEntrypointsFn>(),
modifyFileSystemRoutes: createAsyncHook<ModifyFileSystemRoutesFn>(),
modifyServerRoutes: createAsyncHook<ModifyServerRoutesFn>(),
deploy: createAsyncHook<DeplpoyFn>(),
},
setup: api => {
api.onPrepare(() => {
const hooks = api.getHooks();
hooks.checkEntryPoint.call({ path: '', entry: '' });
console.log('app-tools prepare', options);
});
},
Expand Down
45 changes: 43 additions & 2 deletions packages/solutions/app-tools/src/v3/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,53 @@
import type { CLIPluginAPI } from '@modern-js/plugin-v2';
import type {
CLIPluginAPI,
PluginHookTap,
TransformFunction,
} from '@modern-js/plugin-v2';
import type {
Entrypoint,
NestedRouteForCli,
PageRoute,
RouteLegacy,
ServerPlugin,
ServerRoute,
} from '@modern-js/types';
import type {
AppToolsNormalizedConfig,
AppToolsUserConfig,
} from '../../types/config';
import type { RuntimePlugin } from '../../types/hooks';
import type { Bundler } from '../../types/utils';

export type InternalRuntimePluginsFn = TransformFunction<{
entrypoint: Entrypoint;
plugins: RuntimePlugin[];
}>;
export type InternalServerPluginsFn = TransformFunction<{
plugins: ServerPlugin[];
}>;
export type CheckEntryPointFn = TransformFunction<{
path: string;
entry: false | string;
}>;
export type ModifyEntrypointsFn = TransformFunction<Entrypoint[]>;
export type ModifyFileSystemRoutesFn = TransformFunction<{
entrypoint: Entrypoint;
routes: RouteLegacy[] | (NestedRouteForCli | PageRoute)[];
}>;
export type ModifyServerRoutesFn = TransformFunction<{ routes: ServerRoute[] }>;
export type DeplpoyFn = () => Promise<void> | void;

export interface AppTools<B extends Bundler>
extends CLIPluginAPI<
AppToolsUserConfig<B>,
AppToolsNormalizedConfig<AppToolsUserConfig<'shared'>>
> {}
> {
_internalRuntimePlugins: PluginHookTap<InternalRuntimePluginsFn>;
_internalServerPlugins: PluginHookTap<InternalServerPluginsFn>;
checkEntryPoint: PluginHookTap<CheckEntryPointFn>;
modifyEntrypoints: PluginHookTap<ModifyEntrypointsFn>;
modifyFileSystemRoutes: PluginHookTap<ModifyFileSystemRoutesFn>;
modifyServerRoutes: PluginHookTap<ModifyServerRoutesFn>;

deploy: PluginHookTap<DeplpoyFn>;
}
20 changes: 19 additions & 1 deletion packages/toolkit/plugin-v2/src/cli/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { PluginHookTap } from '../types';
import type { CLIPluginAPI } from '../types/cli/api';
import type { InternalContext } from '../types/cli/context';
import type { PluginManager } from '../types/plugin';
Expand All @@ -8,7 +9,7 @@ export function initPluginAPI<Config, NormalizedConfig>({
context: InternalContext<Config, NormalizedConfig>;
pluginManager: PluginManager;
}): CLIPluginAPI<Config, NormalizedConfig> {
const { hooks } = context;
const { hooks, extendsHooks } = context;
function getAppContext() {
if (context) {
const { hooks, config, normalizedConfig, pluginAPI, ...appContext } =
Expand All @@ -31,10 +32,26 @@ export function initPluginAPI<Config, NormalizedConfig>({
throw new Error('Cannot access normalized config');
}

function getHooks() {
return {
...context.hooks,
...context.extendsHooks,
};
}
const extendsPluginApi: Record<
string,
PluginHookTap<(...args: any[]) => any>
> = {};

Object.keys(extendsHooks).forEach(hookName => {
extendsPluginApi[hookName] = extendsHooks[hookName].tap;
});

return {
getAppContext,
getConfig,
getNormalizedConfig,
getHooks,

config: hooks.config.tap,
modifyConfig: hooks.modifyConfig.tap,
Expand Down Expand Up @@ -62,5 +79,6 @@ export function initPluginAPI<Config, NormalizedConfig>({
onBeforeDeploy: hooks.onBeforeDeploy.tap,
onAfterDeploy: hooks.onAfterDeploy.tap,
onBeforeExit: hooks.onBeforeExit.tap,
...extendsPluginApi,
};
}
10 changes: 10 additions & 0 deletions packages/toolkit/plugin-v2/src/cli/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';
import type { AppContext, InternalContext } from '../types/cli/context';
import type { CLIPlugin } from '../types/cli/plugin';
import type { PluginHook } from '../types/hooks';
import { initHooks } from './hooks';

interface ContextParams<Config, NormalizedConfig> {
Expand Down Expand Up @@ -39,9 +40,18 @@ export async function createContext<Config, NormalizedConfig>({
}: ContextParams<Config, NormalizedConfig>): Promise<
InternalContext<Config, NormalizedConfig>
> {
const { plugins } = appContext;
const extendsHooks: Record<string, PluginHook<(...args: any[]) => any>> = {};
plugins.forEach(plugin => {
const { registryHooks = {} } = plugin;
Object.keys(registryHooks).forEach(hookName => {
extendsHooks[hookName] = registryHooks[hookName];
});
});
return {
...appContext,
hooks: initHooks<Config, NormalizedConfig>(),
extendsHooks,
config,
normalizedConfig,
};
Expand Down
67 changes: 1 addition & 66 deletions packages/toolkit/plugin-v2/src/cli/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
OnBeforeBuildFn,
OnBeforeCreateCompilerFn,
} from '@rsbuild/core';
import { createAsyncHook, createCollectAsyncHook } from '../hooks';
import type {
AddCommandFn,
AddWatchFilesFn,
Expand All @@ -27,72 +28,6 @@ import type {
} from '../types/cli/hooks';
import type { DeepPartial } from '../types/utils';

export type AsyncHook<Callback extends (...args: any[]) => any> = {
tap: (cb: Callback) => void;
call: (...args: Parameters<Callback>) => Promise<Parameters<Callback>>;
};

export function createAsyncHook<
Callback extends (...args: any[]) => any,
>(): AsyncHook<Callback> {
const callbacks: Callback[] = [];

const tap = (cb: Callback) => {
callbacks.push(cb);
};

const call = async (...params: Parameters<Callback>) => {
for (const callback of callbacks) {
const result = await callback(...params);

if (result !== undefined) {
params[0] = result;
}
}

return params;
};

return {
tap,
call,
};
}

export type CollectAsyncHook<Callback extends (...args: any[]) => any> = {
tap: (cb: Callback) => void;
call: (...args: Parameters<Callback>) => Promise<ReturnType<Callback>[]>;
};

export function createCollectAsyncHook<
Callback extends (...args: any[]) => any,
>(): CollectAsyncHook<Callback> {
const callbacks: Callback[] = [];

const tap = (cb: Callback) => {
callbacks.push(cb);
};

const call = async (...params: Parameters<Callback>) => {
const results: ReturnType<Callback>[] = [];
for (const callback of callbacks) {
const result = await callback(...params);

if (result !== undefined) {
params[0] = result;
results.push(result);
}
}

return results;
};

return {
tap,
call,
};
}

export function initHooks<Config, NormalizedConfig>() {
return {
/**
Expand Down
57 changes: 57 additions & 0 deletions packages/toolkit/plugin-v2/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { AsyncHook, CollectAsyncHook } from './types/hooks';

export function createAsyncHook<
Callback extends (...args: any[]) => any,
>(): AsyncHook<Callback> {
const callbacks: Callback[] = [];

const tap = (cb: Callback) => {
callbacks.push(cb);
};

const call = async (...params: Parameters<Callback>) => {
for (const callback of callbacks) {
const result = await callback(...params);

if (result !== undefined) {
params[0] = result;
}
}

return params;
};

return {
tap,
call,
};
}

export function createCollectAsyncHook<
Callback extends (...args: any[]) => any,
>(): CollectAsyncHook<Callback> {
const callbacks: Callback[] = [];

const tap = (cb: Callback) => {
callbacks.push(cb);
};

const call = async (...params: Parameters<Callback>) => {
const results: ReturnType<Callback>[] = [];
for (const callback of callbacks) {
const result = await callback(...params);

if (result !== undefined) {
params[0] = result;
results.push(result);
}
}

return results;
};

return {
tap,
call,
};
}
1 change: 1 addition & 0 deletions packages/toolkit/plugin-v2/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { createPluginManager } from './manager';
export { createAsyncHook, createCollectAsyncHook } from './hooks';
export * from './cli';

export * from './types';
Loading

0 comments on commit bfa95d7

Please sign in to comment.