Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: runtime plugin use plugin v2 define #6709

Merged
merged 19 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/thirty-monkeys-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@modern-js/runtime': minor
'@modern-js/plugin-v2': minor
---

feat: runtime plugin use plugin v2

feat: runtime 插件使用插件 v2
9 changes: 8 additions & 1 deletion packages/runtime/plugin-garfish/src/cli/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import type {
AppToolsFeatureHooks,
NormalizedConfig,
} from '@modern-js/app-tools';
import type { CollectAsyncHook } from '@modern-js/plugin-v2';
import type { Entrypoint } from '@modern-js/types';
import { fs } from '@modern-js/utils';
import type { AppendEntryCodeFn } from './hooks';
import * as template from './template';
import { generateAsyncEntryCode } from './utils';

Expand All @@ -27,7 +29,12 @@ export const generateCode = async (
entrypoints.map(async entrypoint => {
const { entryName, isAutoMount, entry, customEntry, customBootstrap } =
entrypoint;
const appendCode = await hooks.appendEntryCode.call({ entrypoint });
const appendCode = await (
hooks.appendEntryCode as CollectAsyncHook<AppendEntryCodeFn>
).call({
entrypoint,
code: '',
});

if (isAutoMount) {
// index.jsx
Expand Down
6 changes: 6 additions & 0 deletions packages/runtime/plugin-garfish/src/cli/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Entrypoint } from '@modern-js/types';

export type AppendEntryCodeFn = (params: {
entrypoint: Entrypoint;
code: string;
}) => string | Promise<string>;
7 changes: 1 addition & 6 deletions packages/runtime/plugin-garfish/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import type {
} from '@modern-js/app-tools';
import type { CliHookCallbacks, useConfigContext } from '@modern-js/core';
import { createCollectAsyncHook } from '@modern-js/plugin-v2';
import type { Entrypoint } from '@modern-js/types';
import { createRuntimeExportsUtils, getEntryOptions } from '@modern-js/utils';
import { logger } from '../util';
import { generateCode } from './code';
import type { AppendEntryCodeFn } from './hooks';
import { getRuntimeConfig, setRuntimeConfig } from './utils';

export type UseConfig = ReturnType<typeof useConfigContext>;
Expand Down Expand Up @@ -39,11 +39,6 @@ export function getDefaultMicroFrontedConfig(
};
}

type AppendEntryCodeFn = (params: {
entrypoint: Entrypoint;
code: string;
}) => string | Promise<string>;

export const garfishPlugin = (): CliPluginFuture<AppTools<'shared'>> => ({
name: '@modern-js/plugin-garfish',
pre: ['@modern-js/runtime'],
Expand Down
4 changes: 0 additions & 4 deletions packages/runtime/plugin-garfish/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createApp } from '@modern-js/runtime';
import { createRuntime } from '@modern-js/runtime/plugin';
import fetchMock from 'jest-fetch-mock';
import '@testing-library/jest-dom';
import 'jest-location-mock';
Expand Down Expand Up @@ -152,7 +151,6 @@ describe('plugin-garfish', () => {
let unmount = () => {};
await act(async () => {
const AppWrapper = createApp({
runtime: createRuntime(),
plugins: [garfishPlugin(microFrontendConfig)],
})(App);
const res = render(<AppWrapper />);
Expand Down Expand Up @@ -256,7 +254,6 @@ describe('plugin-garfish', () => {

await act(async () => {
const AppWrapper = createApp({
runtime: createRuntime(),
plugins: [garfishPlugin(microFrontendConfig)],
})(App);
render(<AppWrapper />, {});
Expand Down Expand Up @@ -313,7 +310,6 @@ describe('plugin-garfish', () => {

await act(async () => {
const AppWrapper = createApp({
runtime: createRuntime(),
plugins: [garfishPlugin(microFrontendConfig)],
})(App);
render(<AppWrapper />, {});
Expand Down
7 changes: 5 additions & 2 deletions packages/runtime/plugin-router-v5/src/runtime/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { createWaterfall } from '@modern-js/plugin';
import { createSyncHook } from '@modern-js/plugin-v2';
import type { RouteProps } from 'react-router-dom';
import type { SingleRouteConfig } from './plugin';

const modifyRoutesHook = createWaterfall<RouteProps[]>();
// only for inhouse use
const modifyRoutesHook =
createSyncHook<(routes: RouteProps[]) => SingleRouteConfig[]>();

export { modifyRoutesHook };
193 changes: 96 additions & 97 deletions packages/runtime/plugin-router-v5/src/runtime/plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { RuntimeReactContext, isBrowser } from '@meta/runtime';
import { getGlobalLayoutApp, getGlobalRoutes } from '@meta/runtime/context';
import type { Plugin } from '@modern-js/runtime';
import type { RuntimePluginFuture } from '@modern-js/runtime';
import { merge } from '@modern-js/runtime-utils/merge';
import { parsedJSONFromElement } from '@modern-js/runtime-utils/parsed';
import {
type BrowserHistoryBuildOptions,
type HashHistoryBuildOptions,
Expand Down Expand Up @@ -62,100 +61,58 @@ export type RouterConfig = Partial<HistoryConfig> & {

let routes: SingleRouteConfig[] = [];

export const routerPlugin = (userConfig: RouterConfig = {}): Plugin => {
export const routerPlugin = (
userConfig: RouterConfig = {},
): RuntimePluginFuture<{
extendHooks: {
modifyRoutes: typeof modifyRoutesHook;
};
}> => {
return {
name: '@modern-js/plugin-router',
registerHook: {
registryHooks: {
modifyRoutes: modifyRoutesHook,
},
setup: api => {
return {
beforeRender(context) {
context.router = {
useRouteMatch,
useLocation,
useHistory,
};

Object.defineProperty(context, 'routes', {
get() {
return routes;
},
});
},
wrapRoot: App => {
const pluginConfig: Record<string, any> =
api.useRuntimeConfigContext();
const {
serverBase = [],
history: customHistory,
supportHtml5History = true,
routesConfig,
createRoutes,
historyOptions = {},
} = merge(pluginConfig.router || {}, userConfig) as RouterConfig;
const finalRouteConfig = {
routes: getGlobalRoutes() as SingleRouteConfig[],
globalApp: getGlobalLayoutApp(),
...routesConfig,
};
const originRoutes = finalRouteConfig?.routes;
const isBrow = isBrowser();
api.onBeforeRender(context => {
context.router = {
useRouteMatch,
useLocation,
useHistory,
};

const select = (pathname: string) =>
serverBase.find(baseUrl => pathname.search(baseUrl) === 0) || '/';
Object.defineProperty(context, 'routes', {
get() {
return routes;
},
});
});
api.wrapRoot(App => {
const pluginConfig: Record<string, any> = api.getRuntimeConfig();
const {
serverBase = [],
history: customHistory,
supportHtml5History = true,
routesConfig,
createRoutes,
historyOptions = {},
} = merge(pluginConfig.router || {}, userConfig) as RouterConfig;
const finalRouteConfig = {
routes: getGlobalRoutes() as SingleRouteConfig[],
globalApp: getGlobalLayoutApp(),
...routesConfig,
};
const originRoutes = finalRouteConfig?.routes;
const isBrow = isBrowser();

const getRouteApp = () => {
if (isBrow) {
return (props: any) => {
const runtimeContext = useContext(RuntimeReactContext);
const baseUrl = select(location.pathname).replace(/^\/*/, '/');
const basename =
baseUrl === '/'
? urlJoin(
baseUrl,
runtimeContext._internalRouterBaseName ||
(historyOptions.basename as string),
)
: baseUrl;
const select = (pathname: string) =>
serverBase.find(baseUrl => pathname.search(baseUrl) === 0) || '/';

historyOptions.basename = basename;
const history =
customHistory ||
(supportHtml5History
? createBrowserHistory(historyOptions)
: createHashHistory(historyOptions));
const runner = (api as any).useHookRunners();
routes = runner.modifyRoutes(originRoutes);
finalRouteConfig && (finalRouteConfig.routes = routes);
/**
* when exist createRoutes function, App.tsx must be exist, and support Component props
* this is compatible config routes
*/
return (
<Router history={history}>
{createRoutes ? (
<App Component={createRoutes()} />
) : App && !finalRouteConfig?.routes ? (
<App {...props} />
) : (
renderRoutes(finalRouteConfig, props)
)}
</Router>
);
};
}
const getRouteApp = () => {
if (isBrow) {
return (props: any) => {
const runtimeContext = useContext(RuntimeReactContext);
const { ssrContext } = runtimeContext;
const location = getLocation(ssrContext);
const routerContext = ssrContext?.redirection || {};
const request = ssrContext?.request;
const baseUrl = (request?.baseUrl as string)?.replace(
/^\/*/,
'/',
);

const baseUrl = select(location.pathname).replace(/^\/*/, '/');
const basename =
baseUrl === '/'
? urlJoin(
Expand All @@ -164,30 +121,72 @@ export const routerPlugin = (userConfig: RouterConfig = {}): Plugin => {
(historyOptions.basename as string),
)
: baseUrl;
const runner = (api as any).useHookRunners();
const routes = runner.modifyRoutes(originRoutes);

historyOptions.basename = basename;
const history =
customHistory ||
(supportHtml5History
? createBrowserHistory(historyOptions)
: createHashHistory(historyOptions));
const hooks = api.getHooks();
routes = hooks.modifyRoutes.call(originRoutes);
finalRouteConfig && (finalRouteConfig.routes = routes);
/**
* when exist createRoutes function, App.tsx must be exist, and support Component props
* this is compatible config routes
*/
return (
<StaticRouter
basename={basename === '/' ? '' : basename}
location={location}
context={routerContext}
>
<Router history={history}>
{createRoutes ? (
<App Component={createRoutes()} />
) : App && !finalRouteConfig?.routes ? (
<App {...props} />
) : (
renderRoutes(finalRouteConfig, props)
)}
</StaticRouter>
</Router>
);
};
}
return (props: any) => {
const runtimeContext = useContext(RuntimeReactContext);
const { ssrContext } = runtimeContext;
const location = getLocation(ssrContext);
const routerContext = ssrContext?.redirection || {};
const request = ssrContext?.request;
const baseUrl = (request?.baseUrl as string)?.replace(/^\/*/, '/');

const basename =
baseUrl === '/'
? urlJoin(
baseUrl,
runtimeContext._internalRouterBaseName ||
(historyOptions.basename as string),
)
: baseUrl;
const hooks = api.getHooks();
const routes = hooks.modifyRoutes.call(originRoutes);
finalRouteConfig && (finalRouteConfig.routes = routes);
return (
<StaticRouter
basename={basename === '/' ? '' : basename}
location={location}
context={routerContext}
>
{createRoutes ? (
<App Component={createRoutes()} />
) : App && !finalRouteConfig?.routes ? (
<App {...props} />
) : (
renderRoutes(finalRouteConfig, props)
)}
</StaticRouter>
);
};
};

return getRouteApp();
},
};
return getRouteApp();
});
},
};
};
Loading
Loading