Astro has recently become my favourite framework for building websites. It has a great developer experience, features, community, and it’s frequently updated.
These are some findings or quirks I’ve noted when using it that don’t warrant a separate blog post, things that you may encounter depending on the Astro version you’re using. These may be things I’ve missed in the documentation, something I’ve done incorrectly (likely), or an actual issue or bug (less likely).
Upgrading to Astro 4.0
astro-icon with local images
Update to astro-icon@0.8.2 to be able to use local icons in an Astro 4.0 project.
View Transitions
Selectors with page events
When selecting elements, make sure to call them inside the called function of the event listener, otherwise the reference will be stale when you get to the next page:
define:vars with lifecycle events
If you use define:vars to pass frontmatter variables into your script tag, everything inside will re-run everytime that variable changes:
Issues with CSS animations
There is a visual issue I’ve encountered with Firefox when using <ViewTransitions />
with the default fallback (for browsers that don’t support the View Transitions API yet) and a CSS opacity animation on page load.
The opacity was set to 0 and set to animate to 100% with a CSS animation but using View Transitions resulted in the animation never running (or the opacity not being set).
The workaround was to use a fallback of swap
:
This is something I’ll look to investigate in the future.
z-index
If you use z-index
on an element (this could be a sticky header) that is placed over an element that uses a transition animation (for example, an h1
heading with transition:name
), this element may show in front of the header during page transitions.
As a workaround, set transition:name
on this z-index element, even if that element doesn’t use any animations:
Collections
Querying all collections
There is no built-in way to query all collections. One workaround to do this is using Astro.glob
to pull all markdown files:
The data returned from this will be different from the data returned from getCollection. If you needed it in the same structure, you could extract the folder names only using the data from Astro.glob
, and then loop over them with getCollection
.
Images
Remote images with subdomains
You need to specify the subdomain for any remote image links in astro.config.mjs
, otherwise it won’t get optimized and the original source will be used:
Content collections
When referencing images in content collections using the image
helper, you can also reference the image from the root directory (src
).
You may need to do this for compatibility with your CMS, for example, if it doesn’t support reading relative paths for things like image previews.
_image
endpoint
In hybrid
or server
mode, you can manually use the _image
endpoint to optimize an image in your public folder:
With a /public/photo.jpg
folder. The URL will need to be encoded properly.
Referencing images in .md or .mdx
You can use TypeScript alias based imports for any content or body images:
This will also work when built, unlike absolute paths (like /src/assets/image.png
).
Framework Components / Islands
client:only priority
client:only
is meant to have a high priority and behaves like client:load
(except server rendering is skipped), but any component using client:only
won’t immediately show its static content (without hydration) resulting in a flash (unlike client:load
). This doesn’t seem to change if your page is server rendered or static.
Mixing frameworks
When using components from multiple frameworks together, not adding the extension may result in an error of This component likely uses @astrojs/react ...
:
Change this to:
Alternatively (although I’m not sure why you would do this), you can force the component to hydrate for a particular framework with client:only to make it work without the extension.
Svelte without client directive
You must use a client directive for a Svelte component’s slot to appear, even if this component doesn’t need to hydrate.
The same behaviour also happens with named slots.
You don’t need to do this with React or Vue.
TypeScript
Props with client directives
You may get various type errors when using client directives with any props other than children
(not sure if this applies to other non-React frameworks):
Which results in:
A (bad) workaround is to mark these prop(s) as optional in your type or interface inside that component:
There is likely a better solution as this hides the error even if the prop(s) isn’t optional.
WebStorm
There are some issues resolving types with WebStorm with an active issue here.
One solution which solves a lot of the problems is using the bundled TypeScript setting. Open Settings > Preferences > Languages & Frameworks > TypeScript > Bundled.
Forms
Could not parse content as FormData
If you get an error of Could not parse content as FormData
when trying to parse form data in an API endpoint, it may be because the site is static. The site will need to be in hybrid
or server
mode.
Preventing a page change
For doing things like preventing a page from changing for unsaved form changes with View Transitions, you can use the before-preparation
event:
Or normally without using View Transitions:
Cookies
Passing credentials
You don’t need to use credentials
in a fetch call to an Astro endpoint for it to receive your cookies. If you pass omit
however, it naturally won’t work.
Make sure to not call the endpoint from the frontmatter as well - you won’t receive any cookies because this call will be made from a server perspective, not the client.
Miscellaneous
Importing the Astro config
If you want to import your config from astro.config.mjs
elsewhere in your project, it will only work in development.
All of these methods will fail during build:
This is due to the use of any Astro imports like @astrojs/react
which I guess can’t be properly parsed or serialized during build.
One workaround is to create a separate config file that doesn’t use any Astro related imports which you import in astro.config.mjs
and anywhere else:
With this method you won’t be able to read the functions you set, but if you wanted to, you could set additional values in the config object (config.ts
) which you import in astro.config.mjs
, and manually add the functions to the relevant key like integrations
, based on which ones exist.
Syntax or rehype plugins
To use a plugin like Rehype Pretty Code, you will need to disable the default Astro syntax highlighting in your astro.config.mjs
:
Astro’s highlighting runs last, so it has priority over any existing plugins.
CSS define:vars
When using a property like content
, you will need to wrap your variable in additional quotes for it to work - otherwise the style will only be content: Hello
:
Using additional asset types e.g. zip
You can include other asset types like .zip
s by including them in your Vite configuration’s assetsInclude
array:
If you want to use these in content collections, you can reference the assets as strings (if the file is in the same folder as the collection for example):
And then you can dynamically import them with import.meta.glob
.