Add display: contents for hydrated components (#1794)
* Add display: contents for hydrated components * Only serialize boolean attrs that are data attrs * Adds a changeset
This commit is contained in:
parent
83be55d5dd
commit
b958088c3d
7 changed files with 42 additions and 9 deletions
5
.changeset/dull-steaks-dance.md
Normal file
5
.changeset/dull-steaks-dance.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Make astro-root be a display: contents element
|
|
@ -112,7 +112,7 @@ export async function generateHydrateScript(scriptOptions: HydrateScriptOptions,
|
|||
`;
|
||||
|
||||
const hydrationScript = {
|
||||
props: { type: 'module' },
|
||||
props: { type: 'module', 'data-astro-component-hydration': true },
|
||||
children: `import setup from 'astro/client/${hydrate}.js';
|
||||
setup("${astroId}", {${metadata.hydrateArgs ? `value: ${JSON.stringify(metadata.hydrateArgs)}` : ''}}, async () => {
|
||||
${hydrationSource}
|
||||
|
|
|
@ -222,7 +222,12 @@ export function addAttribute(value: any, key: string) {
|
|||
return ` ${key.slice(0, -5)}="${toAttributeString(serializeListValue(value))}"`;
|
||||
}
|
||||
|
||||
return ` ${key}="${toAttributeString(value)}"`;
|
||||
// Boolean only needs the key
|
||||
if(value === true && key.startsWith('data-')) {
|
||||
return ` ${key}`;
|
||||
} else {
|
||||
return ` ${key}="${toAttributeString(value)}"`;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds support for `<Component {...value} />
|
||||
|
@ -278,14 +283,21 @@ export async function renderPage(result: SSRResult, Component: AstroComponentFac
|
|||
props: { ...style.props, 'astro-style': true },
|
||||
})
|
||||
);
|
||||
let needsHydrationStyles = false;
|
||||
const scripts = Array.from(result.scripts)
|
||||
.filter(uniqueElements)
|
||||
.map((script, i) =>
|
||||
renderElement('script', {
|
||||
.map((script, i) => {
|
||||
if('data-astro-component-hydration' in script.props) {
|
||||
needsHydrationStyles = true;
|
||||
}
|
||||
return renderElement('script', {
|
||||
...script,
|
||||
props: { ...script.props, 'astro-script': result._metadata.pathname + '/script-' + i },
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
if(needsHydrationStyles) {
|
||||
styles.push(renderElement('style', { props: { 'astro-style': true },children: 'astro-root, astro-fragment { display: contents; }' }))
|
||||
}
|
||||
return template.replace('</head>', styles.join('\n') + scripts.join('\n') + '</head>');
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import parse5 from 'parse5';
|
|||
import srcsetParse from 'srcset-parse';
|
||||
import * as npath from 'path';
|
||||
import { promises as fs } from 'fs';
|
||||
import { getAttribute, getTagName, insertBefore, remove, createScript, createElement, setAttribute } from '@web/parse5-utils';
|
||||
import { getAttribute, hasAttribute, getTagName, insertBefore, remove, createScript, createElement, setAttribute } from '@web/parse5-utils';
|
||||
import { addRollupInput } from './add-rollup-input.js';
|
||||
import { findAssets, findInlineScripts, findInlineStyles, getTextContent, isStylesheetLink } from './extract-assets.js';
|
||||
import { render as ssrRender } from '../core/ssr/index.js';
|
||||
|
@ -109,7 +109,7 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
|||
|
||||
let styles = '';
|
||||
for (const node of findInlineStyles(document)) {
|
||||
if (getAttribute(node, 'astro-style')) {
|
||||
if (hasAttribute(node, 'astro-style')) {
|
||||
styles += getTextContent(node);
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
|||
|
||||
// Page styles for <style> usage, if not already appended via links.
|
||||
for (const style of findInlineStyles(document)) {
|
||||
if (getAttribute(style, 'astro-style')) {
|
||||
if (hasAttribute(style, 'astro-style')) {
|
||||
if (!pageCSSAdded) {
|
||||
pageCSSAdded = appendStyleChunksBefore(style, pathname, cssChunkMap.get(styleId));
|
||||
}
|
||||
|
|
|
@ -125,4 +125,13 @@ describe('Styles SSR', () => {
|
|||
|
||||
expect($('#passed-in').attr('class')).to.match(/outer astro-[A-Z0-9]+ astro-[A-Z0-9]+/);
|
||||
});
|
||||
|
||||
it('Using hydrated components adds astro-root styles', async () => {
|
||||
const html = await fixture.readFile('/index.html');
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
const href = '/' + $('link').attr('href');
|
||||
const css = await fixture.readFile(href);
|
||||
expect(css).to.include('display: contents;');
|
||||
});
|
||||
});
|
||||
|
|
5
packages/astro/test/fixtures/astro-styles-ssr/src/components/ReactDynamic.jsx
vendored
Normal file
5
packages/astro/test/fixtures/astro-styles-ssr/src/components/ReactDynamic.jsx
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function() {
|
||||
return <div></div>;
|
||||
}
|
|
@ -7,6 +7,7 @@ import VueCSS from '../components/VueCSS.vue';
|
|||
import VueScoped from '../components/VueScoped.vue';
|
||||
import VueModules from '../components/VueModules.vue';
|
||||
import SvelteScoped from '../components/SvelteScoped.svelte';
|
||||
import ReactDynamic from '../components/ReactDynamic.jsx';
|
||||
---
|
||||
|
||||
<html>
|
||||
|
@ -33,6 +34,7 @@ import SvelteScoped from '../components/SvelteScoped.svelte';
|
|||
<VueScoped />
|
||||
<VueModules />
|
||||
<SvelteScoped />
|
||||
<ReactDynamic client:load />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue