Next bugs (#1681)
* fix(#1679): hoisted <script> rendering * fix(#1679): do not print global for styles, but do for scripts * fix: update ObjectSet implementation * fix: dedupe elements in sets
This commit is contained in:
parent
502c799b1d
commit
2da8ce211d
3 changed files with 34 additions and 18 deletions
|
@ -52,8 +52,13 @@ export interface SSRMetadata {
|
|||
}
|
||||
|
||||
export interface SSRResult {
|
||||
styles: Set<string>;
|
||||
scripts: Set<string>;
|
||||
styles: Set<SSRElement>;
|
||||
scripts: Set<SSRElement>;
|
||||
createAstro(Astro: TopLevelAstro, props: Record<string, any>, slots: Record<string, any> | null): AstroGlobal;
|
||||
_metadata: SSRMetadata;
|
||||
}
|
||||
|
||||
export interface SSRElement {
|
||||
props: Record<string, any>;
|
||||
children: string;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { BuildResult } from 'esbuild';
|
||||
import type { ViteDevServer } from '../vite';
|
||||
import type { AstroConfig, ComponentInstance, GetStaticPathsResult, Params, Props, Renderer, RouteCache, RouteData, RuntimeMode, SSRError } from '../../@types/astro-core';
|
||||
import type { AstroGlobal, TopLevelAstro, SSRResult } from '../../@types/astro-runtime';
|
||||
import type { AstroGlobal, TopLevelAstro, SSRResult, SSRElement } from '../../@types/astro-runtime';
|
||||
import type { LogOptions } from '../logger';
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
|
@ -118,8 +118,8 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
|
|||
// This object starts here as an empty shell (not yet the result) but then
|
||||
// calling the render() function will populate the object with scripts, styles, etc.
|
||||
const result: SSRResult = {
|
||||
styles: new Set(),
|
||||
scripts: new Set(),
|
||||
styles: new Set<SSRElement>(),
|
||||
scripts: new Set<SSRElement>(),
|
||||
/** This function returns the `Astro` faux-global */
|
||||
createAstro(astroGlobal: TopLevelAstro, props: Record<string, any>, slots: Record<string, any> | null) {
|
||||
const site = new URL(origin);
|
||||
|
@ -193,3 +193,4 @@ ${frame}
|
|||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { AstroComponentMetadata, Renderer } from '../../@types/astro-core';
|
||||
import type { SSRResult } from '../../@types/astro-runtime';
|
||||
import type { SSRResult, SSRElement } from '../../@types/astro-runtime';
|
||||
import type { TopLevelAstro } from '../../@types/astro-runtime';
|
||||
|
||||
import { valueToEstree } from 'estree-util-value-to-estree';
|
||||
|
@ -147,7 +147,7 @@ interface HydrateScriptOptions {
|
|||
}
|
||||
|
||||
/** For hydrated components, generate a <script type="module"> to load the component */
|
||||
async function generateHydrateScript(scriptOptions: HydrateScriptOptions, metadata: Required<AstroComponentMetadata>) {
|
||||
async function generateHydrateScript(scriptOptions: HydrateScriptOptions, metadata: Required<AstroComponentMetadata>): Promise<SSRElement> {
|
||||
const { renderer, astroId, props } = scriptOptions;
|
||||
const { hydrate, componentUrl, componentExport } = metadata;
|
||||
|
||||
|
@ -168,13 +168,14 @@ async function generateHydrateScript(scriptOptions: HydrateScriptOptions, metada
|
|||
return () => {};
|
||||
`;
|
||||
|
||||
const hydrationScript = `<script type="module">
|
||||
import setup from 'astro/client/${hydrate}.js';
|
||||
const hydrationScript = {
|
||||
props: { type: 'module' },
|
||||
children: `import setup from 'astro/client/${hydrate}.js';
|
||||
setup("${astroId}", {${metadata.hydrateArgs ? `value: ${JSON.stringify(metadata.hydrateArgs)}` : ''}}, async () => {
|
||||
${hydrationSource}
|
||||
});
|
||||
</script>
|
||||
`;
|
||||
`,
|
||||
};
|
||||
|
||||
return hydrationScript;
|
||||
}
|
||||
|
@ -354,16 +355,23 @@ export function defineScriptVars(vars: Record<any, any>) {
|
|||
return output;
|
||||
}
|
||||
|
||||
export async function renderToString(result: any, componentFactory: AstroComponentFactory, props: any, children: any) {
|
||||
export async function renderToString(result: SSRResult, componentFactory: AstroComponentFactory, props: any, children: any) {
|
||||
const Component = await componentFactory(result, props, children);
|
||||
let template = await renderAstroComponent(Component);
|
||||
return template;
|
||||
}
|
||||
|
||||
export async function renderPage(result: any, Component: AstroComponentFactory, props: any, children: any) {
|
||||
// Filter out duplicate elements in our set
|
||||
const uniqueElements = (item: any, index: number, all: any[]) => {
|
||||
const props = JSON.stringify(item.props);
|
||||
const children = item.children;
|
||||
return index === all.findIndex(i => JSON.stringify(i.props) === props && i.children == children)
|
||||
}
|
||||
|
||||
export async function renderPage(result: SSRResult, Component: AstroComponentFactory, props: any, children: any) {
|
||||
const template = await renderToString(result, Component, props, children);
|
||||
const styles = Array.from(result.styles).map((style: any) => renderElement('style', style));
|
||||
const scripts = Array.from(result.scripts);
|
||||
const styles = Array.from(result.styles).filter(uniqueElements).map((style) => renderElement('style', style));
|
||||
const scripts = Array.from(result.scripts).filter(uniqueElements).map((script) => renderElement('script', script));
|
||||
return template.replace('</head>', styles.join('\n') + scripts.join('\n') + '</head>');
|
||||
}
|
||||
|
||||
|
@ -379,18 +387,20 @@ export async function renderAstroComponent(component: InstanceType<typeof AstroC
|
|||
return template;
|
||||
}
|
||||
|
||||
function renderElement(name: string, { props: _props, children = '' }: { props: Record<any, any>; children?: string }) {
|
||||
function renderElement(name: string, { props: _props, children = '' }: SSRElement) {
|
||||
// Do not print `hoist`, `lang`, `global`
|
||||
const { hoist: _0, lang: _1, global = false, 'data-astro-id': astroId, 'define:vars': defineVars, ...props } = _props;
|
||||
const { lang: _, 'data-astro-id': astroId, 'define:vars': defineVars, ...props } = _props;
|
||||
if (defineVars) {
|
||||
if (name === 'style') {
|
||||
if (global) {
|
||||
if (props.global) {
|
||||
children = defineStyleVars(`:root`, defineVars) + '\n' + children;
|
||||
} else {
|
||||
children = defineStyleVars(`.astro-${astroId}`, defineVars) + '\n' + children;
|
||||
}
|
||||
delete props.global;
|
||||
}
|
||||
if (name === 'script') {
|
||||
delete props.hoist;
|
||||
children = defineScriptVars(defineVars) + '\n' + children;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue