Skip to content

Commit

Permalink
feat: support Script with script properties (#6528)
Browse files Browse the repository at this point in the history
  • Loading branch information
clChenLiang authored Nov 12, 2024
1 parent 2a59ded commit 99469d6
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 11 deletions.
8 changes: 8 additions & 0 deletions .changeset/curvy-buttons-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@modern-js/runtime': patch
'app-docmuent': patch
---

feat: support script properties with Script

feat: 支持 script 原生属性
26 changes: 21 additions & 5 deletions packages/runtime/plugin-runtime/src/document/Script.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import React from 'react';
import { renderToString } from 'react-dom/server';
import {
DOCUMENT_SCRIPT_ATTRIBUTES_END,
DOCUMENT_SCRIPT_ATTRIBUTES_START,
DOCUMENT_SCRIPT_PLACEHOLDER_END,
DOCUMENT_SCRIPT_PLACEHOLDER_START,
} from './constants';

export function Script(props: { content: () => void }) {
const { content } = props;
const contentStr = content.toString();
const contentIIFE = encodeURIComponent(`(${contentStr})()`);
export function Script(props: DocumentScriptProps) {
const { content, ...rests } = props;
const contentStr = content?.toString();
const contentIIFE = contentStr?.length
? encodeURIComponent(`(${contentStr})()`)
: '';
const scriptProperties = renderToString(<script {...rests} />);
const scriptpPropertiesStr = encodeURIComponent(
scriptProperties.replace('<script ', '').replace('></script>', ''),
);

return (
<>
{`${DOCUMENT_SCRIPT_PLACEHOLDER_START}`}
{`${DOCUMENT_SCRIPT_ATTRIBUTES_START}${scriptpPropertiesStr}${DOCUMENT_SCRIPT_ATTRIBUTES_END}`}
{`${contentIIFE}`}
{`${DOCUMENT_SCRIPT_PLACEHOLDER_END}`}
</>
);
}

// tofix: 之前错误的给了 content 作为 Script 组件的 IIFE 载体,但 content 在 htmlelement.meta 上有含义
export interface DocumentScriptProps
extends Omit<React.ScriptHTMLAttributes<HTMLScriptElement>, 'content'> {
content?: () => void;
}
11 changes: 7 additions & 4 deletions packages/runtime/plugin-runtime/src/document/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import React from 'react';
import ReactDomServer from 'react-dom/server';

import { DocumentContext } from '../DocumentContext';

import {
BODY_PARTICALS_SEPARATOR,
DOCUMENT_CHUNKSMAP_PLACEHOLDER,
Expand All @@ -20,6 +21,8 @@ import {
DOCUMENT_LINKS_PLACEHOLDER,
DOCUMENT_META_PLACEHOLDER,
DOCUMENT_SCRIPTS_PLACEHOLDER,
DOCUMENT_SCRIPT_ATTRIBUTES_END,
DOCUMENT_SCRIPT_ATTRIBUTES_START,
DOCUMENT_SCRIPT_PLACEHOLDER_END,
DOCUMENT_SCRIPT_PLACEHOLDER_START,
DOCUMENT_SSRDATASCRIPT_PLACEHOLDER,
Expand Down Expand Up @@ -240,16 +243,16 @@ export const documentPlugin = (): CliPlugin<AppTools> => ({
html.includes(DOCUMENT_SCRIPT_PLACEHOLDER_START) &&
html.includes(DOCUMENT_SCRIPT_PLACEHOLDER_END)
) {
const { nonce } = config.security;
const { nonce } = config.security || {};
const nonceAttr = nonce ? `nonce=${nonce}` : '';

html = html.replace(
new RegExp(
`${DOCUMENT_SCRIPT_PLACEHOLDER_START}(.*?)${DOCUMENT_SCRIPT_PLACEHOLDER_END}`,
`${DOCUMENT_SCRIPT_PLACEHOLDER_START}${DOCUMENT_SCRIPT_ATTRIBUTES_START}(.*)${DOCUMENT_SCRIPT_ATTRIBUTES_END}(.*?)${DOCUMENT_SCRIPT_PLACEHOLDER_END}`,
'g',
),
(_scriptStr, $1) =>
`<script ${nonceAttr}>${decodeURIComponent($1)}</script>`,
(_scriptStr, $1, $2) =>
`<script ${decodeURIComponent($1)} ${nonceAttr}>${decodeURIComponent($2)}</script>`,
);
}
// if the Document.tsx has a style, replace to convert it
Expand Down
6 changes: 6 additions & 0 deletions packages/runtime/plugin-runtime/src/document/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export const DOCUMENT_SCRIPT_PLACEHOLDER_START = encodeURIComponent(
export const DOCUMENT_SCRIPT_PLACEHOLDER_END = encodeURIComponent(
'<!-- script-end -->',
);
export const DOCUMENT_SCRIPT_ATTRIBUTES_START = encodeURIComponent(
'<!-- script-scriptpProperties-start -->',
);
export const DOCUMENT_SCRIPT_ATTRIBUTES_END = encodeURIComponent(
'<!-- script-scriptpProperties-end -->',
);
export const DOCUMENT_STYLE_PLACEHOLDER_START = encodeURIComponent(
'<!-- style-start -->',
);
Expand Down
12 changes: 10 additions & 2 deletions tests/integration/app-document/src/sub/Document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
Head,
Html,
Root,
Script,
Style,
} from '@modern-js/runtime/document';
// biome-ignore lint/style/useImportType: <explanation>
import React from 'react';
import { useContext } from 'react';
import React, { useContext } from 'react';

export default function Document(): React.ReactElement {
// props: Record<string, unknown>,
Expand Down Expand Up @@ -46,6 +46,14 @@ export default function Document(): React.ReactElement {
__html: `var a = function() {console.log('sss')}; a();`,
}}
/>
<Script
defer
async
id="script-has-id"
content={() => {
console.log('this is a IIFE function');
}}
/>
</Head>
<Body {...{ dir: 'ltr' }}>
<Root {...{ class: 'root' }}>
Expand Down
14 changes: 14 additions & 0 deletions tests/integration/app-document/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ describe('test dev and build', () => {
);
expect(htmlWithDoc.includes('<title>test-title</title>')).toBe(true);
});

test('should has Script origin script properties', async () => {
const htmlWithDoc = fs.readFileSync(
path.join(appDir, 'dist', 'html/sub/index.html'),
'utf-8',
);
expect(
htmlWithDoc.includes('<script defer="" async="" id="script-has-id" >'),
).toBe(true);
// IIFE should worked
expect(
htmlWithDoc.includes('console.log("this is a IIFE function");'),
).toBe(true);
});
});

describe('test dev', () => {
Expand Down

0 comments on commit 99469d6

Please sign in to comment.