Compare commits

...

3 commits

Author SHA1 Message Date
Matthew Phillips
8d94f5c94e Add the changeset 2021-08-03 10:11:41 -04:00
Matthew Phillips
5e568571f0 Completely fixes head/doctype stuff 2021-08-03 10:10:47 -04:00
Matthew Phillips
b2075cc137 Adds a changeset 2021-08-03 10:04:18 -04:00
9 changed files with 84 additions and 48 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes issue with head content being rendered in the wrong place

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes issue with head content being put into the wrong place

View file

@ -146,8 +146,8 @@ async function __render(props, ...children) {
value: props,
enumerable: true
},
css: {
value: (props[__astroInternal] && props[__astroInternal].css) || [],
pageCSS: {
value: (props[__astroContext] && props[__astroContext].pageCSS) || [],
enumerable: true
},
isPage: {
@ -177,6 +177,7 @@ export async function __renderPage({request, children, props, css}) {
Object.defineProperty(props, __astroContext, {
value: {
pageCSS: css,
request
},
writable: false,
@ -185,7 +186,6 @@ export async function __renderPage({request, children, props, css}) {
Object.defineProperty(props, __astroInternal, {
value: {
css,
isPage: true
},
writable: false,

View file

@ -73,7 +73,7 @@ export default function (opts: TransformOptions): Transformer {
start: 0,
end: 0,
type: 'Expression',
codeChunks: ['Astro.css.map(css => (', '))'],
codeChunks: ['Astro.pageCSS.map(css => (', '))'],
children: [
{
type: 'Element',
@ -162,22 +162,15 @@ export default function (opts: TransformOptions): Transformer {
);
}
const conditionalNode = {
start: 0,
end: 0,
type: 'Expression',
codeChunks: ['Astro.isPage ? (', ') : null'],
children: [
{
start: 0,
end: 0,
type: 'Fragment',
children,
},
],
};
eoh.append(conditionalNode);
if(eoh.foundHeadOrHtmlElement) {
const topLevelFragment = {
start: 0,
end: 0,
type: 'Fragment',
children,
};
eoh.append(topLevelFragment);
}
},
};
}

View file

@ -1,12 +1,15 @@
import type { TemplateNode } from '@astrojs/parser';
const beforeHeadElements = new Set(['!doctype', 'html']);
const validHeadElements = new Set(['!doctype', 'title', 'meta', 'link', 'style', 'script', 'noscript', 'base']);
export class EndOfHead {
private html: TemplateNode | null = null;
private head: TemplateNode | null = null;
private firstNonHead: TemplateNode | null = null;
private parent: TemplateNode | null = null;
private stack: TemplateNode[] = [];
private foundHeadElements: boolean = false;
public append: (...node: TemplateNode[]) => void = () => void 0;
@ -14,6 +17,14 @@ export class EndOfHead {
return !!(this.head || this.firstNonHead);
}
get foundHeadContent(): boolean {
return !!this.head || this.foundHeadElements;
}
get foundHeadOrHtmlElement(): boolean {
return !!(this.html || this.head);
}
enter(node: TemplateNode) {
if (this.found) {
return;
@ -35,6 +46,14 @@ export class EndOfHead {
return;
}
// Skip !doctype and html elements
if(beforeHeadElements.has(name)) {
if(name === 'html') {
this.html = node;
}
return;
}
if (!validHeadElements.has(name)) {
this.firstNonHead = node;
this.parent = this.stack[this.stack.length - 2];

View file

@ -1,36 +1,11 @@
import { fileURLToPath } from 'url';
import { suite } from 'uvu';
import * as assert from 'uvu/assert';
import { loadConfig } from '#astro/config';
import { createRuntime } from '#astro/runtime';
import { doc } from './test-utils.js';
import { setup } from './helpers.js';
const DType = suite('doctype');
let runtime, setupError;
DType.before(async () => {
try {
const astroConfig = await loadConfig(fileURLToPath(new URL('./fixtures/astro-doctype', import.meta.url)));
const logging = {
level: 'error',
dest: process.stderr,
};
runtime = await createRuntime(astroConfig, { logging });
} catch (err) {
console.error(err);
setupError = err;
}
});
DType.after(async () => {
(await runtime) && runtime.shutdown();
});
DType('No errors creating a runtime', () => {
assert.equal(setupError, undefined);
});
setup(DType, './fixtures/astro-doctype');
DType('Automatically prepends the standards mode doctype', async () => {
const result = await runtime.load('/prepend');
@ -65,4 +40,23 @@ DType('User provided doctype is case insensitive', async () => {
assert.not.ok(html.includes('</!DOCTYPE>'), 'There should not be a closing tag');
});
DType('Doctype can be provided in a layout', async ({ runtime }) => {
const result = await runtime.load('/in-layout');
assert.ok(!result.error, `build error: ${result.error}`);
const html = result.contents.toString('utf-8');
assert.ok(html.startsWith('<!doctype html>'), 'doctype is at the front');
const $ = doc(html);
assert.equal($('head link').length, 1, 'A link inside of the head');
});
DType('Doctype is added in a layout without one', async ({ runtime }) => {
const result = await runtime.load('/in-layout-no-doctype');
assert.ok(!result.error, `build error: ${result.error}`);
const html = result.contents.toString('utf-8');
assert.ok(html.startsWith('<!doctype html>'), 'doctype is at the front');
});
DType.run();

View file

@ -0,0 +1,5 @@
---
import SubMeta from './SubMeta.astro';
---
<meta name="author" content="Astro Fan">
<SubMeta />

View file

@ -0,0 +1 @@
<meta name="keywords" content="JavaScript,Astro">

View file

@ -0,0 +1,14 @@
---
import '../styles/global.css';
import Meta from '../components/Meta.astro';
---
<!doctype html>
<html lang="en">
<head>
<title>My App</title>
<Meta />
</head>
<body>
</body>
</html>