diff --git a/.changeset/warm-weeks-yell.md b/.changeset/warm-weeks-yell.md
new file mode 100644
index 000000000000..9c0ca21daa02
--- /dev/null
+++ b/.changeset/warm-weeks-yell.md
@@ -0,0 +1,13 @@
+---
+"astro": major
+---
+
+`astro:assets` is now enabled by default. If you were previously using the `experimental.assets` flag, please remove it from your config. Also note that the previous `@astrojs/image` integration is incompatible, and must be removed.
+
+This also brings two important changes to using images in Astro:
+
+- New ESM shape: importing an image will now return an object with different properties describing the image such as its path, format and dimensions. This is a breaking change and may require you to update your existing images.
+- In Markdown, MDX, and Markdoc, the `![]()` syntax will now resolve relative images located anywhere in your project in addition to remote images and images stored in the `public/` folder. This notably unlocks storing images next to your content.
+
+Please see our existing [Assets page in Docs](https://docs.astro.build/en/guides/assets/) for more information about using `astro:assets`.
+
diff --git a/packages/astro/client-base.d.ts b/packages/astro/client-base.d.ts
deleted file mode 100644
index 3b0ee490167d..000000000000
--- a/packages/astro/client-base.d.ts
+++ /dev/null
@@ -1,427 +0,0 @@
-///
-
-// eslint-disable-next-line @typescript-eslint/no-namespace
-declare namespace App {
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
- export interface Locals {}
-}
-
-interface ImportMetaEnv {
- /**
- * The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro.
- */
- readonly ASSETS_PREFIX: string;
- /**
- * This is set to the site option specified in your project’s Astro config file.
- */
- readonly SITE: string;
-}
-
-interface ImportMeta {
- /**
- * Astro and Vite expose environment variables through `import.meta.env`. For a complete list of the environment variables available, see the two references below.
- *
- * - [Astro reference](https://docs.astro.build/en/guides/environment-variables/#default-environment-variables)
- * - [Vite reference](https://vitejs.dev/guide/env-and-mode.html#env-variables)
- */
- readonly env: ImportMetaEnv;
-}
-
-declare module 'astro:assets' {
- // Exporting things one by one is a bit cumbersome, not sure if there's a better way - erika, 2023-02-03
- type AstroAssets = {
- // getImage's type here is different from the internal function since the Vite module implicitly pass the service config
- /**
- * Get an optimized image and the necessary attributes to render it.
- *
- * **Example**
- * ```astro
- * ---
- * import { getImage } from 'astro:assets';
- * import originalImage from '../assets/image.png';
- *
- * const optimizedImage = await getImage({src: originalImage, width: 1280 });
- * ---
- *
- * ```
- *
- * This is functionally equivalent to using the `` component, as the component calls this function internally.
- */
- getImage: (
- options:
- | import('./dist/assets/types.js').ImageTransform
- | import('./dist/assets/types.js').UnresolvedImageTransform
- ) => Promise;
- getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
- Image: typeof import('./components/Image.astro').default;
- };
-
- type WithRequired = T & { [P in K]-?: T[P] };
- type Simplify = { [KeyType in keyof T]: T[KeyType] };
- type ImgAttributes = WithRequired<
- Omit, 'src' | 'width' | 'height'>,
- 'alt'
- >;
-
- export type LocalImageProps = Simplify<
- import('./dist/assets/types.js').LocalImageProps
- >;
- export type RemoteImageProps = Simplify<
- import('./dist/assets/types.js').RemoteImageProps
- >;
- export const { getImage, getConfiguredImageService, Image }: AstroAssets;
-}
-
-declare module 'astro:transitions' {
- type TransitionModule = typeof import('./dist/transitions/index.js');
- export const slide: TransitionModule['slide'];
- export const fade: TransitionModule['fade'];
-
- type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
- export const ViewTransitions: ViewTransitionsModule['default'];
-}
-
-type MD = import('./dist/@types/astro').MarkdownInstance>;
-interface ExportedMarkdownModuleEntities {
- frontmatter: MD['frontmatter'];
- file: MD['file'];
- url: MD['url'];
- getHeadings: MD['getHeadings'];
- /** @deprecated Renamed to `getHeadings()` */
- getHeaders: () => void;
- Content: MD['Content'];
- rawContent: MD['rawContent'];
- compiledContent: MD['compiledContent'];
- load: MD['default'];
-}
-
-declare module '*.md' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.markdown' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mkdn' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mkd' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mdwn' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mdown' {
- const { load }: ExportedMarkdownModuleEntities;
- export const {
- frontmatter,
- file,
- url,
- getHeadings,
- getHeaders,
- Content,
- rawContent,
- compiledContent,
- }: ExportedMarkdownModuleEntities;
- export default load;
-}
-
-declare module '*.mdx' {
- type MDX = import('./dist/@types/astro').MDXInstance>;
-
- export const frontmatter: MDX['frontmatter'];
- export const file: MDX['file'];
- export const url: MDX['url'];
- export const getHeadings: MDX['getHeadings'];
- export const Content: MDX['Content'];
-
- const load: MDX['default'];
- export default load;
-}
-
-declare module 'astro:ssr-manifest' {
- export const manifest: import('./dist/@types/astro').SSRManifest;
-}
-
-// Everything below are Vite's types (apart from image types, which are in `client.d.ts`)
-
-// CSS modules
-type CSSModuleClasses = { readonly [key: string]: string };
-
-declare module '*.module.css' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.scss' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.sass' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.less' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.styl' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.stylus' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.pcss' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-declare module '*.module.sss' {
- const classes: CSSModuleClasses;
- export default classes;
-}
-
-// CSS
-declare module '*.css' {
- const css: string;
- export default css;
-}
-declare module '*.scss' {
- const css: string;
- export default css;
-}
-declare module '*.sass' {
- const css: string;
- export default css;
-}
-declare module '*.less' {
- const css: string;
- export default css;
-}
-declare module '*.styl' {
- const css: string;
- export default css;
-}
-declare module '*.stylus' {
- const css: string;
- export default css;
-}
-declare module '*.pcss' {
- const css: string;
- export default css;
-}
-declare module '*.sss' {
- const css: string;
- export default css;
-}
-
-// Built-in asset types
-// see `src/node/constants.ts`
-
-// images
-declare module '*.jfif' {
- const src: string;
- export default src;
-}
-declare module '*.pjpeg' {
- const src: string;
- export default src;
-}
-declare module '*.pjp' {
- const src: string;
- export default src;
-}
-declare module '*.ico' {
- const src: string;
- export default src;
-}
-
-// media
-declare module '*.mp4' {
- const src: string;
- export default src;
-}
-declare module '*.webm' {
- const src: string;
- export default src;
-}
-declare module '*.ogg' {
- const src: string;
- export default src;
-}
-declare module '*.mp3' {
- const src: string;
- export default src;
-}
-declare module '*.wav' {
- const src: string;
- export default src;
-}
-declare module '*.flac' {
- const src: string;
- export default src;
-}
-declare module '*.aac' {
- const src: string;
- export default src;
-}
-
-declare module '*.opus' {
- const src: string;
- export default src;
-}
-
-// fonts
-declare module '*.woff' {
- const src: string;
- export default src;
-}
-declare module '*.woff2' {
- const src: string;
- export default src;
-}
-declare module '*.eot' {
- const src: string;
- export default src;
-}
-declare module '*.ttf' {
- const src: string;
- export default src;
-}
-declare module '*.otf' {
- const src: string;
- export default src;
-}
-
-// other
-declare module '*.webmanifest' {
- const src: string;
- export default src;
-}
-declare module '*.pdf' {
- const src: string;
- export default src;
-}
-declare module '*.txt' {
- const src: string;
- export default src;
-}
-
-// wasm?init
-declare module '*.wasm?init' {
- const initWasm: (options: WebAssembly.Imports) => Promise;
- export default initWasm;
-}
-
-// web worker
-declare module '*?worker' {
- const workerConstructor: {
- new (): Worker;
- };
- export default workerConstructor;
-}
-
-declare module '*?worker&inline' {
- const workerConstructor: {
- new (): Worker;
- };
- export default workerConstructor;
-}
-
-declare module '*?worker&url' {
- const src: string;
- export default src;
-}
-
-declare module '*?sharedworker' {
- const sharedWorkerConstructor: {
- new (): SharedWorker;
- };
- export default sharedWorkerConstructor;
-}
-
-declare module '*?sharedworker&inline' {
- const sharedWorkerConstructor: {
- new (): SharedWorker;
- };
- export default sharedWorkerConstructor;
-}
-
-declare module '*?sharedworker&url' {
- const src: string;
- export default src;
-}
-
-declare module '*?raw' {
- const src: string;
- export default src;
-}
-
-declare module '*?url' {
- const src: string;
- export default src;
-}
-
-declare module '*?inline' {
- const src: string;
- export default src;
-}
diff --git a/packages/astro/client-image.d.ts b/packages/astro/client-image.d.ts
deleted file mode 100644
index ffcc1c63c95f..000000000000
--- a/packages/astro/client-image.d.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-///
-
-// TODO: Merge this file with `client-base.d.ts` in 3.0, when the `astro:assets` feature isn't under a flag anymore.
-
-type InputFormat = import('./dist/assets/types.js').ImageInputFormat;
-
-interface ImageMetadata {
- src: string;
- width: number;
- height: number;
- format: InputFormat;
-}
-
-declare module '*.gif' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.jpeg' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.jpg' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.png' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.tiff' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.webp' {
- const metadata: ImageMetadata;
- export default metadata;
-}
-declare module '*.svg' {
- const metadata: ImageMetadata;
- export default metadata;
-}
diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts
index 96f59d5868a0..7f701b0c0507 100644
--- a/packages/astro/client.d.ts
+++ b/packages/astro/client.d.ts
@@ -1,31 +1,465 @@
-///
+///
-// images
+// eslint-disable-next-line @typescript-eslint/no-namespace
+declare namespace App {
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
+ export interface Locals {}
+}
+
+interface ImportMetaEnv {
+ /**
+ * The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro.
+ */
+ readonly ASSETS_PREFIX: string;
+ /**
+ * This is set to the site option specified in your project’s Astro config file.
+ */
+ readonly SITE: string;
+}
+
+interface ImportMeta {
+ /**
+ * Astro and Vite expose environment variables through `import.meta.env`. For a complete list of the environment variables available, see the two references below.
+ *
+ * - [Astro reference](https://docs.astro.build/en/guides/environment-variables/#default-environment-variables)
+ * - [Vite reference](https://vitejs.dev/guide/env-and-mode.html#env-variables)
+ */
+ readonly env: ImportMetaEnv;
+}
+
+declare module 'astro:assets' {
+ // Exporting things one by one is a bit cumbersome, not sure if there's a better way - erika, 2023-02-03
+ type AstroAssets = {
+ // getImage's type here is different from the internal function since the Vite module implicitly pass the service config
+ /**
+ * Get an optimized image and the necessary attributes to render it.
+ *
+ * **Example**
+ * ```astro
+ * ---
+ * import { getImage } from 'astro:assets';
+ * import originalImage from '../assets/image.png';
+ *
+ * const optimizedImage = await getImage({src: originalImage, width: 1280 });
+ * ---
+ *
+ * ```
+ *
+ * This is functionally equivalent to using the `` component, as the component calls this function internally.
+ */
+ getImage: (
+ options:
+ | import('./dist/assets/types.js').ImageTransform
+ | import('./dist/assets/types.js').UnresolvedImageTransform
+ ) => Promise;
+ getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
+ Image: typeof import('./components/Image.astro').default;
+ };
+
+ type WithRequired = T & { [P in K]-?: T[P] };
+ type Simplify = { [KeyType in keyof T]: T[KeyType] };
+ type ImgAttributes = WithRequired<
+ Omit, 'src' | 'width' | 'height'>,
+ 'alt'
+ >;
+
+ export type LocalImageProps = Simplify<
+ import('./dist/assets/types.js').LocalImageProps
+ >;
+ export type RemoteImageProps = Simplify<
+ import('./dist/assets/types.js').RemoteImageProps
+ >;
+ export const { getImage, getConfiguredImageService, Image }: AstroAssets;
+}
+
+type InputFormat = import('./dist/assets/types.js').ImageInputFormat;
+
+interface ImageMetadata {
+ src: string;
+ width: number;
+ height: number;
+ format: InputFormat;
+}
+
+declare module '*.gif' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.jpeg' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
declare module '*.jpg' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.png' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.tiff' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.webp' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+declare module '*.svg' {
+ const metadata: ImageMetadata;
+ export default metadata;
+}
+
+declare module 'astro:transitions' {
+ type TransitionModule = typeof import('./dist/transitions/index.js');
+ export const slide: TransitionModule['slide'];
+ export const fade: TransitionModule['fade'];
+
+ type ViewTransitionsModule = typeof import('./components/ViewTransitions.astro');
+ export const ViewTransitions: ViewTransitionsModule['default'];
+}
+
+type MD = import('./dist/@types/astro').MarkdownInstance>;
+interface ExportedMarkdownModuleEntities {
+ frontmatter: MD['frontmatter'];
+ file: MD['file'];
+ url: MD['url'];
+ getHeadings: MD['getHeadings'];
+ /** @deprecated Renamed to `getHeadings()` */
+ getHeaders: () => void;
+ Content: MD['Content'];
+ rawContent: MD['rawContent'];
+ compiledContent: MD['compiledContent'];
+ load: MD['default'];
+}
+
+declare module '*.md' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.markdown' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mkdn' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mkd' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mdwn' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mdown' {
+ const { load }: ExportedMarkdownModuleEntities;
+ export const {
+ frontmatter,
+ file,
+ url,
+ getHeadings,
+ getHeaders,
+ Content,
+ rawContent,
+ compiledContent,
+ }: ExportedMarkdownModuleEntities;
+ export default load;
+}
+
+declare module '*.mdx' {
+ type MDX = import('./dist/@types/astro').MDXInstance>;
+
+ export const frontmatter: MDX['frontmatter'];
+ export const file: MDX['file'];
+ export const url: MDX['url'];
+ export const getHeadings: MDX['getHeadings'];
+ export const Content: MDX['Content'];
+
+ const load: MDX['default'];
+ export default load;
+}
+
+declare module 'astro:ssr-manifest' {
+ export const manifest: import('./dist/@types/astro').SSRManifest;
+}
+
+// Everything below are Vite's types (apart from image types, which are in `client.d.ts`)
+
+// CSS modules
+type CSSModuleClasses = { readonly [key: string]: string };
+
+declare module '*.module.css' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.scss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.sass' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.less' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.styl' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.stylus' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.pcss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+declare module '*.module.sss' {
+ const classes: CSSModuleClasses;
+ export default classes;
+}
+
+// CSS
+declare module '*.css' {
+ const css: string;
+ export default css;
+}
+declare module '*.scss' {
+ const css: string;
+ export default css;
+}
+declare module '*.sass' {
+ const css: string;
+ export default css;
+}
+declare module '*.less' {
+ const css: string;
+ export default css;
+}
+declare module '*.styl' {
+ const css: string;
+ export default css;
+}
+declare module '*.stylus' {
+ const css: string;
+ export default css;
+}
+declare module '*.pcss' {
+ const css: string;
+ export default css;
+}
+declare module '*.sss' {
+ const css: string;
+ export default css;
+}
+
+// Built-in asset types
+// see `src/node/constants.ts`
+
+// images
+declare module '*.jfif' {
const src: string;
export default src;
}
-declare module '*.jpeg' {
+declare module '*.pjpeg' {
const src: string;
export default src;
}
-declare module '*.png' {
+declare module '*.pjp' {
const src: string;
export default src;
}
-declare module '*.gif' {
+declare module '*.ico' {
const src: string;
export default src;
}
-declare module '*.svg' {
+
+// media
+declare module '*.mp4' {
const src: string;
export default src;
}
-declare module '*.webp' {
+declare module '*.webm' {
+ const src: string;
+ export default src;
+}
+declare module '*.ogg' {
+ const src: string;
+ export default src;
+}
+declare module '*.mp3' {
+ const src: string;
+ export default src;
+}
+declare module '*.wav' {
+ const src: string;
+ export default src;
+}
+declare module '*.flac' {
+ const src: string;
+ export default src;
+}
+declare module '*.aac' {
+ const src: string;
+ export default src;
+}
+
+declare module '*.opus' {
+ const src: string;
+ export default src;
+}
+
+// fonts
+declare module '*.woff' {
+ const src: string;
+ export default src;
+}
+declare module '*.woff2' {
+ const src: string;
+ export default src;
+}
+declare module '*.eot' {
+ const src: string;
+ export default src;
+}
+declare module '*.ttf' {
+ const src: string;
+ export default src;
+}
+declare module '*.otf' {
const src: string;
export default src;
}
-declare module '*.avif' {
+
+// other
+declare module '*.webmanifest' {
+ const src: string;
+ export default src;
+}
+declare module '*.pdf' {
+ const src: string;
+ export default src;
+}
+declare module '*.txt' {
+ const src: string;
+ export default src;
+}
+
+// wasm?init
+declare module '*.wasm?init' {
+ const initWasm: (options: WebAssembly.Imports) => Promise;
+ export default initWasm;
+}
+
+// web worker
+declare module '*?worker' {
+ const workerConstructor: {
+ new (): Worker;
+ };
+ export default workerConstructor;
+}
+
+declare module '*?worker&inline' {
+ const workerConstructor: {
+ new (): Worker;
+ };
+ export default workerConstructor;
+}
+
+declare module '*?worker&url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?sharedworker' {
+ const sharedWorkerConstructor: {
+ new (): SharedWorker;
+ };
+ export default sharedWorkerConstructor;
+}
+
+declare module '*?sharedworker&inline' {
+ const sharedWorkerConstructor: {
+ new (): SharedWorker;
+ };
+ export default sharedWorkerConstructor;
+}
+
+declare module '*?sharedworker&url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?raw' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?url' {
+ const src: string;
+ export default src;
+}
+
+declare module '*?inline' {
const src: string;
export default src;
}
diff --git a/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs b/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs
index 8a9f43bcc93c..78c248963065 100644
--- a/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs
@@ -9,7 +9,6 @@ export default defineConfig({
integrations: [react()],
experimental: {
viewTransitions: true,
- assets: true,
},
vite: {
build: {
diff --git a/packages/astro/env.d.ts b/packages/astro/env.d.ts
index 079370becebd..876a29c60f49 100644
--- a/packages/astro/env.d.ts
+++ b/packages/astro/env.d.ts
@@ -1,8 +1,8 @@
-///
+///
// Caution! The types here are only available inside Astro files (injected automatically by our language server)
// As such, if the typings you're trying to add should be available inside ex: React components, they should instead
-// be inside `client-base.d.ts`
+// be inside `client.d.ts`
type Astro = import('./dist/@types/astro.js').AstroGlobal;
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 18918f934805..0c04cc5585a4 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -34,8 +34,6 @@
"./env": "./env.d.ts",
"./types": "./types.d.ts",
"./client": "./client.d.ts",
- "./client-base": "./client-base.d.ts",
- "./client-image": "./client-image.d.ts",
"./import-meta": "./import-meta.d.ts",
"./astro-jsx": "./astro-jsx.d.ts",
"./tsconfigs/*.json": "./tsconfigs/*",
@@ -91,8 +89,6 @@
"zod.mjs",
"env.d.ts",
"client.d.ts",
- "client-base.d.ts",
- "client-image.d.ts",
"content-types.template.d.ts",
"content-module.template.mjs",
"import-meta.d.ts",
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index d070b9825a5e..e2b3e6d63f7f 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -132,7 +132,6 @@ export interface CLIFlags {
config?: string;
drafts?: boolean;
open?: boolean;
- experimentalAssets?: boolean;
}
/**
@@ -1231,27 +1230,6 @@ export interface AstroUserConfig {
* These flags are not guaranteed to be stable.
*/
experimental?: {
- /**
- * @docs
- * @name experimental.assets
- * @type {boolean}
- * @default `false`
- * @version 2.1.0
- * @description
- * Enable experimental support for optimizing and resizing images. With this enabled, a new `astro:assets` module will be exposed.
- *
- * To enable this feature, set `experimental.assets` to `true` in your Astro config:
- *
- * ```js
- * {
- * experimental: {
- * assets: true,
- * },
- * }
- * ```
- */
- assets?: boolean;
-
/**
* @docs
* @name experimental.viewTransitions
diff --git a/packages/astro/src/assets/image-endpoint.ts b/packages/astro/src/assets/image-endpoint.ts
index 8dc15c36ae5c..d9a101679d35 100644
--- a/packages/astro/src/assets/image-endpoint.ts
+++ b/packages/astro/src/assets/image-endpoint.ts
@@ -1,11 +1,8 @@
import mime from 'mime/lite.js';
import type { APIRoute } from '../@types/astro.js';
-import { isRemotePath } from '../core/path.js';
-import { getConfiguredImageService } from './internal.js';
-import { isLocalService } from './services/service.js';
import { etag } from './utils/etag.js';
// @ts-expect-error
-import { imageServiceConfig } from 'astro:assets';
+import { getConfiguredImageService, imageServiceConfig } from 'astro:assets';
async function loadRemoteImage(src: URL) {
try {
@@ -28,7 +25,7 @@ export const GET: APIRoute = async ({ request }) => {
try {
const imageService = await getConfiguredImageService();
- if (!isLocalService(imageService)) {
+ if (!('transform' in imageService)) {
throw new Error('Configured image service is not a local service');
}
@@ -70,3 +67,7 @@ export const GET: APIRoute = async ({ request }) => {
return new Response(`Server Error: ${err}`, { status: 500 });
}
};
+
+function isRemotePath(src: string) {
+ return /^(http|ftp|https|ws):?\/\//.test(src) || src.startsWith('data:');
+}
diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts
index 06e4f8cc0c89..a49828a46f04 100644
--- a/packages/astro/src/assets/internal.ts
+++ b/packages/astro/src/assets/internal.ts
@@ -9,6 +9,7 @@ import type {
} from './types.js';
export function injectImageEndpoint(settings: AstroSettings) {
+ // TODO: Add a setting to disable the image endpoint
settings.injectedRoutes.push({
pattern: '/_image',
entryPoint: 'astro/assets/image-endpoint',
diff --git a/packages/astro/src/cli/flags.ts b/packages/astro/src/cli/flags.ts
index 703422d50d61..3d7360a290e7 100644
--- a/packages/astro/src/cli/flags.ts
+++ b/packages/astro/src/cli/flags.ts
@@ -23,9 +23,6 @@ export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
open: typeof flags.open === 'boolean' ? flags.open : undefined,
},
- experimental: {
- assets: typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
- },
};
}
diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts
index 238e32c5f7ce..078197cd04f1 100644
--- a/packages/astro/src/content/types-generator.ts
+++ b/packages/astro/src/content/types-generator.ts
@@ -155,8 +155,7 @@ export async function createContentTypesGenerator({
fileURLToPath(event.entry),
contentPaths,
contentEntryExts,
- dataEntryExts,
- settings.config.experimental.assets
+ dataEntryExts
);
if (fileType === 'ignored') {
return { shouldGenerateTypes: false };
diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts
index d273dc105ec4..369e187a8230 100644
--- a/packages/astro/src/content/utils.ts
+++ b/packages/astro/src/content/utils.ts
@@ -93,8 +93,7 @@ export async function getEntryData(
_internal: EntryInternal;
},
collectionConfig: CollectionConfig,
- pluginContext: PluginContext,
- config: AstroConfig
+ pluginContext: PluginContext
) {
let data;
if (collectionConfig.type === 'data') {
@@ -106,12 +105,6 @@ export async function getEntryData(
let schema = collectionConfig.schema;
if (typeof schema === 'function') {
- if (!config.experimental.assets) {
- throw new Error(
- 'The function shape for schema can only be used when `experimental.assets` is enabled.'
- );
- }
-
schema = schema({
image: createImage(pluginContext, entry._internal.filePath),
});
@@ -250,9 +243,7 @@ export function getEntryType(
entryPath: string,
paths: Pick,
contentFileExts: string[],
- dataFileExts: string[],
- // TODO: Unflag this when we're ready to release assets - erika, 2023-04-12
- experimentalAssets = false
+ dataFileExts: string[]
): 'content' | 'data' | 'config' | 'ignored' | 'unsupported' {
const { ext, base } = path.parse(entryPath);
const fileUrl = pathToFileURL(entryPath);
@@ -260,7 +251,7 @@ export function getEntryType(
if (
hasUnderscoreBelowContentDirectoryPath(fileUrl, paths.contentDir) ||
isOnIgnoreList(base) ||
- (experimentalAssets && isImageAsset(ext))
+ isImageAsset(ext)
) {
return 'ignored';
} else if (contentFileExts.includes(ext)) {
diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts
index a659dd4a0181..4643e0922872 100644
--- a/packages/astro/src/content/vite-plugin-content-imports.ts
+++ b/packages/astro/src/content/vite-plugin-content-imports.ts
@@ -131,13 +131,7 @@ export const _internal = {
configureServer(viteServer) {
viteServer.watcher.on('all', async (event, entry) => {
if (CHOKIDAR_MODIFIED_EVENTS.includes(event)) {
- const entryType = getEntryType(
- entry,
- contentPaths,
- contentEntryExts,
- dataEntryExts,
- settings.config.experimental.assets
- );
+ const entryType = getEntryType(entry, contentPaths, contentEntryExts, dataEntryExts);
if (!COLLECTION_TYPES_TO_INVALIDATE_ON.includes(entryType)) return;
// The content config could depend on collection entries via `reference()`.
@@ -194,7 +188,7 @@ type GetEntryModuleParams =
async function getContentEntryModule(
params: GetEntryModuleParams
): Promise {
- const { fileId, contentDir, pluginContext, config } = params;
+ const { fileId, contentDir, pluginContext } = params;
const { collectionConfig, entryConfig, entry, rawContents, collection } =
await getEntryModuleBaseInfo(params);
@@ -221,8 +215,7 @@ async function getContentEntryModule(
? await getEntryData(
{ id, collection, _internal, unvalidatedData },
collectionConfig,
- pluginContext,
- config
+ pluginContext
)
: unvalidatedData;
@@ -241,7 +234,7 @@ async function getContentEntryModule(
async function getDataEntryModule(
params: GetEntryModuleParams
): Promise {
- const { fileId, contentDir, pluginContext, config } = params;
+ const { fileId, contentDir, pluginContext } = params;
const { collectionConfig, entryConfig, entry, rawContents, collection } =
await getEntryModuleBaseInfo(params);
@@ -256,8 +249,7 @@ async function getDataEntryModule(
? await getEntryData(
{ id, collection, _internal, unvalidatedData },
collectionConfig,
- pluginContext,
- config
+ pluginContext
)
: unvalidatedData;
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index f8d1bf6b490c..c99a8881bf6e 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -186,15 +186,13 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
}
}
- if (opts.settings.config.experimental.assets) {
- info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
- for (const imageData of getStaticImageList()) {
- await generateImage(opts, imageData[1].options, imageData[1].path);
- }
-
- delete globalThis?.astroAsset?.addStaticImage;
+ info(opts.logging, null, `\n${bgGreen(black(` generating optimized images `))}`);
+ for (const imageData of getStaticImageList()) {
+ await generateImage(opts, imageData[1].options, imageData[1].path);
}
+ delete globalThis?.astroAsset?.addStaticImage;
+
await runHookBuildGenerated({
config: opts.settings.config,
logging: opts.logging,
diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts
index 5b1ecf4040f3..07b9b2f7ca17 100644
--- a/packages/astro/src/core/build/index.ts
+++ b/packages/astro/src/core/build/index.ts
@@ -102,9 +102,7 @@ class AstroBuilder {
logging,
});
- // HACK: Since we only inject the endpoint if `experimental.assets` is on and it's possible for an integration to
- // add that flag, we need to only check and inject the endpoint after running the config setup hook.
- if (this.settings.config.experimental.assets && isServerLikeOutput(this.settings.config)) {
+ if (isServerLikeOutput(this.settings.config)) {
this.settings = injectImageEndpoint(this.settings);
}
diff --git a/packages/astro/src/core/build/plugins/plugin-pages.ts b/packages/astro/src/core/build/plugins/plugin-pages.ts
index 966426439734..ff63acd740ef 100644
--- a/packages/astro/src/core/build/plugins/plugin-pages.ts
+++ b/packages/astro/src/core/build/plugins/plugin-pages.ts
@@ -8,6 +8,7 @@ import type { StaticBuildOptions } from '../types';
import { MIDDLEWARE_MODULE_ID } from './plugin-middleware.js';
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
import { ASTRO_PAGE_EXTENSION_POST_PATTERN, getPathFromVirtualModulePageName } from './util.js';
+import type { AstroSettings } from '../../../@types/astro';
export const ASTRO_PAGE_MODULE_ID = '@astro-page:';
export const ASTRO_PAGE_RESOLVED_MODULE_ID = '\0' + ASTRO_PAGE_MODULE_ID;
@@ -74,11 +75,7 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
exports.push(`export { renderers };`);
// The middleware should not be imported by the pages
- if (
- // TODO: remover in Astro 4.0
- !opts.settings.config.build.excludeMiddleware ||
- opts.settings.adapter?.adapterFeatures?.edgeMiddleware === true
- ) {
+ if (shouldBundleMiddleware(opts.settings)) {
const middlewareModule = await this.resolve(MIDDLEWARE_MODULE_ID);
if (middlewareModule) {
imports.push(`import { onRequest } from "${middlewareModule.id}";`);
@@ -94,6 +91,17 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
};
}
+export function shouldBundleMiddleware(settings: AstroSettings) {
+ // TODO: Remove in Astro 4.0
+ if (settings.config.build.excludeMiddleware === true) {
+ return false;
+ }
+ if (settings.adapter?.adapterFeatures?.edgeMiddleware === true) {
+ return false;
+ }
+ return true;
+}
+
export function pluginPages(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
return {
build: 'ssr',
diff --git a/packages/astro/src/core/build/plugins/plugin-prerender.ts b/packages/astro/src/core/build/plugins/plugin-prerender.ts
index a0d6a9c7bf6d..402264c6edb5 100644
--- a/packages/astro/src/core/build/plugins/plugin-prerender.ts
+++ b/packages/astro/src/core/build/plugins/plugin-prerender.ts
@@ -14,7 +14,7 @@ function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals
extendManualChunks(outputOptions, {
after(id, meta) {
// Split the Astro runtime into a separate chunk for readability
- if (id.includes('astro/dist')) {
+ if (id.includes('astro/dist/runtime')) {
return 'astro';
}
const pageInfo = internals.pagesByViteID.get(id);
diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts
index 29b0bb23a415..ba089c9a7727 100644
--- a/packages/astro/src/core/config/config.ts
+++ b/packages/astro/src/core/config/config.ts
@@ -124,8 +124,6 @@ export function resolveFlags(flags: Partial): CLIFlags {
host:
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
- experimentalAssets:
- typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
};
}
diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts
index 9b7f42327f3d..48b0f3a59ac9 100644
--- a/packages/astro/src/core/config/schema.ts
+++ b/packages/astro/src/core/config/schema.ts
@@ -44,7 +44,6 @@ const ASTRO_CONFIG_DEFAULTS = {
legacy: {},
redirects: {},
experimental: {
- assets: false,
viewTransitions: false,
optimizeHoistedScript: false,
},
@@ -241,7 +240,6 @@ export const AstroConfigSchema = z.object({
.default(ASTRO_CONFIG_DEFAULTS.vite),
experimental: z
.object({
- assets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.assets),
viewTransitions: z
.boolean()
.optional()
diff --git a/packages/astro/src/core/config/settings.ts b/packages/astro/src/core/config/settings.ts
index 1d0938c00f33..30ca7c4c2b3b 100644
--- a/packages/astro/src/core/config/settings.ts
+++ b/packages/astro/src/core/config/settings.ts
@@ -17,7 +17,6 @@ export function createBaseSettings(config: AstroConfig): AstroSettings {
config,
tsConfig: undefined,
tsConfigPath: undefined,
-
adapter: undefined,
injectedRoutes: [],
resolvedInjectedRoutes: [],
diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts
index 846d6109d3a0..5b2ebfa21bab 100644
--- a/packages/astro/src/core/create-vite.ts
+++ b/packages/astro/src/core/create-vite.ts
@@ -132,7 +132,7 @@ export async function createVite(
astroContentImportPlugin({ fs, settings }),
astroContentAssetPropagationPlugin({ mode, settings }),
vitePluginSSRManifest(),
- settings.config.experimental.assets ? [astroAssetsPlugin({ settings, logging, mode })] : [],
+ astroAssetsPlugin({ settings, logging, mode }),
astroTransitions({ config: settings.config }),
],
publicDir: fileURLToPath(settings.config.publicDir),
diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts
index d4e41e96d46a..4aeb35f3a486 100644
--- a/packages/astro/src/core/dev/container.ts
+++ b/packages/astro/src/core/dev/container.ts
@@ -50,11 +50,7 @@ export async function createContainer({
isRestart,
});
- // HACK: Since we only inject the endpoint if `experimental.assets` is on and it's possible for an integration to
- // add that flag, we need to only check and inject the endpoint after running the config setup hook.
- if (settings.config.experimental.assets) {
- settings = injectImageEndpoint(settings);
- }
+ settings = injectImageEndpoint(settings);
const { host, headers, open } = settings.config.server;
diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts
index e669f293b3f4..124d870d9070 100644
--- a/packages/astro/src/core/routing/manifest/create.ts
+++ b/packages/astro/src/core/routing/manifest/create.ts
@@ -185,7 +185,12 @@ function injectedRouteToItem(
{ config, cwd }: { config: AstroConfig; cwd?: string },
{ pattern, entryPoint }: InjectedRoute
): Item {
- const resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] });
+ let resolved: string;
+ try {
+ resolved = require.resolve(entryPoint, { paths: [cwd || fileURLToPath(config.root)] });
+ } catch (e) {
+ resolved = fileURLToPath(new URL(entryPoint, config.root));
+ }
const ext = path.extname(pattern);
diff --git a/packages/astro/src/vite-plugin-inject-env-ts/index.ts b/packages/astro/src/vite-plugin-inject-env-ts/index.ts
index 8ac7c5281e90..0f0fbb86d01a 100644
--- a/packages/astro/src/vite-plugin-inject-env-ts/index.ts
+++ b/packages/astro/src/vite-plugin-inject-env-ts/index.ts
@@ -50,26 +50,6 @@ export async function setUpEnvTs({
if (fs.existsSync(envTsPath)) {
let typesEnvContents = await fs.promises.readFile(envTsPath, 'utf-8');
- // TODO: Remove this logic in 3.0, as `astro/client-image` will be merged into `astro/client`
- if (settings.config.experimental.assets && typesEnvContents.includes('types="astro/client"')) {
- typesEnvContents = typesEnvContents.replace(
- 'types="astro/client"',
- 'types="astro/client-image"'
- );
- await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
- info(logging, 'assets', `Added ${bold(envTsPathRelativetoRoot)} types`);
- } else if (
- !settings.config.experimental.assets &&
- typesEnvContents.includes('types="astro/client-image"')
- ) {
- typesEnvContents = typesEnvContents.replace(
- 'types="astro/client-image"',
- 'types="astro/client"'
- );
- await fs.promises.writeFile(envTsPath, typesEnvContents, 'utf-8');
- info(logging, 'assets', `Removed ${bold(envTsPathRelativetoRoot)} types`);
- }
-
if (!fs.existsSync(dotAstroDir))
// Add `.astro` types reference if none exists
return;
@@ -83,11 +63,7 @@ export async function setUpEnvTs({
} else {
// Otherwise, inject the `env.d.ts` file
let referenceDefs: string[] = [];
- if (settings.config.experimental.assets) {
- referenceDefs.push('/// ');
- } else {
- referenceDefs.push('/// ');
- }
+ referenceDefs.push('/// ');
if (fs.existsSync(dotAstroDir)) {
referenceDefs.push(dotAstroTypeReference);
diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts
index be77b3caadab..ae26bfb420f2 100644
--- a/packages/astro/src/vite-plugin-markdown/index.ts
+++ b/packages/astro/src/vite-plugin-markdown/index.ts
@@ -75,7 +75,6 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
...settings.config.markdown,
fileURL: new URL(`file://${fileId}`),
frontmatter: raw.data,
- experimentalAssets: settings.config.experimental.assets,
});
let html = renderResult.code;
@@ -83,7 +82,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
// Resolve all the extracted images from the content
let imagePaths: { raw: string; resolved: string }[] = [];
- if (settings.config.experimental.assets && renderResult.vfile.data.imagePaths) {
+ if (renderResult.vfile.data.imagePaths) {
for (let imagePath of renderResult.vfile.data.imagePaths.values()) {
imagePaths.push({
raw: imagePath,
@@ -116,7 +115,7 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)};
${layout ? `import Layout from ${JSON.stringify(layout)};` : ''}
- ${settings.config.experimental.assets ? 'import { getImage } from "astro:assets";' : ''}
+ import { getImage } from "astro:assets";
export const images = {
${imagePaths.map(
diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js
index 8c09de245211..ff0adde52324 100644
--- a/packages/astro/test/core-image.test.js
+++ b/packages/astro/test/core-image.test.js
@@ -20,9 +20,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService({ foo: 'bar' }),
},
@@ -434,9 +431,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-errors/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -502,9 +496,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-base/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -558,9 +549,6 @@ describe('astro:image', () => {
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -582,9 +570,6 @@ describe('astro:image', () => {
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-ssg/',
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -748,9 +733,6 @@ describe('astro:image', () => {
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
@@ -775,9 +757,6 @@ describe('astro:image', () => {
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
diff --git a/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs b/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs
index 7393b72b8aff..a5c3c5532628 100644
--- a/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs
+++ b/packages/astro/test/fixtures/astro-assets-prefix/astro.config.mjs
@@ -1,5 +1,5 @@
-import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
+import { defineConfig } from 'astro/config';
import { testImageService } from '../../test-image-service.js';
// https://astro.build/config
@@ -10,9 +10,6 @@ export default defineConfig({
build: {
assetsPrefix: 'http://localhost:4321',
},
- experimental: {
- assets: true,
- },
image: {
service: testImageService(),
},
diff --git a/packages/astro/test/fixtures/astro-assets/src/pages/index.astro b/packages/astro/test/fixtures/astro-assets/src/pages/index.astro
index 341f2744c592..8da7feb0cc1e 100644
--- a/packages/astro/test/fixtures/astro-assets/src/pages/index.astro
+++ b/packages/astro/test/fixtures/astro-assets/src/pages/index.astro
@@ -9,7 +9,7 @@ import p2Url from '../images/penguin2.jpg?url';
Icons
-
+