New Props API (#515)
* wip: update props api * feat(#139, #309): enable new props api * chore: migrate examples to new props API * docs: update syntax guide for new props API * chore: update examples to new props API * chore: update docs to new Props API * fix: hide __astroInternal from `Astro.props` consumers * chore: remove scratchpad file * chore: fix script error * test: fix failing collection tests * fix: set __astroInternal to `enumerable: false` * chore: add changeset * feat: warn users using old props api
This commit is contained in:
parent
bc9e0f180c
commit
a136c85e6b
57 changed files with 275 additions and 132 deletions
63
.changeset/rich-starfishes-begin.md
Normal file
63
.changeset/rich-starfishes-begin.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
'astro': minor
|
||||
---
|
||||
|
||||
**This is a breaking change!**
|
||||
|
||||
Astro props are now accessed from the `Astro.props` global. This change is meant to make prop definitions more ergonomic, leaning into JavaScript patterns you already know (destructuring and defaults). Astro components previously used a prop syntax borrowed from [Svelte](https://svelte.dev/docs#1_export_creates_a_component_prop), but it became clear that this was pretty confusing for most users.
|
||||
|
||||
|
||||
```diff
|
||||
---
|
||||
+ const { text = 'Hello world!' } = Astro.props;
|
||||
- export let text = 'Hello world!';
|
||||
---
|
||||
|
||||
<div>{text}</div>
|
||||
```
|
||||
|
||||
[Read more about the `.astro` syntax](https://github.com/snowpackjs/astro/blob/main/docs/syntax.md#data-and-props)
|
||||
|
||||
---
|
||||
|
||||
### How do I define what props my component accepts?
|
||||
|
||||
Astro frontmatter scripts are TypeScript! Because of this, we can leverage TypeScript types to define the shape of your props.
|
||||
|
||||
```ts
|
||||
---
|
||||
export interface Props {
|
||||
text?: string;
|
||||
}
|
||||
const { text = 'Hello world!' } = Astro.props as Props;
|
||||
---
|
||||
```
|
||||
|
||||
> **Note** Casting `Astro.props as Props` is a temporary workaround. We expect our Language Server to handle this automatically soon!
|
||||
|
||||
### How do I access props I haven't explicitly defined?
|
||||
|
||||
One of the great things about this change is that it's straight-forward to access _any_ props. Just use `...props`!
|
||||
|
||||
```ts
|
||||
---
|
||||
export interface Props {
|
||||
text?: string;
|
||||
[attr: string]: unknown;
|
||||
}
|
||||
const { text = 'Hello world!', ...props } = Astro.props as Props;
|
||||
---
|
||||
```
|
||||
|
||||
### What about prop validation?
|
||||
|
||||
We considered building prop validation into Astro, but decided to leave that implementation up to you! This way, you can use any set of tools you like.
|
||||
|
||||
```ts
|
||||
---
|
||||
const { text = 'Hello world!' } = Astro.props;
|
||||
|
||||
if (typeof text !== 'string') throw new Error(`Expected "text" to be of type "string" but recieved "${typeof string}"!`);
|
||||
---
|
||||
```
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
---
|
||||
export let type = "tip";
|
||||
export let title;
|
||||
export interface Props {
|
||||
title: string;
|
||||
type?: 'tip' | 'warning' | 'error'
|
||||
}
|
||||
const { type = 'tip', title } = Astro.props;
|
||||
---
|
||||
|
||||
<aside class={`note type-${type}`}>
|
||||
|
|
|
@ -4,7 +4,7 @@ import SiteSidebar from '../components/SiteSidebar.astro';
|
|||
import ThemeToggle from '../components/ThemeToggle.tsx';
|
||||
import DocSidebar from '../components/DocSidebar.tsx';
|
||||
|
||||
export let content;
|
||||
const { content } = Astro.props;
|
||||
const headers = content?.astro?.headers;
|
||||
let editHref = Astro?.request?.url?.pathname?.slice(1) ?? '';
|
||||
if (editHref === '') editHref = `index`;
|
||||
|
|
|
@ -63,7 +63,7 @@ const data = Astro.fetchContent('../pages/post/*.md'); // returns an array of po
|
|||
### `collection`
|
||||
|
||||
```jsx
|
||||
export let collection;
|
||||
const { collection } = Astro.props;
|
||||
```
|
||||
|
||||
When using the [Collections API][docs-collections], `collection` is a prop exposed to the page with the following shape:
|
||||
|
|
|
@ -23,7 +23,7 @@ To create a new Astro Collection, you must do three things:
|
|||
|
||||
2. Define and export the `collection` prop: `collection.data` is how you'll access the data for every page in the collection. Astro populates this prop for you automatically. It MUST be named `collection` and it must be exported.
|
||||
|
||||
- Example: `export let collection;`
|
||||
- Example: `const { collection } = Astro.props;`
|
||||
|
||||
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.
|
||||
|
||||
|
@ -35,7 +35,7 @@ To create a new Astro Collection, you must do three things:
|
|||
```jsx
|
||||
---
|
||||
// Define the `collection` prop.
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
// Define a `createCollection` function.
|
||||
export async function createCollection() {
|
||||
|
@ -72,7 +72,7 @@ export async function createCollection() {
|
|||
// prop also provides some important metadata for you to use, like: `collection.page`,
|
||||
// `collection.url`, `collection.start`, `collection.end`, and `collection.total`.
|
||||
// In this example, we'll use these values to do pagination in the template.
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
export async function createCollection() { /* See Previous Example */ }
|
||||
---
|
||||
<html lang="en">
|
||||
|
@ -107,7 +107,7 @@ export async function createCollection() { /* See Previous Example */ }
|
|||
```jsx
|
||||
---
|
||||
// Define the `collection` prop.
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
// Define a `createCollection` function.
|
||||
// In this example, we'll customize the URLs that we generate to
|
||||
|
@ -155,7 +155,7 @@ export async function createCollection() {
|
|||
```jsx
|
||||
---
|
||||
// Define the `collection` prop.
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
// Define a `createCollection` function.
|
||||
// In this example, we'll create a new page for every single pokemon.
|
||||
|
|
|
@ -34,7 +34,7 @@ The rendered Markdown content is placed into the default `<slot />` element.
|
|||
|
||||
```jsx
|
||||
---
|
||||
export let content;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<html>
|
||||
|
|
|
@ -209,7 +209,7 @@ Instead, let `<Button>` control its own styles, and try a prop:
|
|||
```jsx
|
||||
---
|
||||
// src/components/Button.astro
|
||||
export let theme;
|
||||
const { theme } = Astro.props;
|
||||
---
|
||||
<style lang="scss">
|
||||
.btn {
|
||||
|
|
|
@ -86,14 +86,27 @@ let name = 'world';
|
|||
</main>
|
||||
```
|
||||
|
||||
`.astro` components can also accept props when they are rendered. Public props can be marked using the `export` keyword.
|
||||
|
||||
Local values are overwritten when props are passed, otherwise they are considered the default value.
|
||||
`.astro` components can also accept props when they are rendered. Public props are exposed on the `Astro.props` global.
|
||||
|
||||
```jsx
|
||||
---
|
||||
export let greeting = 'Hello';
|
||||
export let name;
|
||||
const { greeting = 'Hello', name } = Astro.props;
|
||||
---
|
||||
|
||||
<main>
|
||||
<h1>{greeting} {name}!</h1>
|
||||
</main>
|
||||
```
|
||||
|
||||
To define the props which your component accepts, you may export a TypeScript interface or type named `Props`.
|
||||
```tsx
|
||||
---
|
||||
export interface Props {
|
||||
name: string;
|
||||
greeting?: string;
|
||||
}
|
||||
|
||||
const { greeting = 'Hello', name } = Astro.props;
|
||||
---
|
||||
|
||||
<main>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
---
|
||||
export let content;
|
||||
---
|
||||
|
||||
<html>
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
---
|
||||
// props
|
||||
export let title: string;
|
||||
export let description: string;
|
||||
export let image: string | undefined;
|
||||
export let type: string | undefined;
|
||||
export let next: string | undefined;
|
||||
export let prev: string | undefined;
|
||||
export let canonicalURL: string | undefined;
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
image?: string;
|
||||
type?: string;
|
||||
next?: string;
|
||||
prev?: string;
|
||||
canonicalURL?: string;
|
||||
}
|
||||
|
||||
const { title, description, image, type, next, prev, canonicalURL } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<!-- Common -->
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
---
|
||||
export let title;
|
||||
export interface Props {
|
||||
title: string;
|
||||
}
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -57,4 +60,4 @@ a {
|
|||
<li><a href="/author/sancho">Author: Sancho</a></li>
|
||||
<li><a href="/about">About</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</nav>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
---
|
||||
export let prevUrl: string;
|
||||
export let nextUrl: string;
|
||||
export interface Props {
|
||||
prevUrl: string;
|
||||
nextUrl: string;
|
||||
}
|
||||
|
||||
const { prevUrl, nextUrl } = Astro.props;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
---
|
||||
export let post;
|
||||
export let author;
|
||||
export interface Props {
|
||||
post: any;
|
||||
author: string;
|
||||
}
|
||||
const { post, author } = Astro.props;
|
||||
|
||||
function formatDate(date) {
|
||||
return new Date(date).toUTCString().replace(/(\d\d\d\d) .*/, '$1'); // remove everything after YYYY
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
---
|
||||
import MainHead from '../components/MainHead.astro';
|
||||
import Nav from '../components/Nav.astro';
|
||||
|
||||
export let content;
|
||||
|
||||
import authorData from '../data/authors.json';
|
||||
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<html>
|
||||
|
|
|
@ -12,7 +12,8 @@ const author = authorData[collection.params.author];
|
|||
|
||||
// collection
|
||||
import authorData from '../data/authors.json';
|
||||
export let collection: any;
|
||||
|
||||
let { collection } = Astro.props;
|
||||
export async function createCollection() {
|
||||
/** Load posts */
|
||||
let allPosts = Astro.fetchContent('./post/*.md');
|
||||
|
|
|
@ -11,7 +11,7 @@ let canonicalURL = Astro.request.canonicalURL;
|
|||
|
||||
// collection
|
||||
import authorData from '../data/authors.json';
|
||||
export let collection: any;
|
||||
let { collection } = Astro.props;
|
||||
export async function createCollection() {
|
||||
return {
|
||||
/** Load posts, sort newest -> oldest */
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
---
|
||||
export let type = "tip";
|
||||
export let title;
|
||||
export interface Props {
|
||||
title: string;
|
||||
type?: 'tip' | 'warning' | 'error'
|
||||
}
|
||||
const { type = 'tip', title } = Astro.props;
|
||||
---
|
||||
|
||||
<aside class={`note type-${type}`}>
|
||||
|
|
|
@ -4,7 +4,7 @@ import SiteSidebar from '../components/SiteSidebar.astro';
|
|||
import ThemeToggle from '../components/ThemeToggle.tsx';
|
||||
import DocSidebar from '../components/DocSidebar.tsx';
|
||||
|
||||
export let content;
|
||||
const { content } = Astro.props;
|
||||
const headers = content?.astro?.headers;
|
||||
let editHref = Astro?.request?.url?.pathname?.slice(1) ?? '';
|
||||
if (editHref === '') editHref = `index`;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let title = 'Jeanine White: Personal Site';
|
||||
const { title = 'Jeanine White: Personal Site' } = Astro.props;
|
||||
---
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
|
|
@ -4,7 +4,7 @@ import Button from '../components/Button/index.jsx';
|
|||
import Footer from '../components/Footer/index.jsx';
|
||||
import Nav from '../components/Nav/index.jsx';
|
||||
|
||||
export let content: any;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
<html>
|
||||
<head>
|
||||
|
|
|
@ -4,7 +4,7 @@ import Footer from '../components/Footer/index.jsx';
|
|||
import Nav from '../components/Nav/index.jsx';
|
||||
import PortfolioPreview from '../components/PortfolioPreview/index.jsx';
|
||||
|
||||
export let collection;
|
||||
let { collection } = Astro.props;
|
||||
export async function createCollection() {
|
||||
return {
|
||||
async data() {
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
import Banner from './Banner.astro';
|
||||
import Nav from './Nav.astro';
|
||||
|
||||
export let title: string;
|
||||
export let description: string;
|
||||
export let permalink: string;
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
permalink: string;
|
||||
}
|
||||
const { title, description, permalink } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<meta charset="utf-8" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let style;
|
||||
const { style } = Astro.props;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
---
|
||||
export let version: string = '3.1.2';
|
||||
export interface Props {
|
||||
version: string;
|
||||
}
|
||||
const { version = '3.1.2' } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
---
|
||||
export let number: number;
|
||||
export interface Props {
|
||||
number: number;
|
||||
}
|
||||
const { number } = Astro.props;
|
||||
|
||||
const pokemonDataReq = await fetch(`https://pokeapi.co/api/v2/pokemon/${number}`);
|
||||
const pokemonData = await pokemonDataReq.json();
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
export let title: string;
|
||||
export let inputPath: string;
|
||||
export let headers: string;
|
||||
export interface Props {
|
||||
title: string;
|
||||
inputPath: string;
|
||||
headers: string;
|
||||
}
|
||||
const { title, inputPath, headers } = Astro.props;
|
||||
---
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -4,7 +4,7 @@ import Menu from '../components/Menu.astro';
|
|||
import BaseHead from '../components/BaseHead.astro';
|
||||
import BaseLayout from '../components/BaseLayout.astro';
|
||||
|
||||
export let content: any;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
|
|
|
@ -4,7 +4,7 @@ import Menu from '../components/Menu.astro';
|
|||
import BaseHead from '../components/BaseHead.astro';
|
||||
import BaseLayout from '../components/BaseLayout.astro';
|
||||
|
||||
export let content: any;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
|
|
|
@ -3,7 +3,7 @@ import BaseHead from '../components/BaseHead.astro';
|
|||
import BaseLayout from '../components/BaseLayout.astro';
|
||||
import { format as formatDate, parseISO } from 'date-fns';
|
||||
|
||||
export let content: any;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
---
|
||||
import { renderMarkdown } from '@astrojs/markdown-support';
|
||||
|
||||
export let content: string;
|
||||
export let $scope: string;
|
||||
const { content, $scope } = Astro.props;
|
||||
let html = null;
|
||||
|
||||
// This flow is only triggered if a user passes `<Markdown content={content} />`
|
||||
|
|
|
@ -3,8 +3,7 @@ import Prism from 'prismjs';
|
|||
import { addAstro } from '@astrojs/prism';
|
||||
import loadLanguages from 'prismjs/components/index.js';
|
||||
|
||||
export let lang;
|
||||
export let code;
|
||||
const { lang, code } = Astro.props;
|
||||
|
||||
const languageMap = new Map([
|
||||
['ts', 'typescript']
|
||||
|
@ -43,4 +42,4 @@ if (grammar) {
|
|||
let className = lang ? `language-${lang}` : '';
|
||||
---
|
||||
|
||||
<pre class={className}><code class={className}>{html}</code></pre>
|
||||
<pre class={className}><code class={className}>{html}</code></pre>
|
||||
|
|
|
@ -60,6 +60,7 @@ export interface JsxItem {
|
|||
export interface TransformResult {
|
||||
script: string;
|
||||
imports: string[];
|
||||
exports: string[];
|
||||
html: string;
|
||||
css?: string;
|
||||
/** If this page exports a collection, the JS to be executed as a string */
|
||||
|
|
|
@ -260,7 +260,8 @@ interface CodegenState {
|
|||
markers: {
|
||||
insideMarkdown: boolean | Record<string, any>;
|
||||
};
|
||||
importExportStatements: Set<string>;
|
||||
exportStatements: Set<string>;
|
||||
importStatements: Set<string>;
|
||||
}
|
||||
|
||||
/** Compile/prepare Astro frontmatter scripts */
|
||||
|
@ -268,7 +269,6 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
|
|||
const componentImports: ImportDeclaration[] = [];
|
||||
const componentProps: VariableDeclarator[] = [];
|
||||
const componentExports: ExportNamedDeclaration[] = [];
|
||||
|
||||
const contentImports = new Map<string, { spec: string; declarator: string }>();
|
||||
|
||||
let script = '';
|
||||
|
@ -299,9 +299,10 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
|
|||
while (--i >= 0) {
|
||||
const node = body[i];
|
||||
switch (node.type) {
|
||||
// case 'ExportAllDeclaration':
|
||||
// case 'ExportDefaultDeclaration':
|
||||
case 'ExportNamedDeclaration': {
|
||||
if (!node.declaration) break;
|
||||
// const replacement = extract_exports(node);
|
||||
|
||||
if (node.declaration.type === 'VariableDeclaration') {
|
||||
// case 1: prop (export let title)
|
||||
|
@ -312,15 +313,13 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
|
|||
} else {
|
||||
componentProps.push(declaration);
|
||||
}
|
||||
body.splice(i, 1);
|
||||
} else if (node.declaration.type === 'FunctionDeclaration') {
|
||||
// case 2: createCollection (export async function)
|
||||
if (!node.declaration.id || node.declaration.id.name !== 'createCollection') break;
|
||||
createCollection = module.content.substring(node.start || 0, node.end || 0);
|
||||
|
||||
// remove node
|
||||
body.splice(i, 1);
|
||||
}
|
||||
|
||||
body.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
case 'FunctionDeclaration': {
|
||||
|
@ -376,24 +375,23 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
|
|||
});
|
||||
}
|
||||
const { start, end } = componentImport;
|
||||
state.importExportStatements.add(module.content.slice(start || undefined, end || undefined));
|
||||
state.importStatements.add(module.content.slice(start || undefined, end || undefined));
|
||||
}
|
||||
|
||||
// TODO: actually expose componentExports other than __layout and __content
|
||||
for (const componentImport of componentExports) {
|
||||
const { start, end } = componentImport;
|
||||
state.importExportStatements.add(module.content.slice(start || undefined, end || undefined));
|
||||
state.exportStatements.add(module.content.slice(start || undefined, end || undefined));
|
||||
}
|
||||
|
||||
if (componentProps.length > 0) {
|
||||
propsStatement = 'let {';
|
||||
for (const componentExport of componentProps) {
|
||||
propsStatement += `${(componentExport.id as Identifier).name}`;
|
||||
const { init } = componentExport;
|
||||
if (init) {
|
||||
propsStatement += `= ${babelGenerator(init).code}`;
|
||||
}
|
||||
propsStatement += `,`;
|
||||
}
|
||||
propsStatement += `} = props;\n`;
|
||||
const shortname = path.posix.relative(compileOptions.astroConfig.projectRoot.pathname, state.filename);
|
||||
const props = componentProps.map(prop => (prop.id as Identifier)?.name).filter(v => v);
|
||||
console.log();
|
||||
warn(compileOptions.logging, shortname, yellow(`\nDefining props with "export" has been removed! Please see https://github.com/snowpackjs/astro/blob/main/packages/astro/CHANGELOG.md#0150
|
||||
Please update your code to use:
|
||||
|
||||
const { ${props.join(', ')} } = Astro.props;\n`));
|
||||
}
|
||||
|
||||
// handle createCollection, if any
|
||||
|
@ -448,12 +446,16 @@ function compileModule(module: Script, state: CodegenState, compileOptions: Comp
|
|||
for (const [namespace, { spec }] of contentImports.entries()) {
|
||||
const globResult = fetchContent(spec, { namespace, filename: state.filename });
|
||||
for (const importStatement of globResult.imports) {
|
||||
state.importExportStatements.add(importStatement);
|
||||
state.importStatements.add(importStatement);
|
||||
}
|
||||
contentCode += globResult.code;
|
||||
}
|
||||
|
||||
script = propsStatement + contentCode + babelGenerator(program).code;
|
||||
const location = { start: module.start, end: module.end };
|
||||
let transpiledScript = compileExpressionSafe(script, { state, compileOptions, location });
|
||||
if (transpiledScript === null) throw new Error(`Unable to compile script`);
|
||||
script = transpiledScript;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -491,7 +493,7 @@ const FALSY_EXPRESSIONS = new Set(['false', 'null', 'undefined', 'void 0']);
|
|||
/** Compile page markup */
|
||||
async function compileHtml(enterNode: TemplateNode, state: CodegenState, compileOptions: CompileOptions): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
const { components, css, importExportStatements, filename, fileID } = state;
|
||||
const { components, css, importStatements, exportStatements, filename, fileID } = state;
|
||||
const { astroConfig } = compileOptions;
|
||||
|
||||
let paren = -1;
|
||||
|
@ -570,8 +572,8 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
|
|||
case 'InlineComponent': {
|
||||
switch (node.name) {
|
||||
case 'Prism': {
|
||||
if (!importExportStatements.has(PRISM_IMPORT)) {
|
||||
importExportStatements.add(PRISM_IMPORT);
|
||||
if (!importStatements.has(PRISM_IMPORT)) {
|
||||
importStatements.add(PRISM_IMPORT);
|
||||
}
|
||||
if (!components.has('Prism')) {
|
||||
components.set('Prism', {
|
||||
|
@ -634,7 +636,7 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
|
|||
}
|
||||
const { wrapper, wrapperImport } = getComponentWrapper(name, componentInfo, { astroConfig, filename });
|
||||
if (wrapperImport) {
|
||||
importExportStatements.add(wrapperImport);
|
||||
importStatements.add(wrapperImport);
|
||||
}
|
||||
if (curr === 'markdown') {
|
||||
await pushMarkdownToBuffer();
|
||||
|
@ -777,7 +779,8 @@ export async function codegen(ast: Ast, { compileOptions, filename, fileID }: Co
|
|||
markers: {
|
||||
insideMarkdown: false,
|
||||
},
|
||||
importExportStatements: new Set(),
|
||||
importStatements: new Set(),
|
||||
exportStatements: new Set(),
|
||||
};
|
||||
|
||||
const { script, createCollection } = compileModule(ast.module, state, compileOptions);
|
||||
|
@ -788,7 +791,8 @@ export async function codegen(ast: Ast, { compileOptions, filename, fileID }: Co
|
|||
|
||||
return {
|
||||
script: script,
|
||||
imports: Array.from(state.importExportStatements),
|
||||
imports: Array.from(state.importStatements),
|
||||
exports: Array.from(state.exportStatements),
|
||||
html,
|
||||
css: state.css.length ? state.css.join('\n\n') : undefined,
|
||||
createCollection,
|
||||
|
|
|
@ -105,6 +105,7 @@ interface CompileComponentOptions {
|
|||
projectRoot: string;
|
||||
isPage?: boolean;
|
||||
}
|
||||
/** Compiles an Astro component */
|
||||
export async function compileComponent(source: string, { compileOptions, filename, projectRoot, isPage }: CompileComponentOptions): Promise<CompileResult> {
|
||||
const result = await transformFromSource(source, { compileOptions, filename, projectRoot });
|
||||
const site = compileOptions.astroConfig.buildOptions.site || `http://localhost:${compileOptions.astroConfig.devOptions.port}`;
|
||||
|
@ -121,9 +122,10 @@ import { h, Fragment } from 'astro/dist/internal/h.js';
|
|||
const __astroInternal = Symbol('astro.internal');
|
||||
async function __render(props, ...children) {
|
||||
const Astro = {
|
||||
props,
|
||||
site: new URL('/', ${JSON.stringify(site)}),
|
||||
css: props[__astroInternal]?.css || [],
|
||||
request: props[__astroInternal]?.request || {},
|
||||
site: new URL('/', ${JSON.stringify(site)}),
|
||||
isPage: props[__astroInternal]?.isPage || false
|
||||
};
|
||||
|
||||
|
@ -144,11 +146,15 @@ export async function __renderPage({request, children, props, css}) {
|
|||
__render,
|
||||
};
|
||||
|
||||
props[__astroInternal] = {
|
||||
request,
|
||||
css,
|
||||
isPage: true
|
||||
};
|
||||
Object.defineProperty(props, __astroInternal, {
|
||||
value: {
|
||||
request,
|
||||
css,
|
||||
isPage: true
|
||||
},
|
||||
writable: false,
|
||||
enumerable: false
|
||||
})
|
||||
|
||||
const childBodyResult = await currentChild.__render(props, children);
|
||||
|
||||
|
@ -162,7 +168,11 @@ export async function __renderPage({request, children, props, css}) {
|
|||
}
|
||||
|
||||
return childBodyResult;
|
||||
};\n`;
|
||||
};
|
||||
|
||||
${result.exports.join('\n')}
|
||||
|
||||
`;
|
||||
|
||||
return {
|
||||
result,
|
||||
|
|
|
@ -228,7 +228,7 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
|
|||
canonicalURL: canonicalURL(requestURL.pathname, requestURL.origin),
|
||||
},
|
||||
children: [],
|
||||
props: { collection },
|
||||
props: Object.keys(collection).length > 0 ? { collection } : {},
|
||||
css: Array.isArray(mod.css) ? mod.css : typeof mod.css === 'string' ? [mod.css] : [],
|
||||
})) as string;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let content: any;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
|
@ -14,4 +14,4 @@ export let content: any;
|
|||
|
||||
<main><slot></slot></main>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
const allPosts = Astro.fetchContent('./post/**/*.md');
|
||||
|
@ -27,4 +27,4 @@ export async function createCollection() {
|
|||
{collection.data.map((post) => (
|
||||
<a href={post.url}>{post.title}</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
const allPosts = Astro.fetchContent('./post/*.md');
|
||||
|
@ -26,4 +26,4 @@ export async function createCollection() {
|
|||
|
||||
<div id={collection.params.slug}>
|
||||
<h1>{collection.data[0].title}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
const data = await Promise.all([
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection: any;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let content;
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
<html>
|
||||
<head>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export function createCollection() {
|
||||
return {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import { Markdown } from 'astro/components';
|
||||
export const title = 'My Blog Post';
|
||||
export const description = 'This is a post about some stuff.';
|
||||
const title = 'My Blog Post';
|
||||
const description = 'This is a post about some stuff.';
|
||||
---
|
||||
|
||||
<Markdown>
|
||||
|
|
|
@ -4,8 +4,8 @@ import Layout from '../layouts/content.astro';
|
|||
import Hello from '../components/Hello.jsx';
|
||||
import Counter from '../components/Counter.jsx';
|
||||
|
||||
export const title = 'My Blog Post';
|
||||
export const description = 'This is a post about some stuff.';
|
||||
const title = 'My Blog Post';
|
||||
const description = 'This is a post about some stuff.';
|
||||
---
|
||||
|
||||
<Markdown>
|
||||
|
|
|
@ -4,8 +4,8 @@ import Layout from '../layouts/content.astro';
|
|||
import Hello from '../components/Hello.jsx';
|
||||
import Counter from '../components/Counter.jsx';
|
||||
|
||||
export const title = 'My Blog Post';
|
||||
export const description = 'This is a post about some stuff.';
|
||||
const title = 'My Blog Post';
|
||||
const description = 'This is a post about some stuff.';
|
||||
---
|
||||
|
||||
<div id="deep">
|
||||
|
|
|
@ -3,8 +3,8 @@ import { Markdown } from 'astro/components';
|
|||
import Layout from '../layouts/content.astro';
|
||||
import Example from '../components/Example.jsx';
|
||||
|
||||
export const title = 'My Blog Post';
|
||||
export const description = 'This is a post about some stuff.';
|
||||
const title = 'My Blog Post';
|
||||
const description = 'This is a post about some stuff.';
|
||||
---
|
||||
|
||||
<Markdown>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
export let collection;
|
||||
const { collection } = Astro.props;
|
||||
|
||||
export async function createCollection() {
|
||||
return {
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
---
|
||||
import authorData from '../data/authors.json';
|
||||
|
||||
export let authorId: string;
|
||||
export interface Props {
|
||||
authorId: string;
|
||||
}
|
||||
|
||||
const { authorId } = Astro.props;
|
||||
const author = authorData[authorId];
|
||||
---
|
||||
<style>
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
export let title: string;
|
||||
export let description: string;
|
||||
export let permalink: string;
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
permalink: string;
|
||||
}
|
||||
const { title, description, permalink } = Astro.props;
|
||||
---
|
||||
|
||||
<meta charset="utf-8" />
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
export let author: string;
|
||||
export let source: string;
|
||||
export let sourceHref: string;
|
||||
export interface Props {
|
||||
author: string;
|
||||
source: string;
|
||||
sourceHref: string;
|
||||
}
|
||||
const { author, source, sourceHref } = Astro.props;
|
||||
---
|
||||
|
||||
<blockquote>
|
||||
|
|
|
@ -2,10 +2,14 @@
|
|||
import Author from './Author.astro';
|
||||
import GithubStarButton from './GithubStarButton.astro';
|
||||
|
||||
export let title: string;
|
||||
export let author: string;
|
||||
export let publishDate: string;
|
||||
export let heroImage: string;
|
||||
export interface Props {
|
||||
title: string;
|
||||
author: string;
|
||||
publishDate: string;
|
||||
heroImage: string;
|
||||
}
|
||||
|
||||
const { title, author, publishDate, heroImage } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="layout">
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
---
|
||||
import Author from './Author.astro';
|
||||
|
||||
export let title: string;
|
||||
export let publishDate: string;
|
||||
export let href: string;
|
||||
export interface Props {
|
||||
title: string;
|
||||
publishDate: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
const { title, publishDate, href } = Astro.props;
|
||||
---
|
||||
<article class="post-preview">
|
||||
<header>
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
---
|
||||
export let type = "tip";
|
||||
export let title;
|
||||
export interface Props {
|
||||
title: string;
|
||||
type?: 'tip' | 'warning' | 'error'
|
||||
}
|
||||
const { type = 'tip', title } = Astro.props;
|
||||
---
|
||||
|
||||
<aside class={`note type-${type}`}>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
---
|
||||
export let code: string;
|
||||
export interface Props {
|
||||
code: string;
|
||||
}
|
||||
const { code } = Astro.props;
|
||||
---
|
||||
|
||||
<pre><code>{code.trim().split('\n').map(ln => <span class="line">
|
||||
|
|
|
@ -4,7 +4,7 @@ import SiteSidebar from '../components/SiteSidebar.astro';
|
|||
import ThemeToggle from '../components/ThemeToggle.tsx';
|
||||
import DocSidebar from '../components/DocSidebar.tsx';
|
||||
|
||||
export let content;
|
||||
const { content } = Astro.props;
|
||||
const headers = content?.astro?.headers;
|
||||
---
|
||||
|
||||
|
|
Loading…
Reference in a new issue