diff options
author | 2023-10-26 10:14:10 -0400 | |
---|---|---|
committer | 2023-10-26 10:14:10 -0400 | |
commit | fe4079f05ba21c0f3a167f8e3f55eff705506bd2 (patch) | |
tree | 5cbbe39c80a5df4e9c18cc78077763cb32fc84d2 | |
parent | ec7f53168273e040119341c8e3bbdf1571bccfa0 (diff) | |
download | astro-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.md | 24 | ||||
-rw-r--r-- | packages/astro/src/@types/astro.ts | 2 | ||||
-rw-r--r-- | packages/astro/src/core/render/core.ts | 1 | ||||
-rw-r--r-- | packages/astro/src/core/render/result.ts | 2 | ||||
-rw-r--r-- | packages/astro/src/runtime/server/render/astro/render.ts | 4 | ||||
-rw-r--r-- | packages/astro/src/runtime/server/render/common.ts | 4 | ||||
-rw-r--r-- | packages/astro/src/runtime/server/render/component.ts | 2 | ||||
-rw-r--r-- | packages/astro/test/fixtures/partials/astro.config.mjs | 9 | ||||
-rw-r--r-- | packages/astro/test/fixtures/partials/package.json | 9 | ||||
-rw-r--r-- | packages/astro/test/fixtures/partials/src/pages/partials/docs.mdx | 5 | ||||
-rw-r--r-- | packages/astro/test/fixtures/partials/src/pages/partials/item.astro | 4 | ||||
-rw-r--r-- | packages/astro/test/partials.test.js | 47 | ||||
-rw-r--r-- | pnpm-lock.yaml | 9 |
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': |