summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2023-10-26 10:14:10 -0400
committerGravatar GitHub <noreply@github.com> 2023-10-26 10:14:10 -0400
commitfe4079f05ba21c0f3a167f8e3f55eff705506bd2 (patch)
tree5cbbe39c80a5df4e9c18cc78077763cb32fc84d2
parentec7f53168273e040119341c8e3bbdf1571bccfa0 (diff)
downloadastro-fe4079f05ba21c0f3a167f8e3f55eff705506bd2.tar.gz
astro-fe4079f05ba21c0f3a167f8e3f55eff705506bd2.tar.zst
astro-fe4079f05ba21c0f3a167f8e3f55eff705506bd2.zip
Partials (#8755)
* Fragment support * Add a changeset * Linting * debuggin * Rename to partial * Update the chagneset * Make work with mdx * Update .changeset/brave-pots-drop.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update .changeset/brave-pots-drop.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update .changeset/brave-pots-drop.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> --------- Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
-rw-r--r--.changeset/brave-pots-drop.md24
-rw-r--r--packages/astro/src/@types/astro.ts2
-rw-r--r--packages/astro/src/core/render/core.ts1
-rw-r--r--packages/astro/src/core/render/result.ts2
-rw-r--r--packages/astro/src/runtime/server/render/astro/render.ts4
-rw-r--r--packages/astro/src/runtime/server/render/common.ts4
-rw-r--r--packages/astro/src/runtime/server/render/component.ts2
-rw-r--r--packages/astro/test/fixtures/partials/astro.config.mjs9
-rw-r--r--packages/astro/test/fixtures/partials/package.json9
-rw-r--r--packages/astro/test/fixtures/partials/src/pages/partials/docs.mdx5
-rw-r--r--packages/astro/test/fixtures/partials/src/pages/partials/item.astro4
-rw-r--r--packages/astro/test/partials.test.js47
-rw-r--r--pnpm-lock.yaml9
13 files changed, 117 insertions, 5 deletions
diff --git a/.changeset/brave-pots-drop.md b/.changeset/brave-pots-drop.md
new file mode 100644
index 000000000..54de40497
--- /dev/null
+++ b/.changeset/brave-pots-drop.md
@@ -0,0 +1,24 @@
+---
+'astro': minor
+---
+
+Page Partials
+
+A page component can now be identified as a **partial** page, which will render its HTML content without including a `<! DOCTYPE html>` declaration nor any `<head>` content.
+
+A rendering library, like htmx or Stimulus or even just jQuery can access partial content on the client to dynamically update only parts of a page.
+
+Pages marked as partials do not have a `doctype` or any head content included in the rendered result. You can mark any page as a partial by setting this option:
+
+
+```astro
+---
+export const partial = true;
+---
+
+<li>This is a single list item.</li>
+```
+
+Other valid page files that can export a value (e.g. `.mdx`) can also be marked as partials.
+
+Read more about [Astro page partials](/en/core-concepts/astro-pages/#partials) in our documentation.
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 1bcbe20a9..778e5b739 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -1562,6 +1562,7 @@ export type AsyncRendererComponentFn<U> = (
export interface ComponentInstance {
default: AstroComponentFactory;
css?: string[];
+ partial?: boolean;
prerender?: boolean;
/**
* Only used for logging if deprecated drafts feature is used
@@ -2234,6 +2235,7 @@ export interface SSRResult {
*/
clientDirectives: Map<string, string>;
compressHTML: boolean;
+ partial: boolean;
/**
* Only used for logging
*/
diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts
index d8c39ec1a..f8889f47d 100644
--- a/packages/astro/src/core/render/core.ts
+++ b/packages/astro/src/core/render/core.ts
@@ -49,6 +49,7 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag
clientDirectives: env.clientDirectives,
compressHTML: env.compressHTML,
request: renderContext.request,
+ partial: !!mod.partial,
site: env.site,
scripts: renderContext.scripts,
ssr: env.ssr,
diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts
index 6f8ca9303..b96628a5f 100644
--- a/packages/astro/src/core/render/result.ts
+++ b/packages/astro/src/core/render/result.ts
@@ -31,6 +31,7 @@ export interface CreateResultArgs {
renderers: SSRLoadedRenderer[];
clientDirectives: Map<string, string>;
compressHTML: boolean;
+ partial: boolean;
resolve: (s: string) => Promise<string>;
/**
* Used for `Astro.site`
@@ -155,6 +156,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
renderers: args.renderers,
clientDirectives: args.clientDirectives,
compressHTML: args.compressHTML,
+ partial: args.partial,
pathname: args.pathname,
cookies,
/** This function returns the `Astro` faux-global */
diff --git a/packages/astro/src/runtime/server/render/astro/render.ts b/packages/astro/src/runtime/server/render/astro/render.ts
index 7091513c7..3b7cdc052 100644
--- a/packages/astro/src/runtime/server/render/astro/render.ts
+++ b/packages/astro/src/runtime/server/render/astro/render.ts
@@ -33,7 +33,7 @@ export async function renderToString(
// Automatic doctype insertion for pages
if (isPage && !renderedFirstPageChunk) {
renderedFirstPageChunk = true;
- if (!/<!doctype html/i.test(String(chunk))) {
+ if (!result.partial && !/<!doctype html/i.test(String(chunk))) {
const doctype = result.compressHTML ? '<!DOCTYPE html>' : '<!DOCTYPE html>\n';
str += doctype;
}
@@ -84,7 +84,7 @@ export async function renderToReadableStream(
// Automatic doctype insertion for pages
if (isPage && !renderedFirstPageChunk) {
renderedFirstPageChunk = true;
- if (!/<!doctype html/i.test(String(chunk))) {
+ if (!result.partial && !/<!doctype html/i.test(String(chunk))) {
const doctype = result.compressHTML ? '<!DOCTYPE html>' : '<!DOCTYPE html>\n';
controller.enqueue(encoder.encode(doctype));
}
diff --git a/packages/astro/src/runtime/server/render/common.ts b/packages/astro/src/runtime/server/render/common.ts
index 03e9c8308..e5a5d5e86 100644
--- a/packages/astro/src/runtime/server/render/common.ts
+++ b/packages/astro/src/runtime/server/render/common.ts
@@ -77,13 +77,13 @@ function stringifyChunk(
}
}
case 'head': {
- if (result._metadata.hasRenderedHead) {
+ if (result._metadata.hasRenderedHead || result.partial) {
return '';
}
return renderAllHeadContent(result);
}
case 'maybe-head': {
- if (result._metadata.hasRenderedHead || result._metadata.headInTree) {
+ if (result._metadata.hasRenderedHead || result._metadata.headInTree || result.partial) {
return '';
}
return renderAllHeadContent(result);
diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts
index 002f4ebaf..a82b50ff8 100644
--- a/packages/astro/src/runtime/server/render/component.ts
+++ b/packages/astro/src/runtime/server/render/component.ts
@@ -505,7 +505,7 @@ export async function renderComponentToString(
// Automatic doctype and head insertion for pages
if (isPage && !renderedFirstPageChunk) {
renderedFirstPageChunk = true;
- if (!/<!doctype html/i.test(String(chunk))) {
+ if (!result.partial && !/<!doctype html/i.test(String(chunk))) {
const doctype = result.compressHTML ? '<!DOCTYPE html>' : '<!DOCTYPE html>\n';
str += doctype + head;
}
diff --git a/packages/astro/test/fixtures/partials/astro.config.mjs b/packages/astro/test/fixtures/partials/astro.config.mjs
new file mode 100644
index 000000000..b4dfec3ce
--- /dev/null
+++ b/packages/astro/test/fixtures/partials/astro.config.mjs
@@ -0,0 +1,9 @@
+import { defineConfig } from 'astro/config';
+import mdx from '@astrojs/mdx';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [
+ mdx()
+ ]
+});
diff --git a/packages/astro/test/fixtures/partials/package.json b/packages/astro/test/fixtures/partials/package.json
new file mode 100644
index 000000000..347a68803
--- /dev/null
+++ b/packages/astro/test/fixtures/partials/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@test/partials",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "astro": "workspace:*",
+ "@astrojs/mdx": "workspace:*"
+ }
+}
diff --git a/packages/astro/test/fixtures/partials/src/pages/partials/docs.mdx b/packages/astro/test/fixtures/partials/src/pages/partials/docs.mdx
new file mode 100644
index 000000000..7d7850885
--- /dev/null
+++ b/packages/astro/test/fixtures/partials/src/pages/partials/docs.mdx
@@ -0,0 +1,5 @@
+export const partial = true;
+
+# This is heading
+
+and this is some text
diff --git a/packages/astro/test/fixtures/partials/src/pages/partials/item.astro b/packages/astro/test/fixtures/partials/src/pages/partials/item.astro
new file mode 100644
index 000000000..500e7c98b
--- /dev/null
+++ b/packages/astro/test/fixtures/partials/src/pages/partials/item.astro
@@ -0,0 +1,4 @@
+---
+export const partial = true;
+---
+<li>This is a single line item</li>
diff --git a/packages/astro/test/partials.test.js b/packages/astro/test/partials.test.js
new file mode 100644
index 000000000..6f1b50938
--- /dev/null
+++ b/packages/astro/test/partials.test.js
@@ -0,0 +1,47 @@
+import { expect } from 'chai';
+import { loadFixture } from './test-utils.js';
+
+describe('Partials', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/partials/',
+ });
+ });
+
+ describe('dev', () => {
+ /** @type {import('./test-utils.js').DevServer} */
+ let devServer;
+
+ before(async () => {
+ devServer = await fixture.startDevServer();
+ });
+
+ after(async () => {
+ await devServer.stop();
+ });
+
+ it('is only the written HTML', async () => {
+ const html = await fixture.fetch('/partials/item/').then((res) => res.text());
+ expect(html.startsWith('<li>')).to.equal(true);
+ });
+ });
+
+ describe('build', () => {
+ before(async () => {
+ await fixture.build();
+ });
+
+ it('is only the written HTML', async () => {
+ const html = await fixture.readFile('/partials/item/index.html');
+ expect(html.startsWith('<li>')).to.equal(true);
+ });
+
+ it('Works with mdx', async () => {
+ const html = await fixture.readFile('/partials/docs/index.html');
+ expect(html.startsWith('<h1')).to.equal(true);
+ });
+ });
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 125eae2b5..c023f9ce4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2967,6 +2967,15 @@ importers:
specifier: workspace:*
version: link:../../..
+ packages/astro/test/fixtures/partials:
+ dependencies:
+ '@astrojs/mdx':
+ specifier: workspace:*
+ version: link:../../../../integrations/mdx
+ astro:
+ specifier: workspace:*
+ version: link:../../..
+
packages/astro/test/fixtures/postcss:
dependencies:
'@astrojs/solid-js':