summaryrefslogtreecommitdiff
path: root/docs/core-concepts
diff options
context:
space:
mode:
authorGravatar Fred K. Schott <fkschott@gmail.com> 2021-07-14 13:41:51 -0400
committerGravatar GitHub <noreply@github.com> 2021-07-14 13:41:51 -0400
commitd40edb0b673f380c9eb9c07add3e0cd2371d9623 (patch)
tree0ec0d3487ac15cb609402f2f4f7e9c6fd5a6227b /docs/core-concepts
parentd07f3d4186ee0ffe5acb74ebc76c15a5611268fa (diff)
downloadastro-d40edb0b673f380c9eb9c07add3e0cd2371d9623.tar.gz
astro-d40edb0b673f380c9eb9c07add3e0cd2371d9623.tar.zst
astro-d40edb0b673f380c9eb9c07add3e0cd2371d9623.zip
Docs sync (#680)
* test ignoring examples from workspace * docs sync
Diffstat (limited to 'docs/core-concepts')
-rw-r--r--docs/core-concepts/astro-components.md288
-rw-r--r--docs/core-concepts/astro-pages.md52
-rw-r--r--docs/core-concepts/collections.md24
-rw-r--r--docs/core-concepts/component-hydration.md84
-rw-r--r--docs/core-concepts/layouts.md17
-rw-r--r--docs/core-concepts/project-structure.md25
-rw-r--r--docs/core-concepts/ui-renderers.md205
7 files changed, 314 insertions, 381 deletions
diff --git a/docs/core-concepts/astro-components.md b/docs/core-concepts/astro-components.md
index bd0052354..701a27466 100644
--- a/docs/core-concepts/astro-components.md
+++ b/docs/core-concepts/astro-components.md
@@ -3,129 +3,185 @@ layout: ~/layouts/Main.astro
title: Astro Components
---
-## ✨ `.astro` Syntax
+**Astro Components** (files ending with `.astro`) are the foundation of server-side templating in Astro. Think of the Astro component syntax as HTML enhanced with JavaScript.
-Astro comes with its own server-side, component-based templating language. Think of it as HTML enhanced with the full power of JavaScript.
+Learning a new syntax can feel intimidating, so we carefully designed the Astro component syntax to feel as familiar to web developers as possible. It borrows heavily from patterns you likely already know: components, frontmatter, props, and JSX expressions. We're confident that this guide will have you writing Astro components in no time, especially if you are already familiar with HTML & JavaScript.
-Learning a new syntax can be intimidating, but the `.astro` format has been carefully designed with familiarity in mind. It borrows heavily from patterns you likely already know—components, Frontmatter, and JSX-like expressions. We're confident that this guide will help you feel comfortable writing `.astro` files in no time.
+## Syntax Overview
----
+A single `.astro` file represents a single Astro component in your project. This pattern is known as a **Single-File Component (SFC)**. Both Svelte (`.svelte`) and Vue (`.vue`) also follow this pattern.
+
+Below is a walk-through of the different pieces and features of the Astro component syntax. You can read it start-to-finish, or jump between sections.
+
+### HTML Template
+
+Astro component syntax is a superset of HTML. **If you know HTML, you already know enough to write your first Astro component.**
+
+For example, this three-line file is a valid Astro component:
+
+```html
+<!-- Example1.astro - Static HTML is a valid Astro component! -->
+<div class="example-1">
+ <h1>Hello world!</h1>
+</div>
+```
+
+An Astro component represents some snippet of HTML in your project. This can be a reusable component, or an entire page of HTML including `<html>`, `<head>` and `<body>` elements. See our guide on [Astro Pages](/guides/astro-pages) to learn how to build your first full HTML page with Astro.
+
+**Every Astro component must include an HTML template.** While you can enhance your component in several ways (see below) at the end of the day its the HTML template that dictates what your rendered Astro component will look like.
-### The `.astro` format
+### CSS Styles
-If you're already familiar with **HTML or JavaScript**, you'll likely feel comfortable with `.astro` files right away.
+CSS rules inside of a `<style>` tag are automatically scoped to that component. That means that you can reuse class names across multiple components, without worrying about conflicts. Styles are automatically extracted and optimized in the final build so that you don't need to worry about style loading.
-Think of `.astro` as **component-oriented HTML**. Components are reusable, self-contained blocks of HTML and CSS that belong together.
+For best results, you should only have one `<style>` tag per-Astro component. This isn’t necessarily a limitation, but it will often result in better-optimized CSS in your final build. When you're working with pages, the `<style>` tag can go nested inside of your page `<head>`. For standalone components, the `<style>` tag can go at the top-level of your template.
+
+
+```html
+<!-- Astro Component CSS example -->
+<style>
+ .circle {
+ background-color: red;
+ border-radius: 999px;
+ height: 50px;
+ width: 50px;
+ }
+<div class="circle"></div>
+```
```html
-<!-- This is a valid Astro component -->
-<html lang="en">
+<!-- Astro Page CSS example -->
+<html>
<head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Document</title>
+ <style>...</style>
</head>
- <body>
- <main>
- <h1>Hello world!</h1>
- </main>
- </body>
+ <body>...</body>
</html>
```
-```html
-<!-- This is also a valid Astro component! -->
-<main>
+Sass (an alternative to CSS) is also available via `<style lang="scss">`.
+
+📚 Read our full guide on [Component Styling](/guides/styling) to learn more.
+
+### Frontmatter Script
+
+To build a dynamic components, we introduce the idea of a frontmatter component script. [Frontmatter](https://jekyllrb.com/docs/front-matter/) is a common pattern in Markdown, where some config/metadata is contained inside a code fence (`---`) at the top of the file. Astro does something similar, but with full support for JavaScript & TypeScript in your components.
+
+Remember that Astro is a server-side templating language, so your component script will run during the build but only the HTML is rendered to the browser. To send JavaScript to the browser, you can use a `<script>` tag in your HTML template or [convert your component to use a frontend framework](/core-concepts/component-hydration) like React, Svelte, Vue, etc.
+
+```astro
+---
+// Anything inside the `---` code fence is your component script.
+// This JavaScript code runs at build-time.
+// See below to learn more about what you can do.
+console.log('This runs at build-time, is visible in the CLI output');
+// Tip: TypeScript is also supported out-of-the-box!
+const thisWorks: number = 42;
+---
+<div class="example-1">
<h1>Hello world!</h1>
-</main>
+</div>
```
-Developers have come up with a myriad of different techniques for composing blocks of HTML over the years, but far and away the most successful has been [JSX](https://reactjs.org/docs/introducing-jsx.html).
+### Component Imports
-We love JSX! In fact, `.astro` files borrow the highly-expressive expression syntax directly from JSX.
+An Astro component can reuse other Astro components inside of its HTML template. This becomes the foundation of our component system: build new components and then reuse them across your project.
-```jsx
-<!-- This is an Astro component with expressions! -->
-<main>
- <h1>Hello {name}!</h1>
- <ul>
- {items.map((item) => (
- <li>{item}</li>
- ))}
- </ul>
- <h2 data-hint={`Use JS template strings when you need to mix-in ${"variables"}.`}>So good!</h2>
-</main>
-```
+To use an Astro component in your template, you first need to import it in the frontmatter component script. An Astro component is always the file's default import.
-`.astro` files also borrow the concept of [Frontmatter](https://jekyllrb.com/docs/front-matter/) from Markdown. Instead of introducing a new HTML-oriented `import` and `export` syntax, `.astro` just uses JavaScript.
+Once imported, you can use it like any other HTML element in your template. Note that an Astro component **MUST** begin with an uppercase letter. Astro will use this to distinguish between native HTML elements (`form`, `input`, etc.) and your custom Astro components.
-```jsx
+```astro
---
-// This area is TypeScript (and therefore JavaScript)!
-import MyComponent from './MyComponent.astro'
+// Import your components in your component script...
+import SomeComponent from './SomeComponent.astro';
---
-
-<html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- </head>
- <body>
- <MyComponent></MyComponent>
- </body>
-</html>
+<!-- ... then use them in your HTML! -->
+<div>
+ <SomeComponent />
+</div>
```
-### Data and Props
+📚 You can also import and use components from other frontend frameworks like React, Svelte, and Vue. Read our guide on [Component Hydration](/core-concepts/component-hydration) to learn more.
+
+### Dynamic JSX Expressions
-`.astro` components can define local variables inside of the Frontmatter script. These are automatically exposed to the content below.
+Instead of inventing our own custom syntax for dynamic templating, we give you direct access to JavaScript values inside of your HTML, using something that feels just like [JSX](https://reactjs.org/docs/introducing-jsx.html).
-```jsx
+Astro components can define local variables inside of the Frontmatter script. Any script variables are then automatically available in the HTML template below.
+
+#### Dynamic Values
+
+```astro
+---
+const name = "Your name here";
+---
+<div>
+ <h1>Hello {name}!</h1>
+</div>
+```
+#### Dynamic Attributes
+
+```astro
---
-let name = 'world';
+const name = "Your name here";
---
+<div>
+ <div data-name={name}>Attribute expressions supported</div>
+ <div data-hint={`Use JS template strings to mix ${"variables"}.`}>So good!</div>
+</div>
+```
+
+#### Dynamic HTML
-<main>
- <h1>Hello {name}!</h1>
-</main>
+```astro
+---
+const items = ["Dog", "Cat", "Platipus"];
+---
+<ul>
+ {items.map((item) => (
+ <li>{item}</li>
+ ))}
+</ul>
```
-`.astro` components can also accept props when they are rendered. Public props are exposed on the `Astro.props` global.
-```jsx
+### Component Props
+
+An Astro component can define and accept props. Props are available on the `Astro.props` global in your frontmatter script.
+
+```astro
---
+// Example: <SomeComponent greeting="(Optional) Hello" name="Required Name" />
const { greeting = 'Hello', name } = Astro.props;
---
-
-<main>
- <h1>{greeting} {name}!</h1>
-</main>
+<div>
+ <h1>{greeting}, {name}!</h1>
+</div>
```
-To define the props which your component accepts, you may export a TypeScript interface or type named `Props`.
+You can define your props with TypeScript by exporting a `Props` type interface. In the future, Astro will automatically pick up any exported `Props` interface and give type warnings/errors for your project.
-```tsx
+```astro
---
+// Example: <SomeComponent /> (WARNING: "name" prop is required)
export interface Props {
name: string;
greeting?: string;
}
-
const { greeting = 'Hello', name } = Astro.props;
---
-
-<main>
- <h1>{greeting} {name}!</h1>
-</main>
+<div>
+ <h1>{greeting}, {name}!</h1>
+</div>
```
### Slots
-`.astro` files use the [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot) element to enable component composition. Coming from React, this is the same concept as `children`. You can think of the `<slot>` element as a placeholder for markup which will be passed from outside of the component.
+`.astro` files use the [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot) tag to enable component composition. Coming from React or Preact, this is the same concept as `children`. You can think of the `<slot>` element as a placeholder for markup which will be passed in from outside of the component.
```astro
-<!-- MyComponent.astro -->
+<!-- Example: MyComponent.astro -->
<div id="my-component">
<slot /> <!-- children will go here -->
</div>
@@ -136,24 +192,24 @@ const { greeting = 'Hello', name } = Astro.props;
</MyComponent>
```
-Slots are especially powerful when using **named slots**. Rather than a single `<slot>` element which renders _all_ children, named slots allow you to specify where certain children should be placed.
+Slots become even more powerful when using **named slots**. Rather than a single `<slot>` element which renders _all_ children, named slots allow you to specify multiple places where children should be placed.
> **Note** The `slot` attribute is not restricted to plain HTML, components can use `slot` as well!
```astro
-<!-- MyComponent.astro -->
+<!-- Example: MyComponent.astro -->
<div id="my-component">
<header>
- <slot name="header" /> <!-- children with the `slot="header"` attribute will go here -->
+ <!-- children with the `slot="header"` attribute will go here -->
+ <slot name="header" />
</header>
-
<main>
<!-- children without a `slot` (or with the `slot="default"`) attribute will go here -->
<slot />
</main>
-
<footer>
- <slot name="footer"> <!-- children with the `slot="footer"` attribute will go here -->
+ <!-- children with the `slot="footer"` attribute will go here -->
+ <slot name="footer">
</footer>
</div>
@@ -165,7 +221,7 @@ Slots are especially powerful when using **named slots**. Rather than a single `
</MyComponent>
```
-Slots also have the ability to render **fallback content**. When there are no matching children passed to a `<slot>`, a `<slot>` element will be replaced with its own children.
+Slots can also render **fallback content**. When there are no matching children passed to a `<slot>`, a `<slot>` element will render its own placeholder children.
```astro
<!-- MyComponent.astro -->
@@ -174,34 +230,73 @@ Slots also have the ability to render **fallback content**. When there are no ma
<h1>I will render when this slot does not have any children!</h1>
</slot>
</div>
+
+<!-- Usage -->
+<MyComponent />
```
-### Fragments
+### Fragments & Multiple Elements
-At the top-level of an `.astro` file, you may render any number of elements.
+An Astro component template can render as many top-level elements as you'd like. Unlike other UI component frameworks, you don't need to wrap everything in a single `<div>` if you'd prefer not to.
```html
-<!-- Look, no Fragment! -->
+<!-- An Astro component can multiple top-level HTML elements: -->
<div id="a" />
<div id="b" />
<div id="c" />
```
-Inside of an expression, you must wrap multiple elements in a Fragment. Fragments must open with `<>` and close with `</>`.
+When working inside a JSX expression, however, you must wrap multiple elements inside of a **Fragment**. Fragments let you render a set of elements without adding extra nodes to the DOM. This is required in JSX expressions because of a limitation of JavaScript: You can never `return` more than one thing in a JavaScript function or expression. Using a Fragment solves this problem.
-```jsx
-<div>
- {[0, 1, 2].map((id) => (
+A Fragment must open with `<>` and close with `</>`. Don't worry if you forget this, Astro's compiler will warn you that you need to add one.
+
+```astro
+---
+const items = ["Dog", "Cat", "Platipus"];
+---
+<ul>
+ {items.map((item) => (
<>
- <div id={`a-${id}`} />
- <div id={`b-${id}`} />
- <div id={`c-${id}`} />
+ <li>Red {item}</li>
+ <li>Blue {item}</li>
+ <li>Green {item}</li>
</>
))}
-</div>
+</ul>
+```
+
+### Slots
+
+Sometimes, an Astro component will be passed children. This is especially common for components like sidebars or dialog boxes that represent generic "wrappers” around content.
+
+```astro
+<WrapChildrenWithText>
+ <img src="https://placehold.co/400" />
+<WrapChildrenWithText>
```
-### `.astro` versus `.jsx`
+Astro provides a `<slot />` component so that you can control where any children are rendered within the component. This is heavily inspired by the [`<slot>` HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot).
+
+```astro
+---
+// Example: components/WrapChildrenWithText.astro
+// Usage: <WrapChildrenWithText><img src="https://placehold.co/400" /><WrapChildrenWithText>
+// Renders: <h1>Begin</h1><img src="https://placehold.co/400" /><h1>End</h1>
+---
+<h1>Begin</h1>
+<!-- slot: any given children are injected here -->
+<slot />
+<h1>End</h1>
+```
+
+<!-- TODO: https://github.com/snowpackjs/astro/issues/600
+ If you don't provide a `<slot />` component in your HTML template, any children passed to your component will not be rendered. -->
+
+<!-- TODO: https://github.com/snowpackjs/astro/issues/360
+ Document Named Slots -->
+
+
+## Comparing `.astro` versus `.jsx`
`.astro` files can end up looking very similar to `.jsx` files, but there are a few key differences. Here's a comparison between the two formats.
@@ -223,7 +318,7 @@ Inside of an expression, you must wrap multiple elements in a Fragment. Fragment
| Special Characters | `&nbsp;` | `{'\xa0'}` or `{String.fromCharCode(160)}` |
| Attributes | `dash-case` | `camelCase` |
-### URL resolution
+## URL resolution
It’s important to note that Astro **won’t** transform HTML references for you. For example, consider an `<img>` tag with a relative `src` attribute inside `src/pages/about.astro`:
@@ -234,7 +329,7 @@ It’s important to note that Astro **won’t** transform HTML references for yo
Since `src/pages/about.astro` will build to `/about/index.html`, you may not have expected that image to live at `/about/thumbnail.png`. So to fix this, choose either of two options:
-#### Option 1: Absolute URLs
+### Option 1: Absolute URLs
```html
<!-- ✅ Correct: references public/thumbnail.png -->
@@ -243,9 +338,9 @@ Since `src/pages/about.astro` will build to `/about/index.html`, you may not hav
The recommended approach is to place files within `public/*`. This references a file it `public/thumbnail.png`, which will resolve to `/thumbnail.png` at the final build (since `public/` ends up at `/`).
-#### Option 2: Asset import references
+### Option 2: Asset import references
-```jsx
+```astro
---
// ✅ Correct: references src/thumbnail.png
import thumbnailSrc from './thumbnail.png';
@@ -256,4 +351,7 @@ import thumbnailSrc from './thumbnail.png';
If you’d prefer to organize assets alongside Astro components, you may import the file in JavaScript inside the component script. This works as intended but this makes `thumbnail.png` harder to reference in other parts of your app, as its final URL isn’t easily-predictable (unlike assets in `public/*`, where the final URL is guaranteed to never change).
+
[code-ext]: https://marketplace.visualstudio.com/items?itemName=astro-build.astro-vscode
+
+
diff --git a/docs/core-concepts/astro-pages.md b/docs/core-concepts/astro-pages.md
index 1f63ea98b..9d6c5d9db 100644
--- a/docs/core-concepts/astro-pages.md
+++ b/docs/core-concepts/astro-pages.md
@@ -1,11 +1,11 @@
---
layout: ~/layouts/Main.astro
-title: Astro Pages
+title: Pages
---
-**Pages** are a special type of [Astro Component](./astro-components) that handle routing, data loading, and templating for each page of your website. You can think of them like any other Astro component, just with extra responsibilities.
+**Pages** are a special type of [Astro Component](/core-concepts/astro-components) that handle routing, data loading, and templating for each page of your website. You can think of them like any other Astro component, just with extra responsibilities.
-Astro also supports Markdown for content-heavy pages, like blog posts and documentation. See [Markdown Content](./markdown-content.md) for more information on writing pages with Markdown.
+Astro also supports Markdown for content-heavy pages, like blog posts and documentation. See [Markdown Content](/guides/markdown-content) for more information on writing pages with Markdown.
## File-based Routing
@@ -13,8 +13,6 @@ Astro uses Pages to do something called **file-based routing.** Every file in yo
Astro Components (`.astro`) and Markdown Files (`.md`) are the only supported formats for pages. Other page types (like a `.jsx` React component) are not supported, but you can use anything as a UI component inside of an `.astro` page to achieve a similar result.
-### Examples
-
```
src/pages/index.astro -> mysite.com/
src/pages/about.astro -> mysite.com/about
@@ -23,34 +21,9 @@ src/pages/about/me.astro -> mysite.com/about/me
src/pages/posts/1.md -> mysite.com/posts/1
```
-## Data Loading
-
-Astro pages can fetch data to help generate your pages. Astro provides two different tools to pages to help you do this: **fetch()** and **top-level await.**
-
-```astro
----
-// Example: Astro component scripts run at build time
-const response = await fetch('http://example.com/movies.json');
-const data = await response.json();
-console.log(data);
----
-<!-- Output the result to the page -->
-<div>{JSON.stringify(data)}</div>
-```
-
-### `fetch()`
-
-Astro pages have access to the global `fetch()` function in their setup script. `fetch()` is a native JavaScript API ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)) that lets you make HTTP requests for things like APIs and resources.
-
-Even though Astro component scripts run inside of Node.js (and not in the browser) Astro provides this native API so that you can fetch data at page build time.
-
-### Top-level await
-
-`await` is another native JavaScript feature that lets you await the response of some asynchronous promise ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)). Astro supports `await` in the top-level of your component script.
-
## Page Templating
-All Astro components are responsible for returning HTML. Astro Pages return HTML as well, but have the unique responsibility of returning a full `<html>...</html>` page response, including `<head>` ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)) and `<body>` ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)).
+All Astro components are responsible for returning HTML. Astro Pages return HTML as well, but have the unique responsibility of returning a full `<html>...</html>` page response, including `<head>` ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)) and `<body>` ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)).
`<!doctype html>` is optional, and will be added automatically.
@@ -68,3 +41,20 @@ All Astro components are responsible for returning HTML. Astro Pages return HTML
</body>
</html>
```
+
+## Data Loading
+
+Astro pages can fetch data to help generate your pages. Astro provides two different tools to pages to help you do this: **fetch()** and **top-level await.**
+
+📚 Read our [full guide](/guides/data-fetching) on data-fetching to learn more.
+
+```astro
+---
+// Example: Astro component scripts run at build time
+const response = await fetch('http://example.com/movies.json');
+const data = await response.json();
+console.log(data);
+---
+<!-- Output the result to the page -->
+<div>{JSON.stringify(data)}</div>
+``` \ No newline at end of file
diff --git a/docs/core-concepts/collections.md b/docs/core-concepts/collections.md
index edebca3d7..d7efe509c 100644
--- a/docs/core-concepts/collections.md
+++ b/docs/core-concepts/collections.md
@@ -3,7 +3,7 @@ layout: ~/layouts/Main.astro
title: Collections
---
-**Collections** are a special type of [Page](./astro-pages) that help you generate multiple pages from a larger set of data. Example use-cases include:
+**Collections** are a special type of [Page](/core-concepts/astro-pages) that help you generate multiple pages from a larger set of data. Example use-cases include:
- Pagination: `/posts/1`, `/posts/2`, etc.
- Grouping content by author: `/author/fred`, `/author/matthew`, etc.
@@ -29,7 +29,7 @@ To create a new Astro Collection, you must do three things:
3. Define and export `createCollection` function: this tells Astro how to load and structure your collection data. Check out the examples below for documentation on how it should be implemented. It MUST be named `createCollection` and it must be exported.
- Example: `export async function createCollection() { /* ... */ }`
-- API Reference: [createCollection][collection-api]
+- API Reference: [createCollection](/reference/api-reference#collections-api)
## Example: Simple Pagination
@@ -153,6 +153,8 @@ export async function createCollection() {
## Example: Individual Pages from a Collection
+**Note**: collection.data and .params are being fetched async, use optional chaining or some other way of handling this in template. Otherwise you will get build errors.
+
```jsx
---
// Define the `collection` prop.
@@ -188,9 +190,10 @@ export async function createCollection() {
---
<html lang="en">
<head>
- <title>Pokemon: {collection.params.name}</head>
+ <title>Pokemon: {collection.params?.name}</title>
+ </head>
<body>
- Who's that pokemon? It's {collection.data[0].name}!
+ Who's that pokemon? It's {collection.data[0]?.name}!
</body>
</html>
```
@@ -201,13 +204,8 @@ export async function createCollection() {
### 📚 Further Reading
-- [Fetching data in Astro][docs-data]
-- API Reference: [collection][collection-api]
-- API Reference: [createCollection()][create-collection-api]
-- API Reference: [Creating an RSS feed][create-collection-api]
+- [Fetching data in Astro](/guides/data-fetching)
+- API Reference: [collection](/reference/api-reference#collections-api)
+- API Reference: [createCollection()](/reference/api-reference#createcollection)
+- API Reference: [Creating an RSS feed](/reference/api-reference#rss-feed)
-[docs-data]: ../README.md#-fetching-data
-[collection-api]: ./api.md#collection
-[create-collection-api]: ./api.md#createcollection
-[example-blog]: ../examples/blog
-[fetch-content]: ./api.md#fetchcontent
diff --git a/docs/core-concepts/component-hydration.md b/docs/core-concepts/component-hydration.md
index 209e4a8ed..4371583a1 100644
--- a/docs/core-concepts/component-hydration.md
+++ b/docs/core-concepts/component-hydration.md
@@ -1,39 +1,91 @@
---
layout: ~/layouts/Main.astro
-title: React, Svelte, Vue, etc.
+title: Partial Hydration in Astro
---
-By default, Astro generates your site with zero client-side JavaScript. If you use any frontend UI components (React, Svelte, Vue, etc.) Astro will automatically render them **on the server**, generating only HTML and CSS without any client-side JavaScript. This makes your site as fast as possible by default.
+**Astro generates every website with zero client-side JavaScript, by default.** Use any frontend UI component that you'd like (React, Svelte, Vue, etc.) and Astro will automatically render it to HTML at build-time and strip away all JavaScript. This keeps every site fast by default.
-```
+But sometimes, client-side JavaScript is required. This guide shows how interactive components work in Astro using a technique called partial hydration.
+
+```astro
---
+// Example: Importing and then using a React component.
+// By default, Astro renders this to HTML and CSS during
+// your build, with no client-side JavaScript.
+// (Need client-side JavaScript? Read on...)
import MyReactComponent from '../components/MyReactComponent.jsx';
---
-<!-- By default: Astro renders this on the server,
- generating HTML and CSS, but no client-side JavaScript. -->
+<!-- 100% HTML, Zero JavaScript! -->
<MyReactComponent />
```
-However, there are plenty of cases where you might like to include an interactive component on your page:
+## Concept: Partial Hydration
+
+There are plenty of cases where you need an interactive UI component to run in the browser:
- An image carousel
- An auto-complete search bar
- A mobile sidebar open/close button
- A "Buy Now" button
-With Astro, you can hydrate these components individually, without forcing the rest of the page to ship any other unnecesary JavaScript. This technique is called **partial hydration.**
+In Astro, it's up to you as the developer to explicitly "opt-in" any components on the page that need to run in the browser. Astro can then use this info to know exactly what JavaScript is needed, and only hydrate exactly what's needed on the page. This technique is is known as partial hydration.
+
+**Partial hydration** -- the act of only hydrating the individual components that require JavaScript and leaving the rest of your site as static HTML -- may sound relatively straightforward. It should! Websites have been built this way for decades. It was only recently that Single-Page Applications (SPAs) introduced the idea that your entire website is written in JavaScript and compiled/rendered by every user in the browser.
+
+_Note: Partial hydration is sometimes called "progressive enhancement" or "progressive hydration." While there are slight nuances between the terms, for our purposes you can think of these all as synonyms of the same concept._
+
+**Partial hydration is the secret to Astro's fast-by-default performance story.** Next.js, Gatsby, and other JavaScript frameworks cannot support partial hydration because they imagine your entire website/page as a single JavaScript application.
+
+## Concept: Island Architecture
+
+**Island architecture** is the idea of using partial hydration to build entire websites. Island architecture is an alternative to the popular idea of building your website into a client-side JavaScript bundle that must be shipped to the user.
+
+To quote Jason Miller, who [coined the phrase](https://jasonformat.com/islands-architecture/):
+
+> In an "islands" model, server rendering is not a bolt-on optimization aimed at improving SEO or UX. Instead, it is a fundamental part of how pages are delivered to the browser. The HTML returned in response to navigation contains a meaningful and immediately renderable representation of the content the user requested.
+
+Besides the obvious performance benefits of sending less JavaScript down to the browser, there are two key benefits to island architecture:
+
+- **Components load individually.** A lightweight component (like a sidebar toggle) will load and render quickly without being blocked by the heavier components on the page.
+- **Components render in isolation.** Each part of the page is an isolated unit, and a performance issue in one unit won't directly affect the others.
+
+![diagram](https://res.cloudinary.com/wedding-website/image/upload/v1596766231/islands-architecture-1.png)
+
+
+
+## Hydrate Interactive Components
+
+Astro renders every component on the server **at build time**. To hydrate components on the client **at runtime**, you may use any of the following `client:*` directives. A directive is a component attribute (always with a `:`) which tells Astro how your component should be rendered.
+
+```astro
+---
+// Example: hydrating a React component in the browser.
+import MyReactComponent from '../components/MyReactComponent.jsx';
+---
+<!-- "client:visible" means the component won't load any client-side
+ JavaScript until it becomes visible in the user's browser. -->
+<MyReactComponent client:visible />
+```
+
+### `<MyComponent client:load />`
+Hydrate the component on page load.
+
+### `<MyComponent client:idle />`
+Hydrate the component as soon as main thread is free (uses [requestIdleCallback()][mdn-ric]).
+
+### `<MyComponent client:visible />`
+Hydrate the component as soon as the element enters the viewport (uses [IntersectionObserver][mdn-io]). Useful for content lower down on the page.
-## Hydrate Frontend Components
+### `<MyComponent client:media={QUERY} />`
+Hydrate the component as soon as the browser matches the given media query (uses [matchMedia][mdn-mm]). Useful for sidebar toggles, or other elements that should only display on mobile or desktop devices.
-Astro renders every component on the server **at build time**. To hydrate any server-rendered component on the client **at runtime**, you may use any of the following techniques:
+## Can I Hydrate Astro Components?
-- `<MyComponent client:load />` will hydrate the component on page load.
-- `<MyComponent client:idle />` will use [requestIdleCallback()][mdn-ric] to hydrate the component as soon as main thread is free.
-- `<MyComponent client:visible />` will use an [IntersectionObserver][mdn-io] to hydrate the component when the element enters the viewport.
-- `<MyComponent client:media={QUERY} />` will use [matchMedia][mdn-mm] to hydrate the component when a media query is matched.
+[Astro components](./astro-components) (`.astro` files) are HTML-only templating components with no client-side runtime. If you try to hydrate an Astro component with a `client:` modifier, you will get an error.
-## Hydrate Astro Components
+To make your Astro component interactive, you will need to convert it to the frontend framework of your choice: React, Svelte, Vue, etc. If you have no preference, we reccomend React or Preact as most similar to Astro's syntax.
-Astro components (`.astro`) are HTML-only templating languages with no client-side runtime. You cannot hydrate an Astro component to run on the client (because the JavaScript front-matter only ever runs at build time).
+Alternatively, you could add a `<script>` tag to your Astro component HTML template and send JavaScript to the browser that way. While this is fine for the simple stuff, we recommend a frontend framework for more complex interactive components.
-If you want to make your Astro component interactive on the client, you should convert it to React, Svelte, or Vue. Otherwise, you can consider adding a `<script>` tag to your Astro component that will run JavaScript on the page.
+[mdn-io]: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
+[mdn-ric]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
diff --git a/docs/core-concepts/layouts.md b/docs/core-concepts/layouts.md
index 73d9994fa..5a403b615 100644
--- a/docs/core-concepts/layouts.md
+++ b/docs/core-concepts/layouts.md
@@ -3,17 +3,17 @@ layout: ~/layouts/Main.astro
title: Layouts
---
-**Layouts** are a special type of [Component](./astro-components) that help you share and reuse common page layouts within your project.
+**Layouts** are a special type of [Component](/core-concepts/astro-components) that help you share and reuse common page layouts within your project.
Layouts are just like any other reusable Astro component. There's no new syntax or APIs to learn. However, reusable page layouts are such a common pattern in web development that we created this guide to help you use them.
## Usage
-Astro layouts support props, slots, and all of the other features of Astro components. Layouts are just normal components, after all!
+Astro layouts support props, slots, and all of the other features of Astro components. Layouts are just normal components, after all!
Unlike other components, layouts will often contain the full page `<html>`, `<head>` and `<body>` (often referred to as the **page shell**).
-It's a common pattern to put all of your layout components in a single `src/layouts` directory.
+It's a common pattern to put all of your layout components in a single `src/layouts` directory.
## Example
@@ -39,7 +39,7 @@ const {title} = Astro.props;
</html>
```
-📚 The `<slot />` element lets Astro components define where any children elements (passed to the layout) should go. Learn more about how `<slot/>` works in our [Astro Component guide.](/docs/core-concepts/astro-components.md)
+📚 The `<slot />` element lets Astro components define where any children elements (passed to the layout) should go. Learn more about how `<slot/>` works in our [Astro Component guide.](/core-concepts/astro-components)
Once you have your first layout, You can use it like you would any other component on your page. Remember that your layout contains your page `<html>`, `<head>`, and `<body>`. You only need to provide the custom page content.
@@ -54,10 +54,12 @@ import BaseLayout from '../layouts/BaseLayout.astro'
</BaseLayout>
```
+
## Nesting Layouts
You can nest layouts when you want to create more specific page types without copy-pasting. It is common in Astro to have one generic `BaseLayout` and then many more specific layouts (`PostLayout`, `ProductLayout`, etc.) that reuse and build on top of it.
+
```astro
---
// src/layouts/PostLayout.astro
@@ -91,7 +93,7 @@ const {title, description} = Astro.props;
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
```
-Notice how this layout doesn't include your page shell, and only includes some generic elements that should go in your `<head>`. This lets you combine multiple layout components together, to include things
+Notice how this layout doesn't include your page shell, and only includes some generic elements that should go in your `<head>`. This lets you combine multiple layout components together with more control over the overall page structure.
```astro
---
@@ -117,14 +119,13 @@ The one downside to this approach is that you'll need to define the `<html>`, `<
## Markdown Layouts
-Layouts are essential for Markdown files. Markdown files can declare a layout in the file frontmatter. Each Markdown file will be rendered to HTML and then injected into the layout's `<slot />` location.
+Layouts are essential for Markdown files. Markdown files can declare a layout in the file frontmatter. Each Markdown file will be rendered to HTML and then injected into the layout's `<slot />` location.
```markdown
---
title: Blog Post
layout: ../layouts/PostLayout.astro
---
-
This blog post will be **rendered** inside of the `<PostLayout />` layout.
```
@@ -151,4 +152,4 @@ const { content } = Astro.props;
</html>
```
-📚 Learn more about Astro's markdown support in our [Markdown guide](/docs/guides/markdown-content.md).
+📚 Learn more about Astro's markdown support in our [Markdown guide](/guides/markdown-content).
diff --git a/docs/core-concepts/project-structure.md b/docs/core-concepts/project-structure.md
index 08a9b8f60..4d2cd4d80 100644
--- a/docs/core-concepts/project-structure.md
+++ b/docs/core-concepts/project-structure.md
@@ -9,8 +9,7 @@ Astro includes an opinionated folder layout for your project. Every Astro projec
- `public/*` - Your non-code assets (fonts, icons, etc.)
- `package.json` - A project manifest.
-The easiest way to set up your new project is with `npm init astro`. Check out our [Installation Guide](/docs/quick-start.md) for a walkthrough of how to set up your project automatically (with `npm init astro`) or manually.
-
+The easiest way to set up your new project is with `npm init astro`. Check out our [Installation Guide](/quick-start) for a walkthrough of how to set up your project automatically (with `npm init astro`) or manually.
## Project Structure
```
@@ -27,31 +26,31 @@ The easiest way to set up your new project is with `npm init astro`. Check out o
The src folder is where most of your project source code lives. This includes:
-- [Astro Components](/docs/core-concepts/astro-components.md)
-- [Pages](/docs/core-concepts/astro-pages.md)
-- [Markdown](/docs/core-concepts/astro-pages.md)
-- [Layouts](/docs/core-concepts/astro-pages.md)
-- [Frontend JS Components](/docs/core-concepts/component-hydration.md)
-- [Styling (CSS, Sass)](/docs/guides/styling.md)
+- [Astro Components](/core-concepts/astro-components)
+- [Pages](/core-concepts/astro-pages)
+- [Markdown](/core-concepts/astro-pages)
+- [Layouts](/core-concepts/astro-pages)
+- [Frontend JS Components](/core-concepts/component-hydration)
+- [Styling (CSS, Sass)](/guides/styling)
Astro has complete control over how these files get processed, optimized, and bundled in your final site build. Some files (like Astro components) never make it to the browser directly and are instead rendered to HTML. Other files (like CSS) are sent to the browser but may be bundled with other CSS files depending on how your site uses.
### `src/components`
-[Components](/docs/core-concepts/astro-components.md) are reusable units of UI for your HTML pages. It is recommended (but not required) that you put your components in this directory. How you organize them within this directory is up to you.
+[Components](/core-concepts/astro-components) are reusable units of UI for your HTML pages. It is recommended (but not required) that you put your components in this directory. How you organize them within this directory is up to you.
Your non-Astro UI components (React, Preact, Svelte, Vue, etc.) can also live in the `src/components` directory. Astro will automatically render all components to HTML unless you've enabled a frontend component via partial hydration.
### `src/layouts`
-[Layouts](/docs/core-concepts/layouts.md) are reusable components for HTML page layouts. It is recommended (but not required) that you put your layout components in this directory. How you organize them within this directory is up to you.
+[Layouts](/core-concepts/layouts) are reusable components for HTML page layouts. It is recommended (but not required) that you put your layout components in this directory. How you organize them within this directory is up to you.
### `src/pages`
-[Pages](/docs/core-concepts/astro-pages.md) contain all pages (`.astro` and `.md` supported) for your website. It is **required** that you put your pages in this directory.
-
+[Pages](/core-concepts/astro-pages) contain all pages (`.astro` and `.md` supported) for your website. It is **required** that you put your pages in this directory.
+
### `public/`
For most users, the majority of your files will live inside of the `src/` directory so that Astro can properly handle and optimize them in your final build. By contrast, the `public/` directory is the place for any files to live outside of the Astro build process.
-If you put a file into the public folder, it will not be processed by Astro. Instead it will be copied into the build folder untouched. This can be useful for assets like images and fonts, or when you need to include a specific file like `robots.txt` or `manifest.webmanifest`.
+If you put a file into the public folder, it will not be processed by Astro. Instead it will be copied into the build folder untouched. This can be useful for assets like images and fonts, or when you need to include a specific file like `robots.txt` or `manifest.webmanifest`. \ No newline at end of file
diff --git a/docs/core-concepts/ui-renderers.md b/docs/core-concepts/ui-renderers.md
deleted file mode 100644
index 2d91f1811..000000000
--- a/docs/core-concepts/ui-renderers.md
+++ /dev/null
@@ -1,205 +0,0 @@
----
-layout: ~/layouts/Main.astro
-title: UI Renderers
----
-
-Astro is designed to support your favorite UI frameworks. [React](https://npm.im/@astrojs/renderer-react), [Svelte](https://npm.im/@astrojs/renderer-svelte), [Vue](https://npm.im/@astrojs/renderer-vue), and [Preact](https://npm.im/@astrojs/renderer-preact) are all built-in to Astro and supported out of the box. No configuration is needed to enable these.
-
-Internally, each framework is supported via a framework **renderer.** A renderer is a type of Astro plugin that adds support for a framework. Some are built-in, but you can also provide your own third-party renderers to add Astro support for new frameworks.
-
-## What is a renderer?
-
-A renderer is an NPM package that has two responsiblities:
-
-1. _render a component to a static string of HTML_ at build time
-2. _rehydrate that HTML to create an interactive component_ on the client.
-
-Take a look at any one of Astro's built-in [`renderers`](https://github.com/snowpackjs/astro/tree/main/packages/renderers) to see this in action. We'll go into more detail in the following sections.
-
-## Add a renderer to Astro
-
-Astro enables a few popular framework renderers by default. If you want to add a new renderer to your project, you first need to set the built-in renderers that you care about.
-
-```js
-// astro.config.js
-export default {
- renderers: [
- // Add the framework renderers that you want to enable for your project.
- // If you set an empty array here, no UI frameworks will work.
- // '@astrojs/renderer-svelte',
- // '@astrojs/renderer-vue',
- // '@astrojs/renderer-react',
- // '@astrojs/renderer-preact',
- ],
-};
-```
-
-To add a new custom renderer, install the npm package dependency in your project and then update the `renderers` array to include it:
-
-```js
-// astro.config.js
-export default {
- renderers: ['my-custom-renderer', '@astrojs/renderer-svelte', '@astrojs/renderer-vue', '@astrojs/renderer-react', '@astrojs/renderer-preact'],
-};
-```
-
-#### Managing Framework Versions
-
-In Astro, the renderer plugin defines which version of your framework to use with Astro. This should be set to as wide of a range as possible, but often will be pinned to a specific major version:
-
-- `@astrojs/renderer-vue`: `"vue": "^3.0.0"`
-- `@astrojs/renderer-react`: `"react": "^17.0.0"`
-- See all: https://github.com/snowpackjs/astro/tree/main/packages/renderers
-
-This is required because the renderer itself also uses these packages and requires a specific API to work. For example, If the user updated from Vue 2 to Vue 3 (or vice versa) then the renderer itself would break since the `vue` package would have changed.
-
-**What if I want to use a beta framework (ex: react@next)?** Check to see if the renderer has a `@next` version that you could manually install and use. If one doesn't exist, feel free to request it: https://github.com/snowpackjs/astro/issues/new/choose
-
-**What if I need to override the framework version in my project?** You can use the "resolutions" feature of many npm package managers to override or pin the framework version for your entire project. Just be sure to select a version that is compatible with your renderer:
-
-- **yarn:** https://classic.yarnpkg.com/en/docs/selective-version-resolutions/
-- **pnpm:** https://pnpm.io/package_json#pnpmoverrides
-- **npm:** see https://stackoverflow.com/questions/15806152/how-do-i-override-nested-npm-dependency-versions
-
-## Building Your Own Renderer
-
-> **Building a renderer?** We'd love for you to contribute renderers for popular frameworks back to the Astro repo. Feel free to open an issue or pull request to discuss.
-
-A simple renderer only needs a few files:
-
-```
-/my-custom-renderer/
-├── package.json
-├── index.js
-├── server.js
-└── client.js
-```
-
-### Package Manifest (`package.json`)
-
-A renderer should include any framework dependencies as package dependencies. For example, `@astrojs/renderer-react` includes `react` & `react-dom` as dependencies in the `package.json` manifest.
-
-```js
-// package.json
-"name": "@astrojs/renderer-react",
-"dependencies": {
- "react": "^17.0.0",
- "react-dom": "^17.0.0"
-}
-```
-
-This means that Astro users don't need to install the UI framework packages themselves. The renderer is the only package that your users will need to install.
-
-### Renderer Entrypoint (`index.js`)
-
-The main entrypoint of a renderer is a simple JS file which exports a manifest for the renderer. The required values are `name`, `server`, and `client`.
-
-Additionally, this entrypoint can define a [Snowpack plugin](https://www.snowpack.dev/guides/plugins) that should be used to load non-JavaScript files.
-
-```js
-export default {
- name: '@astrojs/renderer-xxx', // the renderer name
- client: './client.js', // relative path to the client entrypoint
- server: './server.js', // optional, relative path to the server entrypoint
- snowpackPlugin: '@snowpack/plugin-xxx', // optional, the name of a snowpack plugin to inject
- snowpackPluginOptions: { example: true }, // optional, any options to be forwarded to the snowpack plugin
- knownEntrypoint: ['framework'], // optional, entrypoint modules that will be used by compiled source
- external: ['dep'] // optional, dependencies that should not be built by snowpack
- polyfills: ['./shadow-dom-polyfill.js'] // optional, module scripts that should be loaded before client hydration.
- hydrationPolyfills: ['./hydrate-framework.js'] // optional, polyfills that need to run before hydration ever occurs.
-};
-```
-
-### Server Entrypoint (`server.js`)
-
-The server entrypoint of a renderer is responsible for checking if a component should use this renderer, and if so, how that component should be rendered to a string of static HTML.
-
-```js
-export default {
- // should Component use this renderer?
- check(Component, props, childHTML) {},
- // Component => string of static HTML
- renderToStaticMarkup(Component, props, childHTML) {},
-};
-```
-
-#### `check`
-
-`check` is a function that determines whether a Component should be "claimed" by this renderer.
-
-In it's simplest form, it can check for the existence of a flag on Object-based components.
-
-```js
-function check(Component) {
- return Component.isMyFrameworkComponent;
-}
-```
-
-In more complex scenarios, like when a Component is a `Function` without any flags, you may need to use `try/catch` to attempt a full render. This result is cached so that it only runs once per-component.
-
-```js
-function check(Component, props, childHTML) {
- try {
- const { html } = renderToStaticMarkup(Component, props, childHTML);
- return Boolean(html);
- } catch (e) {}
- return false;
-}
-```
-
-#### `renderToStaticMarkup`
-
-`renderToStaticMarkup` is a function that renders a Component to a static string of HTML. There's usually a method exported by frameworks named something like `renderToString`.
-
-```js
-import { renderToString } from 'xxx';
-
-function renderToStaticMarkup(Component, props, childHTML) {
- const html = renderToString(h(Component, { ...props, innerHTML: childHTML }));
- return { html };
-}
-```
-
-Note that `childHTML` is an HTML string representing this component's children. If your framework does not support rendering HTML directly, you are welcome to use a wrapper component. By convention, Astro uses the `astro-fragment` custom element to inject `childHTML` into. Your renderer should use that, too.
-
-```js
-import { h, renderToString } from 'xxx';
-
-const Wrapper = ({ value }) => h('astro-fragment', { dangerouslySetInnerHTML: { __html: value } });
-
-function renderToStaticMarkup(Component, props, childHTML) {
- const html = renderToString(h(Component, props, h(Wrapper, { value: childHTML })));
- return { html };
-}
-```
-
-### Client Entrypoint (`client.js`)
-
-The client entrypoint of a renderer is responsible for rehydrating static HTML (the result of `renderToStaticMarkup`) back into a fully interactive component. Its `default` export should be a `function` which accepts the host element of the Component, an `astro-root` custom element.
-
-> If your framework supports non-destructive component hydration (as opposed to a destructive `render` method), be sure to use that! Following your framework's Server Side Rendering (SSR) guide should point you in the right direction.
-
-```js
-import { hydrate } from 'xxx';
-
-export default (element) => {
- return (Component, props, childHTML) => {
- hydrate(h(Component, { ...props, innerHTML: childHTML }), element);
- };
-};
-```
-
-Note that `childHTML` is an HTML string representing this component's children. If your framework does not support rendering HTML directly, you should use the same wrapper component you used for the server entrypoint.
-
-```js
-import { h, hydrate } from 'xxx';
-import SharedWrapper from './SharedWrapper.js';
-
-export default (element) => {
- return (Component, props, childHTML) => {
- hydrate(h(Component, props, h(SharedWrapper, { value: childHTML })), element);
- };
-};
-```
-
-[astro-config]: ./config.md