Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest using import.meta.glob #9181

Merged
merged 14 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 113 additions & 13 deletions src/content/docs/en/guides/imports.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,21 @@ The following file types are supported out-of-the-box by Astro:
- CSS Modules (`.module.css`)
- Images & Assets (`.svg`, `.jpg`, `.png`, etc.)

Additionally, you can extend Astro to add support for different [UI Frameworks](/en/guides/framework-components/) like React, Svelte and Vue components. You can also install the [Astro MDX integration](/en/guides/integrations-guide/mdx/) and use `.mdx` files in your project.
Additionally, you can extend Astro to add support for different [UI Frameworks](/en/guides/framework-components/) like React, Svelte and Vue components. You can also install the [Astro MDX integration](/en/guides/integrations-guide/mdx/) or the [Astro Markdoc integration](/en/guides/integrations-guide/markdoc/) to use `.mdx` or `.mdoc` files in your project.

### Files in `public/`

You can place any static asset in the [`public/` directory](/en/basics/project-structure/#public) of your project, and Astro will copy it directly into your final build untouched. `public/` files are not built or bundled by Astro, which means that any type of file is supported. You can reference a `public/` file by a URL path directly in your HTML templates.
You can place any static asset in the [`public/` directory](/en/basics/project-structure/#public) of your project, and Astro will copy it directly into your final build untouched. `public/` files are not built or bundled by Astro, which means that any type of file is supported.

You can reference a `public/` file by a URL path directly in your HTML templates.

```astro
// To link to /public/reports/annual/2024.pdf
Download the <a href="/reports/annual/2024.pdf">2024 annual statement as a PDF</a>.

// To display /public/assets/cats/ginger.jpg
<img src="/assets/cats/ginger.jpg" alt="An orange cat sleeping on a bed.">
```

## Import statements

Expand Down Expand Up @@ -183,16 +193,17 @@ import logoUrl from '@assets/logo.png?url';
These aliases are also integrated automatically into [VS Code](https://code.visualstudio.com/docs/languages/jsconfig) and other editors.


## `Astro.glob()`
## `import.meta.glob()`
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved

[`Astro.glob()`](/en/reference/api-reference/#astroglob) is a way to import many files at once.
[Vite's `import.meta.glob()`](https://vitejs.dev/guide/features.html#glob-import) is a way to import many files at once using wildcards to create a list of pathnames.

`Astro.glob()` only takes one parameter: a relative [glob pattern](/en/guides/imports/#glob-patterns) matching the local files you'd like to import. It’s asynchronous, and returns an array of each matching file's exports.
`import.meta.glob()` takes a relative [glob pattern](/en/guides/imports/#glob-patterns) matching the local files you'd like to import as a parameter. It returns an array of each matching file's exports. To load all matched modules up front, pass `{ eager: true }` as the second argument:

```astro title="src/components/my-component.astro"
```astro title="src/components/my-component.astro" {3,4}
---
// imports all files that end with `.md` in `./src/pages/post/`
const posts = await Astro.glob('../pages/post/*.md');
const matches = await import.meta.glob('../pages/post/*.md', { eager: true });
const posts = Object.values(matches);
---
<!-- Renders an <article> for the first 5 blog posts -->
<div>
Expand All @@ -206,12 +217,12 @@ const posts = await Astro.glob('../pages/post/*.md');
</div>
```

Astro components imported using `Astro.glob` are of type [`AstroInstance`](/en/reference/api-reference/#astro-files). You can render each component instance using its `default` property:
Astro components imported using `import.meta.glob` are of type [`AstroInstance`](#astro-files). You can render each component instance using its `default` property:

```astro title="src/pages/component-library.astro" {8}
---
// imports all files that end with `.astro` in `./src/components/`
const components = await Astro.glob('../components/*.astro');
const components = Object.values(await import.meta.glob('../components/*.astro', { eager: true }));
---
<!-- Display all of our components -->
{components.map((component) => (
Expand All @@ -221,6 +232,96 @@ const components = await Astro.glob('../components/*.astro');
))}
```

### Supported Values

Vite's `import.meta.glob()` function only supports static string literals. It does not support dynamic variables and string interpolation.

A common workaround is to instead import a larger set of files that includes all the files you need, then filter them:

```astro {6-7}
---
// src/components/featured.astro
const { postSlug } = Astro.props;
const pathToMyFeaturedPost = `src/pages/blog/${postSlug}.md`;

const posts = await Astro.glob('../pages/blog/*.md');
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved
const myFeaturedPost = posts.find(post => post.file.includes(pathToMyFeaturedPost));
---
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved

<p>
Take a look at my favorite post, <a href={myFeaturedPost.url}>{myFeaturedPost.frontmatter.title}</a>!
</p>
```

### Import type utilities

#### Markdown files

Markdown files loaded with `import.meta.glob()` return the following `MarkdownInstance` interface:

```ts
export interface MarkdownInstance<T extends Record<string, any>> {
/* Any data specified in this file's YAML frontmatter */
frontmatter: T;
/* The absolute file path of this file */
file: string;
/* The rendered path of this file */
url: string | undefined;
/* Astro Component that renders the contents of this file */
Content: AstroComponentFactory;
/** (Markdown only) Raw Markdown file content, excluding layout HTML and YAML frontmatter */
rawContent(): string;
/** (Markdown only) Markdown file compiled to HTML, excluding layout HTML */
compiledContent(): string;
/* Function that returns an array of the h1...h6 elements in this file */
getHeadings(): Promise<{ depth: number; slug: string; text: string }[]>;
default: AstroComponentFactory;
}
```

You can optionally provide a type for the `frontmatter` variable using a TypeScript generic.

```astro
---
interface Frontmatter {
title: string;
description?: string;
}

const posts = import.meta.glob<MarkdownInstance<Frontmatter>>('./posts/**/*.md');
---

<ul>
{posts.map(post => <li>{post.frontmatter.title}</li>)}
</ul>
```

#### Astro files

Astro files have the following interface:

```ts
export interface AstroInstance {
/* The file path of this file */
file: string;
/* The URL for this file (if it is in the pages directory) */
url: string | undefined;
default: AstroComponentFactory;
}
```

#### Other files

Other files may have various different interfaces, but `import.meta.glob()` accepts a TypeScript generic if you know exactly what an unrecognized file type contains.

```ts
---
interface CustomDataFile {
default: Record<string, any>;
}
const data = await import.meta.glob<CustomDataFile>('../data/**/*.js');
---
```

### Glob Patterns

Expand All @@ -230,19 +331,18 @@ For example, the glob pattern `./pages/**/*.{md,mdx}` starts within the pages su

#### Glob Patterns in Astro

To use with `Astro.glob()`, the glob pattern must be a string literal and cannot contain any variables. See [the troubleshooting guide](/en/guides/troubleshooting/#astroglob---no-matches-found) for a workaround.
To use with `import.meta.glob()`, the glob pattern must be a string literal and cannot contain any variables.

Additionally, glob patterns must begin with one of the following:
- `./` (to start in the current directory)
- `../` (to start in the parent directory)
- `/` (to start at the root of the project)


[Read more about the glob pattern syntax](https://github.com/mrmlnc/fast-glob#pattern-syntax).

#### `Astro.glob()` vs `getCollection()`
### `import.meta.glob()` vs `getCollection()`

[Content collections](/en/guides/content-collections/) provide a [`getCollection()` API](/en/reference/api-reference/#getcollection) for loading multiple files instead of `Astro.glob()`. If your content files (e.g. Markdown, MDX, Markdoc) are located in collections within the `src/content/` directory, use `getCollection()` to [query a collection](/en/guides/content-collections/#querying-collections) and return content entries.
[Content collections](/en/guides/content-collections/) provide a [`getCollection()` API](/en/reference/api-reference/#getcollection) for loading multiple collection entries instead of `import.meta.glob()`. If your files exist in a collection, use `getCollection()` to [query a collection](/en/guides/content-collections/#querying-collections) and return content entries.

## WASM

Expand Down
36 changes: 11 additions & 25 deletions src/content/docs/en/guides/markdown-content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,16 @@ Visit the [MDX website](https://mdxjs.com/table-of-components/) for a full list

You can import Markdown and MDX files directly into your Astro files. This gives you access to their Markdown content, as well as other properties such as frontmatter values that can be used within Astro's JSX-like expressions.

You can import one specific page with an `import` statement, or multiple pages with [`Astro.glob()`](/en/guides/imports/#astroglob).
You can import one specific page with an `import` statement, or multiple pages with [`import.meta.glob()`](/en/guides/imports/#importmetaglob).

```astro title="src/pages/index.astro"
---
// Import a single file
import * as myPost from '../pages/post/my-post.md';

// Import multiple files with Astro.glob
const posts = await Astro.glob('../pages/post/*.md');
// Import multiple files with import.meta.glob
const matches = await import.meta.glob('../pages/post/*.md', { eager: true });
const posts = Object.values(posts);
---
```

Expand All @@ -238,7 +239,7 @@ Here is my _great_ post!
---
import * as greatPost from '../pages/post/great-post.md';

const posts = await Astro.glob('../pages/post/*.md');
const posts = Object.values(await import.meta.glob('../pages/post/*.md', { eager: true }));
---

<p>{greatPost.frontmatter.title}</p>
Expand Down Expand Up @@ -272,30 +273,13 @@ import * as greatPost from '../pages/post/mdx-post.mdx';
<p>{greatPost.description}</p>
```

You can optionally provide a type for the `frontmatter` variable using a TypeScript generic:

```astro title="src/pages/index.astro" ins={2-5} ins="<Frontmatter>"
---
interface Frontmatter {
title: string;
description?: string;
}
const posts = await Astro.glob<Frontmatter>('../pages/post/*.md');
---

<ul>
{posts.map(post => <li>{post.frontmatter.title}</li>)}
<!-- post.frontmatter.title will be `string`! -->
</ul>
```

### Exported Properties

:::note[Using an Astro layout?]
See the [properties exported to an Astro layout component](/en/basics/layouts/#markdown-layout-props) when using Astro's special [frontmatter layout](#frontmatter-layout).
:::

The following properties are available to a `.astro` component when using an `import` statement or `Astro.glob()`:
The following properties are available to a `.astro` component when using an `import` statement or `import.meta.glob()`:

- **`file`** - The absolute file path (e.g. `/home/user/projects/.../file.md`).
- **`url`** - If it's a page, the URL of the page (e.g. `/en/guides/markdown-content`).
Expand Down Expand Up @@ -329,7 +313,8 @@ To access your Markdown content, pass the `<Content/>` component through the Ast
```astro title="src/pages/[slug].astro" {9-11} "Content" "Astro.props.post"
---
export async function getStaticPaths() {
const posts = await Astro.glob('../posts/**/*.md')
const matches = await import.meta.glob('../posts/**/*.md', { eager: true })
const posts = Object.values(matches);

return posts.map(post => ({
params: {
Expand Down Expand Up @@ -359,12 +344,13 @@ For example, you can export a `title` field from an MDX page or component.
export const title = 'My first MDX post'
```

This `title` will be accessible from `import` and [Astro.glob()](/en/reference/api-reference/#astroglob) statements:
This `title` will be accessible from `import` and [import.meta.glob()](/en/guides/imports/#importmetaglob) statements:

```astro
---
// src/pages/index.astro
const posts = await Astro.glob('./*.mdx');
const matches = await import.meta.glob('./*.mdx', { eager: true });
const posts = Object.values(posts);
---

{posts.map(post => <p>{post.title}</p>)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ Here are some tips for converting a CRA `.js` component into a `.astro` componen

5. Decide whether any imported components also need to be converted to Astro. You can keep them as React components for now, or forever. But, you may eventually want to convert them to `.astro` components, especially if they do not need to be interactive!

6. Replace `useEffect()` with import statements or [`Astro.glob()`](/en/reference/api-reference/#astroglob) to query your local files. Use `fetch()` to fetch external data.
6. Replace `useEffect()` with import statements or [`import.meta.glob()`](/en/guides/imports/#importmetaglob) to query your local files. Use `fetch()` to fetch external data.

### Migrating Tests

Expand Down Expand Up @@ -325,7 +325,7 @@ See more about [specific `<slot />` usage in Astro](/en/basics/astro-components/

Fetching data in a Create React App component is similar to Astro, with some slight differences.

You will need to remove any instances of a side effect hook (`useEffect`) for either `Astro.glob()` or `getCollection()`/`getEntryBySlug()` to access data from other files in your project source.
You will need to remove any instances of a side effect hook (`useEffect`) for either `import.meta.glob()` or `getCollection()`/`getEntryBySlug()` to access data from other files in your project source.

To [fetch remote data](/en/guides/data-fetching/), use `fetch()`.

Expand All @@ -339,7 +339,7 @@ import { getCollection } from 'astro:content';
const allBlogPosts = await getCollection('blog');

// Get all `src/pages/posts/` entries
const allPosts = await Astro.glob('../pages/posts/*.md');
const allPosts = await Object.values(await import.meta.glob('../pages/post/*.md', { eager: true }));

// Fetch remote data
const response = await fetch('https://randomuser.me/api/');
Expand All @@ -348,7 +348,7 @@ const randomUser = data.results[0];
---
```

See more about [local files imports with `Astro.glob()`](/en/guides/imports/#astroglob), [querying using the Collections API](/en/guides/content-collections/#querying-collections) or [fetching remote data](/en/guides/data-fetching/).
See more about [local files imports with [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [querying using the Collections API](/en/guides/content-collections/#querying-collections) or [fetching remote data](/en/guides/data-fetching/).

### CRA Styling to Astro

Expand Down
8 changes: 4 additions & 4 deletions src/content/docs/en/guides/migrate-to-astro/from-gatsby.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ When you rebuild your Gatsby site in Astro, you will notice some important diffe

- [Astro components](/en/basics/astro-components/) are not written as exported functions that return page templating. Instead, you'll split your code into a "code fence" for your JavaScript and a body exclusively for the HTML you generate.

- [Local file data](/en/guides/imports/): Gatsby uses GraphQL to retrieve data from your project files. Astro uses ESM imports and top-level await functions (e.g. [`Astro.glob()`](/en/guides/imports/#astroglob), [`getCollection()`](/en/guides/content-collections/#querying-collections)) to import data from your project files. You can manually add GraphQL to your Astro project but it is not included by default.
- [Local file data](/en/guides/imports/): Gatsby uses GraphQL to retrieve data from your project files. Astro uses ESM imports and top-level await functions (e.g. [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [`getCollection()`](/en/guides/content-collections/#querying-collections)) to import data from your project files. You can manually add GraphQL to your Astro project but it is not included by default.

## Convert your Gatsby Project

Expand Down Expand Up @@ -123,7 +123,7 @@ Here are some tips for converting a Gatsby `.js` component into a `.astro` compo

5. Decide whether any imported components also need to be converted to Astro. With the official React integration installed, you can [use existing React components in your Astro files](/en/guides/framework-components/). But, you may want to convert them to `.astro` components, especially if they do not need to be interactive!

6. Remove any GraphQL queries. Instead, use import and [`Astro.glob()`](/en/reference/api-reference/#astroglob) statements to query your local files.
6. Remove any GraphQL queries. Instead, use import and [`import.meta.glob()`](/en/guides/imports/#importmetaglob) statements to query your local files.

See [an example from Gatsby's Blog starter template converted step-by-step](#guided-example-gatsby-layout-to-astro)

Expand Down Expand Up @@ -351,7 +351,7 @@ You can learn more about [using images in Astro](/en/guides/images/) in the Imag

### Gatsby GraphQL to Astro

Remove all references to GraphQL queries, and instead use [`Astro.glob()`](/en/guides/imports/#astroglob) to access data from your local files.
Remove all references to GraphQL queries, and instead use [`import.meta.glob()`](/en/guides/imports/#importmetaglob) to access data from your local files.

Or, if using content collections, query your Markdown and MDX files in `src/content/` using [`getEntry()` and `getCollection()`](/en/guides/content-collections/#querying-collections).

Expand All @@ -366,7 +366,7 @@ import { getCollection } from 'astro:content';
const allBlogPosts = await getCollection('blog');

// Get all `src/pages/posts/` entries
const allPosts = await Astro.glob('../pages/posts/*.md');
const allPosts = await Object.values(await import.meta.glob('../pages/post/*.md', { eager: true }));
---

export const pageQuery = graphql`
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/en/guides/migrate-to-astro/from-gridsome.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ When you rebuild your Gridsome site in Astro, you will notice some important dif

- As an SPA, Gridsome uses `vue-router` for SPA routing, and `vue-meta` for managing `<head>`. In Astro, you will create separate HTML pages and control your page `<head>` directly, or in a [layout component](/en/basics/layouts/).

- [Local file data](/en/guides/imports/): Gridsome uses GraphQL to retrieve data from your project files. Astro uses ESM imports and the [`Astro.glob()`](/en/guides/imports/#astroglob) helper to import data from local project files. Remote resources can be loaded using the standard `fetch()` API. GraphQL may be optionally added to your project, but is not included by default.
- [Local file data](/en/guides/imports/): Gridsome uses GraphQL to retrieve data from your project files. Astro uses ESM imports and [`import.meta.glob()`](/en/guides/imports/#importmetaglob) to import data from local project files. Remote resources can be loaded using the standard `fetch()` API. GraphQL may be optionally added to your project, but is not included by default.

## Switch from Gridsome to Astro

Expand Down Expand Up @@ -61,7 +61,7 @@ Bring your existing Markdown (or MDX, with our optional integration) files as co

Since Gridsome's project structure is similar to Astro's, you may be able to copy several existing files from your project into the same location in your new Astro project. However, the two project structures are not identical. You may want to examine [Astro's project structure](/en/basics/project-structure/) to see what the differences are.

Since Astro queries and imports your local files differently than Gridsome, you may want to read about [how to load files using `Astro.glob()`](/en/guides/imports/#astroglob) to understand how to work with your local files.
Since Astro queries and imports your local files differently than Gridsome, you may want to read about [how to load files using [`import.meta.glob()`](/en/guides/imports/#importmetaglob) to understand how to work with your local files.

To convert other types of sites, such as a portfolio or documentation site, see more official starter templates on [astro.new](https://astro.new). You'll find a link to each project's GitHub repository, as well as one-click links to open a working project in StackBlitz, CodeSandbox and Gitpod online development environments.

Expand Down
Loading
Loading