diff --git a/.changeset/twelve-lions-tie.md b/.changeset/twelve-lions-tie.md
new file mode 100644
index 0000000000..2010637cab
--- /dev/null
+++ b/.changeset/twelve-lions-tie.md
@@ -0,0 +1,14 @@
+---
+'astro': patch
+---
+
+Add support for components defined in Frontmatter. Previously, the following code would throw an error. Now it is officially supported!
+
+```astro
+---
+const { level = 1 } = Astro.props;
+const Element = `h${level}`;
+---
+
+Hello world!
+```
diff --git a/packages/astro/src/compiler/transform/head.ts b/packages/astro/src/compiler/transform/head.ts
index 94105a03fd..99ba47c87e 100644
--- a/packages/astro/src/compiler/transform/head.ts
+++ b/packages/astro/src/compiler/transform/head.ts
@@ -24,7 +24,8 @@ export default function (opts: TransformOptions): Transformer {
if (hasComponents) {
return;
}
-
+ // Initialize eoh if there are no elements
+ eoh.enter(node);
if (node.attributes && node.attributes.some(({ name }: any) => name.startsWith('client:'))) {
hasComponents = true;
return;
@@ -36,6 +37,9 @@ export default function (opts: TransformOptions): Transformer {
hasComponents = true;
}
},
+ leave(node) {
+ eoh.leave(node);
+ },
},
Element: {
enter(node) {
diff --git a/packages/astro/test/astro-hmr.test.js b/packages/astro/test/astro-hmr.test.js
index 2d295c0b7e..1189c1f9bd 100644
--- a/packages/astro/test/astro-hmr.test.js
+++ b/packages/astro/test/astro-hmr.test.js
@@ -39,4 +39,14 @@ HMR('Adds script to static pages too', async ({ runtime }) => {
assert.ok(/window\.HMR_WEBSOCKET_PORT/.test(html), 'websocket port added');
});
+HMR('Adds script to pages even if there aren\'t any elements in the template', async ({ runtime }) => {
+ const result = await runtime.load('/no-elements');
+ if (result.error) throw new Error(result.error);
+
+ const html = result.contents;
+ const $ = doc(html);
+ assert.equal($('[src="/_snowpack/hmr-client.js"]').length, 1);
+ assert.ok(/window\.HMR_WEBSOCKET_PORT/.test(html), 'websocket port added');
+});
+
HMR.run();
diff --git a/packages/astro/test/fixtures/astro-hmr/src/components/Demo.astro b/packages/astro/test/fixtures/astro-hmr/src/components/Demo.astro
new file mode 100644
index 0000000000..8772ee9031
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-hmr/src/components/Demo.astro
@@ -0,0 +1,8 @@
+
+
+ My Test
+
+
+ Hello world
+
+
diff --git a/packages/astro/test/fixtures/astro-hmr/src/pages/no-elements.astro b/packages/astro/test/fixtures/astro-hmr/src/pages/no-elements.astro
new file mode 100644
index 0000000000..02bbe60d6e
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-hmr/src/pages/no-elements.astro
@@ -0,0 +1,4 @@
+---
+import Demo from '../components/Demo.astro';
+---
+
diff --git a/packages/astro/test/fixtures/no-head-el/src/pages/no-elements.astro b/packages/astro/test/fixtures/no-head-el/src/pages/no-elements.astro
new file mode 100644
index 0000000000..c4266514f5
--- /dev/null
+++ b/packages/astro/test/fixtures/no-head-el/src/pages/no-elements.astro
@@ -0,0 +1,6 @@
+---
+import Something from '../components/Something.jsx';
+import Child from '../components/Child.astro';
+---
+
+
diff --git a/packages/astro/test/no-head-el.test.js b/packages/astro/test/no-head-el.test.js
index 2ecc405319..749acd975f 100644
--- a/packages/astro/test/no-head-el.test.js
+++ b/packages/astro/test/no-head-el.test.js
@@ -25,4 +25,14 @@ NoHeadEl('Places style and scripts before the first non-head element', async ({
assert.equal($('script[src="/_snowpack/hmr-client.js"]').length, 1, 'Only the hmr client for the page');
});
+NoHeadEl('Injects HMR script even when there are no elements on the page', async ({ runtime }) => {
+ const result = await runtime.load('/no-elements');
+ if (result.error) throw new Error(result.error);
+
+ const html = result.contents;
+ const $ = doc(html);
+
+ assert.equal($('script[src="/_snowpack/hmr-client.js"]').length, 1, 'Only the hmr client for the page');
+});
+
NoHeadEl.run();