Skip to content

Commit

Permalink
feat: use server.useJsonScript instead ssr.inlineScript (#6625)
Browse files Browse the repository at this point in the history
  • Loading branch information
zllkjc authored Dec 10, 2024
1 parent 30f89d5 commit 524d6af
Show file tree
Hide file tree
Showing 23 changed files with 213 additions and 80 deletions.
7 changes: 7 additions & 0 deletions .changeset/eleven-otters-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@modern-js/runtime': patch
'@modern-js/server-core': patch
---

feat: add server.useJsonScript , for instead ssr.inlineScript
feat: 添加 server.useJsonScript 配置,代替 ssr.inlineScript
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ When the value type is `Object`, the following properties can be configured:
| ---------------- | ------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------- |
| mode | `string` | `string` | which defaults to using `renderToString` for rendering. Configure `stream` to enable streaming rendering |
| forceCSR | `boolean` | `false` | which is off by default for forcing CSR rendering. Configure `true` to force CSR by adding `?csr=true` or adding `x-modern-ssr-fallback` header when accessing the page |
| inlineScript | `boolean` | `true` | By default, SSR data is injected into HTML as inline scripts and assigned directly to global variables. Configure `false` to distribute JSON instead of assigning to global variables, this configuration doesn't work in Streaming SSR |
| disablePrerender | `boolean` | `fasle` | To ensure compatibility with the old data request method (`useLoader`), by default, Modern.js performs pre-rendering of components.However, if developers want to reduce one rendering when there is no use of the useLoader API in your project, you can set the configuration `disablePrerender=true` |
| unsafeHeaders | `string[]` | `[]` | For safety reasons, Modern.js does not add excessive content to SSR_DATA. Developers can use this configuration to specify the headers that need to be injected |
| scriptLoading | `defer \| blocking \| module \| async` | `defer` | The configuration is the same as [html.scriptLoading](/configure/app/html/script-loading), supporting SSR injected script set to `async` loading. The priority is `ssr.scriptLoading` > `html.scriptLoading` |
Expand All @@ -42,7 +41,6 @@ export default defineConfig({
ssr: {
forceCSR: true,
mode: 'stream',
inlineScript: false,
unsafeHeaders: ['User-Agent'],
scriptLoading: 'async',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export default defineConfig({
| ---------------- | ------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------- |
| mode | `string` | `string` | 默认为使用 `renderToString` 渲染。配置为 `stream` 开启流式渲染 |
| forceCSR | `boolean` | `false` | 默认关闭强制 CSR 渲染。配置为 `true` 后,在页面访问时添加 `?csr=true` 或添加请求头 `x-modern-ssr-fallback` 即可强制 CSR |
| inlineScript | `boolean` | `true` | 默认情况下,SSR 的数据会以内联脚本的方式注入到 HTML 中,并且直接赋值给全局变量。配置为 `false` 后,会下发 JSON,而不是赋值给全局变量,Streaming SSR 下,该配置不会生效 |
| disablePrerender | `boolean` | `fasle` | 为了兼容旧数据请求方式 - `useLoader`, 默认情况下 Modern.js 会对组件进行一次预渲染即有两次渲染 |
| unsafeHeaders | `string[]` | `[]` | 为了安全考虑,Modern.js 不会往 SSR_DATA 添加过多的内容。开发者可以通过该配置,对需要注入的 headers 进行配置 |
| scriptLoading | `defer \| blocking \| module \| async` | `defer` | 配置同 [html.scriptLoading](/configure/app/html/script-loading),支持 ssr 注入的 script 设置为 async 加载方式。优先级为 `ssr.scriptLoading` > `html.scriptLoading` |
Expand All @@ -42,7 +41,6 @@ export default defineConfig({
ssr: {
forceCSR: true,
mode: 'stream',
inlineScript: false,
disablePrerender: true,
unsafeHeaders: ['User-Agent'],
scriptLoading: 'async',
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/plugin-runtime/src/core/react/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function createRoot(UserApp?: React.ComponentType | null) {
const App = UserApp || getGlobalApp();

if (isBrowser()) {
// we should get data from HTMLElement when set ssr.inlineScript = false
// we should get data from HTMLElement when set server.useJsonScript = true
window._SSR_DATA =
window._SSR_DATA || parsedJSONFromElement(SSR_DATA_JSON_ID);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { getGlobalRunner } from '../plugin/runner';
import { createRoot } from '../react';
import type { SSRServerContext } from '../types';
import { CHUNK_CSS_PLACEHOLDER } from './constants';
import { getSSRConfigByEntry, getSSRInlineScript, getSSRMode } from './utils';
import { getSSRConfigByEntry, getSSRMode } from './utils';

export type { RequestHandlerConfig as HandleRequestConfig } from '@modern-js/app-tools';

Expand Down Expand Up @@ -62,7 +62,7 @@ function createSSRContext(
reporter,
} = options;

const { nonce } = config;
const { nonce, useJsonScript } = config;

const { entryName, route } = resource;

Expand Down Expand Up @@ -100,15 +100,14 @@ function createSSRContext(
config.ssr,
config.ssrByEntries,
);

const ssrMode = getSSRMode(ssrConfig);
const inlineScript = getSSRInlineScript(ssrConfig);

const loaderFailureMode =
typeof ssrConfig === 'object' ? ssrConfig.loaderFailureMode : undefined;

return {
nonce,
useJsonScript,
loaderContext,
redirection: {},
htmlModifiers: [],
Expand Down Expand Up @@ -138,7 +137,6 @@ function createSSRContext(
},
reporter,
mode: ssrMode,
inlineScript,
onError,
onTiming,
loaderFailureMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { SSRContainer } from '../../types';
import { SSR_DATA_PLACEHOLDER } from '../constants';
import type { HandleRequestConfig } from '../requestHandler';
import { type BuildHtmlCb, type SSRConfig, buildHtml } from '../shared';
import { attributesToString, getSSRInlineScript, safeReplace } from '../utils';
import { attributesToString, safeReplace } from '../utils';

export type BuildShellAfterTemplateOptions = {
runtimeContext: RuntimeContext;
Expand All @@ -29,6 +29,7 @@ export function buildShellAfterTemplate(
request,
ssrConfig,
nonce: config.nonce,
useJsonScript: config.useJsonScript,
runtimeContext,
renderLevel,
}),
Expand Down Expand Up @@ -62,9 +63,11 @@ function createReplaceSSRData(options: {
runtimeContext: RuntimeContext;
ssrConfig: SSRConfig;
nonce?: string;
useJsonScript?: boolean;
renderLevel: RenderLevel;
}) {
const { runtimeContext, nonce, renderLevel, ssrConfig } = options;
const { runtimeContext, nonce, renderLevel, useJsonScript, ssrConfig } =
options;

const { request, reporter } = runtimeContext.ssrContext!;

Expand Down Expand Up @@ -102,16 +105,11 @@ function createReplaceSSRData(options: {
renderLevel,
};
const attrsStr = attributesToString({ nonce });

const inlineScript = getSSRInlineScript(ssrConfig);
const useInlineScript = inlineScript !== false;
const serializeSSRData = serializeJson(ssrData);

const ssrDataScript = useInlineScript
? `
<script${attrsStr}>window._SSR_DATA = ${serializeSSRData}</script>
`
: `<script type="application/json" id="${SSR_DATA_JSON_ID}">${serializeSSRData}</script>`;
const ssrDataScript = useJsonScript
? `<script type="application/json" id="${SSR_DATA_JSON_ID}">${serializeSSRData}</script>`
: `<script${attrsStr}>window._SSR_DATA = ${serializeSSRData}</script>`;

return (template: string) =>
safeReplace(template, SSR_DATA_PLACEHOLDER, ssrDataScript);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const renderString: RenderString = async (
chunkSet,
routerContext,
nonce: config.nonce,
useJsonScript: config.useJsonScript,
}),
];

Expand Down
24 changes: 9 additions & 15 deletions packages/runtime/plugin-runtime/src/core/server/string/ssrData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import type { HeadersData } from '@modern-js/runtime-utils/universal/request';
import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID } from '../../constants';
import type { SSRContainer, SSRServerContext } from '../../types';
import type { SSRConfig } from '../shared';
import {
attributesToString,
getSSRInlineScript,
serializeErrors,
} from '../utils';
import { attributesToString, serializeErrors } from '../utils';
import type { ChunkSet, Collector } from './types';

export interface SSRDataCreatorOptions {
Expand All @@ -19,6 +15,7 @@ export interface SSRDataCreatorOptions {
ssrConfig?: SSRConfig;
routerContext?: StaticHandlerContext;
nonce?: string;
useJsonScript?: boolean;
}

export class SSRDataCollector implements Collector {
Expand Down Expand Up @@ -86,22 +83,19 @@ export class SSRDataCollector implements Collector {
ssrData: Record<string, any>,
routerData?: Record<string, any>,
) {
const { nonce, ssrConfig } = this.#options;
const inlineScript = getSSRInlineScript(ssrConfig);

const useInlineScript = inlineScript !== false;
const { nonce, useJsonScript = false } = this.#options;
const serializeSSRData = serializeJson(ssrData);
const attrsStr = attributesToString({ nonce });

let ssrDataScripts = useInlineScript
? `<script${attrsStr}>window._SSR_DATA = ${serializeSSRData}</script>`
: `<script type="application/json" id="${SSR_DATA_JSON_ID}">${serializeSSRData}</script>`;
let ssrDataScripts = useJsonScript
? `<script type="application/json" id="${SSR_DATA_JSON_ID}">${serializeSSRData}</script>`
: `<script${attrsStr}>window._SSR_DATA = ${serializeSSRData}</script>`;

if (routerData) {
const serializedRouterData = serializeJson(routerData);
ssrDataScripts += useInlineScript
? `\n<script${attrsStr}>window._ROUTER_DATA = ${serializedRouterData}</script>`
: `\n<script type="application/json" id="${ROUTER_DATA_JSON_ID}">${serializedRouterData}</script>`;
ssrDataScripts += useJsonScript
? `\n<script type="application/json" id="${ROUTER_DATA_JSON_ID}">${serializedRouterData}</script>`
: `\n<script${attrsStr}>window._ROUTER_DATA = ${serializedRouterData}</script>`;
}
return ssrDataScripts;
}
Expand Down
8 changes: 0 additions & 8 deletions packages/runtime/plugin-runtime/src/core/server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,3 @@ export function getSSRMode(ssrConfig?: SSRConfig): 'string' | 'stream' | false {

return ssrConfig?.mode === 'stream' ? 'stream' : 'string';
}

export function getSSRInlineScript(ssrConfig?: SSRConfig): boolean {
if (typeof ssrConfig === 'object') {
return ssrConfig.inlineScript === undefined ? true : ssrConfig.inlineScript;
}

return true;
}
2 changes: 1 addition & 1 deletion packages/runtime/plugin-runtime/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export type SSRServerContext = Pick<
loaderFailureMode?: 'clientRender' | 'errorBoundary';
onError?: (e: unknown) => void;
onTiming?: (name: string, dur: number) => void;
inlineScript?: boolean;
useJsonScript?: boolean;
};

/* 通过 useRuntimeContext 获取的 SSRContext */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import { serializeErrors } from './utils';
*/
const DeferredDataScripts = (props?: {
nonce?: string;
inlineScript?: boolean;
useJsonScript?: boolean;
context: StaticHandlerContext;
}) => {
const staticContext = props?.context;
const inlineScript = props?.inlineScript;
const useJsonScript = props?.useJsonScript;
const hydratedRef = useRef(false);

useEffect(() => {
Expand Down Expand Up @@ -52,12 +52,14 @@ const DeferredDataScripts = (props?: {
errors: serializeErrors(staticContext.errors),
};

const initialScript0 = inlineScript ? '' : `${serializeJson(_ROUTER_DATA)}`;
const initialScript1 = inlineScript
? [`_ROUTER_DATA = ${serializeJson(_ROUTER_DATA)};`, modernInline].join(
const initialScript0 = useJsonScript
? `${serializeJson(_ROUTER_DATA)}`
: '';
const initialScript1 = useJsonScript
? modernInline
: [`_ROUTER_DATA = ${serializeJson(_ROUTER_DATA)};`, modernInline].join(
'\n',
)
: modernInline;
);
const deferredDataScripts: JSX.Element[] = [];

const initialScripts = Object.entries(activeDeferreds).map(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export const routerPlugin = (
const context = useContext(RuntimeReactContext);
const { remixRouter, routerContext, ssrContext } = context;

const { nonce, mode, inlineScript } = ssrContext!;
const { nonce, mode, useJsonScript } = ssrContext!;

const routerWrapper = (
<>
Expand All @@ -182,7 +182,7 @@ export const routerPlugin = (
<DeferredDataScripts
nonce={nonce}
context={routerContext!}
inlineScript={inlineScript}
useJsonScript={useJsonScript}
/>
)}
{mode === 'stream' && JSX_SHELL_STREAM_END_MARK}
Expand Down
1 change: 1 addition & 0 deletions packages/server/core/src/plugins/render/ssrRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,6 @@ function createRequestHandlerConfig(
enableInlineStyles: output?.enableInlineStyles,
crossorigin: html?.crossorigin,
scriptLoading: html?.scriptLoading,
useJsonScript: server?.useJsonScript,
};
}
7 changes: 5 additions & 2 deletions packages/server/core/src/types/config/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@ export interface ServerUserConfig {
ssrByEntries?: SSRByEntries;
baseUrl?: string | string[];
port?: number;
enableMicroFrontendDebug?: boolean;
watchOptions?: WatchOptions;
compiler?: 'babel' | 'typescript';
enableFrameworkExt?: boolean;
/**
* @description use json script tag instead of inline script
* @default false
*/
useJsonScript?: boolean;
}

export type ServerNormalizedConfig = ServerUserConfig;
1 change: 1 addition & 0 deletions packages/server/core/src/types/requestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type RequestHandlerConfig = {
enableInlineScripts?: boolean | RegExp;
ssr?: ServerUserConfig['ssr'];
ssrByEntries?: ServerUserConfig['ssrByEntries'];
useJsonScript?: ServerUserConfig['useJsonScript'];
};

export type LoaderContext = Map<string, any>;
Expand Down
Loading

0 comments on commit 524d6af

Please sign in to comment.