From 524d6affa35ca5dffa117355c9c83cf98feebed7 Mon Sep 17 00:00:00 2001
From: zero <68810266+zllkjc@users.noreply.github.com>
Date: Tue, 10 Dec 2024 16:57:10 +0800
Subject: [PATCH] feat: use server.useJsonScript instead ssr.inlineScript
(#6625)
---
.changeset/eleven-otters-cry.md | 7 +++
.../docs/en/configure/app/server/ssr.mdx | 2 -
.../docs/zh/configure/app/server/ssr.mdx | 2 -
.../plugin-runtime/src/core/react/index.tsx | 2 +-
.../src/core/server/requestHandler.ts | 8 +--
.../src/core/server/stream/afterTemplate.ts | 18 +++---
.../src/core/server/string/index.ts | 1 +
.../src/core/server/string/ssrData.ts | 24 +++-----
.../plugin-runtime/src/core/server/utils.ts | 8 ---
.../runtime/plugin-runtime/src/core/types.ts | 2 +-
.../runtime/DeferredDataScripts.node.tsx | 16 ++---
.../src/router/runtime/plugin.node.tsx | 4 +-
.../core/src/plugins/render/ssrRender.ts | 1 +
.../server/core/src/types/config/server.ts | 7 ++-
.../server/core/src/types/requestHandler.ts | 1 +
pnpm-lock.yaml | 60 +++++++++++--------
.../server-json-script/modern.config.ts | 12 ++++
.../server-json-script/package.json | 31 ++++++++++
.../server-json-script/src/routes/layout.tsx | 9 +++
.../server-json-script/src/routes/page.tsx | 5 ++
.../server-json-script/tests/index.test.ts | 48 +++++++++++++++
.../server-json-script/tests/tsconfig.json | 12 ++++
.../server-json-script/tsconfig.json | 13 ++++
23 files changed, 213 insertions(+), 80 deletions(-)
create mode 100644 .changeset/eleven-otters-cry.md
create mode 100644 tests/integration/server-json-script/modern.config.ts
create mode 100644 tests/integration/server-json-script/package.json
create mode 100644 tests/integration/server-json-script/src/routes/layout.tsx
create mode 100644 tests/integration/server-json-script/src/routes/page.tsx
create mode 100644 tests/integration/server-json-script/tests/index.test.ts
create mode 100644 tests/integration/server-json-script/tests/tsconfig.json
create mode 100644 tests/integration/server-json-script/tsconfig.json
diff --git a/.changeset/eleven-otters-cry.md b/.changeset/eleven-otters-cry.md
new file mode 100644
index 000000000000..dc0db5b93744
--- /dev/null
+++ b/.changeset/eleven-otters-cry.md
@@ -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
diff --git a/packages/document/main-doc/docs/en/configure/app/server/ssr.mdx b/packages/document/main-doc/docs/en/configure/app/server/ssr.mdx
index 0e80b84b492a..d476d107cd09 100644
--- a/packages/document/main-doc/docs/en/configure/app/server/ssr.mdx
+++ b/packages/document/main-doc/docs/en/configure/app/server/ssr.mdx
@@ -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` |
@@ -42,7 +41,6 @@ export default defineConfig({
ssr: {
forceCSR: true,
mode: 'stream',
- inlineScript: false,
unsafeHeaders: ['User-Agent'],
scriptLoading: 'async',
},
diff --git a/packages/document/main-doc/docs/zh/configure/app/server/ssr.mdx b/packages/document/main-doc/docs/zh/configure/app/server/ssr.mdx
index f6214c70a2c5..d37d7e899a3d 100644
--- a/packages/document/main-doc/docs/zh/configure/app/server/ssr.mdx
+++ b/packages/document/main-doc/docs/zh/configure/app/server/ssr.mdx
@@ -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` |
@@ -42,7 +41,6 @@ export default defineConfig({
ssr: {
forceCSR: true,
mode: 'stream',
- inlineScript: false,
disablePrerender: true,
unsafeHeaders: ['User-Agent'],
scriptLoading: 'async',
diff --git a/packages/runtime/plugin-runtime/src/core/react/index.tsx b/packages/runtime/plugin-runtime/src/core/react/index.tsx
index 0301f856813d..a25fcb317f65 100644
--- a/packages/runtime/plugin-runtime/src/core/react/index.tsx
+++ b/packages/runtime/plugin-runtime/src/core/react/index.tsx
@@ -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);
diff --git a/packages/runtime/plugin-runtime/src/core/server/requestHandler.ts b/packages/runtime/plugin-runtime/src/core/server/requestHandler.ts
index 2de74c3cfc29..420df0bed819 100644
--- a/packages/runtime/plugin-runtime/src/core/server/requestHandler.ts
+++ b/packages/runtime/plugin-runtime/src/core/server/requestHandler.ts
@@ -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';
@@ -62,7 +62,7 @@ function createSSRContext(
reporter,
} = options;
- const { nonce } = config;
+ const { nonce, useJsonScript } = config;
const { entryName, route } = resource;
@@ -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: [],
@@ -138,7 +137,6 @@ function createSSRContext(
},
reporter,
mode: ssrMode,
- inlineScript,
onError,
onTiming,
loaderFailureMode,
diff --git a/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts b/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts
index bf3ed2357647..b4a1618500ea 100644
--- a/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts
+++ b/packages/runtime/plugin-runtime/src/core/server/stream/afterTemplate.ts
@@ -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;
@@ -29,6 +29,7 @@ export function buildShellAfterTemplate(
request,
ssrConfig,
nonce: config.nonce,
+ useJsonScript: config.useJsonScript,
runtimeContext,
renderLevel,
}),
@@ -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!;
@@ -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
- ? `
-
- `
- : ``;
+ const ssrDataScript = useJsonScript
+ ? ``
+ : ``;
return (template: string) =>
safeReplace(template, SSR_DATA_PLACEHOLDER, ssrDataScript);
diff --git a/packages/runtime/plugin-runtime/src/core/server/string/index.ts b/packages/runtime/plugin-runtime/src/core/server/string/index.ts
index efb53f702156..3dd7ca2afc06 100644
--- a/packages/runtime/plugin-runtime/src/core/server/string/index.ts
+++ b/packages/runtime/plugin-runtime/src/core/server/string/index.ts
@@ -96,6 +96,7 @@ export const renderString: RenderString = async (
chunkSet,
routerContext,
nonce: config.nonce,
+ useJsonScript: config.useJsonScript,
}),
];
diff --git a/packages/runtime/plugin-runtime/src/core/server/string/ssrData.ts b/packages/runtime/plugin-runtime/src/core/server/string/ssrData.ts
index d62b2e07dafa..03e5a09af24f 100644
--- a/packages/runtime/plugin-runtime/src/core/server/string/ssrData.ts
+++ b/packages/runtime/plugin-runtime/src/core/server/string/ssrData.ts
@@ -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 {
@@ -19,6 +15,7 @@ export interface SSRDataCreatorOptions {
ssrConfig?: SSRConfig;
routerContext?: StaticHandlerContext;
nonce?: string;
+ useJsonScript?: boolean;
}
export class SSRDataCollector implements Collector {
@@ -86,22 +83,19 @@ export class SSRDataCollector implements Collector {
ssrData: Record,
routerData?: Record,
) {
- 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
- ? ``
- : ``;
+ let ssrDataScripts = useJsonScript
+ ? ``
+ : ``;
if (routerData) {
const serializedRouterData = serializeJson(routerData);
- ssrDataScripts += useInlineScript
- ? `\n`
- : `\n`;
+ ssrDataScripts += useJsonScript
+ ? `\n`
+ : `\n`;
}
return ssrDataScripts;
}
diff --git a/packages/runtime/plugin-runtime/src/core/server/utils.ts b/packages/runtime/plugin-runtime/src/core/server/utils.ts
index 8556d0c241b8..a2f028aba921 100644
--- a/packages/runtime/plugin-runtime/src/core/server/utils.ts
+++ b/packages/runtime/plugin-runtime/src/core/server/utils.ts
@@ -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;
-}
diff --git a/packages/runtime/plugin-runtime/src/core/types.ts b/packages/runtime/plugin-runtime/src/core/types.ts
index 39047be86450..313343e7c794 100644
--- a/packages/runtime/plugin-runtime/src/core/types.ts
+++ b/packages/runtime/plugin-runtime/src/core/types.ts
@@ -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 */
diff --git a/packages/runtime/plugin-runtime/src/router/runtime/DeferredDataScripts.node.tsx b/packages/runtime/plugin-runtime/src/router/runtime/DeferredDataScripts.node.tsx
index fa3f0c9fb3d9..d5092a74e1d3 100644
--- a/packages/runtime/plugin-runtime/src/router/runtime/DeferredDataScripts.node.tsx
+++ b/packages/runtime/plugin-runtime/src/router/runtime/DeferredDataScripts.node.tsx
@@ -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(() => {
@@ -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(
diff --git a/packages/runtime/plugin-runtime/src/router/runtime/plugin.node.tsx b/packages/runtime/plugin-runtime/src/router/runtime/plugin.node.tsx
index b6cc35ffa0fe..73e100e40751 100644
--- a/packages/runtime/plugin-runtime/src/router/runtime/plugin.node.tsx
+++ b/packages/runtime/plugin-runtime/src/router/runtime/plugin.node.tsx
@@ -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 = (
<>
@@ -182,7 +182,7 @@ export const routerPlugin = (
)}
{mode === 'stream' && JSX_SHELL_STREAM_END_MARK}
diff --git a/packages/server/core/src/plugins/render/ssrRender.ts b/packages/server/core/src/plugins/render/ssrRender.ts
index 9d5ea8babca2..088920c1e764 100644
--- a/packages/server/core/src/plugins/render/ssrRender.ts
+++ b/packages/server/core/src/plugins/render/ssrRender.ts
@@ -160,5 +160,6 @@ function createRequestHandlerConfig(
enableInlineStyles: output?.enableInlineStyles,
crossorigin: html?.crossorigin,
scriptLoading: html?.scriptLoading,
+ useJsonScript: server?.useJsonScript,
};
}
diff --git a/packages/server/core/src/types/config/server.ts b/packages/server/core/src/types/config/server.ts
index 0ef5ede1efd7..d93db409c691 100644
--- a/packages/server/core/src/types/config/server.ts
+++ b/packages/server/core/src/types/config/server.ts
@@ -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;
diff --git a/packages/server/core/src/types/requestHandler.ts b/packages/server/core/src/types/requestHandler.ts
index c6fee3631880..e50fec86a308 100644
--- a/packages/server/core/src/types/requestHandler.ts
+++ b/packages/server/core/src/types/requestHandler.ts
@@ -19,6 +19,7 @@ export type RequestHandlerConfig = {
enableInlineScripts?: boolean | RegExp;
ssr?: ServerUserConfig['ssr'];
ssrByEntries?: ServerUserConfig['ssrByEntries'];
+ useJsonScript?: ServerUserConfig['useJsonScript'];
};
export type LoaderContext = Map;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 97f71ee9f2fa..1fce53c156bd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6848,6 +6848,37 @@ importers:
specifier: ^5
version: 5.3.3
+ tests/integration/server-json-script:
+ dependencies:
+ '@modern-js/runtime':
+ specifier: workspace:*
+ version: link:../../../packages/runtime/plugin-runtime
+ axios:
+ specifier: ^1.7.4
+ version: 1.7.8(debug@4.3.7)
+ express:
+ specifier: ^4.17.2
+ version: 4.21.1
+ react:
+ specifier: ^18.3.1
+ version: 18.3.1
+ react-dom:
+ specifier: ^18.3.1
+ version: 18.3.1(react@18.3.1)
+ devDependencies:
+ '@modern-js/app-tools':
+ specifier: workspace:*
+ version: link:../../../packages/solutions/app-tools
+ '@types/jest':
+ specifier: ^29
+ version: 29.5.14
+ '@types/node':
+ specifier: ^14
+ version: 14.18.35
+ jest:
+ specifier: ^29
+ version: 29.5.0(@types/node@14.18.35)(ts-node@10.9.2(@swc/core@1.3.42)(@types/node@14.18.35)(typescript@5.6.3))
+
tests/integration/server-prod:
dependencies:
'@modern-js/runtime':
@@ -15555,9 +15586,6 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
- function-bind@1.1.1:
- resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
-
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -15590,9 +15618,6 @@ packages:
get-func-name@2.0.0:
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
- get-intrinsic@1.2.0:
- resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
-
get-intrinsic@1.2.4:
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
engines: {node: '>= 0.4'}
@@ -15792,9 +15817,6 @@ packages:
resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==}
engines: {node: '>=8'}
- has-property-descriptors@1.0.0:
- resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
-
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
@@ -29747,8 +29769,8 @@ snapshots:
call-bind@1.0.2:
dependencies:
- function-bind: 1.1.1
- get-intrinsic: 1.2.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
call-bind@1.0.7:
dependencies:
@@ -30680,7 +30702,7 @@ snapshots:
define-properties@1.1.4:
dependencies:
- has-property-descriptors: 1.0.0
+ has-property-descriptors: 1.0.2
object-keys: 1.1.1
defined@1.0.0: {}
@@ -31559,7 +31581,7 @@ snapshots:
extract-zip@2.0.1:
dependencies:
- debug: 4.3.4
+ debug: 4.3.7(supports-color@5.5.0)
get-stream: 5.2.0
yauzl: 2.10.0
optionalDependencies:
@@ -31945,8 +31967,6 @@ snapshots:
fsevents@2.3.3:
optional: true
- function-bind@1.1.1: {}
-
function-bind@1.1.2: {}
function.prototype.name@1.1.5:
@@ -31990,12 +32010,6 @@ snapshots:
get-func-name@2.0.0: {}
- get-intrinsic@1.2.0:
- dependencies:
- function-bind: 1.1.2
- has: 1.0.3
- has-symbols: 1.0.3
-
get-intrinsic@1.2.4:
dependencies:
es-errors: 1.3.0
@@ -32246,10 +32260,6 @@ snapshots:
has-own-prop@2.0.0: {}
- has-property-descriptors@1.0.0:
- dependencies:
- get-intrinsic: 1.2.4
-
has-property-descriptors@1.0.2:
dependencies:
es-define-property: 1.0.0
diff --git a/tests/integration/server-json-script/modern.config.ts b/tests/integration/server-json-script/modern.config.ts
new file mode 100644
index 000000000000..77fb66c86f4d
--- /dev/null
+++ b/tests/integration/server-json-script/modern.config.ts
@@ -0,0 +1,12 @@
+import { applyBaseConfig } from '../../utils/applyBaseConfig';
+
+export default applyBaseConfig({
+ runtime: {
+ router: true,
+ state: false,
+ },
+ server: {
+ ssr: true,
+ useJsonScript: true,
+ },
+});
diff --git a/tests/integration/server-json-script/package.json b/tests/integration/server-json-script/package.json
new file mode 100644
index 000000000000..ad9978cd58ee
--- /dev/null
+++ b/tests/integration/server-json-script/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "server-json-script",
+ "version": "2.9.0",
+ "private": true,
+ "scripts": {
+ "new": "modern new",
+ "reset": "rm -rf node_modules",
+ "dev": "modern dev",
+ "build": "modern build",
+ "serve": "modern serve",
+ "test": "jest",
+ "preview": "modern deploy --mode preview",
+ "deploy": "modern deploy"
+ },
+ "engines": {
+ "node": ">=14.17.6"
+ },
+ "dependencies": {
+ "@modern-js/runtime": "workspace:*",
+ "axios": "^1.7.4",
+ "express": "^4.17.2",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ },
+ "devDependencies": {
+ "@modern-js/app-tools": "workspace:*",
+ "@types/jest": "^29",
+ "@types/node": "^14",
+ "jest": "^29"
+ }
+}
diff --git a/tests/integration/server-json-script/src/routes/layout.tsx b/tests/integration/server-json-script/src/routes/layout.tsx
new file mode 100644
index 000000000000..5bc3d7c33409
--- /dev/null
+++ b/tests/integration/server-json-script/src/routes/layout.tsx
@@ -0,0 +1,9 @@
+import { Link, Outlet, useLoaderData } from '@modern-js/runtime/router';
+
+export default function Layout() {
+ return (
+
+
+
+ );
+}
diff --git a/tests/integration/server-json-script/src/routes/page.tsx b/tests/integration/server-json-script/src/routes/page.tsx
new file mode 100644
index 000000000000..0dd15f8aa5cb
--- /dev/null
+++ b/tests/integration/server-json-script/src/routes/page.tsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+export default function App() {
+ return Hello Modern.js
;
+}
diff --git a/tests/integration/server-json-script/tests/index.test.ts b/tests/integration/server-json-script/tests/index.test.ts
new file mode 100644
index 000000000000..2ed023c19482
--- /dev/null
+++ b/tests/integration/server-json-script/tests/index.test.ts
@@ -0,0 +1,48 @@
+import path from 'path';
+import puppeteer, { type Browser, type Page } from 'puppeteer';
+import {
+ getPort,
+ killApp,
+ launchApp,
+ launchOptions,
+} from '../../../utils/modernTestUtils';
+
+const appDir = path.resolve(__dirname, '../');
+let app: any;
+let appPort: number;
+
+beforeAll(async () => {
+ appPort = await getPort();
+});
+
+afterAll(async () => {
+ if (app) {
+ await killApp(app);
+ }
+});
+
+describe('test basic usage', () => {
+ jest.setTimeout(25000);
+
+ test(`should start successfully`, async () => {
+ app = await launchApp(appDir, appPort, {}, {});
+ const browser = await puppeteer.launch(launchOptions as any);
+ const page = await browser.newPage();
+ await page.goto(`http://localhost:${appPort}`, {
+ waitUntil: ['networkidle0'],
+ });
+
+ const scriptType1 = await page.$eval('#__MODERN_ROUTER_DATA__', el => {
+ return el.getAttribute('type');
+ });
+ const scriptType2 = await page.$eval('#__MODERN_ROUTER_DATA__', el => {
+ return el.getAttribute('type');
+ });
+
+ expect(scriptType1).toBe('application/json');
+ expect(scriptType2).toBe('application/json');
+
+ await page.close();
+ await browser.close();
+ });
+});
diff --git a/tests/integration/server-json-script/tests/tsconfig.json b/tests/integration/server-json-script/tests/tsconfig.json
new file mode 100644
index 000000000000..10f49432232c
--- /dev/null
+++ b/tests/integration/server-json-script/tests/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "@modern-js/tsconfig/base",
+ "compilerOptions": {
+ "declaration": true,
+ "jsx": "preserve",
+ "baseUrl": "./",
+ "emitDeclarationOnly": true,
+ "isolatedModules": true,
+ "paths": {},
+ "types": ["node", "jest"]
+ }
+}
diff --git a/tests/integration/server-json-script/tsconfig.json b/tests/integration/server-json-script/tsconfig.json
new file mode 100644
index 000000000000..6e9938432374
--- /dev/null
+++ b/tests/integration/server-json-script/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "@modern-js/tsconfig/base",
+ "compilerOptions": {
+ "declaration": false,
+ "types": ["jest", "node"],
+ "jsx": "preserve",
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src", "server", "modern.config.ts"]
+}