Skip to content

Commit

Permalink
fix: improve runtime context logic (#6898)
Browse files Browse the repository at this point in the history
  • Loading branch information
zllkjc authored Mar 3, 2025
1 parent dc78fc0 commit b337977
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 66 deletions.
7 changes: 7 additions & 0 deletions .changeset/little-icons-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@modern-js/runtime': patch
'@modern-js/types': patch
---

fix: requestContext should be add on runtimeContext before init
fix: requestContext 应该在 init 前添加到 runtimeContext
6 changes: 3 additions & 3 deletions packages/runtime/plugin-runtime/src/core/browser/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ const getQuery = () =>
return res;
}, {});

function getSSRData(): SSRContainer & ExtraSSRContainer {
function getSSRData(): SSRContainer {
const ssrData = window._SSR_DATA;

const ssrRequest = ssrData?.context?.request;

const finalSSRData: SSRContainer & ExtraSSRContainer = {
const finalSSRData: SSRContainer = {
...(ssrData || {
renderLevel: 0,
mode: 'string',
Expand Down Expand Up @@ -117,7 +117,7 @@ export async function render(
}),
// garfish plugin params
_internalRouterBaseName: App.props.basename,
...{ ssrContext: ssrData.context },
ssrContext: ssrData.context,
});

context.initialData = ssrData.data?.initialData;
Expand Down
29 changes: 29 additions & 0 deletions packages/runtime/plugin-runtime/src/core/compat/requestContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// this plugin is use to provide request context to runtime context
import type { RuntimeContext } from '../context';
import type { RuntimePluginFuture } from '../plugin/types';
import type { TSSRContext } from '../types';

export const makeRequestContext = (context: RuntimeContext) => {
const baseSSRContext = context.ssrContext;
const requestContext = baseSSRContext
? {
isBrowser: context.isBrowser,
request: baseSSRContext.request || ({} as TSSRContext['request']),
response: baseSSRContext.response || ({} as TSSRContext['response']),
logger: baseSSRContext.logger || ({} as TSSRContext['logger']),
}
: ({} as TSSRContext);

return requestContext;
};

export const requestContextPlugin = (): RuntimePluginFuture => ({
name: '@modern-js/runtime-plugin-request-context',

setup(api) {
api.onBeforeRender(context => {
const requestContext = makeRequestContext(context);
context.context = requestContext;
});
},
});
17 changes: 2 additions & 15 deletions packages/runtime/plugin-runtime/src/core/compatible.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const bootstrap: BootStrap = async (
loaderManager: createLoaderManager(initialLoadersState, {
skipStatic: true,
}),
...(ssrData ? { ssrContext: ssrData?.context } : {}),
ssrContext: ssrData?.context || {},
});

context.initialData = ssrData?.data?.initialData;
Expand Down Expand Up @@ -228,23 +228,10 @@ export const bootstrap: BootStrap = async (
export const useRuntimeContext = () => {
const context = useContext(RuntimeReactContext);

const baseSSRContext = context.ssrContext;
const tSSRContext = baseSSRContext
? {
isBrowser: context.isBrowser,
request: baseSSRContext.request || ({} as TSSRContext['request']),
response: baseSSRContext.response || ({} as TSSRContext['response']),
logger: baseSSRContext.logger || ({} as TSSRContext['logger']),
getInitData: () => {
return Object.freeze(context.initialData);
},
}
: ({} as TSSRContext);

// TODO: Here we should not provide all the RuntimeReactContext to the user
const pickedContext: TRuntimeContext = {
...context,
context: tSSRContext,
context: context.context || ({} as TSSRContext),
request: context.ssrContext?.request,
response: context.ssrContext?.response,
};
Expand Down
3 changes: 3 additions & 0 deletions packages/runtime/plugin-runtime/src/core/context/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ interface BaseRuntimeContext {
store?: Store;
routeManifest: RouteManifest;
routerContext?: StaticHandlerContext;
context?: TSSRContext;
/**
* private
*/
unstable_getBlockNavState?: () => boolean;
}

// It's the RuntimeContext passed internally
export interface RuntimeContext extends BaseRuntimeContext {
[key: string]: any;
}
Expand All @@ -30,6 +32,7 @@ export const RuntimeReactContext = createContext<RuntimeContext>({} as any);

export const ServerRouterContext = createContext({} as any);

// TODO: We should export this context to user as RuntimeContext, use in `init` function
export interface TRuntimeContext extends Partial<BaseRuntimeContext> {
initialData?: Record<string, unknown>;
isBrowser: boolean;
Expand Down
8 changes: 7 additions & 1 deletion packages/runtime/plugin-runtime/src/core/plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { runtime } from '@modern-js/plugin-v2/runtime';
import { merge } from '@modern-js/runtime-utils/merge';
import { compatPlugin } from '../compat';
import { handleSetupResult } from '../compat/hooks';
import { requestContextPlugin } from '../compat/requestContext';
import { setGlobalInternalRuntimeContext } from '../context';
import type { Plugin as RuntimePlugin } from './base';
import type {
Expand All @@ -23,7 +24,12 @@ export function registerPlugin(
) {
const { plugins = [] } = runtimeConfig || {};
const { runtimeContext } = runtime.run({
plugins: [compatPlugin(), ...internalPlugins, ...plugins] as Plugin[],
plugins: [
compatPlugin(),
requestContextPlugin(),
...internalPlugins,
...plugins,
] as Plugin[],
config: runtimeConfig || {},
handleSetupResult,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ function createSSRContext(
params,
headers: headersData,
host,
referer: headers.get('referer')!,
raw: request,
},
response: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { IncomingHttpHeaders } from 'http';
import { serializeJson } from '@modern-js/runtime-utils/node';
import type { HeadersData } from '@modern-js/runtime-utils/universal/request';
import { type RenderLevel, SSR_DATA_JSON_ID } from '../../constants';
Expand Down Expand Up @@ -99,7 +100,7 @@ function createReplaceSSRData(options: {
pathname: request.pathname,
host: request.host,
url: request.url,
headers,
headers: headers as IncomingHttpHeaders,
},
},
mode: 'stream',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { IncomingHttpHeaders } from 'http';
import { serializeJson } from '@modern-js/runtime-utils/node';
import type { StaticHandlerContext } from '@modern-js/runtime-utils/remix-router';
import type { HeadersData } from '@modern-js/runtime-utils/universal/request';
Expand Down Expand Up @@ -68,7 +69,7 @@ export class SSRDataCollector implements Collector {
pathname: request.pathname,
host: request.host,
url: request.url,
headers,
headers: headers as IncomingHttpHeaders,
},
reporter: {
sessionId: reporter?.sessionId,
Expand Down
23 changes: 6 additions & 17 deletions packages/runtime/plugin-runtime/src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { IncomingHttpHeaders } from 'node:http';
import type { OnError, OnTiming } from '@modern-js/app-tools';
import type { BaseSSRServerContext } from '@modern-js/types';
import type { RenderLevel } from './constants';
Expand Down Expand Up @@ -31,14 +32,7 @@ export interface SSRContainer {
mode: SSRMode;
data?: SSRData; // string ssr data
context?: {
request: {
params: Record<string, any>;
query: Record<string, string>;
pathname: string;
host: string;
url: string;
headers?: Record<string, string | undefined>;
};
request: BaseSSRServerContext['request'];
reporter?: {
sessionId?: string;
};
Expand All @@ -62,9 +56,6 @@ export type SSRServerContext = Pick<
> & {
request: BaseSSRServerContext['request'] & {
baseUrl: string;
userAgent: string;
cookie: string;
cookieMap: Record<string, string>;
raw: Request;
};
htmlModifiers: BuildHtmlCb[];
Expand All @@ -76,21 +67,19 @@ export type SSRServerContext = Pick<

/* 通过 useRuntimeContext 获取的 SSRContext */
interface TSSRBaseContext {
request: BaseSSRServerContext['request'] & {
userAgent: string;
cookie: string;
};
request: BaseSSRServerContext['request'];
[propName: string]: any;
}

interface ServerContext extends TSSRBaseContext {
export interface ServerContext extends TSSRBaseContext {
isBrowser: false;
response: BaseSSRServerContext['response'];
logger: BaseSSRServerContext['logger'];
}

interface ClientContext extends TSSRBaseContext {
export interface ClientContext extends TSSRBaseContext {
isBrowser: true;
}

// TODO: rename it, maybe requestContext or renderContext
export declare type TSSRContext = ServerContext | ClientContext;
4 changes: 4 additions & 0 deletions packages/toolkit/types/server/context.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export type BaseSSRServerContext<T extends 'node' | 'worker' = 'node'> = {
headers: IncomingHttpHeaders;
host: string;
url: string;
referer?: string;
userAgent?: string;
cookie?: string;
cookieMap?: Record<string, string>;
[propsName: string]: any;
};
response: BaseResponseLike;
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/integration/ssr/fixtures/init/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dependencies": {
"@modern-js/app-tools": "workspace:*",
"@modern-js/runtime": "workspace:*",
"@modern-js/tsconfig": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
Expand Down
28 changes: 0 additions & 28 deletions tests/integration/ssr/fixtures/init/src/App.jsx

This file was deleted.

30 changes: 30 additions & 0 deletions tests/integration/ssr/fixtures/init/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { type RuntimeContext, useRuntimeContext } from '@modern-js/runtime';

const App = () => {
const { initialData, context } = useRuntimeContext();

console.log(context.request.url, '!!!');
return (
<div className="text-center" id="data">
Hello, Modern.js. env name: {(initialData?.name || '') as string}
</div>
);
};

App.init = (context: RuntimeContext) => {
const { request } = context.context!;

if (context.isBrowser && !context?.initialData?.name) {
return {
name: 'client',
};
} else if (!request.query.browser) {
return {
name: 'server',
};
}

return {};
};

export default App;
14 changes: 14 additions & 0 deletions tests/integration/ssr/fixtures/init/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "@modern-js/tsconfig/base",
"compilerOptions": {
"declaration": false,
"jsx": "preserve",
"baseUrl": "./",
"paths": {
"@/*": ["./src/*"],
"@shared/*": ["./shared/*"],
"@api/*": ["./api/*"]
}
},
"include": ["src", "shared", "config", "modern.config.ts", "api", "server"]
}

0 comments on commit b337977

Please sign in to comment.