diff --git a/proposals/partials.md b/proposals/partials.md new file mode 100644 index 00000000..dd721501 --- /dev/null +++ b/proposals/partials.md @@ -0,0 +1,119 @@ +- Start Date: 2023-10-03 +- Reference Issues: https://github.com/withastro/roadmap/issues/697 +- Implementation PR: + +# Summary + +Provide a configuration flag for page components to opt-in to *partial* behavior, preventing head injection of scripts and styles, and the doctype. + +# Example + +In any component inside of the __pages__ directory set the `partial` option: + +```astro +--- +export const partial = true; +--- + +
This is a partial!
+``` + +This will produce this exactly HTML output: + +```html +
This is a partial!
+``` + +Both head content and the `` are omitted, unlike in non-partial pages. + +# Background & Motivation + +Partials are a technique that has been used by web applications for decades, popularized in frameworks such as Ruby on Rails. Frontend oriented JavaScript frameworks have typically not used partials, but instead use JSON APIs and front-end templating in order to dynamically change parts of the page. Nevertheless, partials have remained a niche feature, and with Astro's backend focus we have had interest in support for a long time. + +Recently the popularity of projects like [htmx](https://htmx.org/) and [Unpoly](https://unpoly.com/) have revived interest in this technique. Since Astro treats each page request as a request for a full page it automatically attaches the doctype and head elements, making it difficult to simply inject into the page. + +# Goals + +- The ability to request a URL from Astro that excludes the usual page elements (doctype, head injection). +- The base feature should work the same in SSG and SSR apps. Partials are still output as `.html` files in a static build. + +# Non-Goals + +- This isn't an integration specifically for HTMX or any one library. It should work with any library or manual DOM manipulation that does `innerHTML`. +- No client-side scripts from Astro will be part of this change. +- Support for integrations or middleware at this time. It could be possible to allow middleware to communicate that a request is for a partial, but that is not part of this RFC. + +# Detailed Design + +partials are opted into on a per-page basis. Any page within the `pages` directory can become a partial through this config: + +```astro +--- +export const partial = true; +--- +``` + +This value must be either: + +- A literal boolean of `true` or `false` (there's no reason to every use false). +- A configuration value from `import.meta` such as: + + ```astro + --- + export const partial = import.meta.env.USE_partialS; + --- + ``` + +The value *must* be identified statically. This means that a page can't be both a full page and a partial. If you want to share the same logic and template for a partial and partial you can do so by putting the common code into a component. + +## Implementation + +This is a very small change. Internally Astro uses an object known as a `result` that stores intoformation about a request. That result object will add a `partial` property: + +```ts +interface AstroResult { + partial: boolean; +} +``` + +When rendering the partial value is taken from the __component module__ and placed on the result object. + +This boolean is then used in two places: + +- In head injection it will be used to prevent head injection. +- In page rendering it will be used to prevent doctype prepending. + +These are the only changes needed. + +# Testing Strategy + +We want to verify that partials do not include head content with tests for: + +- A component that contains `