Code Monkey home page Code Monkey logo

roadmap's Introduction

Astro Project Roadmap

Overview

Glossary

Proposal Champion: A proposal is more likely to move forward in this process if it has a champion attached to it. This role is self-nominated and open to anyone (both maintainers and community members are welcome to volunteer). It may be the original proposal author, or someone who joins later. The responsibility of a champion is to help shepard the proposal through the later parts of this process, including: writing the detailed RFC, responding to and incorporating feedback, and eventually implementing the proposal in code.

You are not alone as a champion! If this is your first time writing an RFC or design document, our maintainer team is expected to work with you and guide you through this process.

Stage 1: Proposal

Goal: Unstructured, low-friction conversations on ideas and improvements to Astro. Useful for gathering early feedback and gauging interest with the community and maintainers.

Requirements: None! To suggest an improvement, create a new Discussion using our (completely optional) proposal template.

Location: GitHub Discussions (see all open proposals). The Astro Discord channel #feedback-ideas can also be used to throw an idea out for quick initial feedback, but be warned that chat is short-lived and not designed for longer-lived discussion.

Stage 2: Accepted Proposal

Goal: Confirm proposal feasibility with Astro Maintainers and the Technical Steering Committee (TSC).

Requirements: An existing proposal (Stage 1). In addition, a proposal is more likely to be accepted if it is detailed and well thought-out, can demonstrate community interest, has at least one champion volunteer, and has buy-in/interest from Astro maintainer(s).

Location: GitHub Issues (see all accepted proposals).

What to Expect: A proposal reaches this stage (aka "is accepted") during a meeting with Maintainers and TSC, following our existing RFC Proposal voting process.

When a proposal is accepted, a TSC member will create a new GitHub Issue summarizing the original proposal using our official template. At this point, the proposal champion is free to move on to the next stage. If a champion doesn't exist yet, then an accepted proposal may remain open until a champion volunteers by posting in the GitHub Issue.

In some cases, a proposal may be explicitly rejected by TSC if it is known to be infeasible, or go against some existing goals/mission of the project. In the event of an explicit rejection, a TSC member will comment on to the proposal explaining the reasoning for rejection.

A stale, accepted proposal can be removed (rejected after a previous acceptance) at any time following the same, existing RFC Proposal voting process.

Stage 3: RFC & Development

Goal: Begin development! Gather implementation feedback and work with maintainers during development.

Requirements: An accepted proposal (Stage 2) and a proposal champion to author and implement the RFC.

Location: GitHub Pull Requests (see all in-progress RFCs) (see all finished RFCs)

What to Expect: To create an RFC for an already-accepted proposal, the proposal champion must use our stage-3--rfc-template.md RFC template in the repo. The initial sections of the RFC template should be copy-pasted from the the accepted proposal (they match 1:1). All remaining sections are left for the champion to complete with the implementation and tradeoff details of the RFC.

You do not need to get an RFC approved before beginning development! One of the best ways to validate your RFC is to prototype, so early prototyping and parallel development alongside the RFC is strongly encouraged. The RFC is a living document during this stage, and is most useful for gathering feedback as you build. An RFC will not be accepted and merged until it's PR is also ready to merge.

The proposal champion can request feedback on their RFC at any point, either asynchronously in Discord (inside the #dev/#dev-ptal channel) or during our weekly community call. Maintainers are expected to provide timely feedback at this stage so that the RFC author is never blocked. If you are an RFC champion and need access to the #dev-ptal channel, message @fks for permission.

Stage 4: Ship it!

An RFC is ready to be approved and finalized once it's Pull Request is ready for its final review. When a champion thinks the RFC is ready he can ask for a call for consensus.

At this time, some member of the core team will motion for a final comment period (FCP). This follows our existing RFC Proposal voting process. Once the final comment period has elapsed the RFC will be merged if there are no objections.


Prior Art / Special Thanks

This process is an amalgamation of Remix's Open Development process and our previous RFC process, which had been based on the RFC processeses of the Vue, React, Rust, and Ember projects.

roadmap's People

Contributors

bholmesdev avatar bluwy avatar boehs avatar ematipico avatar florian-lefebvre avatar fredkschott avatar jerrywu1234 avatar jonathantneal avatar lilnasy avatar matthewp avatar mrienstra avatar natemoo-re avatar princesseuh avatar sgruenholz2 avatar sylvinus avatar thepassle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

roadmap's Issues

Container API: render components in isolation

Body

  • Accepted Date: 23/03/23
  • Reference Issues/Discussions: #462
  • Author: @natemoo-re
  • Implementation PR: No PR yet. See the feat/container branch for an exploration of implementation.

Summary

Astro components are tightly coupled to astro (the metaframework). This proposal introduces a possible server-side API for rendering .astro files in isolation, outside of the full astro build pipeline.

Background & Motivation

Some of our own proposals, as well as many third-party tool integrations, are blocked until we expose a proper server-side rendering API for .astro components. Other frameworks have tools like preact-render-to-string or react-dom/server that make rendering components on the server straight-forward.

We've avoided doing this because... it's very hard! Part of the appeal of .astro components is that they have immediate access to a number of powerful APIs, context about your site, and a rich set of framework renderers. In the full astro build process, we are able to wire up all this context invisibly. Wiring up the context manually as a third-party is prohibitively complex.

Goals

  • Provide an API for rendering .astro components in isolation
  • Expose a familiar, user-friendly API
  • Surface enough control for full astro parity, but abstract away internal APIs
  • Enable third-party tools to consume .astro files on the server
  • Enable unit testing of .astro component output
  • Possibly unblock .mdx compiledContent/html output?
  • Support Astro framework renderers (@astrojs/*) if possible

Example

import { AstroContainer } from 'astro/container';
import Component from './components/Component.astro';

const astro = new AstroContainer();
console.log(await astro.renderToString(Component, { props, slots }))

The container can be optionally constructed with some settings that are typically reserved for Astro configuration.

const astro = new AstroContainer({
  mode?: 'development' | 'production';
  site?: string;
  renderers?: Renderer[]
});

The second argument to renderToString optionally provides render-specific data that may be exposed through the Astro global, like props, slots, request, and/or params.

await astro.renderToString(Component, { props, slots, request, params })

Images are not collected in Markdown files when using HTML syntax

Astro Info

Astro                    v4.5.9
Node                     v18.17.1
System                   Linux (x64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             none

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

The issue

Astro seems to support images co-location in content collections only when Markdown syntax is used. When using HTML syntax (ie. an img tag), the image is not processed and result in a 404:

  • If I use ![a working image](../assets/image.png), the image is processed and visible in the browser.
  • However, if I use <img alt="a failing image" src="../assets/image.png" />, the image seems to be ignored. I only see the alt text and the console shows a 404.

I think the issue comes from those lines in packages/markdown/remark/src/remark-collect-images.ts:

visit(tree, ['image', 'imageReference'], (node: Image | ImageReference) => {
	if (node.type === 'image') {
		if (shouldOptimizeImage(node.url)) imagePaths.add(node.url);
	}
	if (node.type === 'imageReference') {
		const imageDefinition = definition(node.identifier);
		if (imageDefinition) {
			if (shouldOptimizeImage(imageDefinition.url)) imagePaths.add(imageDefinition.url);
		}
	}
});

When using HTML syntax, the node type is html so the image is not collected by Astro. I guess we need to parse the HTML with a regex to collect the src attribute for all images encountered in the node.value.

Steps to reproduce

In addition to the Stackblitz link below, here are the few steps to reproduce the bug:

  1. Create a new project: npm create astro@latest -- --template minimal (answer Yes to all and Strict to Typescript)
  2. Create a folder to store our images and another for our posts in src/content: mkdir -p src/content/{assets,blog}
  3. Put an image in src/content/assets
  4. Create a Markdown file: touch src/content/blog/first-post.md
  5. Add the image in that file with the two syntax (Markdown and HTML):
![a working image](../assets/image.png)

<img alt="a failing image" src="../assets/image.png" />
  1. Edit src/pages/index.astro to load our post:
---
import { getEntry } from "astro:content";

const entry = await getEntry("blog", "first-post");
const { Content } = await entry.render();
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <meta name="generator" content={Astro.generator} />
    <title>Astro</title>
  </head>
  <body>
    <h1>{entry.data.title}</h1>
    <Content />
  </body>
</html>
  1. Launch the server: npm run dev
  2. Open the website in a browser and see the difference between the two images (you can also see a 404 in the terminal).

Additional context

I use a Git submodule to separate the content directory from the website code so I need to colocate the images with Markdown files. In addition, sometimes I want to wrap the images in a figure to add a figcaption so I need to write HTML inside the Markdown file.

What's the expected result?

I should be able to use both ![alt text](./path/to/an/img.jpg) and <img alt="alt text" src="./path/to/an/img.jpg" /> to render an image in a Markdown file.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/astro-markdown-images?file=src%2Fcontent%2Fblog%2Ffirst-post.md

Participation

  • I am willing to submit a pull request for this issue.

env variables aren't populated even though process.env exists

Astro Info

Astro                    v4.2.4
Node                     v18.18.0
System                   Linux (x64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             none

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

Astro seems to have the concept of process.env on the server, but it doesn't populate it with stuff from .env.local for example. This is reaally annoying for library authors trying to automatically infer values for their users. If there is a process.env, we usually chooses to got with that, and only falling back to import.meta.env if that fails (for example if typeof process === "undefined")

What's the expected result?

either process not to exist or for the variables to be put there. this middleground seems very confusing...

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-hdhenl?file=src%2Fpages%2Fapi%2Fhello.ts

Participation

  • I am willing to submit a pull request for this issue.

Redirects

Body

  • Accepted Date: 2023-02-03
  • Reference Issues/Discussions: #319
  • Implementation PR:

Summary

It would be useful if Astro could support redirects for static builds. Possibly for server builds, too?

Sometimes users want to rename a route or refactor how pages are organized. It's not possible to just rename a page as there may be links pointing to it, so redirects have to be generated. While this is possible to do manually, it's not very convenient.

Background & Motivation

Redirects for static and server mode are fairly straight-forward to implement. Other tools like Jekyll expose this ability, and hosting providers do as well.

It would be helpful if Astro could generate these automatically as a convenience. This feature could also normalize the implementation across hosting providers and output mode.

Goals

  • Simplify boilerplate by providing a first-party API for redirects.
  • Automatically generate markup for redirects in static mode
  • Maybe: automatically configure redirects for adapters in server mode to avoid host-specific redirect configuration?

Non-Goals

None at this time.

Example

API TBD, but this could either be a built-in redirect configuration

import { defineConfig } from 'astro/config';

export default defineConfig({
  redirects: {
    '/foo/bar': '/unicorn/rainbow'
  }
})

or exposed as an official integration

import { defineConfig } from 'astro/config';
import redirects from '@astrojs/redirects';

export default defineConfig({
  integrations: [
    redirects({
      '/foo/bar': '/unicorn/rainbow'
    })
  ]
})

Markdoc support in content collections

Body

Summary

This is a proposal to add Markdoc support to content collections.

Background & Motivation

We've received multiple user requests for Markdoc support since its public launch. In fact, we've seen early community projects bringing Markdoc to robust project themes.

Markdoc is also designed to solve existing limitations of MDX in Astro.

  1. Performance suffers at scale. Unlike plain Markdown that outputs a string of HTML, MDX outputs a JavaScript module of JSX components. This requires Astro and Babel preprocessing for even the simplest MDX documents. Notably, this required a bump to our maximum memory usage when building / deploying docs.astro.build after migrating to MDX.
  2. Your content is tied to your UI. MDX can import styles and components directly, which is convenient from a developer standpoint. However, this causes issues when content needs to be reused in multiple contexts. A common example is RSS, where you may want a component-rich version from your blog and a simplified HTML output for your RSS feed.

Markdoc is built to solve (2) by separating content from the components, styles, and assets you choose to render. You can use an Astro component renderer when using on your site, Markdoc's own html renderer for RSS, and even write your own renderer to traverse Markdoc pages yourself. (1) Is something we're excited to test, requiring a thorough performance benchmark.

The content collections API was built generically to support this future, choosing format-agnostic naming like data instead of frontmatter and body instead of rawContent. Because of this, introducing new authoring formats is possible without breaking changes.

Goals

  • Create an @astrojs/markdoc integration that adds .mdoc support to content collections.
  • Support Astro components and server-rendered UI components (React, Vue, Svelte, etc) within Markdoc files. Note this excludes client-rendered UI components (see non-goals).
  • Benchmark Markdoc performance against MDX at 1000+ documents. This addresses problem (1) from the previous section. Metrics to compare: SSG build time, SSG and SSR build memory usage, SSR response speed.

Non-goals

  • ESM import and src/pages/ support for Markdoc files. See discussion for context.
  • Allowing the .md extension. This would mean overriding Astro's .md renderer, which is tightly coupled to remark and your markdown configuration options today. We agree using .md for Markdoc is a common use case, and deserves a separate proposal to make Astro's Markdown rendering flexible.
  • A solution for client-rendered UI components. Unlike MDX, Markdoc doesn't have a concept of directives, and our compiler doesn't have a clear way to dynamically render client-side components (see challenges). We will recommend users wrap their components in an Astro component to apply the client: directive.
  • Full alignment with Markdown and MDX rendered result. Namely, the computed headings property (which can be tackled in future releases) and frontmatter manipulation via remark (since remark is incompatible with Markdoc).

Example implementation

Markdoc will be introduced as an integration. To standardize our process for adding new collection teams, we may experiment with a (private) integration helper internally. This example shows an addContentEntryType hook to setup the .mdoc extension, and attach logic for parsing the data and body properties:

// @astrojs/markdoc/index.ts
export const markdoc: AstroIntegration = () => ({
		'astro:config:setup'({ addContentEntryType }) {
			addContentEntryType({
				extensions: ['.mdoc'],
				parser: '@astrojs/markdoc/contentEntryParser',
			});
		}
	}
});

// @astrojs/markdoc/contentEntryParser.ts
import parseFrontmatter from 'gray-matter';
export default {
	getEntryInfo({ contents }) {
		const parsed = parseFrontmatter(contents);
		return {
			// The unparsed data object that can be passed to a Zod schema.
			data: parsed.data,
			// The body of the data file. This should be the raw file contents with metadata (i.e. frontmatter block) stripped
			body: parsed.content,
			// (Optional) The untouched frontmatter block with newlines and formatting preserved. Used for computing error line hints.
			rawData: parsed.matter,
		}
	}
}

// astro.config.mjs
import markdoc from '@astrojs/markdoc';

export default {
	integrations: [markdoc()],
}

Example Usage

Say you've authored a collection of blog posts using Markdoc. You can store these entries as a blog collection, identically to Markdown or MDX:

src/content/
	blog/
		# Could also use `.md`
		post-1.mdoc
		post-2.mdoc
		post-3.mdoc
...

Then, you can query entry frontmatter with the same getCollection() and getEntryBySlug() APIs:

---
import { getCollection, getEntryBySlug } from 'astro:content';

const blog = await getCollection('blog');
const firstEntry = await getEntryBySlug('blog', 'post-1');
---

Users should also be free to render Markdoc contents using a Content component. This will be exposed from the render() result, and feature two props:

  • components?: Record<string, ComponentRenderer>: A mapping from Markdoc tags or elements to Astro components.
  • config?: import('@markdoc/markdoc').Config: An (optional) Markdoc config to be used during the transformation step.
---
import Title from '../components/Title.astro';
import Marquee from '../components/Marquee.astro';
import { getEntryBySlug } from 'astro:content';

const mdocEntry = await getEntryBySlug('blog', 'test');
const { Content } = await mdocEntry.render();
---

<html lang="en">
	<body>
		<Content
			config={{
				variables: { underlineTitle: true },
			}}
			components={{
				h1: Title,
				marquee: Marquee,
			}}
		/>
	</body>
</html>

Sharing config

This solution is flexible, but we expect users to reuse config and components across their project. For this, we will recommend creating a utility component to encapsulate that config. Here is one example that can render any blog collection entry with an {% aside /%} shortcode:

---
// src/components/BlogContent.astro
import Aside from './Aside.astro';
import type { CollectionEntry } from 'astro:content';

type Props = {
	entry: CollectionEntry<'blog'>;
};

const { entry } = Astro.props;
const { Content } = await entry.render();
---

<Content
	config={{
		tags: {
			aside: {
				render: 'Aside',
				attributes: {
					type: { type: String },
					title: { type: String },
				},
			},
		},
	}}
	components={{ Aside }}
/>

Now, you can pass any blog collection entry to render the result with this config:

---
import { getEntryBySlug } from 'astro:content';
import BlogContent from '../components/BlogContent.astro';

const mdocEntry = await getEntryBySlug('blog', 'test');
---

<h1>{intro.data.title}</h1>
<BlogContent entry={mdocEntry} />

See this example video for more.

Advanced use case: component prop mapping

Component renderers can also include a props() function to map Markdoc attributes and AST entries to component props. This is useful when:

  • computing props based on the Markdoc AST
  • mapping Markdoc's generated attributes to prop names

This example maps Markdoc's generated data-language attribute for code blocks to the lang prop used by Astro's Code component, and stringifies the contents to HTML for use with Shiki:

---
import { Code } from 'astro/components';
import { Title } from '../components/Title.astro';
import Markdoc from '@markdoc/markdoc';
...
---

...
<Content
	components={{
		h1: Title,
		pre: {
			component: Code,
			props({ attributes, getTreeNode }) {
				return {
					lang: attributes['data-language'],
					code: Markdoc.renderers.html(getTreeNode().children),
				};
			},
		},
	}}
/>

Production Dependencies

What version of astro are you using?

2.9.3

Are you using an SSR adapter? If so, which one?

Node

What package manager are you using?

npm

What operating system are you using?

Mac

What browser are you using?

Chrome

Describe the Bug

After installing only production packages (npm i --omit dev) for the project, I noticed that possibly many installed packages are not required for the runtime. They probably should be declared as devDependencies. e.g. typescript, @babel/*, esbuild, vite. Having them declared as dependencies greatly increases the size of node_modules, making, e.g. building a small docker image of the app very difficult. The node_modules for a "hello world" app has about 160 MB.

What's the expected result?

All dependencies that are not required for the runtime should be declared as devDependencies.

Link to Minimal Reproducible Example

https://github.com/withastro/astro/blob/main/packages/astro/package.json

Participation

  • I am willing to submit a pull request for this issue.

First-party support for a Picture component

  • Accepted Date: 2023-09-14
  • Reference Issues/Discussions: #598
  • Author: @tony-sull
  • Champion(s): @Princesseuh
  • Implementation PR: WIP

Summary

astro:assets shipped successfully in 3.0. Now that it's available for everyone to enjoy, we'd like to start extending it with new features. One of the most requested feature coming from 3.0 was a Picture component, to allow supporting multiple format and sizes.

Background & Motivation

Images on the web are tricky 😅

When it comes to performance, it's best for pages to load the correct size and image format based on the browser's support and window size. Multiple sizes can be handled by <img srcset="">, but only the <picture> element has support for defining multiple image formats like .jpg, .webp, and .avif for the browser to select from. Ideally, supporting both is the most optimal thing to do, but a Picture component would be a start.

Goals

  • include a <Picture> component in astro:assets that supports building multiple and formats and sizes

Out of scope

  • Full support of art direction where different sizes also have different aspect ratios.
    • This requires cropping, which we choose not to support in our default image services at this time. The underlying APIs are flexible enough that implement this yourself is possible however.
  • Adding header sniffing support into the injected _image API route used to optimize images in SSR pages
    • In addition to believing this is bad design, a SSR-only solution is unsuitable for Astro. 3.1 adds the option to add a custom endpoint for image, so this is possible for users to implement it themselves if they want to.

Example implementations

None of the implementation below are finals, they're merely inspirations to get the discussion going.

@astrojs/image's <Picture>

@astrojs/image included a <Picture> component that may be a decent starting point. It had a few shortcomings (didn't apply width and height as expected, couldn't set attributes on the underlying img etc.) but nothing we wouldn't be able to solve in a more complete version.

---
import { Picture } from "@astrojs/image/components"
---

<Picture widths={[450, 900, 1800]} formats={["avif", "webp", "jpg"]} />

Composition API

Essentially an easier to use normal picture element. Every source element could inherit props from the Picture component (somehow), so you'd be able to set, ex: a src for Picture that would work for every Source that does not have its own src

---
import {Picture, Source} from "astro:assets";
import myImage from "../something.png";
---

<Picture src={myImage}>
	<Source format="avif" width={500} />
	<Source />
<Picture>

CDN support

Body

  • Accepted Date: 2023-03-23
  • Reference Issues/Discussions: #456
  • Implementation PR:

Summary

Provide an option to specify a CDN URL for static assets to serve from in production.

Background & Motivation

Large traffic sites often have CDN servers that are optimized to serve assets only. For example, a site served from https://astro.build would reference all it's assets from https://cdn.astro.build.

A CDN URL would also allow assets from multiple sites to be deployed to the same CDN server to share the performance, where they can be separated by URL subpaths.

There are also prior art from other frameworks that users want in Astro too:

Goals

  • Provide an option to prepend generated asset links with the CDN URL.
  • Provide an env variable to access the CDN URL (import.meta.env.*) to prepend links manually.
  • Works with static and server output.
  • Works with existing Astro features, like content collections, astro:assets images, and @astrojs/image.

Non-Goals

  • Auto-prefixing CDN URLs to user-created <link href> or <img src> etc.
  • Allow changing the CDN URL in runtime.
  • Handling CDN URLs for files in the public directory.
    • Users have to preprend the URL themselves if needed.
  • The Astro CDN service.

Example

Astro config:

// astro.config.js
export default defineConfig({
  build: {
    cdnUrl: 'https://cdn.example.com'
  }
})

Generated HTML example:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="https://cdn.example.com/index.123456.css" />
  </head>
  <body>
    <!-- if astro images are used -->
    <img src="https://cdn.example.com/penguin.png" />
  </body>
 </html>

Details and behaviours:

  • With the default build.assets option of _astro directory, the user will copy all the files from the dist/_astro directory to the https://cdn.example.com server.
  • The CDN URL is not affected by base option, because base is the serving base of the user-facing site URL, e.g. https://example.com/foo/. (similar to prior art)
  • The CDN URL can accept any pathname, for example https://cdn.example.com/project-a, and Astro would include it in the built URL.

More prior art research

Framework Option What users have to do Public files supported?
Nextjs assetPrefix Upload .next/static/ as https://cdn.com/_next/static/
Nuxt app.cdnURL Upload .output/public/_nuxt/ as https://cdn.com/_nuxt/
SvelteKit path.assets Upload .svelte-kit/output/client/_app/ as https://cdn.com/_app/

*Upload path may depend on deployment target / adapter

CSS Ordering

Body

  • Accepted Date: 2023-03-24
  • Reference Issues/Discussions: #510 and #371
  • Implementation PR:

Summary

Allow styles in Astro files to override global styles.

Background & Motivation

A common pattern in an application is to have some global styles in a global style file like so:

global.css

input {
  border-width: 1px;
}

And then to use them in an Astro component.

---
import '../global.css';
---
<style>
  input {
    border-width: 2px;
  }
</style>

<input type="text">

The intent is to override the styles on this page (or component). But due to chunking of shared dependencies, we cannot guarantee that CSS ordering will be correct.

And due to the use of :where() for scoping, scoped styles can't win in specificity to apply the overriden styles. (as :where preserves specifity, unlike Vue or Svelte that adds attributes/classes to increase specificity) (See original RFC for details)

We need a solution for this.

Goals

  • A way to have scoped styles take priority over global styles.
  • A consistent and predictable implementation of CSS ordering.
  • Better browser support (or an easy way to support old browsers).

Non-Goals

  • Auto-polyfilling CSS features.

Example

Below are possible solutions:

  1. Go back to using scoped-attributes/classes (like Vue and Svelte), this would increase specificity by 1.
  2. Use @layer: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer. However, this doesn't have better browser support than :where.
  3. Manually mark certain CSS files to be global (via astro.config?), and order them first to have lower priority.
  4. [FUTURE] Use @scope: https://www.w3.org/TR/css-scoping-1/

Allow framework components to stream responses or run in parallel

What version of astro are you using?

2.6.4

Are you using an SSR adapter? If so, which one?

Node

What package manager are you using?

pnpm, npm

What operating system are you using?

Mac

What browser are you using?

Chrome

Describe the Bug

When I try to test parallel rendering of React components with promises it seems to block the entire document, until the promises resolve.

await new Promise((res) => setTimeout(res, 1800));

const ReactComponent = () => {
  return (
    <h1>{1800}ms Delayed</h1>
  );
};

export default ReactComponent;

Parallel rendring works as intended when I use Astro components. If I'm doing something wrong, please point me in the right direction.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-wsphny?file=src%2Fpages%2Findex.astro

Participation

  • I am willing to submit a pull request for this issue.

CSRF Protection #471

Summary

Provide the infrastructure to protect Astro websites from CSRF attacks

Background & Motivation

Most background is available here: https://owasp.org/www-community/attacks/csrf

Astro should provide some level of security to users.

Goals

  • Add the required checks to prevent CSRF, probably via an option

Non-Goals

  • Give the users the possibility to customise the implementation of the protection

Rerouting

Summary

Programmatic control over routing.

Background & Motivation

As astro grows in popularity, it is being used for more and more use cases. One of these is multitenant websites where a tenant may be given a subdomain. This proposal introduces a powerful primitive that allows astro users to build websites with complex routing requirements. Rather than a limitation, file-based routing is now a sensible default!

Goals

  • Defuse.
  • Make it unnecessary to rely on implicit routing rules
  • Introduce framework-designed 404 and 500 pages
  • Make middleware run for requests that don't match a route (with framework-designed error pages)

Non-Goals

  • Reroute to an external service.
  • Support for functionPerRoute

Built-in SVG components

Summary

Let's support importing and using .svg files as Astro components.

Background & Motivation

Users have reported that .svg files are currently difficult to use—this is a problem we should provide an optimized solution for. Working with .svgs doesn’t need to be difficult or bloat your client-side JavaScript.

The Astro team has discussed and experimented with an "icon" primitive since before Astro v1.0 shipped. Now that we have shipped 3.0 with full astro:assets support, I firmly believe all of the pieces are in place to finally make this happen.

Goals

  • Allow users to import and render local .svg files as if they were an Astro component
  • Allow passing props onto the root <svg> element while overriding the existing props
  • Automate best practices for to minimize performance footguns
    • Including many inlined <svg> on a page can hurt browser parsing performance. We can automatically reduce the number of nodes by using <symbol> and <use>.
    • Inline <svg> often have xmlns and xmlns:xlink and version attributes. These are not needed in HTML5 and we can automatically drop them to save a few bytes.
  • Support this in a backwards-compatible way, meaning the current public interface of an .svg import remains unchanged
  • Stretch: support rendering .svg components in frameworks without inlining them into the client side JavaScript
    • Creating framework components for .svg icons is an anti-pattern. It’s a terrible idea that bloats your JavaScript and creates all sorts of headaches for HMR and clientside performance in production.
    • If we provide a great <Icon> component for each supported framework, we’ll make it easy for users to avoid this anti-pattern. It’s so common now because there aren’t many other good solutions.

Non-Goals

  • Future: @iconify/json support
  • Future: unplugin-icons support? Making this as seamless as possible would be awesome but supporting local .svg files is a good place to start.

Astro middleware

Body

  • Accepted Date: 2023-03-22
  • Reference Issues/Discussions:
  • Implementation PR:

Summary

Introduce a middleware to Astro, where you can define code that runs on every request. This API should work regardless of the rendering mode (SSG or SSR) or adapter used. Also introduces a simple way to share request-specific data between proposed middleware, API routes, and .astro routes.

Background & Motivation

Middleware has been one of the most heavily requested feature in Astro. It's useful for handling common tasks like auth guards and setting cache headers. For me, it would make handling authentication much easier.

This proposal is heavily inspired by SvelteKit's handle hooks;

Goals

  • Provide a way intercept requests and responses, allowing users to set cookies and headers
  • Works both in SSR and SSG mode
  • Allow users to use community-created middlewares (libraries)
    • Make available via integrations API.
  • Provide an API for request-specific data
  • Non-Node runtimes specific APIs. ie. Cloudflare Durable Objects.
    • Add middleware from adapter.

Non-Goals

  • Route specific middleware, middlewares that are run only on specific routes

Example

A quick prototype

Middlewares can be defined in src/middleware.ts by exporting middleware (array):

export cost middleware = []

A simple middleware looks like so:

export const middleware: Middleware = async (context: APIContext, resolve: Resolve) => {
  const session = await getSession(context.request);
  const isProtectedRoute = matchRoute(context.url);
  if (!session && isProtectedRoute) {
    // early response
    return new Response(null, {
      status: 400,
    });
  }
  context.cookies.set("random-cookie", "some-value");
  const response = await resolve(context); // resolve api route or render page
  return response;
};

context is the same one provided to API route handlers. Most of Astro's request handling process will be behind resolve(), and the response object returned from middleware will be sent to the user's browser.

Multiple middleware

sequence can be imported to run multiple middlewares in sequence.

export const middleware: Middleware = sequence(
  async (context, resolve) => {
    console.log("1a");
    const response = await resolve(event);
    console.log("1b");
    return response;
  },
  async (context, resolve) => {
    console.log("2a");
    const response = await resolve(event);
    console.log("2b");
    return response;
  }
);

The log result for this example is:

1a
2a
2b
1b

locals

This proposal also adds locals property to APIContext and AsroGlobal. This locals object will be forwarded across the request handling process, allowing for data to be shared between middlewares, API routes, and .astro pages. This is useful for storing request specific data, such as user data, across the rendering step.

export const middleware = async (context: APIContext, resolve: Resolve) => {
  context.session = await getSession(context.request);
  const response = await resolve(context);
  return response;
};
---
// pages/index.astro
const session = Astro.locals.session;
---

The value type of locals can be anything as it won't be JSON-stringified:

---
// pages/index.astro
const session = await Astro.locals.getSession();
---

locals can be typed inside src/env.d.ts (I think it's possible?):

// src/env.d.ts
// at least one of these should be possible
type Locals {}

declare namespace App {
    type Locals = {}
}

SSG mode

The middleware function will run on each route's pre-rendering step, as if it were handling a normal SSR request.

export const middleware = async (context: APIContext, resolve: Resolve) => {
  const response = await resolve(context); // pre-render step here
  return response;
};

Incremental Builds

Summary

Incremental Build support in Astro aims to significantly speed up repeated runs of astro build. Initial builds will populate some kind of cache, which will allow subsequent builds to bypass Rollup for unchanged trees of the module graph.

Background & Motivation

The original incremental build support proposal is one of our oldest and most highly upvoted issues. Unfortunately, users have not shared many concrete examples in that thread. However, from the extensive performance profiling we've done, we know that Rollup is the main bottleneck in Astro's build process.

Now that our rendering, Markdown, and MDX performance has been optimized about as far as we can take it, now is the time to explore new options. The best option we have is to move as much of our build process out of Rollup as possible, likely with some sort of build cache. That is the goal of introducing incremental builds.

Why now? The reason is straightforward—caching is notoriously difficult to get right. We did not want to take on the additional complexity until our API surface was stable and our internal build process was easier to reason about. Thanks to significant effort from @bluwy and @ematipico in the past few months, we're now in a good place to tackle this.

Goals

  • Improve astro build performance
  • Avoid as much repeated processing during astro build as possible
  • Implement a generic API that enables incremental builds
  • Eventually, enable incremental builds by default
  • Support existing static, hybrid, and server outputs

Non-Goals

  • Vendor lock-in. Incremental builds will be implemented generically, supporting our existing ecosystem of deployment platforms where possible. If a host caches assets between builds, it is likely that they will support incremental builds automatically.
  • Incremental Static Regeneration (also known as ISR or DPR). The proposal for supporting ISR is an entirely different topic, not covered by this accepted proposal. These features are not mutually exclusive. Implementing incremental build support benefits every user of Astro and does not prevent Astro from potentially introducing ISR in the future.
  • Future: Adapter API. Some adapters perform a significant amount of processing and may also want some form of incremental build support. To reduce the scope of this proposal, we are not considering exposing a public Adapter API for this. This may be implemented in the future as an enhancement.

Supporting CSS-in-JS

It's not super clear which CSS-in-JS libraries work, so I'm creating this issue as sort of a place to start the conversation and document the current status.

Here's a few popular libraries that I know about (will keep this list updated):

Library Status Notes
styled-components 🟡 Partially works Prod build errors with: styled.div is not a function.
Can be worked around with client:only or by using buildSsrCjsExternalHeuristics and ssr.noExternal (will cause FOUC).
emotion 🟡 Partially works Prod build errors with: styled.div is not a function.
Can be worked around with client:only or by using conditional default import (will cause FOUC). Can also patch @astrojs/react.
linaria 🟡 Partially works Prod build errors with: Named export 'styled' not found.
Can be worked around using buildSsrCjsExternalHeuristics and ssr.noExternal or by downgrading to v3.
stitches 🟡 Partially works <style> tag for SSR needs to be in React component
typestyle ✅ Works -
vanilla-extract ✅ Works -
solid-styled 🟡 Partially works Causes FOUC
styled-jsx ❌ Doesn't work No vite or rollup plugin, requires babel
compiled ❌ Doesn't work No vite or rollup plugin, requires babel

From what I understand, if a library doesn't work in astro, it's because of one or more of these reasons*:

  • no support for vite/rollup
  • it requires babel
  • it uses context
  • it requires access to the renderer for SSR styles
  • it doesn't work with new react 18 apis

*I could be wrong so would be nice if someone can verify the above points.


Additionally, here's what @FredKSchott would like to see (quote message from discord):

  1. A table of which CSS-in-JS libraries are/aren't supported in Astro. If not supported, it would also list the reason. If supported, these could also have tests in the repo so that we don't break them in the future.
  2. Some time to go through the ones that aren't supported and try to fix any issues that are fixable by Astro.
  3. For any the css-in-JS libraries that still aren't supported after that, a clear error message inside of Astro core when it sees you try to import the package.

GitHub repo with examples:

https://github.com/mayank99/astro-css-in-js-tests

Participation

  • I am willing to submit a pull request for this issue.

CSS `define:vars` should only add definitions to top-level components

Astro Info

Astro                    v4.2.4
Node                     v20.11.0
System                   macOS (arm64)
Package Manager          pnpm
Output                   hybrid
Adapter                  @astrojs/vercel/serverless
Integrations             auto-import
                         @astrojs/mdx
                         astro-icon
                         @astrojs/partytown
                         @astrojs/sitemap
                         astro-robots-txt

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

Right now, <style define:vars={{}}> adds the variable definitions to every single element in the component. This drastically increases the footprint of components, it's difficult to read, and it will cause issues if a user intentionally wants to override a local variable within the component itself.

What's the expected result?

The CSS var definitions should only be added to the top-level components.

This issue was closed before it was discussed in withastro/astro#7328.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-sdeict-dc8tm6?file=src%2Fcomponents%2FDefineVars.astro

Participation

  • I am willing to submit a pull request for this issue.

Assets: Request for Stricter `getImage()` Attributes

What version of astro are you using?

2.4.5

Are you using an SSR adapter? If so, which one?

Vercel

What package manager are you using?

pnpm

What operating system are you using?

Max

What browser are you using?

N/A

Describe the Bug

I recently shipped an example for plaiceholder using the experimental (and wonderful) "assets" feature
https://github.com/joe-bell/plaiceholder/blob/main/examples/astro

One minor thing that I've had to patch around for now, is that an image's attributes are a bit looser than I would expect:
https://github.com/joe-bell/plaiceholder/blob/main/examples/astro/src/pages/base64/multiple.astro#L18

CleanShot 2023-05-25 at 19 25 15@2x

My expectation here would be that getImage() is at least retrieving the height/width for me (that's what's outputted, but the types don't reflect that currently)

Thanks again for all your work on this feature, having a blast :rock

Link to Minimal Reproducible Example

https://github.com/joe-bell/plaiceholder/blob/main/examples/astro

Participation

  • I am willing to submit a pull request for this issue.

`@astrojs/alpinejs` Lacks TypeScript Support For Alpine Shorthand Directives

What version of astro are you using?

1.6.0

Are you using an SSR adapter? If so, which one?

None

What package manager are you using?

npm

What operating system are you using?

macOS Big Sur v11.4

Describe the Bug

When using the @astrojs/alpinejs integration (v0.1.2) in an Astro project with strict TypeScript config, using shorthand attributes (i.e. @click instead of x-on:click), I get the following VS Code TypeScript error:

Property _click does not exist on type ButtonHTMLAttributes

It's not really reproducible outside of VSCode as StackBlitz doesn't really do the same level of error checking, but I left a link anyways.

Some Commentary & Ideas to Fix It

In my mind the fix for this is to have the Alpine integration modify the astro-jsx.d.ts file to account for all of the various Alpine attributes. In addition to fixing this error, this should (hopefully?) also add VS Code autocomplete support for those attributes—which I think would be really neat!

I'm more than happy to go in and write typings for the different attributes (that seems straightforward enough)—I'm just not sure how to patch into the Astro Integrations API to modify the typings that VS Code / Astro is looking at. If someone could point me in the right direction though, I'm more than willing to figure it out!

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-pf1rr5-egafck

Participation

  • I am willing to submit a pull request for this issue.

i18n routing

  • Accepted Date: 2022-09-14
  • Reference Issues/Discussions: #600
  • Author: @ematipico
  • Champion(s): @ematipico
  • Implementation PR:

Summary

First-class support for localized routes, aka i18n routing.

Background & Motivation

Many websites need to ship support for translated/localised websites for many reasons:

  • legal;
  • localised content;
  • localised market;
  • etc.

Nowadays there are workarounds in Astro to make it work, although these workarounds have limitations, and because of that many users can't ship their website properly, or they have to work more to compensate the lack of first-class support.

Goals

  • Localised routes with locale prefixes;
  • Default locale with no prefix;
  • Redirect to default locale if prefix enabled;
  • Localise injected routes;
  • Domain support, with the help of Adapter features, so this will be bound to the limitations of the hosting provider;
  • Provide the necessary APIs for integrations and libraries to request information about the current locales;
  • Locale detection via the Accept-Language header, so support SSR;
  • Provide first-class APIs to users to work around locales (.astro components, endpoints, middleware);

Non-Goals

  • Localised data (dates, numbers, plurals, et.c);
  • Dictionaries where users can store translations of pre-defined words;
  • SEO optimisations;

astro check --watch

Body

  • Accepted Date: 2-3-2023
  • Reference Issues/Discussions: #436
  • Implementation PR:

Summary

Add a --watch flag to astro check.

Background & Motivation

In development mode there isn't a way to know if your .astro files contain no errors, aside from editor feedback. If you use astro check you will know about errors, but might not see them until CI unless you remember to run the command before pushing.

Goals

  • A way to check TS errors in .astro files during development workflow.

Non-Goals

  • Having errors reported in the UI. This could be a nice enhancement in the future but would come with some downsides (such as possibly slowing down dev) that we want to punt on.

Example

astro check --watch

CSS Inlining

Summary

Provide a configuration option to specify inlining behavior of styles authored or imported in astro modules.

Background & Motivation

There has been a constant interest in inlining styles while still taking advantage of scoping and other processing steps since before 1.0 (see: withastro/astro#918), with many users incorrectly assuming that is:inline directive is the solution (see: withastro/astro#6388).

Simple one-page websites do not benefit from an external stylesheet, since there is no other page that could use the cached stylesheet. On the other hand, large websites are overoptimized for cacheability, since our chunking splits the styles too granularly. Case in point, Astro docs homepage has 20 linked stylesheets, 14 of them are less than 1kb (see: withastro/astro#6528).

So far we have not provided a way to allow inlining stylesheets, prompting workarounds. However, coming from other frameworks, users might expect to be able to configure this behavior.

Goals

  • Provide a way to reduce the number of HTTP requests for stylesheets.
  • Maintain current behavior when not explicitly configured.
  • Works with both server and static outputs.

Non-Goals

  • Identify "critical" CSS rules.
  • Enable a single external stylesheet.
  • Preloading.
  • Inlining of scripts

Improved env handling

Summary

This RFC aims to improve DX (and eventually security) around env variables.

Background & Motivation

Env variables are an important part of any web application. You need to store sensitive data (think API secrets, tokens etc) without being leaked inside your git repo. But that's only the 1st part of the story. It's easy to leak this data by importing in the wrong place, eg. the frontend like Resend a few weeks ago.

Other JS frameworks (eg. SvelteKit) are handling env pretty well. From my understanding, the env story is currently a bit tricky in Astro. According to the docs, here is how env variables are currently handled:

  • Astro uses Vite’s built-in support for environment variables
  • Static variables (ie. replaced statically at build time) are accessible via import.meta.env
  • import.meta.env includes some default variables like SSR, BASE_URL...
  • A public variable key has to be prefixed by PUBLIC_
  • A non public variable accessed using import.meta.env on the client side will be undefined (value will be accessible server side)
  • Env variables can be loaded through .env (or .env.production, .env.development) and CLI
  • Any non built-in variable can be manually typed
  • Runtime variables should be access using process.env, or following the used runtime (eg. Deno.env.get() for the deno adapter)
  • I'm not sure if process.env has any protection against client-side usage (like import.meta.env), but I guess it doesn't

Goals

  • Provide a fully type-safe experience for environment variables, without manual type definitions
  • Allow users to mark environment variables as required, providing hints when a variable is missing
  • Reduce user confusion between inlined, static variables and dynamic, runtime variables
  • Allow adapters to specify how runtime env variables should be handled

Non-Goals

  • Complex validation or type casting of env variables. We might want to enable this at some point, but there is likely a performance cost for this at runtime. We should punt on this if possible!
  • Allowing integrations to define environment variable constraints. This is a great idea, but until we know what this feature looks like, we should consider it out of scope.
  • Future: allow adapters to customize build-time variable handling. Better runtime handling is the most important problem this proposal aims to solve, but if we find an API that enables this as well, that's great.

Improve `astro:build:done` hooks, remove `RouteData`

What version of astro are you using?

1.9.1

Are you using an SSR adapter? If so, which one?

no

What package manager are you using?

npm

What operating system are you using?

Linux

Describe the Bug

When printing out the routeData for a dynamic route (e.g. test-[id].astro), a url for a specific page is printed.
image

Perhaps you should remove the distURL for dynamic routes. Or even better, add all URLs for the route to the routeData

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-9zdqva?file=astro.config.mjs,src%2Fpages%2Ftest-[id].astro&on=stackblitz

Participation

  • I am willing to submit a pull request for this issue.

A plan for a core image story

Body

  • Accepted Date: 2023-02-08
  • Reference Issues/Discussions: #468
  • Authors: @Princesseuh
  • Implementation PR:

Summary

This proposal aims to outline a plan for a core story for images in Astro, doing so by:

  • Making the image component easier to use through reducing the amount of necessary props in most cases, more intuitive properties, behaviour that is closer to similar tools in the ecosystem and an overall enhanced developer experience (better error messages, better types etc)
  • Adding a new path to import images assets from in a consistent way (inspired by the current src/content)
  • Make things nice and easy to use both in Astro files and in Markdown
  • All of it in core, no more integration to install!

Background & Motivation

src/assets folder

Using images in Astro is currently a bit confusing. Should my images go in public or src? How do I refer to them?

For this, we'd like to introduce a src/assets folder. This folder would be used for your source assets, as in, your not optimized, raw assets. Usage of this folder would be recommended, but not forced.

To make it easier to use this folder from anywhere in the project, an alias will be provided so it is possible to write ~/assets. Due to necessitating tsconfig.json changes, this will only affect new projects, and is completely optional.

Content Collection integration

It is fairly common for one of the property of a Markdown piece of content to need to be a reference to an asset (think, cover image for an article, picture for an author etc).

In tandem with the src/assets folder, we'd like to introduce a way for users to specify that a specific property needs to refer to a valid asset from the src/assets folder. This would allow us to provide validation of the asset, think cover needs to be a png of size 240x240, including validating that the file actually exists.

Facts

  • ESM importing images from other folders than src/assets is supported and they would be optimized, like before.
  • In Markdown, referring relatively to assets from other folders than src/assets is also supported (ex: ![...](./image.png)) in addition to the src/assets folder (ex: ![...](~/assets/image.png))
  • Images in the public folder can still be referred to, however, they won't be optimized / transformed. We would like for this folder to be kept for its original purpose, for assets that will be copied as-is.
  • Content collection-powered validation only works for assets inside the src/assets folder. Remote images are currently out of scope and still need to be referred to using a z.string.
  • TL;DR:
    • In Astro files, refer to local assets by ESM import anywhere in src and they'll be optimized.
    • In Markdown, use the ![] syntax and refer to images in src/assets or relative to the file and they'll be optimized.
    • Need an asset in the frontmatter and want to valid it through content collection? Refer to one from src/assets.

Image component

(see #447 for an earlier version of this proposal)

The current Image component can be confusing to use at time. Why do I need to set an aspectRatio? (what even is the aspect ratio of my image?) Why is my image getting cropped? What format should I use? What does quality means?

width, height and aspectRatio

We'd like to make it so less properties are needed in general. In most cases, the width and height would be automatically inferred from the source file and not passing them would just result in the same dimensions, but a smaller weight.

For cases where they're needed, we'd like to remove the aspectRatio property, instead preferring that users manually set both width and height. Combined with [[#Better behaviour for resizing images]], we believe that this will lead to a more consistant and easier to resonate about experience.

format

format would be set to webp by default, removing the need for it to be passed completely. We believe WebP to be a sensible default for most images, providing with a smaller file size while not sacrificing on compatibility and support for transparency.

quality

For quality, we'd like to make it easier for people to use without needing to know the in-and-out of the loader's algorithm for quality. We propose to fix this by introducing different presets that users can choose from, for example: quality: 'low' would automatically set an appropriate, approximative quality that is considered 'low' (specific implementation is left to the loaders to decide.)

Better behaviour for resizing images

Despite the tremendous power it offered, users were often confused by how @astrojs/image would crop their images to fit the desired aspect ratio. This was especially confusing for users coming from other popular frameworks that don't offer this feature.

As such, this feature would be removed of the base toolkit. Resizing would now only operate in ways that follow the original image aspect ratio (based on width). To control how an image is fitted inside its container, the object-fit and object-position CSS properties can be used.

For users used to other frameworks, this is a similar behaviour to the one offered by NextJS's next/image and Eleventy's eleventy-img.

Facts

  • For ESM images, the only required property would be src. Remote images (ex: http://example.com/image.png, /image.png or ${import.meta.env.BASE_URL}/image.png) would however require width and height to be set manually.
  • Remote images would not be optimized or resized. We understand the need for this, but would like to orient our users towards self-hosing their images as much as much as possible, at least for now.
  • src can be a dynamic import, but be aware that it must respect Vite's limitations on dynamic imports
  • format would be set to webp by default, with the possibility to override as needed. If you desire to have the same format as the original, for remote images it needs to be manually provided whereas for local images, it is possible to do format={myImage.format}.
  • quality now accepts two types of values, either a preset (low | mid | high | max) or a specific number (0 - 100).
  • alt is a required property in all cases. It can be explicitly set to "", for cases where an alt-text is not required.
  • By default, images are loading="lazy" and decoding="async", with possibility to override as needed.
  • TL;DR: The complete list of property would be src, width, height, quality, and all the properties natively available on the img tag (alt, loading, decoding, style etc)

Shape of ESM imports

Currently, importing images in Astro returns a simple string with the path of the image. The @astrojs/image integration enhance this by instead returning the following shape: {src: string, width: number, height: number, format: string}, allowing users to easily construct img tags with no CLS:

---
import image from "../my_image.png"
---

<img src={image.src} width={image.width} height={image.height} />

This shape should also give most of the information an user could need to build their own image integrations based on ESM imports.

Since this would be directly in core, there would be no more configuration changes needed to get the proper types and as such, editor integration should be painless (completions, type checking etc) and address user confusion around this.

In order to avoid any breakage, this shape would be under an experimental flag until the next major release of Astro. Similarly to content collections, we would automatically update your env.d.ts with the type changes needed for this.

Goals

  • A consistant, robust and friendly way to include images into your page
    • No CLS.
    • Enforced best practices (alt, loading, decoding)
    • Optimized images with good defaults, but still flexible
  • With the all the usual good DX you expect from Astro (good error messages, good types etc)

Non-goals of this proposal

  • Advanced usage in Markdown (ability to set width, height, quality etc)
  • Using optimized images inside framework components
  • Automatic generation of srcset
  • Placeholders generation
  • Background generation
  • Picture component
  • Optimizing remote images
  • .svg support

We realize that many of those features not being goals are considered to be downgrades compared to @astrojs/image. This is on purpose as we'd like to approach this project with a "small MVP, add features over time" mentality.

Creating a perfect Image component for core is a way more complex project than it might seems, the balance between "This has too much options, it's too confusing to use" and "This doesn't have enough options, it's unusable for anything even a little bit complex" is incredibly hard to hit.

We believe that, much like we did with other features in Astro, by building a good core and providing ways build around it, we'll ultimately achieve the best result possible.

Example

All the examples below show the result path in the built website

Basic image from src/assets

Source

---
import { Image } from "astro:image";
import myImage from "~/assets/my_image.png"; // Image is 1600x900

// Relative paths are also supported:
// import myImage from "../../assets/my_image.png"
---

<Image src={myImage} alt="Image showing Elsa from the movie Frozen, she has blonde hair and is wearing a long blue dress" />

Result

<img src="/_astro/my_image.hash.webp" width="1600" height="900" decoding="async" loading="lazy" alt="Image showing Elsa from the movie Frozen, she has blonde hair and is wearing a long blue dress" />

Resized image from src/assets

Source

---
import { Image } from "astro:image";
import myImage from "~/assets/my_image.png"; // Image is 1600x900
---

<Image src={myImage} width={800} alt="..." />

Result

<!-- Result image is a webp of 800x450 -->
<img src="..." width="800" height="450" decoding="async" loading="lazy" alt="..." />

Source

---
import { Image } from "astro:image";
import myImage from "~/assets/my_image.png"; // Image is 1600x900
---

<Image src={myImage} width={800} height={900} alt="..." />

Result

<!-- Result image is a webp of 800x450 -->
<img src="..." width="800" height="900" decoding="async" loading="lazy" alt="..." />

Basic remote image

Source

---
import { Image } from "astro:image";
// Image is 1920x1080
---

<Image src="https://example.com/image.png" alt="..." />
<!-- ERROR! `width` and `height` are required -->

<Image src="https://example.com/image.png" width={1280} alt="..." />
<!-- ERROR! `height` is required -->

<Image src="https://example.com/image.png" width={1280} height={720} alt="..." />

Result (3rd example)

<!-- Remote images are not optimized or resized.
<img src="https://example.com/image.png" decoding="async" loading="lazy" width="1280" height="720" alt="...">

Markdown

Source

Source image is a .png of 640x960

---
cover: ~/assets/cover.png 
---

Result

Result is a .webp of 640x960

{
    cover: {
        src: "/_astro/cover.hash.webp",
        width: 640,
        height: 960
    }
}

Source

My super image of 640x480:
![...](~/assets/my_image.png)

OR

![...](./my_image.png)

OR

![...](../../assets/my_image.png)

Result

<img src="/_astro/my_image.hash.webp" width="640" height="480" loading="lazy" decoding="async" alt="...">

Referencing data from content collections

Details

Summary

Introduce a standard to store data separately from your content (ex. JSON files), with a way to "reference" this data from existing content collections.

Background & Motivation

Content collections are restricted to supporting .md, .mdx, and .mdoc files. This is limiting for other forms of data you may need to store, namely raw data formats like JSON.

Taking a blog post as the example, there will likely be author information thats reused across multiple blog posts. To standardize updates when, say, updating an author's profile picture, it's best to store authors in a separate data entry, with an API to reference this data from any blog post by ID.

The content collections API was built generically to support this future, choosing format-agnostic naming like data instead of frontmatter and body instead of rawContent. Because of this, expanding support to new data formats without API changes is a natural progression.

Use cases

We have a few use cases in mind considering data collections and data references. We expect this list to grow through the RFC discussion and learning from our community!

  • Blog post meta info. Common cases include author bios, project contributors, and tags
  • i18n translations. Many content sites and translation libraries work from key / value pairs stored as JSON. For example, an i18n/ collection containing en.json, fr.json, etc.
  • Image asset metadata. You may want to reference reusable alt text or image widths and heights for standard assets. For example, an images/banner.json file containing the src as a string, alt text, and a preferred width

Goals

  • Introduce JSON collection support, configurable and queryable with similar APIs to content collections.
  • Determine where data collections are stored. We may introduce a new src/data/ directory distinct from src/content/, or simply allow data collections within src/content/.
  • Introduce an API to reference this data from existing content collections by ID. This is based on the strongest user need for data collections: referencing metadata (ex. pull in post authors from a blog post).
  • Consider Both one-to-one and one-to-many relationships between content and data (ex. allow passing a list of author IDs in your frontmatter).

Non-goals

  • User-facing APIs to introduce new data collection formats like YAML or TOML. We recognize the value of community plugins to introduce new formats, and we will experiment with a pluggable API internally. Still, a finalized user-facing API will be considered out-of-scope.

Support prefetch in core

Summary

Deprecate @astrojs/prefetch and provide first-class prefetch support in Astro.

Background & Motivation

With the introduction of View Transitions, it includes partial prefetching code for snappy navigation between pages. We can take this opportunity to support prefetching in core, and share the prefetch behaviour with View Transitions.

I've started an implementation before an RFC as the initial plan was to simply move @astrojs/prefetch to core. However, it would also be a good time to polish up and extend the API.

Goals

  • An option to enable prefetching
  • Enable prefetching via an attribute/hint
  • Enable prefetching for all links by default (required by View transitions)
  • Disable prefetching if all links are enabled by default
  • Different prefetching strategies (click, hover, viewport, etc)
  • Only add JS if using prefetching

Non-Goals

  • Prefetch cache invalidation (Browser relies on cache control)
  • Prefetch external links

NOTE: Stage 2 does not mention solution details, but I've written one in the discussion: withastro/astro#8951

Support for partials

  • Accepted Date: 2023-09-13
  • Reference Issues/Discussions: #266
  • Author: @matthewp
  • Champion(s): @matthewp
  • Implementation PR:

Summary

Allow pages to be marked as being partials, preventing the doctype tag and any head injection from taking place. A partial is defined as a template which belongs in the context of another page and is dependent on that page in order to be fully functional.

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 and Unpoly 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).
  • Some way to optionally communicate extra dependencies, such as styles and scripts, so libraries that support head-diffing can achieve that.
  • 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.
    • We may take into account special headers from popular libraries if there is a way to enhance the base experience.
  • No client-side scripts from Astro will be part of this change.
  • Routing should mostly be unchanged; this is metadata about a page but doesn't change the location or where routes live (still in the pages folder).

Custom Client Directives

Body

  • Accepted Date: 2023-03-22
  • Reference Issues/Discussions:
  • Implementation PR:

Summary

Provide an API for integrations to implement custom client: directives to provide greater control for when client-side JS is loaded and executed.

Background & Motivation

The last client directive added to core was the client:only directive in August 2021. Since that time the core team has been hesitant to add new client directives despite the community asking about them.

Allowing custom client directives would both:

  • Allow the community to experiment with different approaches to lazy-loading client JavaScript.
  • Provide evidence, through telemetry data, on which directives are most used. This data could be used to determine if a directive should be brought into core.

Some examples of custom directives that people have wanted in the past:

  • Loading JavaScript on client interactive, such as mouseover or click.
  • Loading JavaScript when an element is visible, as opposed to within the viewport as client:visible currently does.
  • The Idle Until Urgent pattern which loads on either idle or interaction, whichever comes first.

Goals

  • Provide a way to customize loading of client components.
  • Refactor the implementation of client: loading to get rid of the precompile step (this is a core repo refactor / improvement).
  • Allow integrations to add their own directives.
  • Allow integrations to provide type definitions for their new directives.

Non-Goals

  • Allowing overriding builtin directives.
  • Allowing for additional customization via new types of directives outside of client:.
  • Allowing multiple directives to run at the same time.

Future

  • Solving the client:only load vs idle vs visible problem.

Example

Usage

To use a custom directive in your app, add an integration like any other.

import { defineConfig } from 'astro/config';
import onClickDirective from '@matthewp/astro-click-directive';

export default defineConfig({
  integrations: [onClickDirective()]
});

And then use it in your Astro components:

---
import Counter from '../components/Counter.jsx';
---

<Counter client:click />

Implementation

An implementer of a custom client directive would do so through the hooks API:

export default function() {
  return {
    hooks: {
      'astro:config:setup': ({ addClientDirective }) => {
        addClientDirective({
          name: '@matthewp/astro-click-directive',
          key: 'click',
          entrypoint: '@matthewp/astro-click-directive/client.js'
        });
      },
    }
  }
}

The entrypoint being:

export default function(load, opts, element) {
  element.addEventListener('click', async () => {
    const hydrate = await load();
    await hydrate();
  }, { once: true });
}

Wrong RouteData during build

What version of astro are you using?

1.9.1

Are you using an SSR adapter? If so, which one?

no

What package manager are you using?

npm

What operating system are you using?

Linux

Describe the Bug

When printing out the routeData for a dynamic route (e.g. test-[id].astro), a url for a specific page is printed.
image

Perhaps you should remove the distURL for dynamic routes. Or even better, add all URLs for the route to the routeData

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-9zdqva?file=astro.config.mjs,src%2Fpages%2Ftest-[id].astro&on=stackblitz

Participation

  • I am willing to submit a pull request for this issue.

Client-side Routing

Body

  • Accepted Date: 2023-03-23
  • Reference Issues/Discussions: #307
  • Implementation PR:

Summary

Astro is a server-first framework. As such, it has always relied on the Multi-Page Application (MPA) architecture, meaning that navigations result in a full page refresh and server round-trip.

This proposal offers an opt-in Client-side Routing (CSR) experience, typically associated with Single-Page Application (SPA) architectures.

Note:
For a great overview of relevant terms (MPA/SPA/PEMPA/PESPA), see The Web’s Next Transition by Kent C. Dodds.

Background & Motivation

As users build increasingly complex experiences with Astro, UI Persistence has surfaced as a clear missing piece in the full Astro story. Client-side routing is currently the only way to achieve UI persistence across navigations.

MPAs are the backbone of the web and remain a natural default for Astro projects. SPAs come with their own set of incredibly complex considerations and drawbacks—importantly, we do not believe that client-side routing is a "solved problem" despite becoming the default approach in the industry.

However, the team has discussed a mythical "SPA mode" since the earliest days of the project. Now that we are extremely confident in Astro's mental model and internal priorities, there is no better time to begin layering in new primitives to round out Astro's use cases.

Goals

🔵 points are not finalized, should be discussed and resolved during prototyping

  • New client-side routing behavior should be entirely opt-in
    • Maintain Astro's 0 JS defaults
    • Preserve server routing as the default approach
  • Client-side routing should support all valid output modes
  • No changes to Astro's existing file-based routing system
    • Avoid encoding layout information in the file structure
    • 🔵 Can layout boundaries be derived in the compiler or other methods?
  • Enable UI Persistence
    • Components (🔵 islands only?) should be able to maintain state across soft navigations
    • Should this be automatically applied or require user opt-in?
    • 🔵 Does this require diffing?
  • <head> elements (title, link, script, etc) should be swapped automatically
  • Out-of-the-box accessibility best practices
    • Route changes should be announced to screen readers
    • Focus / scroll management should be automatic
  • Use the platform. Lean on standard browser APIs as much as possible
  • Future friendly. Support (at the very least, do not block) bleeding-edge APIs such as the View Transitions API and forthcoming navigation API

Non-Goals

  • Ability to render Astro components on the client. Astro is a server-first framework that must be rendered on a server (either at build or request time)
  • Other PEMSPA/PESPA primitives such as forms, actions, mutations

Unable to pass variable from the configuration (integration) to (static file) endpoint

What version of astro are you using?

2.5.5

Are you using an SSR adapter? If so, which one?

no

What package manager are you using?

pnpm

What operating system are you using?

Windows

What browser are you using?

Chrome

Describe the Bug

I have tried it like this:
astro.config.js:

import {defineConfig} from 'astro/config'

export default defineConfig({
	integrations: [
		{
			name: ''
			, hooks: {
				'astro:server:setup': ({server: {middlewares}}) => {
					middlewares.use((request, response, next) => {
						response.locals = 'test'//or response.locals.test = 'test'

						next()
					})
				}
			}
		}
	]
})

But in the static file endpoint I am always getting an empty locals object ({}):
((src/pages/)index).js:

export const get = async ({locals}) => {
	console.log(locals)

	return {body: ''}
}

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-z6jvzs?file=astro.config.js,src%2Fpages%2Findex.js

Participation

  • I am willing to submit a pull request for this issue.

Form Actions

Body

Summary

Let's make handling form submissions easy and type-safe both server-side and client-side.

Goals

  • Form actions can accept JSON or FormData payloads.
  • You no longer need boilerplate to safely parse the request body based on the Content-Type.
  • You no longer need boilerplate to retrieve form data values from the request body. The action should be able to enumerate expected input names, and the handler should be able to retrieve these values without a type cast. In other words, no more bangs ! or as string casts as in the example formData.get('expected')! as string.
  • You can call an action using a standard HTML form element with the action property.
  • You can use client JavaScript to call an action using scripts or islands. When doing so, data returned by the action is type-safe without type casting. Note: This should consider form handling in popular component frameworks, like the useActionState() and useFormStatus() hooks in React 19.
  • You can declare actions as an endpoint to call from prerendered / static pages using the hybrid output.

Non-goals

  • A solution to client-side validation. Validation is a major piece to forms with several community libraries to choose from (ex. react-hook-form). Astro may recommend standard HTML attributes for client validation including the required and type properties on an input.
  • A hook to retrieve the return value of an action from Astro frontmatter. Action return values may be accessed from client JavaScript for optimistic updates. Otherwise, we expect actions to persist any state to a database to be retrieved manually from your Astro components.
  • Declaring actions within .astro frontmatter. Frontmatter forms a function closure, which can lead to misuse of variables within an action handler. This challenge is shared by getStaticPaths() and it would be best to avoid repeating this pattern in future APIs.

Background & Motivation

Form submissions are a core building block of the web that Astro has yet to form an opinion on (pun intended).

So far, Astro has been rewarded for waiting on the platform and the Astro community to mature before designing a primitive. By waiting on view transitions, we found a SPA-like routing solution grounded in native APIs. By waiting on libSQL, we found a data storage solution for content sites and apps alike. Now, we've waited on other major frameworks to forge new paths with form actions. This includes Remix actions, SvelteKit actions, React server actions, and more.

At the same time, Astro just launched its database primitive: Astro DB. This is propelling the Astro community from static content to more dynamic use cases:

  • A like button that updates a database counter
  • A comments section that inserts a new comment behind an auth gateway
  • A newsletter form that pings a third party mailing service

To meet our community where it's heading, Astro needs a form submission story.

The problem with existing solutions

Astro presents two solutions to handling form submissions with today's primitives. Though capable, these tools are either too primitive or present unacceptable tradeoffs for common use cases.

JSON API routes

JSON API routes allow developers to handle POST requests and return a JSON response to the client. Astro suggests this approach with a documentation recipe, demonstrating how to create an API route and handle the result from a Preact component.

However, REST endpoints are overly primitive for basic use cases. The developer is left to handle parse errors and API contracts themselves, without type safety on either side. To properly handle all error cases, this grows complex for even the simplest of forms:

REST boilerplate example
// src/api/board/[board]/card/[card].ts
import { db, Card, eq, and, desc } from "astro:db";
import type { APIContext } from "astro";

const POST = async ({params, request}: APIContext) => {
  if (!params.card || !params.board) {
    return new Response(
      JSON.stringify({ success: false, error: "Invalid board or card ID" }),
      { status: 400 }
    );
  }

  if (!request.headers.get("content-type")?.includes("application/x-www-form-urlencoded")) {
    return new Response(
      JSON.stringify({ success: false, error: "Must be a form request" }),
      { status: 400 }
    );
  }

  const body = await request.formData();
  const name = body.get("name");
  const description = body.get("description");
  if (typeof name !== "string" || typeof description !== "string") {
    return new Response(
      JSON.stringify({ success: false, error: "Invalid form data" }),
      { status: 400 }
    );
  }

  // Actual app logic starts here!
  const res = await db
    .update(Card)
    .set({ name, description })
    .where(
      and(eq(Card.boardId, params.board), eq(Card.id, params.card))
    );

  return new Response(
    JSON.stringify({ success: res.rowsAffected > 0 }),
    { status: res.rowsAffected > 0 ? 200 : 404 }
  );
}

The client should also guard against malformed response values. This is accomplished through runtime validation with Zod, or a type cast to the response the client expects. Managing this contract in both places leaves room for types to fall out-of-sync. The manual work of defining and casting types is also added complexity that the Astro docs avoid for beginner use cases.

What's more, there is no guidance to progressively enhance this form. By default, a browser will send the form data to the action field specified on the <form> element, and rerender the page with the action response. This default behavior is important to consider when a user submits a form before client JS has finished parsing, a common concern for poor internet connections.

However, we cannot apply our API route as the action. Since our API route returns JSON, the user would be greeted by a stringified JSON blob rather than the refreshed contents of the page. The developer would need to duplicate this API handler into the page frontmatter to return HTML with the refreshed content. This is added complexity that our docs understandably don't discuss.

View transition forms

View transitions for forms allow developers to handle a submission from Astro frontmatter and re-render the page with a SPA-like refresh.

---
const formData = await Astro.request.formData();
const likes = handleSubmission(formData);
---

<form method="POST">
  <button>Likes {likes}</button>
</form>

This avoids common pitfalls with MPA form submissions, including the "Confirm resubmission?" dialog a user may receive attempting to reload the page. This solution also progressively enhances based on the default form action handler.

However, handling submissions from the page's frontmatter is prohibitive for static sites that cannot afford to server-render every route. It also triggers unnecessary work when client-side update is contained. For example, clicking "Likes" in this example will re-render the blog post and remount all client components without the transition:persist decorator.

Last, the user is left to figure out common needs like optimistic UI updates and loading states. The user can attach event listeners for the view transition lifecycle, though we lack documentation on how to do so from popular client frameworks like React.

HTML Minification

Body

  • Accepted Date: 2023-03-23
  • Reference Issues/Discussions: #165
  • Implementation PR:

Summary

When building for production, we should safely collapse whitespace when generating the HTML

Background & Motivation

Astro users are often confused why we don't minify HTML by default.

The long answer is:

  • HTML minification can cause server/client hydration mismatches
  • Post-processing Astro's HTML output isn't possible in server mode
  • Streaming uses newlines to delineate when to flush buffered text in a response
  • Frameworks can use HTML comments as expression markers, which can cause issues if these are removed by a minifier

The shorter answer is:

  • It is possible, but we haven't made the time to do it properly yet

Goals

  • Safely (non-destructively) collapse whitespace during Astro compilation
  • Enable HTML minification in production by default
  • Allow users to enable/disable minification if they have specific needs

Non-Goals

  • Introduce a generic post-processing step for Astro markup
  • Future: option to control whether user comments should be present in the final markup

Example

Probably just a boolean config option. Name TBD.

Enhance hybrid rendering to prerender all pages by default

Body

Summary

Make an enhancement to Astro's Hybrid Rendering support to make pre-rendering the default for all pages, and opt-out instead of opt-in.

Background & Motivation

Currently, pre-rendering pages in SSR is possible thanks to Hybrid Rendering. However, this uses output: 'server' which defaults all pages to server-rendered. This can be annoying for mostly-static sites that then need to add export const prerender = true; to most pages.

One common use-case (mentioned in the original pre-rendering RFC) is a fully static site with a few server-side api routes. The current implementation requires a migrating user to add output: 'server' to their configuration and then manually add export const prerender = true to each .astro page in their src/pages directory before continuing.

This was originally discussed in the pre-rendering RFC. However it was ultimately removed because it was assumed that this would require a new third internal implementation (static and server (SSR) already exist today) which was considered too much of a maintenance burden to take on.

Goals

  • Support some version of Hybrid Rendering where pages default to export const prerender = true
  • Avoid a third internal build implementation. A new output mode in the user-facing configuration API is okay, as long as it leverages the existing static or server internal build implementation.

Non-Goals

  • N/A

Integration hooks for middleware

  • Accepted Date: 2023-09-19
  • Reference Issues/Discussions: #692
  • Author: @matthewp
  • Champion(s): @matthewp
  • Implementation PR:

Summary

A brief, one or two sentence explanation of the proposal.

Add an API to integrations which allows them to define middleware so that users do not need to go through the boilerplate of creating a middleware file and importing the functionality.

Background & Motivation

When we built the middleware API we anticipated a need for integrations to hook into it, but we decided not to make that a goal for v1 due to the complexity of ordering. Yet the need keeps coming up for the same reasons as before, integrations want to transparently add middleware.

Goals

  • The ability to get middleware into an Astro project simply by adding an integration as normal.
  • Allow an integration to place itself either at the front or end of the stack in terms of ordering.

Non-Goals

  • Not aiming for full control over middleware ordering at this stage. Middleware ordering is determined dynamically as the root middleware module is defined, so an API that allowed integration control over that would be difficult and more broad than in this proposal. There is no known use-case for this regardless.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.