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:
Matthew Phillips 2021-11-11 11:55:50 -05:00 committed by GitHub
parent 83be55d5dd
commit b958088c3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 42 additions and 9 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Make astro-root be a display: contents element

View file

@ -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}

View file

@ -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>');
}

View file

@ -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));
}

View file

@ -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;');
});
});

View file

@ -0,0 +1,5 @@
import React from 'react';
export default function() {
return <div></div>;
}

View file

@ -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>