diff --git a/benchmark/packages/timer/tsconfig.json b/benchmark/packages/timer/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/benchmark/packages/timer/tsconfig.json +++ b/benchmark/packages/timer/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/examples/basics/package.json b/examples/basics/package.json index b01036c9f..3ff333ea2 100644 --- a/examples/basics/package.json +++ b/examples/basics/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/blog/package.json b/examples/blog/package.json index 1433b582e..ef2a4c143 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^1.0.3", + "@astrojs/mdx": "^1.1.0", "@astrojs/rss": "^3.0.0", "@astrojs/sitemap": "^3.0.0", - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/component/package.json b/examples/component/package.json index 9f0d43fe8..460763afe 100644 --- a/examples/component/package.json +++ b/examples/component/package.json @@ -15,7 +15,7 @@ ], "scripts": {}, "devDependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" }, "peerDependencies": { "astro": "^2.0.0-beta.0" diff --git a/examples/deno/package.json b/examples/deno/package.json index 051830bb6..7ead37e41 100644 --- a/examples/deno/package.json +++ b/examples/deno/package.json @@ -10,7 +10,7 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" }, "devDependencies": { "@astrojs/deno": "^5.0.0" diff --git a/examples/framework-alpine/package.json b/examples/framework-alpine/package.json index abf1f3248..31d9e057a 100644 --- a/examples/framework-alpine/package.json +++ b/examples/framework-alpine/package.json @@ -14,6 +14,6 @@ "@astrojs/alpinejs": "^0.3.0", "@types/alpinejs": "^3.7.2", "alpinejs": "^3.12.3", - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/framework-lit/package.json b/examples/framework-lit/package.json index 696117105..a14686cdf 100644 --- a/examples/framework-lit/package.json +++ b/examples/framework-lit/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/lit": "^3.0.0", "@webcomponents/template-shadowroot": "^0.2.1", - "astro": "^3.0.13", + "astro": "^3.1.0", "lit": "^2.8.0" } } diff --git a/examples/framework-multiple/package.json b/examples/framework-multiple/package.json index e2e5e97f7..78fb01e41 100644 --- a/examples/framework-multiple/package.json +++ b/examples/framework-multiple/package.json @@ -16,7 +16,7 @@ "@astrojs/solid-js": "^3.0.1", "@astrojs/svelte": "^4.0.2", "@astrojs/vue": "^3.0.0", - "astro": "^3.0.13", + "astro": "^3.1.0", "preact": "^10.17.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/examples/framework-preact/package.json b/examples/framework-preact/package.json index 04625d2f2..7a42ca07d 100644 --- a/examples/framework-preact/package.json +++ b/examples/framework-preact/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/preact": "^3.0.0", "@preact/signals": "^1.2.1", - "astro": "^3.0.13", + "astro": "^3.1.0", "preact": "^10.17.1" } } diff --git a/examples/framework-react/package.json b/examples/framework-react/package.json index b8d0e91b2..1f99c9729 100644 --- a/examples/framework-react/package.json +++ b/examples/framework-react/package.json @@ -14,7 +14,7 @@ "@astrojs/react": "^3.0.2", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", - "astro": "^3.0.13", + "astro": "^3.1.0", "react": "^18.2.0", "react-dom": "^18.2.0" } diff --git a/examples/framework-solid/package.json b/examples/framework-solid/package.json index 4e07d9909..3d42bab15 100644 --- a/examples/framework-solid/package.json +++ b/examples/framework-solid/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@astrojs/solid-js": "^3.0.1", - "astro": "^3.0.13", + "astro": "^3.1.0", "solid-js": "^1.7.11" } } diff --git a/examples/framework-svelte/package.json b/examples/framework-svelte/package.json index 6d7c5b110..0fa4a9980 100644 --- a/examples/framework-svelte/package.json +++ b/examples/framework-svelte/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@astrojs/svelte": "^4.0.2", - "astro": "^3.0.13", + "astro": "^3.1.0", "svelte": "^4.2.0" } } diff --git a/examples/framework-vue/package.json b/examples/framework-vue/package.json index 1a7ff9a9b..d7cce47c9 100644 --- a/examples/framework-vue/package.json +++ b/examples/framework-vue/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@astrojs/vue": "^3.0.0", - "astro": "^3.0.13", + "astro": "^3.1.0", "vue": "^3.3.4" } } diff --git a/examples/hackernews/package.json b/examples/hackernews/package.json index eb287a812..6c221804b 100644 --- a/examples/hackernews/package.json +++ b/examples/hackernews/package.json @@ -12,6 +12,6 @@ }, "dependencies": { "@astrojs/node": "^6.0.0", - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/integration/package.json b/examples/integration/package.json index 2b3a883cb..d7ee4b2d1 100644 --- a/examples/integration/package.json +++ b/examples/integration/package.json @@ -15,7 +15,7 @@ ], "scripts": {}, "devDependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" }, "peerDependencies": { "astro": "^2.0.0-beta.0" diff --git a/examples/middleware/package.json b/examples/middleware/package.json index 037de1ecd..a97b73972 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@astrojs/node": "^6.0.0", - "astro": "^3.0.13", + "astro": "^3.1.0", "html-minifier": "^4.0.0" } } diff --git a/examples/minimal/package.json b/examples/minimal/package.json index 06b71c51c..b36c4a8d3 100644 --- a/examples/minimal/package.json +++ b/examples/minimal/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/non-html-pages/package.json b/examples/non-html-pages/package.json index 6558d2af2..7e4a6ddbf 100644 --- a/examples/non-html-pages/package.json +++ b/examples/non-html-pages/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/portfolio/package.json b/examples/portfolio/package.json index 54ea001b3..4b4ca5f03 100644 --- a/examples/portfolio/package.json +++ b/examples/portfolio/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/ssr/package.json b/examples/ssr/package.json index bd579bafe..8db6c31e2 100644 --- a/examples/ssr/package.json +++ b/examples/ssr/package.json @@ -14,7 +14,7 @@ "dependencies": { "@astrojs/node": "^6.0.0", "@astrojs/svelte": "^4.0.2", - "astro": "^3.0.13", + "astro": "^3.1.0", "svelte": "^4.2.0" } } diff --git a/examples/with-markdoc/package.json b/examples/with-markdoc/package.json index fafa5d218..9a1ee15db 100644 --- a/examples/with-markdoc/package.json +++ b/examples/with-markdoc/package.json @@ -12,6 +12,6 @@ }, "dependencies": { "@astrojs/markdoc": "^0.5.0", - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/with-markdown-plugins/package.json b/examples/with-markdown-plugins/package.json index 13a4577b3..725433585 100644 --- a/examples/with-markdown-plugins/package.json +++ b/examples/with-markdown-plugins/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/markdown-remark": "^3.1.0", - "astro": "^3.0.13", + "@astrojs/markdown-remark": "^3.2.0", + "astro": "^3.1.0", "hast-util-select": "^5.0.5", "rehype-autolink-headings": "^6.1.1", "rehype-slug": "^5.1.0", diff --git a/examples/with-markdown-shiki/package.json b/examples/with-markdown-shiki/package.json index 56f7aad57..9fae2b331 100644 --- a/examples/with-markdown-shiki/package.json +++ b/examples/with-markdown-shiki/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13" + "astro": "^3.1.0" } } diff --git a/examples/with-mdx/package.json b/examples/with-mdx/package.json index a9aadefd5..dc26ecea1 100644 --- a/examples/with-mdx/package.json +++ b/examples/with-mdx/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^1.0.3", + "@astrojs/mdx": "^1.1.0", "@astrojs/preact": "^3.0.0", - "astro": "^3.0.13", + "astro": "^3.1.0", "preact": "^10.17.1" } } diff --git a/examples/with-nanostores/package.json b/examples/with-nanostores/package.json index 1d00a36bd..d00393ca5 100644 --- a/examples/with-nanostores/package.json +++ b/examples/with-nanostores/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/preact": "^3.0.0", "@nanostores/preact": "^0.5.0", - "astro": "^3.0.13", + "astro": "^3.1.0", "nanostores": "^0.9.3", "preact": "^10.17.1" } diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json index 8f7d5741e..b3bd69f5c 100644 --- a/examples/with-tailwindcss/package.json +++ b/examples/with-tailwindcss/package.json @@ -11,10 +11,10 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^1.0.3", + "@astrojs/mdx": "^1.1.0", "@astrojs/tailwind": "^5.0.0", "@types/canvas-confetti": "^1.6.0", - "astro": "^3.0.13", + "astro": "^3.1.0", "autoprefixer": "^10.4.15", "canvas-confetti": "^1.6.0", "postcss": "^8.4.28", diff --git a/examples/with-vite-plugin-pwa/package.json b/examples/with-vite-plugin-pwa/package.json index e31c8a5c6..b75ab17eb 100644 --- a/examples/with-vite-plugin-pwa/package.json +++ b/examples/with-vite-plugin-pwa/package.json @@ -11,7 +11,7 @@ "astro": "astro" }, "dependencies": { - "astro": "^3.0.13", + "astro": "^3.1.0", "vite-plugin-pwa": "0.16.4", "workbox-window": "^7.0.0" } diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json index c19f7b6d9..1ac25f3d4 100644 --- a/examples/with-vitest/package.json +++ b/examples/with-vitest/package.json @@ -12,7 +12,7 @@ "test": "vitest" }, "dependencies": { - "astro": "^3.0.13", + "astro": "^3.1.0", "vitest": "^0.34.2" } } diff --git a/packages/astro-prism/tsconfig.json b/packages/astro-prism/tsconfig.json index fd652e629..18443cddf 100644 --- a/packages/astro-prism/tsconfig.json +++ b/packages/astro-prism/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "target": "ES2022", - "module": "ES2022", "outDir": "./dist" } } diff --git a/packages/astro-rss/src/util.ts b/packages/astro-rss/src/util.ts index e40301a4c..bc1589780 100644 --- a/packages/astro-rss/src/util.ts +++ b/packages/astro-rss/src/util.ts @@ -1,5 +1,5 @@ import type { z } from 'astro/zod'; -import type { RSSOptions } from './index'; +import type { RSSOptions } from './index.js'; /** Normalize URL to its canonical form */ export function createCanonicalURL( diff --git a/packages/astro-rss/tsconfig.json b/packages/astro-rss/tsconfig.json index d8efd2fec..18443cddf 100644 --- a/packages/astro-rss/tsconfig.json +++ b/packages/astro-rss/tsconfig.json @@ -2,10 +2,6 @@ "extends": "../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022", - "strictNullChecks": true + "outDir": "./dist" } } diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md index 0058bc581..21670dfa8 100644 --- a/packages/astro/CHANGELOG.md +++ b/packages/astro/CHANGELOG.md @@ -1,5 +1,28 @@ # astro +## 3.1.0 + +### Minor Changes + +- [#8467](https://github.com/withastro/astro/pull/8467) [`ecc65abbf`](https://github.com/withastro/astro/commit/ecc65abbf9e086c5bbd1973cd4a820082b4e0dc5) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Add a new `image.endpoint` setting to allow using a custom endpoint in dev and SSR + +- [#8518](https://github.com/withastro/astro/pull/8518) [`2c4fc878b`](https://github.com/withastro/astro/commit/2c4fc878bece36b7fcf1470419c7ce6f1e1e95d0) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds support for using AVIF (`.avif`) files with the Image component. Importing an AVIF file will now correctly return the same object shape as other image file types. See the [Image docs](https://docs.astro.build/en/guides/images/#update-existing-img-tags) for more information on the different properties available on the returned object. + +- [#8464](https://github.com/withastro/astro/pull/8464) [`c92e0acd7`](https://github.com/withastro/astro/commit/c92e0acd715171b3f4c3294099780e21576648c8) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Add types for the object syntax for `style` (ex: `style={{color: 'red'}}`) + +### Patch Changes + +- [#8532](https://github.com/withastro/astro/pull/8532) [`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644) Thanks [@bluwy](https://github.com/bluwy)! - Improve markdown rendering performance by sharing processor instance + +- [#8537](https://github.com/withastro/astro/pull/8537) [`f95febf96`](https://github.com/withastro/astro/commit/f95febf96bb97babb28d78994332f5e47f5f637d) Thanks [@martrapp](https://github.com/martrapp)! - bugfix checking media-type in client-side router + +- [#8536](https://github.com/withastro/astro/pull/8536) [`b85c8a78a`](https://github.com/withastro/astro/commit/b85c8a78a116dbbddc901438bc0b7a1917dc0238) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Improved error messages around `astro:assets` + +- [#7607](https://github.com/withastro/astro/pull/7607) [`45364c345`](https://github.com/withastro/astro/commit/45364c345267429e400baecd1fbc290503f8b13a) Thanks [@FineWolf](https://github.com/FineWolf)! - Add `CollectionKey`, `ContentCollectionKey`, and `DataCollectionKey` exports to `astro:content` + +- Updated dependencies [[`d93987824`](https://github.com/withastro/astro/commit/d93987824d3d6b4f58267be21ab8466ee8d5d5f8), [`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644)]: + - @astrojs/markdown-remark@3.2.0 + ## 3.0.13 ### Patch Changes diff --git a/packages/astro/README.md b/packages/astro/README.md index 9e3ff67c3..682c999c9 100644 --- a/packages/astro/README.md +++ b/packages/astro/README.md @@ -34,10 +34,10 @@ Having trouble? Get help in the official [Astro Discord](https://astro.build/cha **New contributors welcome!** Check out our [Contributors Guide](/CONTRIBUTING.md) for help getting started. -Join us on [Discord](https://astro.build/chat) to meet other maintainers. We'll help you get your first contribution in no time! +Join us on [Discord](https://astro.build/chat) to meet other contributors. We'll help you get your first contribution in no time! ## Sponsors -Astro is generously supported by [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), and several other amazing organizations [listed here.](https://astro.build/) +Astro is generously supported by [Vercel](https://vercel.com/), [storyblok](https://storyblok.com/), and several other amazing organizations [listed here.](https://opencollective.com/astrodotbuild) [❤️ Sponsor Astro! ❤️](https://github.com/withastro/.github/blob/main/FUNDING.md) diff --git a/packages/astro/astro-jsx.d.ts b/packages/astro/astro-jsx.d.ts index b82de9388..3e8a86889 100644 --- a/packages/astro/astro-jsx.d.ts +++ b/packages/astro/astro-jsx.d.ts @@ -471,6 +471,33 @@ declare namespace astroHTML.JSX { | 'treegrid' | 'treeitem'; + type CssProperty = keyof Omit< + CSSStyleDeclaration, + | 'item' + | 'setProperty' + | 'removeProperty' + | 'getPropertyValue' + | 'getPropertyPriority' + | 'parentRule' + | 'length' + | 'cssFloat' + | 'cssText' + | typeof Symbol.iterator + | number + >; + + type KebabCSSDOMProperties = import('./dist/type-utils.js').KebabKeys; + + type DOMCSSProperties = { + [key in CssProperty]?: string | number | null | undefined; + }; + type AllCSSProperties = { + [key: string]: string | number | null | undefined; + }; + type StyleObject = import('./dist/type-utils.js').Simplify< + KebabCSSDOMProperties & DOMCSSProperties & AllCSSProperties + >; + interface HTMLAttributes extends AriaAttributes, DOMAttributes, AstroBuiltinAttributes { // Standard HTML Attributes accesskey?: string | undefined | null; @@ -513,7 +540,7 @@ declare namespace astroHTML.JSX { lang?: string | undefined | null; slot?: string | undefined | null; spellcheck?: 'true' | 'false' | boolean | undefined | null; - style?: string | Record | undefined | null; + style?: string | StyleObject | undefined | null; tabindex?: number | string | undefined | null; title?: string | undefined | null; translate?: 'yes' | 'no' | undefined | null; diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts index 90f06c72d..146ab8355 100644 --- a/packages/astro/client.d.ts +++ b/packages/astro/client.d.ts @@ -52,7 +52,7 @@ declare module 'astro:assets' { | import('./dist/assets/types.js').ImageTransform | import('./dist/assets/types.js').UnresolvedImageTransform ) => Promise; - imageConfig: import('./dist/@types/astro').AstroConfig['image']; + imageConfig: import('./dist/@types/astro.js').AstroConfig['image']; getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService; Image: typeof import('./components/Image.astro').default; }; @@ -108,6 +108,10 @@ declare module '*.svg' { const metadata: ImageMetadata; export default metadata; } +declare module '*.avif' { + const metadata: ImageMetadata; + export default metadata; +} declare module 'astro:transitions' { type TransitionModule = typeof import('./dist/transitions/index.js'); @@ -126,7 +130,7 @@ declare module 'astro:components' { export * from 'astro/components'; } -type MD = import('./dist/@types/astro').MarkdownInstance>; +type MD = import('./dist/@types/astro.js').MarkdownInstance>; interface ExportedMarkdownModuleEntities { frontmatter: MD['frontmatter']; file: MD['file']; @@ -231,7 +235,7 @@ declare module '*.mdown' { } declare module '*.mdx' { - type MDX = import('./dist/@types/astro').MDXInstance>; + type MDX = import('./dist/@types/astro.js').MDXInstance>; export const frontmatter: MDX['frontmatter']; export const file: MDX['file']; @@ -244,7 +248,7 @@ declare module '*.mdx' { } declare module 'astro:ssr-manifest' { - export const manifest: import('./dist/@types/astro').SSRManifest; + export const manifest: import('./dist/@types/astro.js').SSRManifest; } // Everything below are Vite's types (apart from image types, which are in `client.d.ts`) diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro index 77d56e652..9c0a9dfdd 100644 --- a/packages/astro/components/ViewTransitions.astro +++ b/packages/astro/components/ViewTransitions.astro @@ -65,19 +65,19 @@ const { fallback = 'animate' } = Astro.props as Props; }; async function getHTML(href: string) { - let res; try { - res = await fetch(href); + const res = await fetch(href); + const html = await res.text(); + return { + ok: res.ok, + html, + redirected: res.redirected ? res.url : undefined, + // drop potential charset (+ other name/value pairs) as parser needs the mediaType + mediaType: res.headers.get('content-type')?.replace(/;.*$/, ''), + }; } catch (err) { return { ok: false }; } - const html = await res.text(); - return { - ok: res.ok, - html, - redirected: res.redirected ? res.url : undefined, - contentType: res.headers.get('content-type'), - }; } function getFallback(): Fallback { @@ -126,13 +126,13 @@ const { fallback = 'animate' } = Astro.props as Props; // A noop element used to prevent styles from being removed if (import.meta.env.DEV) { - var noopEl: string | undefined = document.createElement('div'); + var noopEl = document.createElement('div'); } async function updateDOM(doc: Document, loc: URL, state?: State, fallback?: Fallback) { // Check for a head element that should persist, either because it has the data // attribute or is a link el. - const persistedHeadElement = (el: Element): Element | null => { + const persistedHeadElement = (el: HTMLElement): Element | null => { const id = el.getAttribute(PERSIST_ATTR); const newEl = id && doc.head.querySelector(`[${PERSIST_ATTR}="${id}"]`); if (newEl) { @@ -189,7 +189,7 @@ const { fallback = 'animate' } = Astro.props as Props; // Swap head for (const el of Array.from(document.head.children)) { - const newEl = persistedHeadElement(el); + const newEl = persistedHeadElement(el as HTMLElement); // If the element exists in the document already, remove it // from the new document and leave the current node alone if (newEl) { @@ -290,16 +290,16 @@ const { fallback = 'animate' } = Astro.props as Props; async function navigate(dir: Direction, loc: URL, state?: State) { let finished: Promise; const href = loc.href; - const { html, ok, contentType, redirected } = await getHTML(href); + const { html, ok, mediaType, redirected } = await getHTML(href); // if there was a redirection, show the final URL in the browser's address bar redirected && (loc = new URL(redirected)); // If there is a problem fetching the new page, just do an MPA navigation to it. - if (!ok || contentType !== 'text/html') { + if (!ok || !(mediaType === 'text/html' || mediaType === 'application/xhtml+xml')) { location.href = href; return; } - const doc = parser.parseFromString(html, contentType); + const doc = parser.parseFromString(html, mediaType); if (!doc.querySelector('[name="astro-view-transitions-enabled"]')) { location.href = href; return; diff --git a/packages/astro/content-types.template.d.ts b/packages/astro/content-types.template.d.ts index 596764fe6..eb560193d 100644 --- a/packages/astro/content-types.template.d.ts +++ b/packages/astro/content-types.template.d.ts @@ -12,7 +12,12 @@ declare module 'astro:content' { export { z } from 'astro/zod'; type Flatten = T extends { [K: string]: infer U } ? U : never; - export type CollectionEntry = Flatten; + + export type CollectionKey = keyof AnyEntryMap; + export type CollectionEntry = Flatten; + + export type ContentCollectionKey = keyof ContentEntryMap; + export type DataCollectionKey = keyof DataEntryMap; // This needs to be in sync with ImageMetadata export type ImageFunction = () => import('astro/zod').ZodObject<{ diff --git a/packages/astro/package.json b/packages/astro/package.json index 8490dd318..396028465 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -1,6 +1,6 @@ { "name": "astro", - "version": "3.0.13", + "version": "3.1.0", "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.", "type": "module", "author": "withastro", @@ -157,6 +157,7 @@ "p-limit": "^4.0.0", "path-to-regexp": "^6.2.1", "preferred-pm": "^3.1.2", + "probe-image-size": "^7.2.3", "prompts": "^2.4.2", "rehype": "^12.0.1", "resolve": "^1.22.4", @@ -197,6 +198,7 @@ "@types/js-yaml": "^4.0.5", "@types/mime": "^3.0.1", "@types/mocha": "^10.0.1", + "@types/probe-image-size": "^7.2.0", "@types/prompts": "^2.4.4", "@types/resolve": "^1.20.2", "@types/send": "^0.17.1", diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 4210dd36d..10e15b6ff 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -13,16 +13,16 @@ import type { AddressInfo } from 'node:net'; import type * as rollup from 'rollup'; import type { TsConfigJson } from 'tsconfig-resolver'; import type * as vite from 'vite'; -import type { RemotePattern } from '../assets/utils/remotePattern'; -import type { SerializedSSRManifest } from '../core/app/types'; -import type { PageBuildData } from '../core/build/types'; -import type { AstroConfigType } from '../core/config'; -import type { AstroTimer } from '../core/config/timer'; -import type { AstroCookies } from '../core/cookies'; +import type { RemotePattern } from '../assets/utils/remotePattern.js'; +import type { SerializedSSRManifest } from '../core/app/types.js'; +import type { PageBuildData } from '../core/build/types.js'; +import type { AstroConfigType } from '../core/config/index.js'; +import type { AstroTimer } from '../core/config/timer.js'; +import type { AstroCookies } from '../core/cookies/index.js'; import type { ResponseWithEncoding } from '../core/endpoint/index.js'; -import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger/core'; -import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server'; -import type { OmitIndexSignature, Simplify } from '../type-utils'; +import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger/core.js'; +import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js'; +import type { OmitIndexSignature, Simplify } from '../type-utils.js'; import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js'; export { type AstroIntegrationLogger }; @@ -39,7 +39,7 @@ export type { ExternalImageService, ImageService, LocalImageService, -} from '../assets/services/service'; +} from '../assets/services/service.js'; export type { GetImageResult, ImageInputFormat, @@ -48,10 +48,10 @@ export type { ImageQuality, ImageQualityPreset, ImageTransform, -} from '../assets/types'; -export type { RemotePattern } from '../assets/utils/remotePattern'; -export type { SSRManifest } from '../core/app/types'; -export type { AstroCookies } from '../core/cookies'; +} from '../assets/types.js'; +export type { RemotePattern } from '../assets/utils/remotePattern.js'; +export type { SSRManifest } from '../core/app/types.js'; +export type { AstroCookies } from '../core/cookies/index.js'; export interface AstroBuiltinProps { 'client:load'?: boolean; @@ -974,6 +974,28 @@ export interface AstroUserConfig { * @name Image Options */ image?: { + /** + * @docs + * @name image.endpoint + * @type {string} + * @default `undefined` + * @version 3.1.0 + * @description + * Set the endpoint to use for image optimization in dev and SSR. Set to `undefined` to use the default endpoint. + * + * The endpoint will always be injected at `/_image`. + * + * ```js + * { + * image: { + * // Example: Use a custom image endpoint + * endpoint: './src/image-endpoint.ts', + * }, + * } + * ``` + */ + endpoint?: string; + /** * @docs * @name image.service diff --git a/packages/astro/src/assets/build/generate.ts b/packages/astro/src/assets/build/generate.ts index 71903e994..dfc0d9a0d 100644 --- a/packages/astro/src/assets/build/generate.ts +++ b/packages/astro/src/assets/build/generate.ts @@ -1,6 +1,6 @@ import fs, { readFileSync } from 'node:fs'; import { basename, join } from 'node:path/posix'; -import type { BuildPipeline } from '../../core/build/buildPipeline'; +import type { BuildPipeline } from '../../core/build/buildPipeline.js'; import { prependForwardSlash } from '../../core/path.js'; import { isServerLikeOutput } from '../../prerender/utils.js'; import { getConfiguredImageService, isESMImportedImage } from '../internal.js'; diff --git a/packages/astro/src/assets/consts.ts b/packages/astro/src/assets/consts.ts index d184c9359..90dfa599c 100644 --- a/packages/astro/src/assets/consts.ts +++ b/packages/astro/src/assets/consts.ts @@ -1,14 +1,6 @@ export const VIRTUAL_MODULE_ID = 'astro:assets'; export const VIRTUAL_SERVICE_ID = 'virtual:image-service'; export const VALID_INPUT_FORMATS = [ - // TODO: `image-size` does not support the following formats, so users can't import them. - // However, it would be immensely useful to add, for three reasons: - // - `heic` and `heif` are common formats, especially among Apple users. - // - AVIF is a common format on the web that's bound to become more and more common. - // - It's totally reasonable for an user's provided image service to want to support more image types. - //'heic', - //'heif', - //'avif', 'jpeg', 'jpg', 'png', @@ -16,6 +8,7 @@ export const VALID_INPUT_FORMATS = [ 'webp', 'gif', 'svg', + 'avif', ] as const; /** * Valid formats that our base services support. @@ -29,5 +22,6 @@ export const VALID_SUPPORTED_FORMATS = [ 'webp', 'gif', 'svg', + 'avif', ] as const; export const VALID_OUTPUT_FORMATS = ['avif', 'png', 'webp', 'jpeg', 'jpg', 'svg'] as const; diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts index dd5e427f6..9d2c9eb0e 100644 --- a/packages/astro/src/assets/internal.ts +++ b/packages/astro/src/assets/internal.ts @@ -11,10 +11,12 @@ import type { import { matchHostname, matchPattern } from './utils/remotePattern.js'; export function injectImageEndpoint(settings: AstroSettings) { + const endpointEntrypoint = settings.config.image.endpoint ?? 'astro/assets/image-endpoint'; + // TODO: Add a setting to disable the image endpoint settings.injectedRoutes.push({ pattern: '/_image', - entryPoint: 'astro/assets/image-endpoint', + entryPoint: endpointEntrypoint, prerender: false, }); @@ -77,12 +79,12 @@ export async function getImage( const service = await getConfiguredImageService(); - // If the user inlined an import, something fairly common especially in MDX, await it for them + // If the user inlined an import, something fairly common especially in MDX, or passed a function that returns an Image, await it for them const resolvedOptions: ImageTransform = { ...options, src: typeof options.src === 'object' && 'then' in options.src - ? (await options.src).default + ? (await options.src).default ?? (await options.src) : options.src, }; diff --git a/packages/astro/src/assets/services/service.ts b/packages/astro/src/assets/services/service.ts index 5af4a898b..69894aa0c 100644 --- a/packages/astro/src/assets/services/service.ts +++ b/packages/astro/src/assets/services/service.ts @@ -1,6 +1,6 @@ import type { AstroConfig } from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../../core/errors/index.js'; -import { joinPaths } from '../../core/path.js'; +import { isRemotePath, joinPaths } from '../../core/path.js'; import { VALID_SUPPORTED_FORMATS } from '../consts.js'; import { isESMImportedImage, isRemoteAllowed } from '../internal.js'; import type { ImageOutputFormat, ImageTransform } from '../types.js'; @@ -126,13 +126,20 @@ export const baseService: Omit = { if (!options.src || (typeof options.src !== 'string' && typeof options.src !== 'object')) { throw new AstroError({ ...AstroErrorData.ExpectedImage, - message: AstroErrorData.ExpectedImage.message(JSON.stringify(options.src)), + message: AstroErrorData.ExpectedImage.message( + JSON.stringify(options.src), + typeof options.src, + JSON.stringify(options, (_, v) => (v === undefined ? null : v)) + ), }); } if (!isESMImportedImage(options.src)) { - // User passed an `/@fs/` path instead of the full image. - if (options.src.startsWith('/@fs/')) { + // User passed an `/@fs/` path or a filesystem path instead of the full image. + if ( + options.src.startsWith('/@fs/') || + (!isRemotePath(options.src) && !options.src.startsWith('/')) + ) { throw new AstroError({ ...AstroErrorData.LocalImageUsedWrongly, message: AstroErrorData.LocalImageUsedWrongly.message(options.src), diff --git a/packages/astro/src/assets/services/vendor/squoosh/codecs.ts b/packages/astro/src/assets/services/vendor/squoosh/codecs.ts index 55b56d596..80aae7520 100644 --- a/packages/astro/src/assets/services/vendor/squoosh/codecs.ts +++ b/packages/astro/src/assets/services/vendor/squoosh/codecs.ts @@ -33,7 +33,7 @@ export interface RotateOptions { } // MozJPEG -import type { MozJPEGModule as MozJPEGEncodeModule } from './mozjpeg/mozjpeg_enc' +import type { MozJPEGModule as MozJPEGEncodeModule } from './mozjpeg/mozjpeg_enc.js' import mozDec from './mozjpeg/mozjpeg_node_dec.js' import mozDecWasm from './mozjpeg/mozjpeg_node_dec.wasm.js' @@ -41,7 +41,7 @@ import mozEnc from './mozjpeg/mozjpeg_node_enc.js' import mozEncWasm from './mozjpeg/mozjpeg_node_enc.wasm.js' // WebP -import type { WebPModule as WebPEncodeModule } from './webp/webp_enc' +import type { WebPModule as WebPEncodeModule } from './webp/webp_enc.js' import webpDec from './webp/webp_node_dec.js' import webpDecWasm from './webp/webp_node_dec.wasm.js' @@ -49,7 +49,7 @@ import webpEnc from './webp/webp_node_enc.js' import webpEncWasm from './webp/webp_node_enc.wasm.js' // AVIF -import type { AVIFModule as AVIFEncodeModule } from './avif/avif_enc' +import type { AVIFModule as AVIFEncodeModule } from './avif/avif_enc.js' import avifDec from './avif/avif_node_dec.js' import avifDecWasm from './avif/avif_node_dec.wasm.js' diff --git a/packages/astro/src/assets/utils/metadata.ts b/packages/astro/src/assets/utils/metadata.ts index de4136b36..7d7ee7457 100644 --- a/packages/astro/src/assets/utils/metadata.ts +++ b/packages/astro/src/assets/utils/metadata.ts @@ -1,8 +1,13 @@ +import probe from 'probe-image-size'; import type { ImageInputFormat, ImageMetadata } from '../types.js'; -import imageSize from '../vendor/image-size/index.js'; export async function imageMetadata(data: Buffer): Promise | undefined> { - const { width, height, type, orientation } = imageSize(data); + const result = probe.sync(data); + if (result === null) { + throw new Error('Failed to probe image size.'); + } + + const { width, height, type, orientation } = result; const isPortrait = (orientation || 0) >= 5; if (!width || !height || !type) { diff --git a/packages/astro/src/assets/vendor/README.md b/packages/astro/src/assets/vendor/README.md deleted file mode 100644 index 7b6927b67..000000000 --- a/packages/astro/src/assets/vendor/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Vendored version of `image-size` and `queue` because we had issues with the CJS nature of those packages. - -Should hopefully be fixed by https://github.com/image-size/image-size/pull/370 diff --git a/packages/astro/src/assets/vendor/image-size/LICENSE b/packages/astro/src/assets/vendor/image-size/LICENSE deleted file mode 100644 index 1341a90d5..000000000 --- a/packages/astro/src/assets/vendor/image-size/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -The MIT License (MIT) - -Copyright © 2017 Aditya Yadav, http://netroy.in - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/astro/src/assets/vendor/image-size/detector.ts b/packages/astro/src/assets/vendor/image-size/detector.ts deleted file mode 100644 index 7a8873ab2..000000000 --- a/packages/astro/src/assets/vendor/image-size/detector.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { typeHandlers, type imageType } from './types.js' - -const keys = Object.keys(typeHandlers) as imageType[] - -// This map helps avoid validating for every single image type -const firstBytes: { [byte: number]: imageType } = { - 0x38: 'psd', - 0x42: 'bmp', - 0x44: 'dds', - 0x47: 'gif', - 0x49: 'tiff', - 0x4d: 'tiff', - 0x52: 'webp', - 0x69: 'icns', - 0x89: 'png', - 0xff: 'jpg' -} - -export function detector(buffer: Buffer): imageType | undefined { - const byte = buffer[0] - if (byte in firstBytes) { - const type = firstBytes[byte] - if (type && typeHandlers[type].validate(buffer)) { - return type - } - } - - const finder = (key: imageType) => typeHandlers[key].validate(buffer) - return keys.find(finder) -} diff --git a/packages/astro/src/assets/vendor/image-size/index.ts b/packages/astro/src/assets/vendor/image-size/index.ts deleted file mode 100644 index 24f910b33..000000000 --- a/packages/astro/src/assets/vendor/image-size/index.ts +++ /dev/null @@ -1,146 +0,0 @@ -import * as fs from "node:fs"; -import * as path from "node:path"; -import Queue from "../queue/queue.js"; -import { detector } from "./detector.js"; -import { typeHandlers, type imageType } from "./types.js"; -import type { ISizeCalculationResult } from "./types/interface.js"; - -type CallbackFn = (e: Error | null, r?: ISizeCalculationResult) => void; - -// Maximum buffer size, with a default of 512 kilobytes. -// TO-DO: make this adaptive based on the initial signature of the image -const MaxBufferSize = 512 * 1024; - -// This queue is for async `fs` operations, to avoid reaching file-descriptor limits -const queue = new Queue({ concurrency: 100, autostart: true }); - -interface Options { - disabledFS: boolean; - disabledTypes: imageType[]; -} - -const globalOptions: Options = { - disabledFS: false, - disabledTypes: [], -}; - -/** - * Return size information based on a buffer - * - * @param {Buffer} buffer - * @param {String} filepath - * @returns {Object} - */ -function lookup(buffer: Buffer, filepath?: string): ISizeCalculationResult { - // detect the file type.. don't rely on the extension - const type = detector(buffer); - - if (typeof type !== "undefined") { - if (globalOptions.disabledTypes.indexOf(type) > -1) { - throw new TypeError("disabled file type: " + type); - } - - // find an appropriate handler for this file type - if (type in typeHandlers) { - const size = typeHandlers[type].calculate(buffer, filepath); - if (size !== undefined) { - size.type = type; - return size; - } - } - } - - // throw up, if we don't understand the file - throw new TypeError( - "unsupported file type: " + type + " (file: " + filepath + ")" - ); -} - -/** - * Reads a file into a buffer. - * @param {String} filepath - * @returns {Promise} - */ -async function asyncFileToBuffer(filepath: string): Promise { - const handle = await fs.promises.open(filepath, "r"); - const { size } = await handle.stat(); - if (size <= 0) { - await handle.close(); - throw new Error("Empty file"); - } - const bufferSize = Math.min(size, MaxBufferSize); - const buffer = Buffer.alloc(bufferSize); - await handle.read(buffer, 0, bufferSize, 0); - await handle.close(); - return buffer; -} - -/** - * Synchronously reads a file into a buffer, blocking the nodejs process. - * - * @param {String} filepath - * @returns {Buffer} - */ -function syncFileToBuffer(filepath: string): Buffer { - // read from the file, synchronously - const descriptor = fs.openSync(filepath, "r"); - const { size } = fs.fstatSync(descriptor); - if (size <= 0) { - fs.closeSync(descriptor); - throw new Error("Empty file"); - } - const bufferSize = Math.min(size, MaxBufferSize); - const buffer = Buffer.alloc(bufferSize); - fs.readSync(descriptor, buffer, 0, bufferSize, 0); - fs.closeSync(descriptor); - return buffer; -} - -export default imageSize; -export function imageSize(input: Buffer | string): ISizeCalculationResult; -export function imageSize(input: string, callback: CallbackFn): void; - -/** - * @param {Buffer|string} input - buffer or relative/absolute path of the image file - * @param {Function=} [callback] - optional function for async detection - */ -export function imageSize( - input: Buffer | string, - callback?: CallbackFn -): ISizeCalculationResult | void { - // Handle buffer input - if (Buffer.isBuffer(input)) { - return lookup(input); - } - - // input should be a string at this point - if (typeof input !== "string" || globalOptions.disabledFS) { - throw new TypeError("invalid invocation. input should be a Buffer"); - } - - // resolve the file path - const filepath = path.resolve(input); - if (typeof callback === "function") { - queue.push(() => - asyncFileToBuffer(filepath) - .then((buffer) => - process.nextTick(callback, null, lookup(buffer, filepath)) - ) - .catch(callback) - ); - } else { - const buffer = syncFileToBuffer(filepath); - return lookup(buffer, filepath); - } -} - -export const disableFS = (v: boolean): void => { - globalOptions.disabledFS = v; -}; -export const disableTypes = (types: imageType[]): void => { - globalOptions.disabledTypes = types; -}; -export const setConcurrency = (c: number): void => { - queue.concurrency = c; -}; -export const types = Object.keys(typeHandlers); diff --git a/packages/astro/src/assets/vendor/image-size/readUInt.ts b/packages/astro/src/assets/vendor/image-size/readUInt.ts deleted file mode 100644 index ede811408..000000000 --- a/packages/astro/src/assets/vendor/image-size/readUInt.ts +++ /dev/null @@ -1,10 +0,0 @@ -type Bits = 16 | 32 -type MethodName = 'readUInt16BE' | 'readUInt16LE' | 'readUInt32BE' | 'readUInt32LE' - -// Abstract reading multi-byte unsigned integers -export function readUInt(buffer: Buffer, bits: Bits, offset: number, isBigEndian: boolean): number { - offset = offset || 0 - const endian = isBigEndian ? 'BE' : 'LE' - const methodName: MethodName = ('readUInt' + bits + endian) as MethodName - return buffer[methodName].call(buffer, offset) -} diff --git a/packages/astro/src/assets/vendor/image-size/types.ts b/packages/astro/src/assets/vendor/image-size/types.ts deleted file mode 100644 index 05f4f82cc..000000000 --- a/packages/astro/src/assets/vendor/image-size/types.ts +++ /dev/null @@ -1,38 +0,0 @@ -// load all available handlers explicitely for browserify support -import { BMP } from './types/bmp.js' -import { CUR } from './types/cur.js' -import { DDS } from './types/dds.js' -import { GIF } from './types/gif.js' -import { ICNS } from './types/icns.js' -import { ICO } from './types/ico.js' -import { J2C } from './types/j2c.js' -import { JP2 } from './types/jp2.js' -import { JPG } from './types/jpg.js' -import { KTX } from './types/ktx.js' -import { PNG } from './types/png.js' -import { PNM } from './types/pnm.js' -import { PSD } from './types/psd.js' -import { SVG } from './types/svg.js' -import { TIFF } from './types/tiff.js' -import { WEBP } from './types/webp.js' - -export const typeHandlers = { - bmp: BMP, - cur: CUR, - dds: DDS, - gif: GIF, - icns: ICNS, - ico: ICO, - j2c: J2C, - jp2: JP2, - jpg: JPG, - ktx: KTX, - png: PNG, - pnm: PNM, - psd: PSD, - svg: SVG, - tiff: TIFF, - webp: WEBP, -} - -export type imageType = keyof typeof typeHandlers diff --git a/packages/astro/src/assets/vendor/image-size/types/bmp.ts b/packages/astro/src/assets/vendor/image-size/types/bmp.ts deleted file mode 100644 index 2f55ccdd1..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/bmp.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { IImage } from './interface' - -export const BMP: IImage = { - validate(buffer) { - return ('BM' === buffer.toString('ascii', 0, 2)) - }, - - calculate(buffer) { - return { - height: Math.abs(buffer.readInt32LE(22)), - width: buffer.readUInt32LE(18) - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/cur.ts b/packages/astro/src/assets/vendor/image-size/types/cur.ts deleted file mode 100644 index 42766baec..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/cur.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ICO } from './ico.js' -import type { IImage } from './interface' - -const TYPE_CURSOR = 2 -export const CUR: IImage = { - validate(buffer) { - if (buffer.readUInt16LE(0) !== 0) { - return false - } - return buffer.readUInt16LE(2) === TYPE_CURSOR - }, - - calculate(buffer) { - return ICO.calculate(buffer) - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/dds.ts b/packages/astro/src/assets/vendor/image-size/types/dds.ts deleted file mode 100644 index e9ceb63ba..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/dds.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { IImage } from './interface' - -export const DDS: IImage = { - validate(buffer) { - return buffer.readUInt32LE(0) === 0x20534444 - }, - - calculate(buffer) { - return { - height: buffer.readUInt32LE(12), - width: buffer.readUInt32LE(16) - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/gif.ts b/packages/astro/src/assets/vendor/image-size/types/gif.ts deleted file mode 100644 index b18b305f1..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/gif.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { IImage } from './interface' - -const gifRegexp = /^GIF8[79]a/ -export const GIF: IImage = { - validate(buffer) { - const signature = buffer.toString('ascii', 0, 6) - return (gifRegexp.test(signature)) - }, - - calculate(buffer) { - return { - height: buffer.readUInt16LE(8), - width: buffer.readUInt16LE(6) - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/icns.ts b/packages/astro/src/assets/vendor/image-size/types/icns.ts deleted file mode 100644 index 5beccb02c..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/icns.ts +++ /dev/null @@ -1,113 +0,0 @@ -import type { IImage, ISize } from './interface' - -/** - * ICNS Header - * - * | Offset | Size | Purpose | - * | 0 | 4 | Magic literal, must be "icns" (0x69, 0x63, 0x6e, 0x73) | - * | 4 | 4 | Length of file, in bytes, msb first. | - * - */ -const SIZE_HEADER = 4 + 4 // 8 -const FILE_LENGTH_OFFSET = 4 // MSB => BIG ENDIAN - -/** - * Image Entry - * - * | Offset | Size | Purpose | - * | 0 | 4 | Icon type, see OSType below. | - * | 4 | 4 | Length of data, in bytes (including type and length), msb first. | - * | 8 | n | Icon data | - */ -const ENTRY_LENGTH_OFFSET = 4 // MSB => BIG ENDIAN - -const ICON_TYPE_SIZE: {[key: string]: number} = { - ICON: 32, - 'ICN#': 32, - // m => 16 x 16 - 'icm#': 16, - icm4: 16, - icm8: 16, - // s => 16 x 16 - 'ics#': 16, - ics4: 16, - ics8: 16, - is32: 16, - s8mk: 16, - icp4: 16, - // l => 32 x 32 - icl4: 32, - icl8: 32, - il32: 32, - l8mk: 32, - icp5: 32, - ic11: 32, - // h => 48 x 48 - ich4: 48, - ich8: 48, - ih32: 48, - h8mk: 48, - // . => 64 x 64 - icp6: 64, - ic12: 32, - // t => 128 x 128 - it32: 128, - t8mk: 128, - ic07: 128, - // . => 256 x 256 - ic08: 256, - ic13: 256, - // . => 512 x 512 - ic09: 512, - ic14: 512, - // . => 1024 x 1024 - ic10: 1024, -} - -function readImageHeader(buffer: Buffer, imageOffset: number): [string, number] { - const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET - return [ - buffer.toString('ascii', imageOffset, imageLengthOffset), - buffer.readUInt32BE(imageLengthOffset) - ] -} - -function getImageSize(type: string): ISize { - const size = ICON_TYPE_SIZE[type] - return { width: size, height: size, type } -} - -export const ICNS: IImage = { - validate(buffer) { - return ('icns' === buffer.toString('ascii', 0, 4)) - }, - - calculate(buffer) { - const bufferLength = buffer.length - const fileLength = buffer.readUInt32BE(FILE_LENGTH_OFFSET) - let imageOffset = SIZE_HEADER - - let imageHeader = readImageHeader(buffer, imageOffset) - let imageSize = getImageSize(imageHeader[0]) - imageOffset += imageHeader[1] - - if (imageOffset === fileLength) { - return imageSize - } - - const result = { - height: imageSize.height, - images: [imageSize], - width: imageSize.width - } - - while (imageOffset < fileLength && imageOffset < bufferLength) { - imageHeader = readImageHeader(buffer, imageOffset) - imageSize = getImageSize(imageHeader[0]) - imageOffset += imageHeader[1] - result.images.push(imageSize) - } - - return result - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/ico.ts b/packages/astro/src/assets/vendor/image-size/types/ico.ts deleted file mode 100644 index 09310176f..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/ico.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { IImage, ISize, ISizeCalculationResult } from './interface' - -const TYPE_ICON = 1 - -/** - * ICON Header - * - * | Offset | Size | Purpose | - * | 0 | 2 | Reserved. Must always be 0. | - * | 2 | 2 | Image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. | - * | 4 | 2 | Number of images in the file. | - * - */ -const SIZE_HEADER = 2 + 2 + 2 // 6 - -/** - * Image Entry - * - * | Offset | Size | Purpose | - * | 0 | 1 | Image width in pixels. Can be any number between 0 and 255. Value 0 means width is 256 pixels. | - * | 1 | 1 | Image height in pixels. Can be any number between 0 and 255. Value 0 means height is 256 pixels. | - * | 2 | 1 | Number of colors in the color palette. Should be 0 if the image does not use a color palette. | - * | 3 | 1 | Reserved. Should be 0. | - * | 4 | 2 | ICO format: Color planes. Should be 0 or 1. | - * | | | CUR format: The horizontal coordinates of the hotspot in number of pixels from the left. | - * | 6 | 2 | ICO format: Bits per pixel. | - * | | | CUR format: The vertical coordinates of the hotspot in number of pixels from the top. | - * | 8 | 4 | The size of the image's data in bytes | - * | 12 | 4 | The offset of BMP or PNG data from the beginning of the ICO/CUR file | - * - */ -const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4 // 16 - -function getSizeFromOffset(buffer: Buffer, offset: number): number { - const value = buffer.readUInt8(offset) - return value === 0 ? 256 : value -} - -function getImageSize(buffer: Buffer, imageIndex: number): ISize { - const offset = SIZE_HEADER + (imageIndex * SIZE_IMAGE_ENTRY) - return { - height: getSizeFromOffset(buffer, offset + 1), - width: getSizeFromOffset(buffer, offset) - } -} - -export const ICO: IImage = { - validate(buffer) { - if (buffer.readUInt16LE(0) !== 0) { - return false - } - return buffer.readUInt16LE(2) === TYPE_ICON - }, - - calculate(buffer) { - const nbImages = buffer.readUInt16LE(4) - const imageSize = getImageSize(buffer, 0) - - if (nbImages === 1) { - return imageSize - } - - const imgs: ISize[] = [imageSize] - for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) { - imgs.push(getImageSize(buffer, imageIndex)) - } - - const result: ISizeCalculationResult = { - height: imageSize.height, - images: imgs, - width: imageSize.width - } - - return result - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/interface.ts b/packages/astro/src/assets/vendor/image-size/types/interface.ts deleted file mode 100644 index 9886b3573..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/interface.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface ISize { - width: number | undefined - height: number | undefined - orientation?: number - type?: string -} - -export interface ISizeCalculationResult extends ISize { - images?: ISize[] -} - -export interface IImage { - validate: (buffer: Buffer) => boolean - calculate: (buffer: Buffer, filepath?: string) => ISizeCalculationResult -} diff --git a/packages/astro/src/assets/vendor/image-size/types/j2c.ts b/packages/astro/src/assets/vendor/image-size/types/j2c.ts deleted file mode 100644 index 301c38cb6..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/j2c.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IImage } from './interface' - -export const J2C: IImage = { - validate(buffer) { - // TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC - return buffer.toString('hex', 0, 4) === 'ff4fff51' - }, - - calculate(buffer) { - return { - height: buffer.readUInt32BE(12), - width: buffer.readUInt32BE(8), - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/jp2.ts b/packages/astro/src/assets/vendor/image-size/types/jp2.ts deleted file mode 100644 index 127a96d60..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/jp2.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type { IImage, ISize } from './interface' - -const BoxTypes = { - ftyp: '66747970', - ihdr: '69686472', - jp2h: '6a703268', - jp__: '6a502020', - rreq: '72726571', - xml_: '786d6c20' -} - -const calculateRREQLength = (box: Buffer): number => { - const unit = box.readUInt8(0) - let offset = 1 + (2 * unit) - const numStdFlags = box.readUInt16BE(offset) - const flagsLength = numStdFlags * (2 + unit) - offset = offset + 2 + flagsLength - const numVendorFeatures = box.readUInt16BE(offset) - const featuresLength = numVendorFeatures * (16 + unit) - return offset + 2 + featuresLength -} - -const parseIHDR = (box: Buffer): ISize => { - return { - height: box.readUInt32BE(4), - width: box.readUInt32BE(8), - } -} - -export const JP2: IImage = { - validate(buffer) { - const signature = buffer.toString('hex', 4, 8) - const signatureLength = buffer.readUInt32BE(0) - if (signature !== BoxTypes.jp__ || signatureLength < 1) { - return false - } - - const ftypeBoxStart = signatureLength + 4 - const ftypBoxLength = buffer.readUInt32BE(signatureLength) - const ftypBox = buffer.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength) - return ftypBox.toString('hex', 0, 4) === BoxTypes.ftyp - }, - - calculate(buffer) { - const signatureLength = buffer.readUInt32BE(0) - const ftypBoxLength = buffer.readUInt16BE(signatureLength + 2) - let offset = signatureLength + 4 + ftypBoxLength - const nextBoxType = buffer.toString('hex', offset, offset + 4) - switch (nextBoxType) { - case BoxTypes.rreq: - // WHAT ARE THESE 4 BYTES????? - const MAGIC = 4 - offset = offset + 4 + MAGIC + calculateRREQLength(buffer.slice(offset + 4)) - return parseIHDR(buffer.slice(offset + 8, offset + 24)) - case BoxTypes.jp2h : - return parseIHDR(buffer.slice(offset + 8, offset + 24)) - default: - throw new TypeError('Unsupported header found: ' + buffer.toString('ascii', offset, offset + 4)) - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/jpg.ts b/packages/astro/src/assets/vendor/image-size/types/jpg.ts deleted file mode 100644 index 68c32b7be..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/jpg.ts +++ /dev/null @@ -1,151 +0,0 @@ -// NOTE: we only support baseline and progressive JPGs here -// due to the structure of the loader class, we only get a buffer -// with a maximum size of 4096 bytes. so if the SOF marker is outside -// if this range we can't detect the file size correctly. - -import { readUInt } from '../readUInt.js' -import type { IImage, ISize } from './interface' - -const EXIF_MARKER = '45786966' -const APP1_DATA_SIZE_BYTES = 2 -const EXIF_HEADER_BYTES = 6 -const TIFF_BYTE_ALIGN_BYTES = 2 -const BIG_ENDIAN_BYTE_ALIGN = '4d4d' -const LITTLE_ENDIAN_BYTE_ALIGN = '4949' - -// Each entry is exactly 12 bytes -const IDF_ENTRY_BYTES = 12 -const NUM_DIRECTORY_ENTRIES_BYTES = 2 - -function isEXIF(buffer: Buffer): boolean { - return (buffer.toString('hex', 2, 6) === EXIF_MARKER) -} - -function extractSize(buffer: Buffer, index: number): ISize { - return { - height : buffer.readUInt16BE(index), - width : buffer.readUInt16BE(index + 2) - } -} - -function extractOrientation(exifBlock: Buffer, isBigEndian: boolean) { - // TODO: assert that this contains 0x002A - // let STATIC_MOTOROLA_TIFF_HEADER_BYTES = 2 - // let TIFF_IMAGE_FILE_DIRECTORY_BYTES = 4 - - // TODO: derive from TIFF_IMAGE_FILE_DIRECTORY_BYTES - const idfOffset = 8 - - // IDF osset works from right after the header bytes - // (so the offset includes the tiff byte align) - const offset = EXIF_HEADER_BYTES + idfOffset - - const idfDirectoryEntries = readUInt(exifBlock, 16, offset, isBigEndian) - - for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) { - const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + (directoryEntryNumber * IDF_ENTRY_BYTES) - const end = start + IDF_ENTRY_BYTES - - // Skip on corrupt EXIF blocks - if (start > exifBlock.length) { - return - } - - const block = exifBlock.slice(start, end) - const tagNumber = readUInt(block, 16, 0, isBigEndian) - - // 0x0112 (decimal: 274) is the `orientation` tag ID - if (tagNumber === 274) { - const dataFormat = readUInt(block, 16, 2, isBigEndian) - if (dataFormat !== 3) { - return - } - - // unsinged int has 2 bytes per component - // if there would more than 4 bytes in total it's a pointer - const numberOfComponents = readUInt(block, 32, 4, isBigEndian) - if (numberOfComponents !== 1) { - return - } - - return readUInt(block, 16, 8, isBigEndian) - } - } -} - -function validateExifBlock(buffer: Buffer, index: number) { - // Skip APP1 Data Size - const exifBlock = buffer.slice(APP1_DATA_SIZE_BYTES, index) - - // Consider byte alignment - const byteAlign = exifBlock.toString('hex', EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES) - - // Ignore Empty EXIF. Validate byte alignment - const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN - const isLittleEndian = byteAlign === LITTLE_ENDIAN_BYTE_ALIGN - - if (isBigEndian || isLittleEndian) { - return extractOrientation(exifBlock, isBigEndian) - } -} - -function validateBuffer(buffer: Buffer, index: number): void { - // index should be within buffer limits - if (index > buffer.length) { - throw new TypeError('Corrupt JPG, exceeded buffer limits') - } - // Every JPEG block must begin with a 0xFF - if (buffer[index] !== 0xFF) { - throw new TypeError('Invalid JPG, marker table corrupted') - } -} - -export const JPG: IImage = { - validate(buffer) { - const SOIMarker = buffer.toString('hex', 0, 2) - return ('ffd8' === SOIMarker) - }, - - calculate(buffer) { - // Skip 4 chars, they are for signature - buffer = buffer.slice(4) - - let orientation: number | undefined - let next: number - while (buffer.length) { - // read length of the next block - const i = buffer.readUInt16BE(0) - - if (isEXIF(buffer)) { - orientation = validateExifBlock(buffer, i) - } - - // ensure correct format - validateBuffer(buffer, i) - - // 0xFFC0 is baseline standard(SOF) - // 0xFFC1 is baseline optimized(SOF) - // 0xFFC2 is progressive(SOF2) - next = buffer[i + 1] - if (next === 0xC0 || next === 0xC1 || next === 0xC2) { - const size = extractSize(buffer, i + 5) - - // TODO: is orientation=0 a valid answer here? - if (!orientation) { - return size - } - - return { - height: size.height, - orientation, - width: size.width - } - } - - // move to the next block - buffer = buffer.slice(i + 2) - } - - throw new TypeError('Invalid JPG, no size found') - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/ktx.ts b/packages/astro/src/assets/vendor/image-size/types/ktx.ts deleted file mode 100644 index 9e43fdeaa..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/ktx.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { IImage } from './interface' - -const SIGNATURE = 'KTX 11' - -export const KTX: IImage = { - validate(buffer) { - return SIGNATURE === buffer.toString('ascii', 1, 7) - }, - - calculate(buffer) { - return { - height: buffer.readUInt32LE(40), - width: buffer.readUInt32LE(36), - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/png.ts b/packages/astro/src/assets/vendor/image-size/types/png.ts deleted file mode 100644 index a31411380..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/png.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { IImage } from './interface' - -const pngSignature = 'PNG\r\n\x1a\n' -const pngImageHeaderChunkName = 'IHDR' - -// Used to detect "fried" png's: http://www.jongware.com/pngdefry.html -const pngFriedChunkName = 'CgBI' - -export const PNG: IImage = { - validate(buffer) { - if (pngSignature === buffer.toString('ascii', 1, 8)) { - let chunkName = buffer.toString('ascii', 12, 16) - if (chunkName === pngFriedChunkName) { - chunkName = buffer.toString('ascii', 28, 32) - } - if (chunkName !== pngImageHeaderChunkName) { - throw new TypeError('Invalid PNG') - } - return true - } - return false - }, - - calculate(buffer) { - if (buffer.toString('ascii', 12, 16) === pngFriedChunkName) { - return { - height: buffer.readUInt32BE(36), - width: buffer.readUInt32BE(32) - } - } - return { - height: buffer.readUInt32BE(20), - width: buffer.readUInt32BE(16) - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/pnm.ts b/packages/astro/src/assets/vendor/image-size/types/pnm.ts deleted file mode 100644 index fa30a53d5..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/pnm.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { IImage, ISize } from './interface' - -const PNMTypes: { [signature: string]: string } = { - P1: 'pbm/ascii', - P2: 'pgm/ascii', - P3: 'ppm/ascii', - P4: 'pbm', - P5: 'pgm', - P6: 'ppm', - P7: 'pam', - PF: 'pfm' -} - -const Signatures = Object.keys(PNMTypes) - -type Handler = (type: string[]) => ISize -const handlers: { [type: string]: Handler} = { - default: (lines) => { - let dimensions: string[] = [] - - while (lines.length > 0) { - const line = lines.shift()! - if (line[0] === '#') { - continue - } - dimensions = line.split(' ') - break - } - - if (dimensions.length === 2) { - return { - height: parseInt(dimensions[1], 10), - width: parseInt(dimensions[0], 10), - } - } else { - throw new TypeError('Invalid PNM') - } - }, - pam: (lines) => { - const size: { [key: string]: number } = {} - while (lines.length > 0) { - const line = lines.shift()! - if (line.length > 16 || line.charCodeAt(0) > 128) { - continue - } - const [key, value] = line.split(' ') - if (key && value) { - size[key.toLowerCase()] = parseInt(value, 10) - } - if (size.height && size.width) { - break - } - } - - if (size.height && size.width) { - return { - height: size.height, - width: size.width - } - } else { - throw new TypeError('Invalid PAM') - } - } -} - -export const PNM: IImage = { - validate(buffer) { - const signature = buffer.toString('ascii', 0, 2) - return Signatures.includes(signature) - }, - - calculate(buffer) { - const signature = buffer.toString('ascii', 0, 2) - const type = PNMTypes[signature] - // TODO: this probably generates garbage. move to a stream based parser - const lines = buffer.toString('ascii', 3).split(/[\r\n]+/) - const handler = handlers[type] || handlers.default - return handler(lines) - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/psd.ts b/packages/astro/src/assets/vendor/image-size/types/psd.ts deleted file mode 100644 index 7521f5e9f..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/psd.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { IImage } from './interface' - -export const PSD: IImage = { - validate(buffer) { - return ('8BPS' === buffer.toString('ascii', 0, 4)) - }, - - calculate(buffer) { - return { - height: buffer.readUInt32BE(14), - width: buffer.readUInt32BE(18) - } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/svg.ts b/packages/astro/src/assets/vendor/image-size/types/svg.ts deleted file mode 100644 index 945be962d..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/svg.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { IImage, ISize } from './interface' - -interface IAttributes { - width: number | null - height: number | null - viewbox?: IAttributes | null -} - -const svgReg = /"']|"[^"]*"|'[^']*')*>/ - -const extractorRegExps = { - height: /\sheight=(['"])([^%]+?)\1/, - root: svgReg, - viewbox: /\sviewBox=(['"])(.+?)\1/i, - width: /\swidth=(['"])([^%]+?)\1/, -} - -const INCH_CM = 2.54 -const units: { [unit: string]: number } = { - in: 96, - cm: 96 / INCH_CM, - em: 16, - ex: 8, - m: 96 / INCH_CM * 100, - mm: 96 / INCH_CM / 10, - pc: 96 / 72 / 12, - pt: 96 / 72, - px: 1 -} - -const unitsReg = new RegExp(`^([0-9.]+(?:e\\d+)?)(${Object.keys(units).join('|')})?$`) - -function parseLength(len: string) { - const m = unitsReg.exec(len) - if (!m) { - return undefined - } - return Math.round(Number(m[1]) * (units[m[2]] || 1)) -} - -function parseViewbox(viewbox: string): IAttributes { - const bounds = viewbox.split(' ') - return { - height: parseLength(bounds[3])!, - width: parseLength(bounds[2])! - } -} - -function parseAttributes(root: string): IAttributes { - const width = root.match(extractorRegExps.width) - const height = root.match(extractorRegExps.height) - const viewbox = root.match(extractorRegExps.viewbox) - return { - height: height && parseLength(height[2])!, - viewbox: viewbox && parseViewbox(viewbox[2])!, - width: width && parseLength(width[2])!, - } -} - -function calculateByDimensions(attrs: IAttributes): ISize { - return { - height: attrs.height!, - width: attrs.width!, - } -} - -function calculateByViewbox(attrs: IAttributes, viewbox: IAttributes): ISize { - const ratio = (viewbox.width!) / (viewbox.height!) - if (attrs.width) { - return { - height: Math.floor(attrs.width / ratio), - width: attrs.width, - } - } - if (attrs.height) { - return { - height: attrs.height, - width: Math.floor(attrs.height * ratio), - } - } - return { - height: viewbox.height!, - width: viewbox.width!, - } -} - -export const SVG: IImage = { - validate(buffer) { - const str = String(buffer) - return svgReg.test(str) - }, - - calculate(buffer) { - const root = buffer.toString('utf8').match(extractorRegExps.root) - if (root) { - const attrs = parseAttributes(root[0]) - if (attrs.width && attrs.height) { - return calculateByDimensions(attrs) - } - if (attrs.viewbox) { - return calculateByViewbox(attrs, attrs.viewbox) - } - } - throw new TypeError('Invalid SVG') - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/tiff.ts b/packages/astro/src/assets/vendor/image-size/types/tiff.ts deleted file mode 100644 index ae228c1b8..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/tiff.ts +++ /dev/null @@ -1,115 +0,0 @@ -// based on http://www.compix.com/fileformattif.htm -// TO-DO: support big-endian as well -import * as fs from 'node:fs' -import { readUInt } from '../readUInt.js' -import type { IImage } from './interface' - -// Read IFD (image-file-directory) into a buffer -function readIFD(buffer: Buffer, filepath: string, isBigEndian: boolean) { - - const ifdOffset = readUInt(buffer, 32, 4, isBigEndian) - - // read only till the end of the file - let bufferSize = 1024 - const fileSize = fs.statSync(filepath).size - if (ifdOffset + bufferSize > fileSize) { - bufferSize = fileSize - ifdOffset - 10 - } - - // populate the buffer - const endBuffer = Buffer.alloc(bufferSize) - const descriptor = fs.openSync(filepath, 'r') - fs.readSync(descriptor, endBuffer, 0, bufferSize, ifdOffset) - fs.closeSync(descriptor) - - return endBuffer.slice(2) -} - -// TIFF values seem to be messed up on Big-Endian, this helps -function readValue(buffer: Buffer, isBigEndian: boolean): number { - const low = readUInt(buffer, 16, 8, isBigEndian) - const high = readUInt(buffer, 16, 10, isBigEndian) - return (high << 16) + low -} - -// move to the next tag -function nextTag(buffer: Buffer) { - if (buffer.length > 24) { - return buffer.slice(12) - } -} - -// Extract IFD tags from TIFF metadata -function extractTags(buffer: Buffer, isBigEndian: boolean) { - const tags: {[key: number]: number} = {} - - let temp: Buffer | undefined = buffer - while (temp?.length) { - const code = readUInt(temp, 16, 0, isBigEndian) - const type = readUInt(temp, 16, 2, isBigEndian) - const length = readUInt(temp, 32, 4, isBigEndian) - - // 0 means end of IFD - if (code === 0) { - break - } else { - // 256 is width, 257 is height - // if (code === 256 || code === 257) { - if (length === 1 && (type === 3 || type === 4)) { - tags[code] = readValue(temp, isBigEndian) - } - - // move to the next tag - temp = nextTag(temp) - } - } - - return tags -} - -// Test if the TIFF is Big Endian or Little Endian -function determineEndianness(buffer: Buffer) { - const signature = buffer.toString('ascii', 0, 2) - if ('II' === signature) { - return 'LE' - } else if ('MM' === signature) { - return 'BE' - } -} - -const signatures = [ - // '492049', // currently not supported - '49492a00', // Little endian - '4d4d002a', // Big Endian - // '4d4d002a', // BigTIFF > 4GB. currently not supported -] - -export const TIFF: IImage = { - validate(buffer) { - return signatures.includes(buffer.toString('hex', 0, 4)) - }, - - calculate(buffer, filepath) { - if (!filepath) { - throw new TypeError('Tiff doesn\'t support buffer') - } - - // Determine BE/LE - const isBigEndian = determineEndianness(buffer) === 'BE' - - // read the IFD - const ifdBuffer = readIFD(buffer, filepath, isBigEndian) - - // extract the tags from the IFD - const tags = extractTags(ifdBuffer, isBigEndian) - - const width = tags[256] - const height = tags[257] - - if (!width || !height) { - throw new TypeError('Invalid Tiff. Missing tags') - } - - return { height, width } - } -} diff --git a/packages/astro/src/assets/vendor/image-size/types/webp.ts b/packages/astro/src/assets/vendor/image-size/types/webp.ts deleted file mode 100644 index aaafbf12d..000000000 --- a/packages/astro/src/assets/vendor/image-size/types/webp.ts +++ /dev/null @@ -1,65 +0,0 @@ -// based on https://developers.google.com/speed/webp/docs/riff_container -import type { IImage, ISize } from './interface' - -function calculateExtended(buffer: Buffer): ISize { - return { - height: 1 + buffer.readUIntLE(7, 3), - width: 1 + buffer.readUIntLE(4, 3) - } -} - -function calculateLossless(buffer: Buffer): ISize { - return { - height: 1 + (((buffer[4] & 0xF) << 10) | (buffer[3] << 2) | ((buffer[2] & 0xC0) >> 6)), - width: 1 + (((buffer[2] & 0x3F) << 8) | buffer[1]) - } -} - -function calculateLossy(buffer: Buffer): ISize { - // `& 0x3fff` returns the last 14 bits - // TO-DO: include webp scaling in the calculations - return { - height: buffer.readInt16LE(8) & 0x3fff, - width: buffer.readInt16LE(6) & 0x3fff - } -} - -export const WEBP: IImage = { - validate(buffer) { - const riffHeader = 'RIFF' === buffer.toString('ascii', 0, 4) - const webpHeader = 'WEBP' === buffer.toString('ascii', 8, 12) - const vp8Header = 'VP8' === buffer.toString('ascii', 12, 15) - return (riffHeader && webpHeader && vp8Header) - }, - - calculate(buffer) { - const chunkHeader = buffer.toString('ascii', 12, 16) - buffer = buffer.slice(20, 30) - - // Extended webp stream signature - if (chunkHeader === 'VP8X') { - const extendedHeader = buffer[0] - const validStart = (extendedHeader & 0xc0) === 0 - const validEnd = (extendedHeader & 0x01) === 0 - if (validStart && validEnd) { - return calculateExtended(buffer) - } else { - // TODO: breaking change - throw new TypeError('Invalid WebP') - } - } - - // Lossless webp stream signature - if (chunkHeader === 'VP8 ' && buffer[0] !== 0x2f) { - return calculateLossy(buffer) - } - - // Lossy webp stream signature - const signature = buffer.toString('hex', 3, 6) - if (chunkHeader === 'VP8L' && signature !== '9d012a') { - return calculateLossless(buffer) - } - - throw new TypeError('Invalid WebP') - } -} diff --git a/packages/astro/src/assets/vendor/queue/LICENSE b/packages/astro/src/assets/vendor/queue/LICENSE deleted file mode 100644 index 50e946098..000000000 --- a/packages/astro/src/assets/vendor/queue/LICENSE +++ /dev/null @@ -1,8 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2014 Jesse Tane - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/astro/src/assets/vendor/queue/queue.js b/packages/astro/src/assets/vendor/queue/queue.js deleted file mode 100644 index 6c7170435..000000000 --- a/packages/astro/src/assets/vendor/queue/queue.js +++ /dev/null @@ -1,225 +0,0 @@ -const has = Object.prototype.hasOwnProperty - -/** - * Since CustomEvent is only supported in nodejs since version 19, - * you have to create your own class instead of using CustomEvent - * @see https://github.com/nodejs/node/issues/40678 - * */ -export class QueueEvent extends Event { - constructor (name, detail) { - super(name) - this.detail = detail - } -} - - -export default class Queue extends EventTarget { - constructor (options = {}) { - super() - const { concurrency = Infinity, timeout = 0, autostart = false, results = null } = options - - this.concurrency = concurrency - this.timeout = timeout - this.autostart = autostart - this.results = results - this.pending = 0 - this.session = 0 - this.running = false - this.jobs = [] - this.timers = [] - - this.addEventListener('error', this._errorHandler) - } - - _errorHandler(evt) { - this.end(evt.detail.error); - } - - pop () { - return this.jobs.pop() - } - - shift () { - return this.jobs.shift() - } - - indexOf (searchElement, fromIndex) { - return this.jobs.indexOf(searchElement, fromIndex) - } - - lastIndexOf (searchElement, fromIndex) { - if (fromIndex !== undefined) { return this.jobs.lastIndexOf(searchElement, fromIndex) } - return this.jobs.lastIndexOf(searchElement) - } - - slice (start, end) { - this.jobs = this.jobs.slice(start, end) - return this - } - - reverse () { - this.jobs.reverse() - return this - } - - push (...workers) { - const methodResult = this.jobs.push(...workers) - if (this.autostart) { - this.start() - } - return methodResult - } - - unshift (...workers) { - const methodResult = this.jobs.unshift(...workers) - if (this.autostart) { - this.start() - } - return methodResult - } - - splice (start, deleteCount, ...workers) { - this.jobs.splice(start, deleteCount, ...workers) - if (this.autostart) { - this.start() - } - return this - } - - get length () { - return this.pending + this.jobs.length - } - - start (callback) { - let awaiter; - - if (callback) { - this._addCallbackToEndEvent(callback) - } else { - awaiter = this._createPromiseToEndEvent(); - } - - this.running = true - - if (this.pending >= this.concurrency) { - return - } - - if (this.jobs.length === 0) { - if (this.pending === 0) { - this.done() - } - return - } - - const job = this.jobs.shift() - const session = this.session - const timeout = (job !== undefined) && has.call(job, 'timeout') ? job.timeout : this.timeout - let once = true - let timeoutId = null - let didTimeout = false - let resultIndex = null - - const next = (error, ...result) => { - if (once && this.session === session) { - once = false - this.pending-- - if (timeoutId !== null) { - this.timers = this.timers.filter((tID) => tID !== timeoutId) - clearTimeout(timeoutId) - } - - if (error) { - this.dispatchEvent(new QueueEvent('error', { error, job })) - } else if (!didTimeout) { - if (resultIndex !== null && this.results !== null) { - this.results[resultIndex] = [...result] - } - this.dispatchEvent(new QueueEvent('success', { result: [...result], job })) - } - - if (this.session === session) { - if (this.pending === 0 && this.jobs.length === 0) { - this.done() - } else if (this.running) { - this.start() - } - } - } - } - - if (timeout) { - timeoutId = setTimeout(() => { - didTimeout = true - this.dispatchEvent(new QueueEvent('timeout', { next, job })) - next() - }, timeout) - this.timers.push(timeoutId) - } - - if (this.results != null) { - resultIndex = this.results.length - this.results[resultIndex] = null - } - - this.pending++ - this.dispatchEvent(new QueueEvent('start', { job })) - - const promise = job(next) - - if (promise !== undefined && typeof promise.then === 'function') { - promise.then(function (result) { - return next(undefined, result) - }).catch(function (err) { - return next(err || true) - }) - } - - if (this.running && this.jobs.length > 0) { - return this.start() - } - - return awaiter; - } - - stop () { - this.running = false - } - - end (error) { - this.clearTimers() - this.jobs.length = 0 - this.pending = 0 - this.done(error) - } - - clearTimers () { - this.timers.forEach((timer) => { - clearTimeout(timer) - }) - - this.timers = [] - } - - _addCallbackToEndEvent (cb) { - const onend = (evt) => { - this.removeEventListener('end', onend) - cb(evt.detail.error, this.results) - } - this.addEventListener('end', onend) - } - - _createPromiseToEndEvent() { - return new Promise((resolve) => { - this._addCallbackToEndEvent((error, results) => { - resolve({ error, results }); - }); - }); - } - - done (error) { - this.session++ - this.running = false - this.dispatchEvent(new QueueEvent('end', { error })) - } -} diff --git a/packages/astro/src/assets/vite-plugin-assets.ts b/packages/astro/src/assets/vite-plugin-assets.ts index f114e7ef8..0fe45d1ab 100644 --- a/packages/astro/src/assets/vite-plugin-assets.ts +++ b/packages/astro/src/assets/vite-plugin-assets.ts @@ -1,7 +1,7 @@ import MagicString from 'magic-string'; import type * as vite from 'vite'; import { normalizePath } from 'vite'; -import type { AstroPluginOptions, ImageTransform } from '../@types/astro'; +import type { AstroPluginOptions, ImageTransform } from '../@types/astro.js'; import { appendForwardSlash, joinPaths, @@ -14,7 +14,7 @@ import { hashTransform, propsToFilename } from './utils/transformToPath.js'; const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID; -const assetRegex = new RegExp(`\.(${VALID_INPUT_FORMATS.join('|')})$`, 'i'); +const assetRegex = new RegExp(`\\.(${VALID_INPUT_FORMATS.join('|')})$`, 'i'); export default function assets({ settings, diff --git a/packages/astro/src/cli/add/babel.ts b/packages/astro/src/cli/add/babel.ts index 7da8eed6c..facaabd54 100644 --- a/packages/astro/src/cli/add/babel.ts +++ b/packages/astro/src/cli/add/babel.ts @@ -3,13 +3,11 @@ import parser from '@babel/parser'; import traverse from '@babel/traverse'; import * as t from '@babel/types'; -// @ts-expect-error @babel/traverse isn't ESM and needs this trick -export const visit = traverse.default as typeof traverse; +export const visit = traverse.default; export { t }; export async function generate(ast: t.File) { - // @ts-expect-error @babel/generator isn't ESM and needs this trick - const astToText = generator.default as typeof generator; + const astToText = generator.default; const { code } = astToText(ast); return code; } diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 5b8ba3824..8625140ea 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -1,5 +1,5 @@ import type { UserConfig } from 'vite'; -import type { AstroUserConfig } from '../@types/astro'; +import type { AstroUserConfig } from '../@types/astro.js'; import { Logger } from '../core/logger/core.js'; export function defineConfig(config: AstroUserConfig) { diff --git a/packages/astro/src/config/vite-plugin-content-listen.ts b/packages/astro/src/config/vite-plugin-content-listen.ts index bb3cd9d2b..1b65c5bfb 100644 --- a/packages/astro/src/config/vite-plugin-content-listen.ts +++ b/packages/astro/src/config/vite-plugin-content-listen.ts @@ -1,6 +1,6 @@ import type fsMod from 'node:fs'; import type { Plugin, ViteDevServer } from 'vite'; -import type { AstroSettings } from '../@types/astro'; +import type { AstroSettings } from '../@types/astro.js'; import { attachContentServerListeners } from '../content/server-listeners.js'; import type { Logger } from '../core/logger/core.js'; diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index 8900419d8..046b73b1c 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -7,7 +7,7 @@ import { normalizePath, type ViteDevServer } from 'vite'; import type { AstroSettings, ContentEntryType } from '../@types/astro.js'; import { AstroError } from '../core/errors/errors.js'; import { AstroErrorData } from '../core/errors/index.js'; -import type { Logger } from '../core/logger/core'; +import type { Logger } from '../core/logger/core.js'; import { isRelativePath } from '../core/path.js'; import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js'; import { diff --git a/packages/astro/src/content/vite-plugin-content-assets.ts b/packages/astro/src/content/vite-plugin-content-assets.ts index 38e1bdc44..5d82a684f 100644 --- a/packages/astro/src/content/vite-plugin-content-assets.ts +++ b/packages/astro/src/content/vite-plugin-content-assets.ts @@ -5,7 +5,7 @@ import type { AstroSettings } from '../@types/astro.js'; import { moduleIsTopLevelPage, walkParentInfos } from '../core/build/graph.js'; import { getPageDataByViteID, type BuildInternals } from '../core/build/internal.js'; import type { AstroBuildPlugin } from '../core/build/plugin.js'; -import type { StaticBuildOptions } from '../core/build/types'; +import type { StaticBuildOptions } from '../core/build/types.js'; import type { ModuleLoader } from '../core/module-loader/loader.js'; import { createViteLoader } from '../core/module-loader/vite.js'; import { joinPaths, prependForwardSlash } from '../core/path.js'; diff --git a/packages/astro/src/core/app/common.ts b/packages/astro/src/core/app/common.ts index 58898b2fe..5426d7721 100644 --- a/packages/astro/src/core/app/common.ts +++ b/packages/astro/src/core/app/common.ts @@ -1,5 +1,5 @@ import { deserializeRouteData } from '../routing/manifest/serialization.js'; -import type { RouteInfo, SerializedSSRManifest, SSRManifest } from './types'; +import type { RouteInfo, SerializedSSRManifest, SSRManifest } from './types.js'; export function deserializeManifest(serializedManifest: SerializedSSRManifest): SSRManifest { const routes: RouteInfo[] = []; diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index 1c0b13148..9cf01f82d 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -5,8 +5,8 @@ import type { RouteData, SSRElement, SSRManifest, -} from '../../@types/astro'; -import type { SinglePageBuiltModule } from '../build/types'; +} from '../../@types/astro.js'; +import type { SinglePageBuiltModule } from '../build/types.js'; import { getSetCookiesFromResponse } from '../cookies/index.js'; import { consoleLogDestination } from '../logger/console.js'; import { AstroIntegrationLogger, Logger } from '../logger/core.js'; @@ -25,7 +25,7 @@ import { } from '../render/ssr-element.js'; import { matchRoute } from '../routing/match.js'; import { EndpointNotFoundError, SSRRoutePipeline } from './ssrPipeline.js'; -import type { RouteInfo } from './types'; +import type { RouteInfo } from './types.js'; export { deserializeManifest } from './common.js'; const clientLocalsSymbol = Symbol.for('astro.locals'); diff --git a/packages/astro/src/core/app/node.ts b/packages/astro/src/core/app/node.ts index 054064a08..1df931eca 100644 --- a/packages/astro/src/core/app/node.ts +++ b/packages/astro/src/core/app/node.ts @@ -1,5 +1,5 @@ -import type { RouteData } from '../../@types/astro'; -import type { SerializedSSRManifest, SSRManifest } from './types'; +import type { RouteData } from '../../@types/astro.js'; +import type { SerializedSSRManifest, SSRManifest } from './types.js'; import * as fs from 'node:fs'; import { IncomingMessage } from 'node:http'; diff --git a/packages/astro/src/core/app/ssrPipeline.ts b/packages/astro/src/core/app/ssrPipeline.ts index 964c9f8c7..94e8c9139 100644 --- a/packages/astro/src/core/app/ssrPipeline.ts +++ b/packages/astro/src/core/app/ssrPipeline.ts @@ -1,5 +1,5 @@ import { Pipeline } from '../pipeline.js'; -import type { Environment } from '../render'; +import type { Environment } from '../render/index.js'; /** * Thrown when an endpoint contains a response with the header "X-Astro-Response" === 'Not-Found' diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index 8812d2c44..0050b5d7a 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -4,8 +4,8 @@ import type { SSRComponentMetadata, SSRLoadedRenderer, SSRResult, -} from '../../@types/astro'; -import type { SinglePageBuiltModule } from '../build/types'; +} from '../../@types/astro.js'; +import type { SinglePageBuiltModule } from '../build/types.js'; export type ComponentPath = string; diff --git a/packages/astro/src/core/build/buildPipeline.ts b/packages/astro/src/core/build/buildPipeline.ts index bdf9c7706..d38361c36 100644 --- a/packages/astro/src/core/build/buildPipeline.ts +++ b/packages/astro/src/core/build/buildPipeline.ts @@ -1,16 +1,16 @@ -import type { AstroConfig, AstroSettings, SSRLoadedRenderer } from '../../@types/astro'; +import type { AstroConfig, AstroSettings, SSRLoadedRenderer } from '../../@types/astro.js'; import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js'; import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; -import type { SSRManifest } from '../app/types'; +import type { SSRManifest } from '../app/types.js'; import { Logger } from '../logger/core.js'; import { Pipeline } from '../pipeline.js'; import { createEnvironment } from '../render/index.js'; import { createAssetLink } from '../render/ssr-element.js'; -import type { BuildInternals } from './internal'; +import type { BuildInternals } from './internal.js'; import { ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js'; import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js'; import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js'; -import type { PageBuildData, StaticBuildOptions } from './types'; +import type { PageBuildData, StaticBuildOptions } from './types.js'; /** * This pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files. diff --git a/packages/astro/src/core/build/common.ts b/packages/astro/src/core/build/common.ts index a4ba0b4ca..5b3811f1d 100644 --- a/packages/astro/src/core/build/common.ts +++ b/packages/astro/src/core/build/common.ts @@ -1,6 +1,6 @@ import npath from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; -import type { AstroConfig, RouteType } from '../../@types/astro'; +import type { AstroConfig, RouteType } from '../../@types/astro.js'; import { appendForwardSlash } from '../../core/path.js'; const STATUS_CODE_PAGES = new Set(['/404', '/500']); diff --git a/packages/astro/src/core/build/css-asset-name.ts b/packages/astro/src/core/build/css-asset-name.ts index ace31c3ab..6e9e2a1c2 100644 --- a/packages/astro/src/core/build/css-asset-name.ts +++ b/packages/astro/src/core/build/css-asset-name.ts @@ -2,7 +2,7 @@ import type { GetModuleInfo } from 'rollup'; import crypto from 'node:crypto'; import npath from 'node:path'; -import type { AstroSettings } from '../../@types/astro'; +import type { AstroSettings } from '../../@types/astro.js'; import { viteID } from '../util.js'; import { getTopLevelPages } from './graph.js'; diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index f1044434b..5dd6af021 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -16,7 +16,7 @@ import type { SSRError, SSRLoadedRenderer, SSRManifest, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { generateImage as generateImageInternal, getStaticImageList, @@ -57,7 +57,7 @@ import type { SinglePageBuiltModule, StaticBuildOptions, StylesheetAsset, -} from './types'; +} from './types.js'; import { getTimeStat } from './util.js'; function createEntryURL(filePath: string, outFolder: URL) { diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 5280e69e3..aefea5080 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -9,7 +9,7 @@ import type { AstroSettings, ManifestData, RuntimeMode, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { injectImageEndpoint } from '../../assets/internal.js'; import { telemetry } from '../../events/index.js'; import { eventCliSession } from '../../events/session.js'; diff --git a/packages/astro/src/core/build/internal.ts b/packages/astro/src/core/build/internal.ts index c1123e36b..55cff37f3 100644 --- a/packages/astro/src/core/build/internal.ts +++ b/packages/astro/src/core/build/internal.ts @@ -1,6 +1,6 @@ import type { Rollup } from 'vite'; -import type { RouteData, SSRResult } from '../../@types/astro'; -import type { PageOptions } from '../../vite-plugin-astro/types'; +import type { RouteData, SSRResult } from '../../@types/astro.js'; +import type { PageOptions } from '../../vite-plugin-astro/types.js'; import { prependForwardSlash, removeFileExtension } from '../path.js'; import { viteID } from '../util.js'; import { @@ -9,7 +9,7 @@ import { } from './plugins/plugin-pages.js'; import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js'; import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js'; -import type { PageBuildData, StylesheetAsset, ViteID } from './types'; +import type { PageBuildData, StylesheetAsset, ViteID } from './types.js'; export interface BuildInternals { /** diff --git a/packages/astro/src/core/build/page-data.ts b/packages/astro/src/core/build/page-data.ts index ea75a0c0b..da002a051 100644 --- a/packages/astro/src/core/build/page-data.ts +++ b/packages/astro/src/core/build/page-data.ts @@ -1,6 +1,6 @@ -import type { AstroSettings, ManifestData } from '../../@types/astro'; -import type { Logger } from '../logger/core'; -import type { AllPagesData } from './types'; +import type { AstroSettings, ManifestData } from '../../@types/astro.js'; +import type { Logger } from '../logger/core.js'; +import type { AllPagesData } from './types.js'; import * as colors from 'kleur/colors'; import { debug } from '../logger/core.js'; diff --git a/packages/astro/src/core/build/plugin.ts b/packages/astro/src/core/build/plugin.ts index e7b1fbc4a..c5da47457 100644 --- a/packages/astro/src/core/build/plugin.ts +++ b/packages/astro/src/core/build/plugin.ts @@ -1,6 +1,6 @@ import type { Plugin as VitePlugin } from 'vite'; -import type { BuildInternals } from './internal'; -import type { StaticBuildOptions, ViteBuildReturn } from './types'; +import type { BuildInternals } from './internal.js'; +import type { StaticBuildOptions, ViteBuildReturn } from './types.js'; type RollupOutputArray = Extract>; type OutputChunkorAsset = RollupOutputArray[number]['output'][number]; diff --git a/packages/astro/src/core/build/plugins/index.ts b/packages/astro/src/core/build/plugins/index.ts index 600e083e2..90620cb28 100644 --- a/packages/astro/src/core/build/plugins/index.ts +++ b/packages/astro/src/core/build/plugins/index.ts @@ -1,6 +1,6 @@ import { astroConfigBuildPlugin } from '../../../content/vite-plugin-content-assets.js'; import { astroHeadBuildPlugin } from '../../../vite-plugin-head/index.js'; -import type { AstroBuildPluginContainer } from '../plugin'; +import type { AstroBuildPluginContainer } from '../plugin.js'; import { pluginAliasResolve } from './plugin-alias-resolve.js'; import { pluginAnalyzer } from './plugin-analyzer.js'; import { pluginComponentEntry } from './plugin-component-entry.js'; diff --git a/packages/astro/src/core/build/plugins/plugin-analyzer.ts b/packages/astro/src/core/build/plugins/plugin-analyzer.ts index 8483748bc..b81932dce 100644 --- a/packages/astro/src/core/build/plugins/plugin-analyzer.ts +++ b/packages/astro/src/core/build/plugins/plugin-analyzer.ts @@ -1,6 +1,6 @@ import type { ModuleInfo, PluginContext } from 'rollup'; import type { Plugin as VitePlugin } from 'vite'; -import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types'; +import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types.js'; import type { BuildInternals } from '../internal.js'; import type { AstroBuildPlugin } from '../plugin.js'; diff --git a/packages/astro/src/core/build/plugins/plugin-css.ts b/packages/astro/src/core/build/plugins/plugin-css.ts index b72acd27e..d85dc8e56 100644 --- a/packages/astro/src/core/build/plugins/plugin-css.ts +++ b/packages/astro/src/core/build/plugins/plugin-css.ts @@ -3,9 +3,9 @@ import * as npath from 'node:path'; import type { GetModuleInfo } from 'rollup'; import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite'; import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js'; -import type { BuildInternals } from '../internal'; -import type { AstroBuildPlugin } from '../plugin'; -import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types'; +import type { BuildInternals } from '../internal.js'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types.js'; import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js'; import * as assetName from '../css-asset-name.js'; diff --git a/packages/astro/src/core/build/plugins/plugin-hoisted-scripts.ts b/packages/astro/src/core/build/plugins/plugin-hoisted-scripts.ts index d31e42807..5c6b40992 100644 --- a/packages/astro/src/core/build/plugins/plugin-hoisted-scripts.ts +++ b/packages/astro/src/core/build/plugins/plugin-hoisted-scripts.ts @@ -1,10 +1,10 @@ import type { Plugin as VitePlugin } from 'vite'; -import type { AstroSettings } from '../../../@types/astro'; +import type { AstroSettings } from '../../../@types/astro.js'; import { viteID } from '../../util.js'; import type { BuildInternals } from '../internal.js'; import { getPageDataByViteID } from '../internal.js'; -import type { AstroBuildPlugin } from '../plugin'; -import type { OutputChunk, StaticBuildOptions } from '../types'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { OutputChunk, StaticBuildOptions } from '../types.js'; function virtualHoistedEntry(id: string) { return id.startsWith('/astro/hoisted.js?q='); diff --git a/packages/astro/src/core/build/plugins/plugin-internals.ts b/packages/astro/src/core/build/plugins/plugin-internals.ts index 6bf00f9dc..03e6dfb37 100644 --- a/packages/astro/src/core/build/plugins/plugin-internals.ts +++ b/packages/astro/src/core/build/plugins/plugin-internals.ts @@ -1,6 +1,6 @@ import type { Plugin as VitePlugin } from 'vite'; import type { BuildInternals } from '../internal.js'; -import type { AstroBuildPlugin } from '../plugin'; +import type { AstroBuildPlugin } from '../plugin.js'; import { normalizeEntryId } from './plugin-component-entry.js'; export function vitePluginInternals(input: Set, internals: BuildInternals): VitePlugin { diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index 5a1a3ce76..41ceb282c 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -4,14 +4,14 @@ import type { OutputChunk } from 'rollup'; import { type Plugin as VitePlugin } from 'vite'; import { runHookBuildSsr } from '../../../integrations/index.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js'; -import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types'; +import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types.js'; import { joinPaths, prependForwardSlash } from '../../path.js'; import { serializeRouteData } from '../../routing/index.js'; import { addRollupInput } from '../add-rollup-input.js'; import { getOutFile, getOutFolder } from '../common.js'; import { cssOrder, mergeInlineCss, type BuildInternals } from '../internal.js'; -import type { AstroBuildPlugin } from '../plugin'; -import type { StaticBuildOptions } from '../types'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { StaticBuildOptions } from '../types.js'; const manifestReplace = '@@ASTRO_MANIFEST_REPLACE@@'; const replaceExp = new RegExp(`['"](${manifestReplace})['"]`, 'g'); @@ -46,8 +46,8 @@ function vitePluginManifest(options: StaticBuildOptions, internals: BuildInterna `import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest'` ); - contents.push(` -const manifest = _deserializeManifest('${manifestReplace}'); + contents.push(` +const manifest = _deserializeManifest('${manifestReplace}'); _privateSetManifestDontUseThis(manifest); `); diff --git a/packages/astro/src/core/build/plugins/plugin-middleware.ts b/packages/astro/src/core/build/plugins/plugin-middleware.ts index 99853c7b1..47ff4b863 100644 --- a/packages/astro/src/core/build/plugins/plugin-middleware.ts +++ b/packages/astro/src/core/build/plugins/plugin-middleware.ts @@ -2,9 +2,9 @@ import type { Plugin as VitePlugin } from 'vite'; import { getOutputDirectory } from '../../../prerender/utils.js'; import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../../constants.js'; import { addRollupInput } from '../add-rollup-input.js'; -import type { BuildInternals } from '../internal'; -import type { AstroBuildPlugin } from '../plugin'; -import type { StaticBuildOptions } from '../types'; +import type { BuildInternals } from '../internal.js'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { StaticBuildOptions } from '../types.js'; export const MIDDLEWARE_MODULE_ID = '@astro-middleware'; diff --git a/packages/astro/src/core/build/plugins/plugin-pages.ts b/packages/astro/src/core/build/plugins/plugin-pages.ts index 13891f812..00401285f 100644 --- a/packages/astro/src/core/build/plugins/plugin-pages.ts +++ b/packages/astro/src/core/build/plugins/plugin-pages.ts @@ -1,11 +1,11 @@ import { extname } from 'node:path'; import type { Plugin as VitePlugin } from 'vite'; -import type { AstroSettings } from '../../../@types/astro'; +import type { AstroSettings } from '../../../@types/astro.js'; import { routeIsRedirect } from '../../redirects/index.js'; import { addRollupInput } from '../add-rollup-input.js'; import { type BuildInternals } from '../internal.js'; -import type { AstroBuildPlugin } from '../plugin'; -import type { StaticBuildOptions } from '../types'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { StaticBuildOptions } from '../types.js'; 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'; diff --git a/packages/astro/src/core/build/plugins/plugin-prerender.ts b/packages/astro/src/core/build/plugins/plugin-prerender.ts index 402264c6e..35e4813fc 100644 --- a/packages/astro/src/core/build/plugins/plugin-prerender.ts +++ b/packages/astro/src/core/build/plugins/plugin-prerender.ts @@ -3,7 +3,7 @@ import type { Plugin as VitePlugin } from 'vite'; import { getPrerenderMetadata } from '../../../prerender/metadata.js'; import type { BuildInternals } from '../internal.js'; import type { AstroBuildPlugin } from '../plugin.js'; -import type { StaticBuildOptions } from '../types'; +import type { StaticBuildOptions } from '../types.js'; import { extendManualChunks } from './util.js'; function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin { diff --git a/packages/astro/src/core/build/plugins/plugin-renderers.ts b/packages/astro/src/core/build/plugins/plugin-renderers.ts index f0cdf8983..6cb45dc59 100644 --- a/packages/astro/src/core/build/plugins/plugin-renderers.ts +++ b/packages/astro/src/core/build/plugins/plugin-renderers.ts @@ -1,7 +1,7 @@ import type { Plugin as VitePlugin } from 'vite'; import { addRollupInput } from '../add-rollup-input.js'; -import type { AstroBuildPlugin } from '../plugin'; -import type { StaticBuildOptions } from '../types'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { StaticBuildOptions } from '../types.js'; export const RENDERERS_MODULE_ID = '@astro-renderers'; export const RESOLVED_RENDERERS_MODULE_ID = `\0${RENDERERS_MODULE_ID}`; diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts index 33462050a..1887351b1 100644 --- a/packages/astro/src/core/build/plugins/plugin-ssr.ts +++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts @@ -1,14 +1,14 @@ import { join } from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import type { Plugin as VitePlugin } from 'vite'; -import type { AstroAdapter, AstroConfig } from '../../../@types/astro'; +import type { AstroAdapter, AstroConfig } from '../../../@types/astro.js'; import { isFunctionPerRouteEnabled } from '../../../integrations/index.js'; import { isServerLikeOutput } from '../../../prerender/utils.js'; import { routeIsRedirect } from '../../redirects/index.js'; import { addRollupInput } from '../add-rollup-input.js'; import type { BuildInternals } from '../internal.js'; -import type { AstroBuildPlugin } from '../plugin'; -import type { StaticBuildOptions } from '../types'; +import type { AstroBuildPlugin } from '../plugin.js'; +import type { StaticBuildOptions } from '../types.js'; import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from './plugin-manifest.js'; import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js'; import { RENDERERS_MODULE_ID } from './plugin-renderers.js'; @@ -246,8 +246,8 @@ function generateSSRCode(config: AstroConfig, adapter: AstroAdapter) { } contents.push(`import * as adapter from '${adapter.serverEntrypoint}'; -import { renderers } from '${RENDERERS_MODULE_ID}'; -import { manifest as defaultManifest} from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}'; +import { renderers } from '${RENDERERS_MODULE_ID}'; +import { manifest as defaultManifest} from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}'; const _manifest = Object.assign(defaultManifest, { ${pageMap}, renderers, diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index c37ad542e..2d4f41f48 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -6,7 +6,7 @@ import fs from 'node:fs'; import path, { extname } from 'node:path'; import { fileURLToPath } from 'node:url'; import * as vite from 'vite'; -import type { RouteData } from '../../@types/astro'; +import type { RouteData } from '../../@types/astro.js'; import { createBuildInternals, eachPageData, @@ -30,7 +30,7 @@ import { ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js'; import { RESOLVED_RENDERERS_MODULE_ID } from './plugins/plugin-renderers.js'; import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from './plugins/plugin-ssr.js'; import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js'; -import type { PageBuildData, StaticBuildOptions } from './types'; +import type { PageBuildData, StaticBuildOptions } from './types.js'; import { getTimeStat } from './util.js'; export async function viteBuild(opts: StaticBuildOptions) { diff --git a/packages/astro/src/core/build/types.ts b/packages/astro/src/core/build/types.ts index 07f2404bc..a51fc8d00 100644 --- a/packages/astro/src/core/build/types.ts +++ b/packages/astro/src/core/build/types.ts @@ -1,4 +1,5 @@ -import type { InlineConfig, default as vite } from 'vite'; +import type * as vite from 'vite'; +import type { InlineConfig } from 'vite'; import type { AstroConfig, AstroSettings, @@ -8,9 +9,9 @@ import type { RouteData, RuntimeMode, SSRLoadedRenderer, -} from '../../@types/astro'; -import type { Logger } from '../logger/core'; -import type { RouteCache } from '../render/route-cache'; +} from '../../@types/astro.js'; +import type { Logger } from '../logger/core.js'; +import type { RouteCache } from '../render/route-cache.js'; export type ComponentPath = string; export type ViteID = string; diff --git a/packages/astro/src/core/compile/cache.ts b/packages/astro/src/core/compile/cache.ts index 673eabd0b..cdd9ddd55 100644 --- a/packages/astro/src/core/compile/cache.ts +++ b/packages/astro/src/core/compile/cache.ts @@ -1,4 +1,4 @@ -import type { AstroConfig } from '../../@types/astro'; +import type { AstroConfig } from '../../@types/astro.js'; import { compile, type CompileProps, type CompileResult } from './compile.js'; type CompilationCache = Map; diff --git a/packages/astro/src/core/compile/compile.ts b/packages/astro/src/core/compile/compile.ts index d66a2d9c6..5e1cad1be 100644 --- a/packages/astro/src/core/compile/compile.ts +++ b/packages/astro/src/core/compile/compile.ts @@ -1,6 +1,6 @@ import type { TransformResult } from '@astrojs/compiler'; import type { ResolvedConfig } from 'vite'; -import type { AstroConfig } from '../../@types/astro'; +import type { AstroConfig } from '../../@types/astro.js'; import { transform } from '@astrojs/compiler'; import { fileURLToPath } from 'node:url'; diff --git a/packages/astro/src/core/compile/index.ts b/packages/astro/src/core/compile/index.ts index 6851c7c5e..4a2094de7 100644 --- a/packages/astro/src/core/compile/index.ts +++ b/packages/astro/src/core/compile/index.ts @@ -4,5 +4,5 @@ export { invalidateCompilation, isCached, } from './cache.js'; -export type { CompileProps, CompileResult } from './compile'; -export type { TransformStyle } from './types'; +export type { CompileProps, CompileResult } from './compile.js'; +export type { TransformStyle } from './types.js'; diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts index 16c7d28bc..d8fdd9bb0 100644 --- a/packages/astro/src/core/config/config.ts +++ b/packages/astro/src/core/config/config.ts @@ -5,7 +5,7 @@ import type { AstroInlineOnlyConfig, AstroUserConfig, CLIFlags, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import * as colors from 'kleur/colors'; import fs from 'node:fs'; diff --git a/packages/astro/src/core/config/index.ts b/packages/astro/src/core/config/index.ts index 758e832bf..4bb1f0537 100644 --- a/packages/astro/src/core/config/index.ts +++ b/packages/astro/src/core/config/index.ts @@ -1,6 +1,6 @@ export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js'; export { createNodeLogger } from './logging.js'; export { mergeConfig } from './merge.js'; -export type { AstroConfigType } from './schema'; +export type { AstroConfigType } from './schema.js'; export { createSettings } from './settings.js'; export { loadTSConfig, updateTSConfigForFramework } from './tsconfig.js'; diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 46ed2a01f..b36017c22 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -1,7 +1,7 @@ import type { RehypePlugin, RemarkPlugin, RemarkRehype } from '@astrojs/markdown-remark'; import { markdownConfigDefaults } from '@astrojs/markdown-remark'; import type { ILanguageRegistration, IShikiTheme, Theme } from 'shiki'; -import type { AstroUserConfig, ViteUserConfig } from '../../@types/astro'; +import type { AstroUserConfig, ViteUserConfig } from '../../@types/astro.js'; import type { OutgoingHttpHeaders } from 'node:http'; import path from 'node:path'; @@ -183,6 +183,7 @@ export const AstroConfigSchema = z.object({ .default(ASTRO_CONFIG_DEFAULTS.redirects), image: z .object({ + endpoint: z.string().optional(), service: z .object({ entrypoint: z diff --git a/packages/astro/src/core/config/settings.ts b/packages/astro/src/core/config/settings.ts index 30ca7c4c2..8b70f6e96 100644 --- a/packages/astro/src/core/config/settings.ts +++ b/packages/astro/src/core/config/settings.ts @@ -1,7 +1,7 @@ import yaml from 'js-yaml'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; -import type { AstroConfig, AstroSettings } from '../../@types/astro'; +import type { AstroConfig, AstroSettings } from '../../@types/astro.js'; import { getContentPaths } from '../../content/index.js'; import { markdownContentEntryType } from '../../vite-plugin-markdown/content-entry-type.js'; import { getDefaultClientDirectives } from '../client-directive/index.js'; diff --git a/packages/astro/src/core/cookies/response.ts b/packages/astro/src/core/cookies/response.ts index 668bd265f..8dc35e8c7 100644 --- a/packages/astro/src/core/cookies/response.ts +++ b/packages/astro/src/core/cookies/response.ts @@ -1,4 +1,4 @@ -import type { AstroCookies } from './cookies'; +import type { AstroCookies } from './cookies.js'; const astroCookiesSymbol = Symbol.for('astro.cookies'); diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 8adf3cac8..5848bbe53 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -1,5 +1,5 @@ -import type { AstroSettings } from '../@types/astro'; -import type { Logger } from './logger/core'; +import type { AstroSettings } from '../@types/astro.js'; +import type { Logger } from './logger/core.js'; import nodeFs from 'node:fs'; import { fileURLToPath } from 'node:url'; @@ -168,7 +168,7 @@ export async function createVite( { // Typings are imported from 'astro' (e.g. import { Type } from 'astro') find: /^astro$/, - replacement: fileURLToPath(new URL('../@types/astro', import.meta.url)), + replacement: fileURLToPath(new URL('../@types/astro.js', import.meta.url)), }, { find: 'astro:middleware', diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index ed318622f..52dd4c1a4 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -1,6 +1,6 @@ import type * as http from 'node:http'; import type { AddressInfo } from 'node:net'; -import type { AstroInlineConfig, AstroSettings } from '../../@types/astro'; +import type { AstroInlineConfig, AstroSettings } from '../../@types/astro.js'; import nodeFs from 'node:fs'; import * as vite from 'vite'; diff --git a/packages/astro/src/core/dev/dev.ts b/packages/astro/src/core/dev/dev.ts index 95555a533..02ba9d872 100644 --- a/packages/astro/src/core/dev/dev.ts +++ b/packages/astro/src/core/dev/dev.ts @@ -3,7 +3,7 @@ import type http from 'node:http'; import type { AddressInfo } from 'node:net'; import { performance } from 'perf_hooks'; import type * as vite from 'vite'; -import type { AstroInlineConfig } from '../../@types/astro'; +import type { AstroInlineConfig } from '../../@types/astro.js'; import { attachContentServerListeners } from '../../content/index.js'; import { telemetry } from '../../events/index.js'; import * as msg from '../messages.js'; diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts index 8770ee16f..2d6ba75f3 100644 --- a/packages/astro/src/core/dev/restart.ts +++ b/packages/astro/src/core/dev/restart.ts @@ -1,14 +1,14 @@ import nodeFs from 'node:fs'; import { fileURLToPath } from 'node:url'; import * as vite from 'vite'; -import type { AstroInlineConfig, AstroSettings } from '../../@types/astro'; +import type { AstroInlineConfig, AstroSettings } from '../../@types/astro.js'; import { eventCliSession, telemetry } from '../../events/index.js'; import { createNodeLogger, createSettings, resolveConfig } from '../config/index.js'; import { collectErrorMetadata } from '../errors/dev/utils.js'; import { isAstroConfigZodError } from '../errors/errors.js'; import { createSafeError } from '../errors/index.js'; import { formatErrorMessage } from '../messages.js'; -import type { Container } from './container'; +import type { Container } from './container.js'; import { createContainer, startContainer } from './container.js'; async function createRestartedContainer( diff --git a/packages/astro/src/core/endpoint/dev/index.ts b/packages/astro/src/core/endpoint/dev/index.ts index 79e5c1fd5..96fe5f3d7 100644 --- a/packages/astro/src/core/endpoint/dev/index.ts +++ b/packages/astro/src/core/endpoint/dev/index.ts @@ -1,4 +1,4 @@ -import type { EndpointHandler } from '../../../@types/astro'; +import type { EndpointHandler } from '../../../@types/astro.js'; import { createRenderContext, type SSROptions } from '../../render/index.js'; import { callEndpoint } from '../index.js'; diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index a3aff6dca..380e9e345 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -6,13 +6,13 @@ import type { MiddlewareEndpointHandler, MiddlewareHandler, Params, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { renderEndpoint } from '../../runtime/server/index.js'; import { ASTRO_VERSION } from '../constants.js'; import { AstroCookies, attachCookiesToResponse } from '../cookies/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import { callMiddleware } from '../middleware/callMiddleware.js'; -import type { Environment, RenderContext } from '../render/index'; +import type { Environment, RenderContext } from '../render/index.js'; const encoder = new TextEncoder(); diff --git a/packages/astro/src/core/errors/dev/utils.ts b/packages/astro/src/core/errors/dev/utils.ts index 837b52fde..fd69b74db 100644 --- a/packages/astro/src/core/errors/dev/utils.ts +++ b/packages/astro/src/core/errors/dev/utils.ts @@ -227,21 +227,21 @@ export function getDocsForError(err: ErrorWithMetadata): string | undefined { * Render a subset of Markdown to HTML or a CLI output */ export function renderErrorMarkdown(markdown: string, target: 'html' | 'cli') { - const linkRegex = /\[(.+)\]\((.+)\)/gm; + const linkRegex = /\[([^\[]+)\]\((.*)\)/gm; const boldRegex = /\*\*(.+)\*\*/gm; - const urlRegex = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\\/%?=~_|!:,.;]*[-A-Z0-9+&@#\\/%=~_|])/gim; + const urlRegex = / (\b(https?|ftp):\/\/[-A-Z0-9+&@#\\/%?=~_|!:,.;]*[-A-Z0-9+&@#\\/%=~_|])/gim; const codeRegex = /`([^`]+)`/gim; if (target === 'html') { return escape(markdown) .replace(linkRegex, `$1`) .replace(boldRegex, '$1') - .replace(urlRegex, ' $1 ') + .replace(urlRegex, ' $1') .replace(codeRegex, '$1'); } else { return markdown - .replace(linkRegex, (fullMatch, m1, m2) => `${bold(m1)} ${underline(m2)}`) - .replace(urlRegex, (fullMatch) => ` ${underline(fullMatch.trim())} `) - .replace(boldRegex, (fullMatch, m1) => `${bold(m1)}`); + .replace(linkRegex, (_, m1, m2) => `${bold(m1)} ${underline(m2)}`) + .replace(urlRegex, (fullMatch) => ` ${underline(fullMatch.trim())}`) + .replace(boldRegex, (_, m1) => `${bold(m1)}`); } } diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index d63fc8852..1f336e5f8 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -594,9 +594,9 @@ export const PrerenderDynamicEndpointPathCollide = { export const ExpectedImage = { name: 'ExpectedImage', title: 'Expected src to be an image.', - message: (options: string) => - `Expected \`src\` property to be either an ESM imported image or a string with the path of a remote image. Received \`${options}\`.`, - hint: 'This error can often happen because of a wrong path. Make sure the path to your image is correct.', + message: (src: string, typeofOptions: string, fullOptions: string) => + `Expected \`src\` property for \`getImage\` or \`\` to be either an ESM imported image or a string with the path of a remote image. Received \`${src}\` (type: \`${typeofOptions}\`).\n\nFull serialized options received: \`${fullOptions}\`.`, + hint: "This error can often happen because of a wrong path. Make sure the path to your image is correct. If you're passing an async function, make sure to call and await it.", } satisfies ErrorData; /** * @docs @@ -712,12 +712,15 @@ export const LocalsNotAnObject = { '`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.', hint: 'If you tried to remove some information from the `locals` object, try to use `delete` or set the property to `undefined`.', } satisfies ErrorData; + /** * @docs * @see * - [Images](https://docs.astro.build/en/guides/images/) * @description - * When using the default image services, `Image`'s and `getImage`'s `src` parameter must be either an imported image or an URL, it cannot be a filepath. + * When using the default image services, `Image`'s and `getImage`'s `src` parameter must be either an imported image or an URL, it cannot be a string of a filepath. + * + * For local images from content collections, you can use the [image() schema helper](https://docs.astro.build/en/guides/images/#images-in-content-collections) to resolve the images. * * ```astro * --- @@ -728,15 +731,22 @@ export const LocalsNotAnObject = { * * Cool image * - * + * + * Cool image + * + * * Cool image + * + * + * Cool image * ``` */ export const LocalImageUsedWrongly = { name: 'LocalImageUsedWrongly', - title: 'ESM imported images must be passed as-is.', + title: 'Local images must be imported.', message: (imageFilePath: string) => - `\`Image\`'s and \`getImage\`'s \`src\` parameter must be an imported image or an URL, it cannot be a filepath. Received \`${imageFilePath}\`.`, + `\`Image\`'s and \`getImage\`'s \`src\` parameter must be an imported image or an URL, it cannot be a string filepath. Received \`${imageFilePath}\`.`, + hint: 'If you want to use an image from your `src` folder, you need to either import it or if the image is coming from a content collection, use the [image() schema helper](https://docs.astro.build/en/guides/images/#images-in-content-collections) See https://docs.astro.build/en/guides/images/#src-required for more information on the `src` property.', } satisfies ErrorData; /** diff --git a/packages/astro/src/core/errors/index.ts b/packages/astro/src/core/errors/index.ts index 0f0096eb4..31071cac3 100644 --- a/packages/astro/src/core/errors/index.ts +++ b/packages/astro/src/core/errors/index.ts @@ -1,4 +1,3 @@ -export type { ErrorLocation, ErrorWithMetadata } from './errors'; export * as AstroErrorData from './errors-data.js'; export { AggregateError, @@ -9,5 +8,6 @@ export { MarkdownError, isAstroError, } from './errors.js'; +export type { ErrorLocation, ErrorWithMetadata } from './errors.js'; export { codeFrame } from './printer.js'; export { createSafeError, positionAt } from './utils.js'; diff --git a/packages/astro/src/core/errors/overlay.ts b/packages/astro/src/core/errors/overlay.ts index 5a24f898a..7ce891348 100644 --- a/packages/astro/src/core/errors/overlay.ts +++ b/packages/astro/src/core/errors/overlay.ts @@ -1,4 +1,4 @@ -import type { AstroErrorPayload } from './dev/vite'; +import type { AstroErrorPayload } from './dev/vite.js'; const style = /* css */ ` * { @@ -336,7 +336,7 @@ const style = /* css */ ` #message-content, #hint-content { white-space: pre-wrap; - line-height: 24px; + line-height: 26px; flex-grow: 1; } @@ -369,7 +369,7 @@ const style = /* css */ ` #message-hints code { font-family: var(--font-monospace); background-color: var(--border); - padding: 4px; + padding: 2px 4px; border-radius: var(--roundiness); white-space: nowrap; } diff --git a/packages/astro/src/core/middleware/callMiddleware.ts b/packages/astro/src/core/middleware/callMiddleware.ts index b83fa4322..1725fd38d 100644 --- a/packages/astro/src/core/middleware/callMiddleware.ts +++ b/packages/astro/src/core/middleware/callMiddleware.ts @@ -4,9 +4,9 @@ import type { EndpointOutput, MiddlewareHandler, MiddlewareNext, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import type { Environment } from '../render'; +import type { Environment } from '../render/index.js'; /** * Utility function that is in charge of calling the middleware. diff --git a/packages/astro/src/core/middleware/index.ts b/packages/astro/src/core/middleware/index.ts index 90c5bdb5e..1b87bf1e1 100644 --- a/packages/astro/src/core/middleware/index.ts +++ b/packages/astro/src/core/middleware/index.ts @@ -1,4 +1,4 @@ -import type { MiddlewareResponseHandler, Params } from '../../@types/astro'; +import type { MiddlewareResponseHandler, Params } from '../../@types/astro.js'; import { createAPIContext } from '../endpoint/index.js'; import { sequence } from './sequence.js'; diff --git a/packages/astro/src/core/middleware/loadMiddleware.ts b/packages/astro/src/core/middleware/loadMiddleware.ts index 5c64565af..9a7f3e4bc 100644 --- a/packages/astro/src/core/middleware/loadMiddleware.ts +++ b/packages/astro/src/core/middleware/loadMiddleware.ts @@ -1,6 +1,6 @@ -import type { AstroSettings } from '../../@types/astro'; +import type { AstroSettings } from '../../@types/astro.js'; import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../constants.js'; -import type { ModuleLoader } from '../module-loader'; +import type { ModuleLoader } from '../module-loader/index.js'; /** * It accepts a module loader and the astro settings, and it attempts to load the middlewares defined in the configuration. diff --git a/packages/astro/src/core/middleware/sequence.ts b/packages/astro/src/core/middleware/sequence.ts index 0358f3719..29b1d1623 100644 --- a/packages/astro/src/core/middleware/sequence.ts +++ b/packages/astro/src/core/middleware/sequence.ts @@ -1,4 +1,4 @@ -import type { APIContext, MiddlewareResponseHandler } from '../../@types/astro'; +import type { APIContext, MiddlewareResponseHandler } from '../../@types/astro.js'; import { defineMiddleware } from './index.js'; // From SvelteKit: https://github.com/sveltejs/kit/blob/master/packages/kit/src/exports/hooks/sequence.js diff --git a/packages/astro/src/core/module-loader/loader.ts b/packages/astro/src/core/module-loader/loader.ts index c686cef03..4d9872717 100644 --- a/packages/astro/src/core/module-loader/loader.ts +++ b/packages/astro/src/core/module-loader/loader.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'node:events'; import type * as fs from 'node:fs'; -import type { TypedEventEmitter } from '../../@types/typed-emitter'; +import type { TypedEventEmitter } from '../../@types/typed-emitter.js'; // This is a generic interface for a module loader. In the astro cli this is // fulfilled by Vite, see vite.ts diff --git a/packages/astro/src/core/module-loader/vite.ts b/packages/astro/src/core/module-loader/vite.ts index 88ad03cf7..f58b2e720 100644 --- a/packages/astro/src/core/module-loader/vite.ts +++ b/packages/astro/src/core/module-loader/vite.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'node:events'; import type * as vite from 'vite'; -import type { ModuleLoader, ModuleLoaderEventEmitter } from './loader'; +import type { ModuleLoader, ModuleLoaderEventEmitter } from './loader.js'; export function createViteLoader(viteServer: vite.ViteDevServer): ModuleLoader { const events = new EventEmitter() as ModuleLoaderEventEmitter; diff --git a/packages/astro/src/core/pipeline.ts b/packages/astro/src/core/pipeline.ts index 0042c288c..438ff275d 100644 --- a/packages/astro/src/core/pipeline.ts +++ b/packages/astro/src/core/pipeline.ts @@ -4,7 +4,7 @@ import type { MiddlewareEndpointHandler, MiddlewareHandler, MiddlewareResponseHandler, -} from '../@types/astro'; +} from '../@types/astro.js'; import { callEndpoint, createAPIContext } from './endpoint/index.js'; import { callMiddleware } from './middleware/callMiddleware.js'; import { renderPage } from './render/core.js'; diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts index 7ba0cb2ea..d754baed1 100644 --- a/packages/astro/src/core/preview/index.ts +++ b/packages/astro/src/core/preview/index.ts @@ -1,6 +1,6 @@ import { createRequire } from 'node:module'; import { fileURLToPath, pathToFileURL } from 'node:url'; -import type { AstroInlineConfig, PreviewModule, PreviewServer } from '../../@types/astro'; +import type { AstroInlineConfig, PreviewModule, PreviewServer } from '../../@types/astro.js'; import { AstroIntegrationLogger } from '../../core/logger/core.js'; import { telemetry } from '../../events/index.js'; import { eventCliSession } from '../../events/session.js'; diff --git a/packages/astro/src/core/preview/static-preview-server.ts b/packages/astro/src/core/preview/static-preview-server.ts index b1c882714..3cb0e89e8 100644 --- a/packages/astro/src/core/preview/static-preview-server.ts +++ b/packages/astro/src/core/preview/static-preview-server.ts @@ -3,8 +3,8 @@ import { fileURLToPath } from 'node:url'; import { performance } from 'perf_hooks'; import enableDestroy from 'server-destroy'; import { preview, type PreviewServer as VitePreviewServer } from 'vite'; -import type { AstroSettings } from '../../@types/astro'; -import type { Logger } from '../logger/core'; +import type { AstroSettings } from '../../@types/astro.js'; +import type { Logger } from '../logger/core.js'; import * as msg from '../messages.js'; import { getResolvedHostForHttpServer } from './util.js'; import { vitePluginAstroPreview } from './vite-plugin-astro-preview.js'; diff --git a/packages/astro/src/core/redirects/component.ts b/packages/astro/src/core/redirects/component.ts index ae4dbb4fe..00b8d176c 100644 --- a/packages/astro/src/core/redirects/component.ts +++ b/packages/astro/src/core/redirects/component.ts @@ -1,5 +1,5 @@ -import type { ComponentInstance } from '../../@types/astro'; -import type { SinglePageBuiltModule } from '../build/types'; +import type { ComponentInstance } from '../../@types/astro.js'; +import type { SinglePageBuiltModule } from '../build/types.js'; // A stub of a component instance for a given route export const RedirectComponentInstance: ComponentInstance = { diff --git a/packages/astro/src/core/redirects/helpers.ts b/packages/astro/src/core/redirects/helpers.ts index a8d5f9938..7574f2714 100644 --- a/packages/astro/src/core/redirects/helpers.ts +++ b/packages/astro/src/core/redirects/helpers.ts @@ -1,4 +1,9 @@ -import type { Params, RedirectRouteData, RouteData, ValidRedirectStatus } from '../../@types/astro'; +import type { + Params, + RedirectRouteData, + RouteData, + ValidRedirectStatus, +} from '../../@types/astro.js'; export function routeIsRedirect(route: RouteData | undefined): route is RedirectRouteData { return route?.type === 'redirect'; diff --git a/packages/astro/src/core/render/context.ts b/packages/astro/src/core/render/context.ts index d6806d682..86efb63e3 100644 --- a/packages/astro/src/core/render/context.ts +++ b/packages/astro/src/core/render/context.ts @@ -5,9 +5,9 @@ import type { RouteData, SSRElement, SSRResult, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import type { Environment } from './environment'; +import type { Environment } from './environment.js'; import { getParamsAndProps } from './params-and-props.js'; const clientLocalsSymbol = Symbol.for('astro.locals'); diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts index 3efbddb99..d8c39ec1a 100644 --- a/packages/astro/src/core/render/core.ts +++ b/packages/astro/src/core/render/core.ts @@ -4,7 +4,7 @@ import type { EndpointHandler, MiddlewareHandler, MiddlewareResponseHandler, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { renderPage as runtimeRenderPage } from '../../runtime/server/index.js'; import { attachCookiesToResponse } from '../cookies/index.js'; import { callEndpoint, createAPIContext } from '../endpoint/index.js'; diff --git a/packages/astro/src/core/render/environment.ts b/packages/astro/src/core/render/environment.ts index a41a0b09e..582ee6129 100644 --- a/packages/astro/src/core/render/environment.ts +++ b/packages/astro/src/core/render/environment.ts @@ -1,4 +1,4 @@ -import type { RuntimeMode, SSRLoadedRenderer } from '../../@types/astro'; +import type { RuntimeMode, SSRLoadedRenderer } from '../../@types/astro.js'; import type { Logger } from '../logger/core.js'; import type { RouteCache } from './route-cache.js'; diff --git a/packages/astro/src/core/render/index.ts b/packages/astro/src/core/render/index.ts index 67c82b5c8..098b7d024 100644 --- a/packages/astro/src/core/render/index.ts +++ b/packages/astro/src/core/render/index.ts @@ -1,5 +1,5 @@ -import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../@types/astro'; -import type { Environment } from './environment'; +import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../@types/astro.js'; +import type { Environment } from './environment.js'; export { createRenderContext } from './context.js'; export type { RenderContext } from './context.js'; export { tryRenderRoute } from './core.js'; diff --git a/packages/astro/src/core/render/paginate.ts b/packages/astro/src/core/render/paginate.ts index f8cd8709d..a8d6abbd2 100644 --- a/packages/astro/src/core/render/paginate.ts +++ b/packages/astro/src/core/render/paginate.ts @@ -5,7 +5,7 @@ import type { Params, Props, RouteData, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; export function generatePaginateFunction( diff --git a/packages/astro/src/core/render/params-and-props.ts b/packages/astro/src/core/render/params-and-props.ts index 2cde3379c..6cdb05ed1 100644 --- a/packages/astro/src/core/render/params-and-props.ts +++ b/packages/astro/src/core/render/params-and-props.ts @@ -1,4 +1,4 @@ -import type { ComponentInstance, Params, Props, RouteData } from '../../@types/astro'; +import type { ComponentInstance, Params, Props, RouteData } from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import type { Logger } from '../logger/core.js'; import { getParams } from '../routing/params.js'; diff --git a/packages/astro/src/core/render/renderer.ts b/packages/astro/src/core/render/renderer.ts index e64a27ba5..4b6015bbb 100644 --- a/packages/astro/src/core/render/renderer.ts +++ b/packages/astro/src/core/render/renderer.ts @@ -1,4 +1,4 @@ -import type { AstroRenderer, SSRLoadedRenderer } from '../../@types/astro'; +import type { AstroRenderer, SSRLoadedRenderer } from '../../@types/astro.js'; import type { ModuleLoader } from '../module-loader/index.js'; export async function loadRenderer( diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index 4d6e4cca5..abfcb5e3e 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -5,7 +5,7 @@ import type { SSRElement, SSRLoadedRenderer, SSRResult, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { renderSlotToString, type ComponentSlots } from '../../runtime/server/index.js'; import { renderJSX } from '../../runtime/server/jsx.js'; import { chunkToString } from '../../runtime/server/render/index.js'; diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts index d43ce514b..4bfb94e93 100644 --- a/packages/astro/src/core/render/route-cache.ts +++ b/packages/astro/src/core/render/route-cache.ts @@ -7,7 +7,7 @@ import type { Params, RouteData, RuntimeMode, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import type { Logger } from '../logger/core.js'; diff --git a/packages/astro/src/core/render/ssr-element.ts b/packages/astro/src/core/render/ssr-element.ts index f282d349a..8593dc0bf 100644 --- a/packages/astro/src/core/render/ssr-element.ts +++ b/packages/astro/src/core/render/ssr-element.ts @@ -1,6 +1,6 @@ -import type { SSRElement } from '../../@types/astro'; +import type { SSRElement } from '../../@types/astro.js'; import { joinPaths, prependForwardSlash, slash } from '../../core/path.js'; -import type { StylesheetAsset } from '../app/types'; +import type { StylesheetAsset } from '../app/types.js'; export function createAssetLink(href: string, base?: string, assetsPrefix?: string): string { if (assetsPrefix) { diff --git a/packages/astro/src/core/request.ts b/packages/astro/src/core/request.ts index 5c671a3fc..f478b0a32 100644 --- a/packages/astro/src/core/request.ts +++ b/packages/astro/src/core/request.ts @@ -1,5 +1,5 @@ import type { IncomingHttpHeaders } from 'node:http'; -import type { Logger } from './logger/core'; +import type { Logger } from './logger/core.js'; type HeaderType = Headers | Record | IncomingHttpHeaders; type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData; diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index f08c2a585..8fd3a8d82 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -5,8 +5,8 @@ import type { ManifestData, RouteData, RoutePart, -} from '../../../@types/astro'; -import type { Logger } from '../../logger/core'; +} from '../../../@types/astro.js'; +import type { Logger } from '../../logger/core.js'; import { createRequire } from 'module'; import nodeFs from 'node:fs'; diff --git a/packages/astro/src/core/routing/manifest/generator.ts b/packages/astro/src/core/routing/manifest/generator.ts index 4945ea9f1..60614f2e5 100644 --- a/packages/astro/src/core/routing/manifest/generator.ts +++ b/packages/astro/src/core/routing/manifest/generator.ts @@ -1,4 +1,4 @@ -import type { AstroConfig, RoutePart } from '../../../@types/astro'; +import type { AstroConfig, RoutePart } from '../../../@types/astro.js'; import { compile } from 'path-to-regexp'; diff --git a/packages/astro/src/core/routing/manifest/serialization.ts b/packages/astro/src/core/routing/manifest/serialization.ts index 4ed067db5..71ffc221d 100644 --- a/packages/astro/src/core/routing/manifest/serialization.ts +++ b/packages/astro/src/core/routing/manifest/serialization.ts @@ -1,4 +1,4 @@ -import type { AstroConfig, RouteData, SerializedRouteData } from '../../../@types/astro'; +import type { AstroConfig, RouteData, SerializedRouteData } from '../../../@types/astro.js'; import { getRouteGenerator } from './generator.js'; diff --git a/packages/astro/src/core/routing/match.ts b/packages/astro/src/core/routing/match.ts index 84b65fd6f..9b91e1e9a 100644 --- a/packages/astro/src/core/routing/match.ts +++ b/packages/astro/src/core/routing/match.ts @@ -1,4 +1,4 @@ -import type { ManifestData, RouteData } from '../../@types/astro'; +import type { ManifestData, RouteData } from '../../@types/astro.js'; /** Find matching route from pathname */ export function matchRoute(pathname: string, manifest: ManifestData): RouteData | undefined { diff --git a/packages/astro/src/core/routing/params.ts b/packages/astro/src/core/routing/params.ts index 1e6b16858..987528d57 100644 --- a/packages/astro/src/core/routing/params.ts +++ b/packages/astro/src/core/routing/params.ts @@ -1,4 +1,4 @@ -import type { GetStaticPathsItem, Params, RouteData } from '../../@types/astro'; +import type { GetStaticPathsItem, Params, RouteData } from '../../@types/astro.js'; import { trimSlashes } from '../path.js'; import { validateGetStaticPathsParameter } from './validation.js'; diff --git a/packages/astro/src/core/routing/validation.ts b/packages/astro/src/core/routing/validation.ts index e9f03eef8..0261c865a 100644 --- a/packages/astro/src/core/routing/validation.ts +++ b/packages/astro/src/core/routing/validation.ts @@ -1,6 +1,6 @@ -import type { ComponentInstance, GetStaticPathsResult, RouteData } from '../../@types/astro'; +import type { ComponentInstance, GetStaticPathsResult, RouteData } from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import type { Logger } from '../logger/core'; +import type { Logger } from '../logger/core.js'; const VALID_PARAM_TYPES = ['string', 'number', 'undefined']; diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 3dea7c714..940ff0524 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -3,7 +3,7 @@ import fsMod from 'node:fs'; import { performance } from 'node:perf_hooks'; import { fileURLToPath } from 'node:url'; import { createServer, type HMRPayload } from 'vite'; -import type { AstroInlineConfig, AstroSettings } from '../../@types/astro'; +import type { AstroInlineConfig, AstroSettings } from '../../@types/astro.js'; import { createContentTypesGenerator } from '../../content/index.js'; import { globalContentConfigObserver } from '../../content/utils.js'; import { telemetry } from '../../events/index.js'; diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index d442e5811..bcfa9a511 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -2,10 +2,10 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { normalizePath } from 'vite'; -import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro'; +import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro.js'; import { isServerLikeOutput } from '../prerender/utils.js'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './constants.js'; -import type { ModuleLoader } from './module-loader'; +import type { ModuleLoader } from './module-loader/index.js'; import { prependForwardSlash, removeTrailingForwardSlash, slash } from './path.js'; /** Returns true if argument is an object of any prototype/class (but not null). */ diff --git a/packages/astro/src/events/session.ts b/packages/astro/src/events/session.ts index 706779d4b..b37530342 100644 --- a/packages/astro/src/events/session.ts +++ b/packages/astro/src/events/session.ts @@ -1,4 +1,4 @@ -import type { AstroUserConfig } from '../@types/astro'; +import type { AstroUserConfig } from '../@types/astro.js'; const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED'; diff --git a/packages/astro/src/integrations/astroFeaturesValidation.ts b/packages/astro/src/integrations/astroFeaturesValidation.ts index eb388745d..7f40479f3 100644 --- a/packages/astro/src/integrations/astroFeaturesValidation.ts +++ b/packages/astro/src/integrations/astroFeaturesValidation.ts @@ -3,7 +3,7 @@ import type { AstroConfig, AstroFeatureMap, SupportsKind, -} from '../@types/astro'; +} from '../@types/astro.js'; import type { Logger } from '../core/logger/core.js'; const STABLE = 'stable'; diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts index 774ea5b04..92f277872 100644 --- a/packages/astro/src/integrations/index.ts +++ b/packages/astro/src/integrations/index.ts @@ -14,8 +14,8 @@ import type { HookParameters, RouteData, } from '../@types/astro.js'; -import type { SerializedSSRManifest } from '../core/app/types'; -import type { PageBuildData } from '../core/build/types'; +import type { SerializedSSRManifest } from '../core/app/types.js'; +import type { PageBuildData } from '../core/build/types.js'; import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.js'; import { mergeConfig } from '../core/config/index.js'; import { AstroIntegrationLogger, type Logger } from '../core/logger/core.js'; diff --git a/packages/astro/src/jsx/babel.ts b/packages/astro/src/jsx/babel.ts index 6ae8ebe1c..e8f9da87e 100644 --- a/packages/astro/src/jsx/babel.ts +++ b/packages/astro/src/jsx/babel.ts @@ -3,7 +3,7 @@ import * as t from '@babel/types'; import { AstroError } from '../core/errors/errors.js'; import { AstroErrorData } from '../core/errors/index.js'; import { resolvePath } from '../core/util.js'; -import type { PluginMetadata } from '../vite-plugin-astro/types'; +import type { PluginMetadata } from '../vite-plugin-astro/types.js'; const ClientOnlyPlaceholder = 'astro-client-only'; diff --git a/packages/astro/src/prerender/metadata.ts b/packages/astro/src/prerender/metadata.ts index 15527af37..a501cc46f 100644 --- a/packages/astro/src/prerender/metadata.ts +++ b/packages/astro/src/prerender/metadata.ts @@ -1,4 +1,4 @@ -import type { ModuleInfo, ModuleLoader } from '../core/module-loader'; +import type { ModuleInfo, ModuleLoader } from '../core/module-loader/index.js'; import { viteID } from '../core/util.js'; type GetPrerenderStatusParams = { diff --git a/packages/astro/src/prerender/routing.ts b/packages/astro/src/prerender/routing.ts index 99ee2886b..1c1b83825 100644 --- a/packages/astro/src/prerender/routing.ts +++ b/packages/astro/src/prerender/routing.ts @@ -1,6 +1,6 @@ -import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro'; +import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro.js'; import { RedirectComponentInstance, routeIsRedirect } from '../core/redirects/index.js'; -import type DevPipeline from '../vite-plugin-astro-server/devPipeline'; +import type DevPipeline from '../vite-plugin-astro-server/devPipeline.js'; import { preload } from '../vite-plugin-astro-server/index.js'; import { getPrerenderStatus } from './metadata.js'; diff --git a/packages/astro/src/prerender/utils.ts b/packages/astro/src/prerender/utils.ts index a3655eead..b44435213 100644 --- a/packages/astro/src/prerender/utils.ts +++ b/packages/astro/src/prerender/utils.ts @@ -1,4 +1,4 @@ -import type { AstroConfig } from '../@types/astro'; +import type { AstroConfig } from '../@types/astro.js'; import { getOutDirWithinCwd } from '../core/build/common.js'; export function isServerLikeOutput(config: AstroConfig) { diff --git a/packages/astro/src/runtime/client/idle.ts b/packages/astro/src/runtime/client/idle.ts index 48aa9dc1f..990d5da6e 100644 --- a/packages/astro/src/runtime/client/idle.ts +++ b/packages/astro/src/runtime/client/idle.ts @@ -1,4 +1,4 @@ -import type { ClientDirective } from '../../@types/astro'; +import type { ClientDirective } from '../../@types/astro.js'; const idleDirective: ClientDirective = (load) => { const cb = async () => { diff --git a/packages/astro/src/runtime/client/load.ts b/packages/astro/src/runtime/client/load.ts index 15a2f1dcb..b603eecb3 100644 --- a/packages/astro/src/runtime/client/load.ts +++ b/packages/astro/src/runtime/client/load.ts @@ -1,4 +1,4 @@ -import type { ClientDirective } from '../../@types/astro'; +import type { ClientDirective } from '../../@types/astro.js'; const loadDirective: ClientDirective = async (load) => { const hydrate = await load(); diff --git a/packages/astro/src/runtime/client/media.ts b/packages/astro/src/runtime/client/media.ts index 3d92d3713..f894af311 100644 --- a/packages/astro/src/runtime/client/media.ts +++ b/packages/astro/src/runtime/client/media.ts @@ -1,4 +1,4 @@ -import type { ClientDirective } from '../../@types/astro'; +import type { ClientDirective } from '../../@types/astro.js'; /** * Hydrate this component when a matching media query is found diff --git a/packages/astro/src/runtime/client/only.ts b/packages/astro/src/runtime/client/only.ts index f67ae3ace..8e072b7a3 100644 --- a/packages/astro/src/runtime/client/only.ts +++ b/packages/astro/src/runtime/client/only.ts @@ -1,4 +1,4 @@ -import type { ClientDirective } from '../../@types/astro'; +import type { ClientDirective } from '../../@types/astro.js'; /** * Hydrate this component only on the client diff --git a/packages/astro/src/runtime/client/visible.ts b/packages/astro/src/runtime/client/visible.ts index cc4f77771..de36b2909 100644 --- a/packages/astro/src/runtime/client/visible.ts +++ b/packages/astro/src/runtime/client/visible.ts @@ -1,4 +1,4 @@ -import type { ClientDirective } from '../../@types/astro'; +import type { ClientDirective } from '../../@types/astro.js'; /** * Hydrate this component when one of it's children becomes visible diff --git a/packages/astro/src/runtime/server/astro-component.ts b/packages/astro/src/runtime/server/astro-component.ts index 57f2d3c3b..9acc099a9 100644 --- a/packages/astro/src/runtime/server/astro-component.ts +++ b/packages/astro/src/runtime/server/astro-component.ts @@ -1,4 +1,4 @@ -import type { PropagationHint } from '../../@types/astro'; +import type { PropagationHint } from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../../core/errors/index.js'; import type { AstroComponentFactory } from './render/index.js'; diff --git a/packages/astro/src/runtime/server/astro-global.ts b/packages/astro/src/runtime/server/astro-global.ts index 82855c669..c15cd8a4a 100644 --- a/packages/astro/src/runtime/server/astro-global.ts +++ b/packages/astro/src/runtime/server/astro-global.ts @@ -1,4 +1,4 @@ -import type { AstroGlobalPartial } from '../../@types/astro'; +import type { AstroGlobalPartial } from '../../@types/astro.js'; import { ASTRO_VERSION } from '../../core/constants.js'; import { AstroError, AstroErrorData } from '../../core/errors/index.js'; diff --git a/packages/astro/src/runtime/server/endpoint.ts b/packages/astro/src/runtime/server/endpoint.ts index 686e3795f..7db5f07ee 100644 --- a/packages/astro/src/runtime/server/endpoint.ts +++ b/packages/astro/src/runtime/server/endpoint.ts @@ -1,4 +1,4 @@ -import type { APIContext, EndpointHandler, Params } from '../../@types/astro'; +import type { APIContext, EndpointHandler, Params } from '../../@types/astro.js'; import type { Logger } from '../../core/logger/core.js'; function getHandlerFromModule(mod: EndpointHandler, method: string, logger: Logger) { diff --git a/packages/astro/src/runtime/server/hydration.ts b/packages/astro/src/runtime/server/hydration.ts index 81a3cf9e2..e9d99c81a 100644 --- a/packages/astro/src/runtime/server/hydration.ts +++ b/packages/astro/src/runtime/server/hydration.ts @@ -3,7 +3,7 @@ import type { SSRElement, SSRLoadedRenderer, SSRResult, -} from '../../@types/astro'; +} from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../../core/errors/index.js'; import { escapeHTML } from './escape.js'; import { serializeProps } from './serialize.js'; diff --git a/packages/astro/src/runtime/server/render/astro/factory.ts b/packages/astro/src/runtime/server/render/astro/factory.ts index 97b8e4574..68d5af739 100644 --- a/packages/astro/src/runtime/server/render/astro/factory.ts +++ b/packages/astro/src/runtime/server/render/astro/factory.ts @@ -1,6 +1,6 @@ -import type { PropagationHint, SSRResult } from '../../../../@types/astro'; -import type { HeadAndContent } from './head-and-content'; -import type { RenderTemplateResult } from './render-template'; +import type { PropagationHint, SSRResult } from '../../../../@types/astro.js'; +import type { HeadAndContent } from './head-and-content.js'; +import type { RenderTemplateResult } from './render-template.js'; export type AstroFactoryReturnValue = RenderTemplateResult | Response | HeadAndContent; diff --git a/packages/astro/src/runtime/server/render/astro/head-and-content.ts b/packages/astro/src/runtime/server/render/astro/head-and-content.ts index d895d9dd6..eb32c3148 100644 --- a/packages/astro/src/runtime/server/render/astro/head-and-content.ts +++ b/packages/astro/src/runtime/server/render/astro/head-and-content.ts @@ -1,4 +1,4 @@ -import type { RenderTemplateResult } from './render-template'; +import type { RenderTemplateResult } from './render-template.js'; const headAndContentSym = Symbol.for('astro.headAndContent'); diff --git a/packages/astro/src/runtime/server/render/astro/index.ts b/packages/astro/src/runtime/server/render/astro/index.ts index d9283b9f9..9510c0cbb 100644 --- a/packages/astro/src/runtime/server/render/astro/index.ts +++ b/packages/astro/src/runtime/server/render/astro/index.ts @@ -1,7 +1,7 @@ -export type { AstroComponentFactory } from './factory'; export { isAstroComponentFactory } from './factory.js'; +export type { AstroComponentFactory } from './factory.js'; export { createHeadAndContent, isHeadAndContent } from './head-and-content.js'; -export type { AstroComponentInstance } from './instance'; export { createAstroComponentInstance, isAstroComponentInstance } from './instance.js'; +export type { AstroComponentInstance } from './instance.js'; export { isRenderTemplateResult, renderTemplate } from './render-template.js'; export { renderToReadableStream, renderToString } from './render.js'; diff --git a/packages/astro/src/runtime/server/render/astro/instance.ts b/packages/astro/src/runtime/server/render/astro/instance.ts index 7502d30a7..feae0e0e8 100644 --- a/packages/astro/src/runtime/server/render/astro/instance.ts +++ b/packages/astro/src/runtime/server/render/astro/instance.ts @@ -1,4 +1,4 @@ -import type { SSRResult } from '../../../../@types/astro'; +import type { SSRResult } from '../../../../@types/astro.js'; import type { ComponentSlots } from '../slot.js'; import type { AstroComponentFactory, AstroFactoryReturnValue } from './factory.js'; diff --git a/packages/astro/src/runtime/server/render/astro/render.ts b/packages/astro/src/runtime/server/render/astro/render.ts index 0c34ef98d..7091513c7 100644 --- a/packages/astro/src/runtime/server/render/astro/render.ts +++ b/packages/astro/src/runtime/server/render/astro/render.ts @@ -1,4 +1,4 @@ -import type { RouteData, SSRResult } from '../../../../@types/astro'; +import type { RouteData, SSRResult } from '../../../../@types/astro.js'; import { AstroError, AstroErrorData } from '../../../../core/errors/index.js'; import { chunkToByteArray, chunkToString, encoder, type RenderDestination } from '../common.js'; import type { AstroComponentFactory } from './factory.js'; diff --git a/packages/astro/src/runtime/server/render/common.ts b/packages/astro/src/runtime/server/render/common.ts index 7beaed2eb..03e9c8308 100644 --- a/packages/astro/src/runtime/server/render/common.ts +++ b/packages/astro/src/runtime/server/render/common.ts @@ -1,4 +1,4 @@ -import type { SSRResult } from '../../../@types/astro'; +import type { SSRResult } from '../../../@types/astro.js'; import type { RenderInstruction } from './instruction.js'; import { HTMLBytes, HTMLString, markHTMLString } from '../escape.js'; diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts index 1c7701fd2..bfb82ceda 100644 --- a/packages/astro/src/runtime/server/render/component.ts +++ b/packages/astro/src/runtime/server/render/component.ts @@ -3,7 +3,7 @@ import type { RouteData, SSRLoadedRenderer, SSRResult, -} from '../../../@types/astro'; +} from '../../../@types/astro.js'; import { createRenderInstruction, type RenderInstruction } from './instruction.js'; import { clsx } from 'clsx'; diff --git a/packages/astro/src/runtime/server/render/dom.ts b/packages/astro/src/runtime/server/render/dom.ts index 1d0ea192f..ca2017018 100644 --- a/packages/astro/src/runtime/server/render/dom.ts +++ b/packages/astro/src/runtime/server/render/dom.ts @@ -1,4 +1,4 @@ -import type { SSRResult } from '../../../@types/astro'; +import type { SSRResult } from '../../../@types/astro.js'; import { markHTMLString } from '../escape.js'; import { renderSlotToString } from './slot.js'; diff --git a/packages/astro/src/runtime/server/render/head.ts b/packages/astro/src/runtime/server/render/head.ts index d2cb43fa3..bad8140ec 100644 --- a/packages/astro/src/runtime/server/render/head.ts +++ b/packages/astro/src/runtime/server/render/head.ts @@ -1,4 +1,4 @@ -import type { SSRResult } from '../../../@types/astro'; +import type { SSRResult } from '../../../@types/astro.js'; import { markHTMLString } from '../escape.js'; import type { MaybeRenderHeadInstruction, RenderHeadInstruction } from './instruction.js'; diff --git a/packages/astro/src/runtime/server/render/index.ts b/packages/astro/src/runtime/server/render/index.ts index da83879e0..55dba8fa8 100644 --- a/packages/astro/src/runtime/server/render/index.ts +++ b/packages/astro/src/runtime/server/render/index.ts @@ -1,10 +1,10 @@ -export type { AstroComponentFactory, AstroComponentInstance } from './astro/index'; export { createHeadAndContent, renderTemplate, renderToString } from './astro/index.js'; +export type { AstroComponentFactory, AstroComponentInstance } from './astro/index.js'; export { Fragment, Renderer, chunkToByteArray, chunkToString } from './common.js'; export { renderComponent, renderComponentToString } from './component.js'; export { renderHTMLElement } from './dom.js'; export { maybeRenderHead, renderHead } from './head.js'; -export type { RenderInstruction } from './instruction'; +export type { RenderInstruction } from './instruction.js'; export { renderPage } from './page.js'; export { renderSlot, renderSlotToString, type ComponentSlots } from './slot.js'; export { renderScriptElement, renderUniqueStylesheet } from './tags.js'; diff --git a/packages/astro/src/runtime/server/render/page.ts b/packages/astro/src/runtime/server/render/page.ts index 74e8a45b7..2f4e87f5f 100644 --- a/packages/astro/src/runtime/server/render/page.ts +++ b/packages/astro/src/runtime/server/render/page.ts @@ -1,6 +1,6 @@ -import type { RouteData, SSRResult } from '../../../@types/astro'; +import type { RouteData, SSRResult } from '../../../@types/astro.js'; import { renderComponentToString, type NonAstroPageComponent } from './component.js'; -import type { AstroComponentFactory } from './index'; +import type { AstroComponentFactory } from './index.js'; import { isAstroComponentFactory } from './astro/index.js'; import { renderToReadableStream, renderToString } from './astro/render.js'; diff --git a/packages/astro/src/runtime/server/render/tags.ts b/packages/astro/src/runtime/server/render/tags.ts index 684480f9f..093c51a3c 100644 --- a/packages/astro/src/runtime/server/render/tags.ts +++ b/packages/astro/src/runtime/server/render/tags.ts @@ -1,5 +1,5 @@ -import type { SSRElement, SSRResult } from '../../../@types/astro'; -import type { StylesheetAsset } from '../../../core/app/types'; +import type { SSRElement, SSRResult } from '../../../@types/astro.js'; +import type { StylesheetAsset } from '../../../core/app/types.js'; import { renderElement } from './util.js'; export function renderScriptElement({ props, children }: SSRElement) { diff --git a/packages/astro/src/runtime/server/render/util.ts b/packages/astro/src/runtime/server/render/util.ts index 5e99eb008..fca449fcf 100644 --- a/packages/astro/src/runtime/server/render/util.ts +++ b/packages/astro/src/runtime/server/render/util.ts @@ -1,4 +1,4 @@ -import type { SSRElement } from '../../../@types/astro'; +import type { SSRElement } from '../../../@types/astro.js'; import type { RenderDestination, RenderDestinationChunk, RenderFunction } from './common.js'; import { clsx } from 'clsx'; diff --git a/packages/astro/src/runtime/server/scripts.ts b/packages/astro/src/runtime/server/scripts.ts index a56f6686a..47cd122f1 100644 --- a/packages/astro/src/runtime/server/scripts.ts +++ b/packages/astro/src/runtime/server/scripts.ts @@ -1,4 +1,4 @@ -import type { SSRResult } from '../../@types/astro'; +import type { SSRResult } from '../../@types/astro.js'; import islandScript from './astro-island.prebuilt.js'; const ISLAND_STYLES = ``; diff --git a/packages/astro/src/runtime/server/serialize.ts b/packages/astro/src/runtime/server/serialize.ts index b52c9e215..0d754ebc8 100644 --- a/packages/astro/src/runtime/server/serialize.ts +++ b/packages/astro/src/runtime/server/serialize.ts @@ -1,5 +1,5 @@ -import type { AstroComponentMetadata } from '../../@types/astro'; -import type { ValueOf } from '../../type-utils'; +import type { AstroComponentMetadata } from '../../@types/astro.js'; +import type { ValueOf } from '../../type-utils.js'; const PROP_TYPE = { Value: 0, diff --git a/packages/astro/src/runtime/server/transition.ts b/packages/astro/src/runtime/server/transition.ts index 4a13c8126..17eece1d9 100644 --- a/packages/astro/src/runtime/server/transition.ts +++ b/packages/astro/src/runtime/server/transition.ts @@ -1,4 +1,8 @@ -import type { SSRResult, TransitionAnimation, TransitionAnimationValue } from '../../@types/astro'; +import type { + SSRResult, + TransitionAnimation, + TransitionAnimationValue, +} from '../../@types/astro.js'; import { fade, slide } from '../../transitions/index.js'; import { markHTMLString } from './escape.js'; diff --git a/packages/astro/src/transitions/index.ts b/packages/astro/src/transitions/index.ts index 7d4711a32..0a58d2d4b 100644 --- a/packages/astro/src/transitions/index.ts +++ b/packages/astro/src/transitions/index.ts @@ -1,4 +1,4 @@ -import type { TransitionAnimationPair, TransitionDirectionalAnimations } from '../@types/astro'; +import type { TransitionAnimationPair, TransitionDirectionalAnimations } from '../@types/astro.js'; const EASE_IN_OUT_QUART = 'cubic-bezier(0.76, 0, 0.24, 1)'; diff --git a/packages/astro/src/type-utils.ts b/packages/astro/src/type-utils.ts index 926b0349d..96970f7c4 100644 --- a/packages/astro/src/type-utils.ts +++ b/packages/astro/src/type-utils.ts @@ -17,5 +17,13 @@ export type OmitIndexSignature = { : KeyType]: ObjectType[KeyType]; }; +// Transform a string into its kebab case equivalent (camelCase -> kebab-case). Useful for CSS-in-JS to CSS. +export type Kebab = T extends `${infer F}${infer R}` + ? Kebab ? '' : '-'}${Lowercase}`> + : A; + +// Transform every key of an object to its kebab case equivalent using the above utility +export type KebabKeys = { [K in keyof T as K extends string ? Kebab : K]: T[K] }; + // Similar to `keyof`, gets the type of all the values of an object export type ValueOf = T[keyof T]; diff --git a/packages/astro/src/vite-plugin-astro-server/base.ts b/packages/astro/src/vite-plugin-astro-server/base.ts index bb6a8a009..7bf57d10a 100644 --- a/packages/astro/src/vite-plugin-astro-server/base.ts +++ b/packages/astro/src/vite-plugin-astro-server/base.ts @@ -1,5 +1,5 @@ import type * as vite from 'vite'; -import type { AstroSettings } from '../@types/astro'; +import type { AstroSettings } from '../@types/astro.js'; import * as fs from 'node:fs'; import type { Logger } from '../core/logger/core.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/controller.ts b/packages/astro/src/vite-plugin-astro-server/controller.ts index 3004e68f3..279863613 100644 --- a/packages/astro/src/vite-plugin-astro-server/controller.ts +++ b/packages/astro/src/vite-plugin-astro-server/controller.ts @@ -1,5 +1,5 @@ -import type { LoaderEvents, ModuleLoader } from '../core/module-loader/index'; -import type { ServerState } from './server-state'; +import type { LoaderEvents, ModuleLoader } from '../core/module-loader/index.js'; +import type { ServerState } from './server-state.js'; import { clearRouteError, diff --git a/packages/astro/src/vite-plugin-astro-server/css.ts b/packages/astro/src/vite-plugin-astro-server/css.ts index 093bda461..46f1235bb 100644 --- a/packages/astro/src/vite-plugin-astro-server/css.ts +++ b/packages/astro/src/vite-plugin-astro-server/css.ts @@ -1,5 +1,5 @@ import type { RuntimeMode } from '../@types/astro.js'; -import type { ModuleLoader } from '../core/module-loader'; +import type { ModuleLoader } from '../core/module-loader/index.js'; import { viteID } from '../core/util.js'; import { isBuildableCSSRequest } from './util.js'; import { crawlGraph } from './vite.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/devPipeline.ts b/packages/astro/src/vite-plugin-astro-server/devPipeline.ts index fbe9c0429..e16b3d7e2 100644 --- a/packages/astro/src/vite-plugin-astro-server/devPipeline.ts +++ b/packages/astro/src/vite-plugin-astro-server/devPipeline.ts @@ -4,11 +4,11 @@ import type { RuntimeMode, SSRLoadedRenderer, SSRManifest, -} from '../@types/astro'; -import type { Logger } from '../core/logger/core'; -import type { ModuleLoader } from '../core/module-loader'; +} from '../@types/astro.js'; +import type { Logger } from '../core/logger/core.js'; +import type { ModuleLoader } from '../core/module-loader/index.js'; import { Pipeline } from '../core/pipeline.js'; -import type { Environment } from '../core/render'; +import type { Environment } from '../core/render/index.js'; import { createEnvironment, loadRenderer } from '../core/render/index.js'; import { RouteCache } from '../core/render/route-cache.js'; import { isServerLikeOutput } from '../prerender/utils.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index b02c57e1c..97592d47a 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -2,7 +2,7 @@ import type { ComponentInstance } from '../@types/astro.js'; import { enhanceViteSSRError } from '../core/errors/dev/index.js'; import { AggregateError, CSSError, MarkdownError } from '../core/errors/index.js'; import { viteID } from '../core/util.js'; -import type DevPipeline from './devPipeline'; +import type DevPipeline from './devPipeline.js'; export async function preload({ pipeline, diff --git a/packages/astro/src/vite-plugin-astro-server/metadata.ts b/packages/astro/src/vite-plugin-astro-server/metadata.ts index 81e972dba..09e2373cf 100644 --- a/packages/astro/src/vite-plugin-astro-server/metadata.ts +++ b/packages/astro/src/vite-plugin-astro-server/metadata.ts @@ -1,5 +1,5 @@ -import type { SSRComponentMetadata, SSRResult } from '../@types/astro'; -import type { ModuleInfo, ModuleLoader } from '../core/module-loader'; +import type { SSRComponentMetadata, SSRResult } from '../@types/astro.js'; +import type { ModuleInfo, ModuleLoader } from '../core/module-loader/index.js'; import { viteID } from '../core/util.js'; import { getAstroMetadata } from '../vite-plugin-astro/index.js'; import { crawlGraph } from './vite.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 80da6d787..daa1c01e6 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -1,6 +1,6 @@ import type fs from 'node:fs'; import type * as vite from 'vite'; -import type { AstroSettings, ManifestData, SSRManifest } from '../@types/astro'; +import type { AstroSettings, ManifestData, SSRManifest } from '../@types/astro.js'; import { patchOverlay } from '../core/errors/overlay.js'; import type { Logger } from '../core/logger/core.js'; import { createViteLoader } from '../core/module-loader/index.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/request.ts b/packages/astro/src/vite-plugin-astro-server/request.ts index cea9349e0..65e97b96f 100644 --- a/packages/astro/src/vite-plugin-astro-server/request.ts +++ b/packages/astro/src/vite-plugin-astro-server/request.ts @@ -1,14 +1,14 @@ import type http from 'node:http'; -import type { ManifestData, SSRManifest } from '../@types/astro'; +import type { ManifestData, SSRManifest } from '../@types/astro.js'; import { collectErrorMetadata } from '../core/errors/dev/index.js'; import { createSafeError } from '../core/errors/index.js'; import * as msg from '../core/messages.js'; import { collapseDuplicateSlashes, removeTrailingForwardSlash } from '../core/path.js'; import { eventError, telemetry } from '../events/index.js'; import { isServerLikeOutput } from '../prerender/utils.js'; -import type { DevServerController } from './controller'; +import type { DevServerController } from './controller.js'; import { runWithErrorHandling } from './controller.js'; -import type DevPipeline from './devPipeline'; +import type DevPipeline from './devPipeline.js'; import { handle500Response } from './response.js'; import { handleRoute, matchRoute } from './route.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/resolve.ts b/packages/astro/src/vite-plugin-astro-server/resolve.ts index f67d83576..cbeda56b0 100644 --- a/packages/astro/src/vite-plugin-astro-server/resolve.ts +++ b/packages/astro/src/vite-plugin-astro-server/resolve.ts @@ -1,4 +1,4 @@ -import type { ModuleLoader } from '../core/module-loader'; +import type { ModuleLoader } from '../core/module-loader/index.js'; import { resolveIdToUrl } from '../core/util.js'; export function createResolve(loader: ModuleLoader, root: URL) { diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts index 9e74a754f..b1c948095 100644 --- a/packages/astro/src/vite-plugin-astro-server/response.ts +++ b/packages/astro/src/vite-plugin-astro-server/response.ts @@ -1,6 +1,6 @@ import type http from 'node:http'; import type { ErrorWithMetadata } from '../core/errors/index.js'; -import type { ModuleLoader } from '../core/module-loader/index'; +import type { ModuleLoader } from '../core/module-loader/index.js'; import { Readable } from 'stream'; import { getSetCookiesFromResponse } from '../core/cookies/index.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index 120fc7722..da2c4b948 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -6,7 +6,7 @@ import type { RouteData, SSRElement, SSRManifest, -} from '../@types/astro'; +} from '../@types/astro.js'; import { AstroErrorData, isAstroError } from '../core/errors/index.js'; import { loadMiddleware } from '../core/middleware/loadMiddleware.js'; import { createRenderContext, getParamsAndProps, type SSROptions } from '../core/render/index.js'; diff --git a/packages/astro/src/vite-plugin-astro-server/scripts.ts b/packages/astro/src/vite-plugin-astro-server/scripts.ts index 55fe20254..00bc4054b 100644 --- a/packages/astro/src/vite-plugin-astro-server/scripts.ts +++ b/packages/astro/src/vite-plugin-astro-server/scripts.ts @@ -1,8 +1,8 @@ -import type { SSRElement } from '../@types/astro'; -import type { ModuleInfo, ModuleLoader } from '../core/module-loader'; +import type { SSRElement } from '../@types/astro.js'; +import type { ModuleInfo, ModuleLoader } from '../core/module-loader/index.js'; import { createModuleScriptElementWithSrc } from '../core/render/ssr-element.js'; import { rootRelativePath, viteID } from '../core/util.js'; -import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types'; +import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types.js'; import { crawlGraph } from './vite.js'; export async function getScriptsForURL( diff --git a/packages/astro/src/vite-plugin-astro-server/vite.ts b/packages/astro/src/vite-plugin-astro-server/vite.ts index ef6ffd308..6c2bc2497 100644 --- a/packages/astro/src/vite-plugin-astro-server/vite.ts +++ b/packages/astro/src/vite-plugin-astro-server/vite.ts @@ -1,6 +1,6 @@ import npath from 'node:path'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../core/constants.js'; -import type { ModuleLoader, ModuleNode } from '../core/module-loader/index'; +import type { ModuleLoader, ModuleNode } from '../core/module-loader/index.js'; import { unwrapId } from '../core/util.js'; import { isCSSRequest } from './util.js'; diff --git a/packages/astro/src/vite-plugin-astro/compile.ts b/packages/astro/src/vite-plugin-astro/compile.ts index 6c6b797ec..768d18d86 100644 --- a/packages/astro/src/vite-plugin-astro/compile.ts +++ b/packages/astro/src/vite-plugin-astro/compile.ts @@ -1,5 +1,5 @@ import { transformWithEsbuild, type ESBuildTransformResult } from 'vite'; -import type { AstroConfig } from '../@types/astro'; +import type { AstroConfig } from '../@types/astro.js'; import { cachedCompilation, type CompileProps, type CompileResult } from '../core/compile/index.js'; import type { Logger } from '../core/logger/core.js'; import { getFileInfo } from '../vite-plugin-utils/index.js'; diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index 6502ae513..65186af5e 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -1,6 +1,6 @@ import { fileURLToPath } from 'node:url'; import type { HmrContext, ModuleNode } from 'vite'; -import type { AstroConfig } from '../@types/astro'; +import type { AstroConfig } from '../@types/astro.js'; import { cachedCompilation, invalidateCompilation, diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index abeade65e..1649d8069 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -1,8 +1,8 @@ import type { SourceDescription } from 'rollup'; import type * as vite from 'vite'; -import type { AstroSettings } from '../@types/astro'; +import type { AstroSettings } from '../@types/astro.js'; import type { Logger } from '../core/logger/core.js'; -import type { PluginMetadata as AstroPluginMetadata } from './types'; +import type { PluginMetadata as AstroPluginMetadata } from './types.js'; import { normalizePath } from 'vite'; import { diff --git a/packages/astro/src/vite-plugin-astro/metadata.ts b/packages/astro/src/vite-plugin-astro/metadata.ts index ee66c12d0..d0a2b3644 100644 --- a/packages/astro/src/vite-plugin-astro/metadata.ts +++ b/packages/astro/src/vite-plugin-astro/metadata.ts @@ -1,5 +1,5 @@ -import type { ModuleInfo } from '../core/module-loader'; -import type { PluginMetadata } from './types'; +import type { ModuleInfo } from '../core/module-loader/index.js'; +import type { PluginMetadata } from './types.js'; export function getAstroMetadata(modInfo: ModuleInfo): PluginMetadata['astro'] | undefined { if (modInfo.meta?.astro) { diff --git a/packages/astro/src/vite-plugin-astro/types.ts b/packages/astro/src/vite-plugin-astro/types.ts index 8b74d7f33..49bbd5fea 100644 --- a/packages/astro/src/vite-plugin-astro/types.ts +++ b/packages/astro/src/vite-plugin-astro/types.ts @@ -1,5 +1,5 @@ import type { TransformResult } from '@astrojs/compiler'; -import type { PropagationHint } from '../@types/astro'; +import type { PropagationHint } from '../@types/astro.js'; export interface PageOptions { prerender?: boolean; diff --git a/packages/astro/src/vite-plugin-config-alias/index.ts b/packages/astro/src/vite-plugin-config-alias/index.ts index 3df286047..8b8535af9 100644 --- a/packages/astro/src/vite-plugin-config-alias/index.ts +++ b/packages/astro/src/vite-plugin-config-alias/index.ts @@ -1,6 +1,6 @@ import path from 'node:path'; import { normalizePath, type ResolvedConfig, type Plugin as VitePlugin } from 'vite'; -import type { AstroSettings } from '../@types/astro'; +import type { AstroSettings } from '../@types/astro.js'; type Alias = { find: RegExp; diff --git a/packages/astro/src/vite-plugin-env/index.ts b/packages/astro/src/vite-plugin-env/index.ts index 2b9f04cd4..1958344e5 100644 --- a/packages/astro/src/vite-plugin-env/index.ts +++ b/packages/astro/src/vite-plugin-env/index.ts @@ -2,7 +2,7 @@ import MagicString from 'magic-string'; import { fileURLToPath } from 'node:url'; import type * as vite from 'vite'; import { loadEnv } from 'vite'; -import type { AstroConfig, AstroSettings } from '../@types/astro'; +import type { AstroConfig, AstroSettings } from '../@types/astro.js'; interface EnvPluginOptions { settings: AstroSettings; diff --git a/packages/astro/src/vite-plugin-head/index.ts b/packages/astro/src/vite-plugin-head/index.ts index 9b0a7fb55..f8a13f925 100644 --- a/packages/astro/src/vite-plugin-head/index.ts +++ b/packages/astro/src/vite-plugin-head/index.ts @@ -1,8 +1,8 @@ import type { ModuleInfo } from 'rollup'; import type * as vite from 'vite'; -import type { SSRComponentMetadata, SSRResult } from '../@types/astro'; +import type { SSRComponentMetadata, SSRResult } from '../@types/astro.js'; import type { AstroBuildPlugin } from '../core/build/plugin.js'; -import type { PluginMetadata } from '../vite-plugin-astro/types'; +import type { PluginMetadata } from '../vite-plugin-astro/types.js'; import { getTopLevelPages, walkParentInfos } from '../core/build/graph.js'; import type { BuildInternals } from '../core/build/internal.js'; diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index deaccebef..163baab0d 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -1,15 +1,15 @@ -import { renderMarkdown } from '@astrojs/markdown-remark'; import { + createMarkdownProcessor, InvalidAstroDataError, - safelyGetAstroData, -} from '@astrojs/markdown-remark/dist/internal.js'; + type MarkdownProcessor, +} from '@astrojs/markdown-remark'; import matter from 'gray-matter'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import type { Plugin } from 'vite'; import { normalizePath } from 'vite'; -import type { AstroSettings } from '../@types/astro'; +import type { AstroSettings } from '../@types/astro.js'; import { AstroError, AstroErrorData, MarkdownError } from '../core/errors/index.js'; import type { Logger } from '../core/logger/core.js'; import { isMarkdownFile, rootRelativePath } from '../core/util.js'; @@ -57,9 +57,14 @@ const astroErrorModulePath = normalizePath( ); export default function markdown({ settings, logger }: AstroPluginOptions): Plugin { + let processor: MarkdownProcessor; + return { enforce: 'pre', name: 'astro:markdown', + async buildStart() { + processor = await createMarkdownProcessor(settings.config.markdown); + }, // Why not the "transform" hook instead of "load" + readFile? // A: Vite transforms all "import.meta.env" references to their values before // passing to the transform hook. This lets us get the truly raw value @@ -70,33 +75,32 @@ export default function markdown({ settings, logger }: AstroPluginOptions): Plug const rawFile = await fs.promises.readFile(fileId, 'utf-8'); const raw = safeMatter(rawFile, id); - const renderResult = await renderMarkdown(raw.content, { - ...settings.config.markdown, - fileURL: new URL(`file://${fileId}`), - frontmatter: raw.data, - }); + const renderResult = await processor + .render(raw.content, { + fileURL: new URL(`file://${fileId}`), + frontmatter: raw.data, + }) + .catch((err) => { + // Improve error message for invalid astro data + if (err instanceof InvalidAstroDataError) { + throw new AstroError(AstroErrorData.InvalidFrontmatterInjectionError); + } + throw err; + }); let html = renderResult.code; - const { headings } = renderResult.metadata; + const { headings, imagePaths: rawImagePaths, frontmatter } = renderResult.metadata; // Resolve all the extracted images from the content - let imagePaths: { raw: string; resolved: string }[] = []; - if (renderResult.vfile.data.imagePaths) { - for (let imagePath of renderResult.vfile.data.imagePaths.values()) { - imagePaths.push({ - raw: imagePath, - resolved: - (await this.resolve(imagePath, id))?.id ?? path.join(path.dirname(id), imagePath), - }); - } + const imagePaths: { raw: string; resolved: string }[] = []; + for (const imagePath of rawImagePaths.values()) { + imagePaths.push({ + raw: imagePath, + resolved: + (await this.resolve(imagePath, id))?.id ?? path.join(path.dirname(id), imagePath), + }); } - const astroData = safelyGetAstroData(renderResult.vfile.data); - if (astroData instanceof InvalidAstroDataError) { - throw new AstroError(AstroErrorData.InvalidFrontmatterInjectionError); - } - - const { frontmatter } = astroData; const { layout } = frontmatter; if (frontmatter.setup) { diff --git a/packages/astro/src/vite-plugin-mdx/index.ts b/packages/astro/src/vite-plugin-mdx/index.ts index b640d6c80..5e2ce2a98 100644 --- a/packages/astro/src/vite-plugin-mdx/index.ts +++ b/packages/astro/src/vite-plugin-mdx/index.ts @@ -1,8 +1,8 @@ import type { TransformResult } from 'rollup'; import { transformWithEsbuild, type Plugin, type ResolvedConfig } from 'vite'; -import type { AstroRenderer, AstroSettings } from '../@types/astro'; +import type { AstroRenderer, AstroSettings } from '../@types/astro.js'; import type { Logger } from '../core/logger/core.js'; -import type { PluginMetadata } from '../vite-plugin-astro/types'; +import type { PluginMetadata } from '../vite-plugin-astro/types.js'; import babel from '@babel/core'; import { CONTENT_FLAG, PROPAGATED_ASSET_FLAG } from '../content/index.js'; diff --git a/packages/astro/src/vite-plugin-utils/index.ts b/packages/astro/src/vite-plugin-utils/index.ts index 468360372..51f0e6cc4 100644 --- a/packages/astro/src/vite-plugin-utils/index.ts +++ b/packages/astro/src/vite-plugin-utils/index.ts @@ -1,6 +1,6 @@ import ancestor from 'common-ancestor-path'; import { fileURLToPath } from 'node:url'; -import type { AstroConfig } from '../@types/astro'; +import type { AstroConfig } from '../@types/astro.js'; import { appendExtension, appendForwardSlash, diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index f5a1b28f4..7a0a46822 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -174,6 +174,22 @@ describe('astro:image', () => { expect(res.status).to.equal(200); expect(loading).to.not.be.undefined; }); + + it('supports avif', async () => { + let res = await fixture.fetch('/avif'); + let html = await res.text(); + $ = cheerio.load(html); + + console.log(html); + + let $img = $('img'); + expect($img).to.have.a.lengthOf(1); + + let src = $img.attr('src'); + res = await fixture.fetch(src); + expect(res.status).to.equal(200); + expect(res.headers.get('content-type')).to.equal('image/avif'); + }); }); describe('vite-isms', () => { @@ -446,6 +462,47 @@ describe('astro:image', () => { expect($('#local img').attr('data-service-config')).to.equal('bar'); }); }); + + describe('custom endpoint', async () => { + /** @type {import('./test-utils').DevServer} */ + let customEndpointDevServer; + + /** @type {import('./test-utils.js').Fixture} */ + let customEndpointFixture; + + before(async () => { + customEndpointFixture = await loadFixture({ + root: './fixtures/core-image/', + image: { + endpoint: './src/custom-endpoint.ts', + service: testImageService({ foo: 'bar' }), + domains: ['avatars.githubusercontent.com'], + }, + }); + + customEndpointDevServer = await customEndpointFixture.startDevServer({ + server: { port: 4324 }, + }); + }); + + it('custom endpoint works', async () => { + const response = await customEndpointFixture.fetch('/'); + const html = await response.text(); + + const $ = cheerio.load(html); + const src = $('#local img').attr('src'); + + let res = await customEndpointFixture.fetch(src); + expect(res.status).to.equal(200); + expect(await res.text()).to.equal( + "You fool! I'm not a image endpoint at all, I just return this!" + ); + }); + + after(async () => { + await customEndpointDevServer.stop(); + }); + }); }); describe('proper errors', () => { diff --git a/packages/astro/test/fixtures/core-image/src/assets/light_walrus.avif b/packages/astro/test/fixtures/core-image/src/assets/light_walrus.avif new file mode 100644 index 000000000..89e1c3a14 Binary files /dev/null and b/packages/astro/test/fixtures/core-image/src/assets/light_walrus.avif differ diff --git a/packages/astro/test/fixtures/core-image/src/custom-endpoint.ts b/packages/astro/test/fixtures/core-image/src/custom-endpoint.ts new file mode 100644 index 000000000..22c32497b --- /dev/null +++ b/packages/astro/test/fixtures/core-image/src/custom-endpoint.ts @@ -0,0 +1,3 @@ +export const GET = async () => { + return new Response("You fool! I'm not a image endpoint at all, I just return this!", { status: 200 }); +}; diff --git a/packages/astro/test/fixtures/core-image/src/pages/avif.astro b/packages/astro/test/fixtures/core-image/src/pages/avif.astro new file mode 100644 index 000000000..be46122a3 --- /dev/null +++ b/packages/astro/test/fixtures/core-image/src/pages/avif.astro @@ -0,0 +1,5 @@ +--- +import light_walrus from "../assets/light_walrus.avif"; +--- + + diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index d8bd9b197..e36a58321 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -4,9 +4,7 @@ "compilerOptions": { "allowJs": true, "declarationDir": "./dist", - "module": "ES2022", "outDir": "./dist", - "target": "ES2022", "jsx": "preserve", "types": ["@types/dom-view-transitions", "network-information-types"] } diff --git a/packages/astro/types.d.ts b/packages/astro/types.d.ts index 0939c828a..638ad762e 100644 --- a/packages/astro/types.d.ts +++ b/packages/astro/types.d.ts @@ -1,5 +1,5 @@ import './astro-jsx'; -import { AstroBuiltinAttributes } from './dist/@types/astro'; +import { AstroBuiltinAttributes } from './dist/@types/astro.js'; /** Any supported HTML or SVG element name, as defined by the HTML specification */ export type HTMLTag = keyof astroHTML.JSX.DefinedIntrinsicElements; @@ -9,6 +9,11 @@ export type HTMLAttributes = Omit< keyof Omit >; +/** + * All the CSS properties available, as defined by the CSS specification + */ +export type CSSProperty = keyof astroHTML.JSX.KebabCSSDOMProperties; + type PolymorphicAttributes

= Omit

, 'as'> & { as?: P['as']; }; diff --git a/packages/create-astro/CHANGELOG.md b/packages/create-astro/CHANGELOG.md index a74291c27..fabd98390 100644 --- a/packages/create-astro/CHANGELOG.md +++ b/packages/create-astro/CHANGELOG.md @@ -1,5 +1,11 @@ # create-astro +## 4.1.0 + +### Minor Changes + +- [#8456](https://github.com/withastro/astro/pull/8456) [`ed952b4ce`](https://github.com/withastro/astro/commit/ed952b4cea6f60a4e158a5b20cc36f5e91a6b07f) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improve startup performance by removing dependencies, lazily initializing async contextual values + ## 4.0.2 ### Patch Changes diff --git a/packages/create-astro/README.md b/packages/create-astro/README.md index 5341d60f0..ba406d942 100644 --- a/packages/create-astro/README.md +++ b/packages/create-astro/README.md @@ -14,17 +14,23 @@ npm create astro@latest yarn create astro ``` +**With PNPM:** + +```bash +pnpm create astro +``` + `create-astro` automatically runs in _interactive_ mode, but you can also specify your project name and template with command line arguments. ```bash -# npm 6.x -npm create astro@latest my-astro-project --template minimal - -# npm 7+, extra double-dash is needed: +# npm npm create astro@latest my-astro-project -- --template minimal # yarn yarn create astro my-astro-project --template minimal + +# pnpm +pnpm create astro my-astro-project --template minimal ``` [Check out the full list][examples] of example templates, available on GitHub. diff --git a/packages/create-astro/create-astro.mjs b/packages/create-astro/create-astro.mjs index b7489a6b1..f9df779d8 100755 --- a/packages/create-astro/create-astro.mjs +++ b/packages/create-astro/create-astro.mjs @@ -4,7 +4,7 @@ const currentVersion = process.versions.node; const requiredMajorVersion = parseInt(currentVersion.split('.')[0], 10); -const minimumMajorVersion = 14; +const minimumMajorVersion = 18; if (requiredMajorVersion < minimumMajorVersion) { console.error(`Node.js v${currentVersion} is out of date and unsupported!`); diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json index 0eb08cdc7..583c98164 100644 --- a/packages/create-astro/package.json +++ b/packages/create-astro/package.json @@ -1,6 +1,6 @@ { "name": "create-astro", - "version": "4.0.2", + "version": "4.1.0", "type": "module", "author": "withastro", "license": "MIT", @@ -31,14 +31,10 @@ "//a": "MOST PACKAGES SHOULD GO IN DEV_DEPENDENCIES! THEY WILL BE BUNDLED.", "//b": "DEPENDENCIES IS FOR UNBUNDLED PACKAGES", "dependencies": { - "@astrojs/cli-kit": "^0.2.3", - "execa": "^8.0.1", - "giget": "1.1.2", - "node-fetch-native": "^1.4.0", - "which-pm-runs": "^1.1.0" + "@astrojs/cli-kit": "^0.3.0", + "giget": "1.1.2" }, "devDependencies": { - "@types/which-pm-runs": "^1.0.0", "arg": "^5.0.2", "astro-scripts": "workspace:*", "chai": "^4.3.7", diff --git a/packages/create-astro/src/actions/context.ts b/packages/create-astro/src/actions/context.ts index c91a0caae..ae720a1b3 100644 --- a/packages/create-astro/src/actions/context.ts +++ b/packages/create-astro/src/actions/context.ts @@ -1,7 +1,7 @@ import { prompt } from '@astrojs/cli-kit'; +import { random } from '@astrojs/cli-kit/utils'; import arg from 'arg'; import os from 'node:os'; -import detectPackageManager from 'which-pm-runs'; import { getName, getVersion } from '../messages.js'; @@ -10,8 +10,8 @@ export interface Context { prompt: typeof prompt; cwd: string; packageManager: string; - username: string; - version: string; + username: Promise; + version: Promise; skipHouston: boolean; fancy?: boolean; dryRun?: boolean; @@ -25,6 +25,7 @@ export interface Context { stdin?: typeof process.stdin; stdout?: typeof process.stdout; exit(code: number): never; + hat?: string; } export async function getContext(argv: string[]): Promise { @@ -51,8 +52,7 @@ export async function getContext(argv: string[]): Promise { { argv, permissive: true } ); - const packageManager = detectPackageManager()?.name ?? 'npm'; - const [username, version] = await Promise.all([getName(), getVersion()]); + const packageManager = detectPackageManager() ?? 'npm'; let cwd = flags['_'][0]; let { '--help': help = false, @@ -86,14 +86,15 @@ export async function getContext(argv: string[]): Promise { help, prompt, packageManager, - username, - version, + username: getName(), + version: getVersion(packageManager), skipHouston, fancy, dryRun, projectName, template, ref: ref ?? 'latest', + hat: fancy ? random(['🎩', '🎩', '🎩', '🎩', '🎓', '👑', '🧢', '🍦']) : undefined, yes, install: install ?? (noInstall ? false : undefined), git: git ?? (noGit ? false : undefined), @@ -105,3 +106,10 @@ export async function getContext(argv: string[]): Promise { }; return context; } + +function detectPackageManager() { + if (!process.env.npm_config_user_agent) return; + const specifier = process.env.npm_config_user_agent.split(' ')[0]; + const name = specifier.substring(0, specifier.lastIndexOf('/')); + return name === 'npminstall' ? 'cnpm' : name; +} diff --git a/packages/create-astro/src/actions/dependencies.ts b/packages/create-astro/src/actions/dependencies.ts index f05e9e93a..1e731099c 100644 --- a/packages/create-astro/src/actions/dependencies.ts +++ b/packages/create-astro/src/actions/dependencies.ts @@ -3,7 +3,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { error, info, spinner, title } from '../messages.js'; import { shell } from '../shell.js'; -import type { Context } from './context'; +import type { Context } from './context.js'; export async function dependencies( ctx: Pick diff --git a/packages/create-astro/src/actions/git.ts b/packages/create-astro/src/actions/git.ts index c2a59b0b3..dd703b1f5 100644 --- a/packages/create-astro/src/actions/git.ts +++ b/packages/create-astro/src/actions/git.ts @@ -1,6 +1,6 @@ import fs from 'node:fs'; import path from 'node:path'; -import type { Context } from './context'; +import type { Context } from './context.js'; import { color } from '@astrojs/cli-kit'; import { error, info, spinner, title } from '../messages.js'; diff --git a/packages/create-astro/src/actions/intro.ts b/packages/create-astro/src/actions/intro.ts index a96c8e434..1781fb260 100644 --- a/packages/create-astro/src/actions/intro.ts +++ b/packages/create-astro/src/actions/intro.ts @@ -1,27 +1,29 @@ -import type { Context } from './context'; +import type { Context } from './context.js'; import { color, label } from '@astrojs/cli-kit'; import { random } from '@astrojs/cli-kit/utils'; import { banner, say, welcome } from '../messages.js'; -export async function intro(ctx: Pick) { +export async function intro( + ctx: Pick +) { + banner(); + if (!ctx.skipHouston) { - const hat = ctx.fancy ? random(['🎩', '🎩', '👑', '🧢', '🍦']) : undefined; await say( [ [ 'Welcome', 'to', label('astro', color.bgGreen, color.black), - (ctx.version ? color.green(`v${ctx.version}`) : '') + ',', - `${ctx.username}!`, + Promise.resolve(ctx.version).then( + (version) => (version ? color.green(`v${version}`) : '') + ',' + ), + Promise.resolve(ctx.username).then((username) => `${username}!`), ], random(welcome), ], - { hat } + { clear: true, hat: ctx.hat } ); - await banner(ctx.version); - } else { - await banner(ctx.version); } } diff --git a/packages/create-astro/src/actions/next-steps.ts b/packages/create-astro/src/actions/next-steps.ts index c79a80525..86907abf5 100644 --- a/packages/create-astro/src/actions/next-steps.ts +++ b/packages/create-astro/src/actions/next-steps.ts @@ -1,9 +1,9 @@ import path from 'node:path'; -import type { Context } from './context'; +import type { Context } from './context.js'; import { nextSteps, say } from '../messages.js'; -export async function next(ctx: Pick) { +export async function next(ctx: Pick) { let projectDir = path.relative(process.cwd(), ctx.cwd); const commandMap: { [key: string]: string } = { @@ -17,7 +17,7 @@ export async function next(ctx: Pick { - const packageManager = detectPackageManager()?.name || 'npm'; +async function getRegistry(packageManager: string): Promise { try { const { stdout } = await shell(packageManager, ['config', 'get', 'registry']); return stdout?.trim()?.replace(/\/$/, '') || 'https://registry.npmjs.org'; @@ -78,10 +75,10 @@ export const getName = () => }); let v: string; -export const getVersion = () => +export const getVersion = (packageManager: string) => new Promise(async (resolve) => { if (v) return resolve(v); - let registry = await getRegistry(); + let registry = await getRegistry(packageManager); const { version } = await fetch(`${registry}/astro/latest`, { redirect: 'follow' }).then( (res) => res.json(), () => ({ version: '' }) @@ -91,12 +88,11 @@ export const getVersion = () => }); export const log = (message: string) => stdout.write(message + '\n'); -export const banner = async (version: string) => - log( - `\n${label('astro', color.bgGreen, color.black)}${ - version ? ' ' + color.green(color.bold(`v${version}`)) : '' - } ${color.bold('Launch sequence initiated.')}` - ); +export const banner = () => { + const prefix = `astro`; + const suffix = `Launch sequence initiated.`; + log(`${label(prefix, color.bgGreen, color.black)} ${suffix}`); +}; export const bannerAbort = () => log(`\n${label('astro', color.bgRed)} ${color.bold('Launch sequence aborted.')}`); diff --git a/packages/create-astro/tsconfig.json b/packages/create-astro/tsconfig.json index 1ab34c5a2..18443cddf 100644 --- a/packages/create-astro/tsconfig.json +++ b/packages/create-astro/tsconfig.json @@ -1,13 +1,7 @@ { "extends": "../../tsconfig.base.json", - "include": ["src", "index.d.ts"], + "include": ["src"], "compilerOptions": { - "allowJs": true, - "emitDeclarationOnly": false, - "noEmit": true, - "target": "ES2022", - "module": "ES2022", - "outDir": "./dist", - "declarationDir": "./dist/types" + "outDir": "./dist" } } diff --git a/packages/integrations/alpinejs/tsconfig.json b/packages/integrations/alpinejs/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/alpinejs/tsconfig.json +++ b/packages/integrations/alpinejs/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index 1fc188e02..0b5f61028 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -41,19 +41,20 @@ "dependencies": { "@astrojs/underscore-redirects": "workspace:*", "@cloudflare/workers-types": "^4.20230821.0", - "esbuild": "^0.19.2", - "tiny-glob": "^0.2.9", - "find-up": "^6.3.0", "@iarna/toml": "^2.2.5", - "dotenv": "^16.3.1", "@miniflare/cache": "^2.14.1", "@miniflare/shared": "^2.14.1", - "@miniflare/storage-memory": "^2.14.1" + "@miniflare/storage-memory": "^2.14.1", + "dotenv": "^16.3.1", + "esbuild": "^0.19.2", + "find-up": "^6.3.0", + "tiny-glob": "^0.2.9" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { + "@types/iarna__toml": "^2.0.2", "astro": "workspace:*", "astro-scripts": "workspace:*", "chai": "^4.3.7", diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index c70c9c5aa..b64d986af 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -14,8 +14,8 @@ import { fileURLToPath, pathToFileURL } from 'node:url'; import glob from 'tiny-glob'; import { getEnvVars } from './parser.js'; -export type { AdvancedRuntime } from './server.advanced'; -export type { DirectoryRuntime } from './server.directory'; +export type { AdvancedRuntime } from './server.advanced.js'; +export type { DirectoryRuntime } from './server.directory.js'; type Options = { mode?: 'directory' | 'advanced'; diff --git a/packages/integrations/cloudflare/tsconfig.json b/packages/integrations/cloudflare/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/cloudflare/tsconfig.json +++ b/packages/integrations/cloudflare/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/deno/package.json b/packages/integrations/deno/package.json index 73cea5b41..7905956c1 100644 --- a/packages/integrations/deno/package.json +++ b/packages/integrations/deno/package.json @@ -36,7 +36,7 @@ "esbuild": "^0.19.2" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { "astro": "workspace:*", diff --git a/packages/integrations/deno/tsconfig.json b/packages/integrations/deno/tsconfig.json index f3c96447a..d999917aa 100644 --- a/packages/integrations/deno/tsconfig.json +++ b/packages/integrations/deno/tsconfig.json @@ -2,11 +2,9 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, "module": "ES2022", "outDir": "./dist", - "target": "ES2022", - // TODO: Due to the shim for Deno imports in `server.ts`, we can't use moduleResolution: 'bundler' or the types get very weird. + // TODO: Due to the shim for Deno imports in `server.ts`, we can't use moduleResolution: 'node16' or the types get very weird. "moduleResolution": "Node" } } diff --git a/packages/integrations/lit/tsconfig.json b/packages/integrations/lit/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/lit/tsconfig.json +++ b/packages/integrations/lit/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/markdoc/package.json b/packages/integrations/markdoc/package.json index 1da973910..0aae4a982 100644 --- a/packages/integrations/markdoc/package.json +++ b/packages/integrations/markdoc/package.json @@ -75,7 +75,7 @@ "zod": "3.21.1" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { "@astrojs/markdown-remark": "workspace:*", diff --git a/packages/integrations/markdoc/src/html/index.ts b/packages/integrations/markdoc/src/html/index.ts index 8798d3c9a..3f947736c 100644 --- a/packages/integrations/markdoc/src/html/index.ts +++ b/packages/integrations/markdoc/src/html/index.ts @@ -1,2 +1,2 @@ -export { htmlTag } from './tagdefs/html.tag'; -export { htmlTokenTransform } from './transform/html-token-transform'; +export { htmlTag } from './tagdefs/html.tag.js'; +export { htmlTokenTransform } from './transform/html-token-transform.js'; diff --git a/packages/integrations/markdoc/src/html/transform/html-token-transform.ts b/packages/integrations/markdoc/src/html/transform/html-token-transform.ts index cfa511a9f..10796cdc0 100644 --- a/packages/integrations/markdoc/src/html/transform/html-token-transform.ts +++ b/packages/integrations/markdoc/src/html/transform/html-token-transform.ts @@ -1,5 +1,6 @@ import type { Tokenizer } from '@markdoc/markdoc'; import { Parser } from 'htmlparser2'; +// @ts-expect-error This type isn't exported import type * as Token from 'markdown-it/lib/token'; export function htmlTokenTransform(tokenizer: Tokenizer, tokens: Token[]): Token[] { diff --git a/packages/integrations/markdoc/tsconfig.json b/packages/integrations/markdoc/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/markdoc/tsconfig.json +++ b/packages/integrations/markdoc/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/mdx/CHANGELOG.md b/packages/integrations/mdx/CHANGELOG.md index ff9317c65..85a4409c7 100644 --- a/packages/integrations/mdx/CHANGELOG.md +++ b/packages/integrations/mdx/CHANGELOG.md @@ -1,5 +1,62 @@ # @astrojs/mdx +## 1.1.0 + +### Minor Changes + +- [#8468](https://github.com/withastro/astro/pull/8468) [`a8d72ceae`](https://github.com/withastro/astro/commit/a8d72ceaeed154434923b21c0ae129a72263b8ed) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support the `img` component export for optimized images. This allows you to customize how optimized images are styled and rendered. + + When rendering an optimized image, Astro will pass the `ImageMetadata` object to your `img` component as the `src` prop. For unoptimized images (i.e. images using URLs or absolute paths), Astro will continue to pass the `src` as a string. + + This example handles both cases and applies custom styling: + + ```astro + --- + // src/components/MyImage.astro + import type { ImageMetadata } from 'astro'; + import { Image } from 'astro:assets'; + + type Props = { + src: string | ImageMetadata; + alt: string; + }; + + const { src, alt } = Astro.props; + --- + + { + typeof src === 'string' ? ( + {alt} + ) : ( + + ) + } + + + ``` + + Now, this components can be applied to the `img` component props object or file export: + + ```md + import MyImage from '../../components/MyImage.astro'; + + export const components = { img: MyImage }; + + # My MDX article + ``` + +### Patch Changes + +- [#8533](https://github.com/withastro/astro/pull/8533) [`74dc3edb3`](https://github.com/withastro/astro/commit/74dc3edb305c49feec49c39082fa836485da8a92) Thanks [@bluwy](https://github.com/bluwy)! - Improve MDX rendering performance by sharing processor instance + +- Updated dependencies [[`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644), [`ecc65abbf`](https://github.com/withastro/astro/commit/ecc65abbf9e086c5bbd1973cd4a820082b4e0dc5), [`2c4fc878b`](https://github.com/withastro/astro/commit/2c4fc878bece36b7fcf1470419c7ce6f1e1e95d0), [`d93987824`](https://github.com/withastro/astro/commit/d93987824d3d6b4f58267be21ab8466ee8d5d5f8), [`c92e0acd7`](https://github.com/withastro/astro/commit/c92e0acd715171b3f4c3294099780e21576648c8), [`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644), [`f95febf96`](https://github.com/withastro/astro/commit/f95febf96bb97babb28d78994332f5e47f5f637d), [`b85c8a78a`](https://github.com/withastro/astro/commit/b85c8a78a116dbbddc901438bc0b7a1917dc0238), [`45364c345`](https://github.com/withastro/astro/commit/45364c345267429e400baecd1fbc290503f8b13a)]: + - astro@3.1.0 + - @astrojs/markdown-remark@3.2.0 + ## 1.0.3 ### Patch Changes diff --git a/packages/integrations/mdx/package.json b/packages/integrations/mdx/package.json index a534c767b..c621384c1 100644 --- a/packages/integrations/mdx/package.json +++ b/packages/integrations/mdx/package.json @@ -1,7 +1,7 @@ { "name": "@astrojs/mdx", "description": "Add support for MDX pages in your Astro site", - "version": "1.0.3", + "version": "1.1.0", "type": "module", "types": "./dist/index.d.ts", "author": "withastro", @@ -51,7 +51,7 @@ "vfile": "^5.3.7" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -74,6 +74,7 @@ "remark-rehype": "^10.1.0", "remark-shiki-twoslash": "^3.1.3", "remark-toc": "^8.0.1", + "unified": "^10.1.2", "vite": "^4.4.9" }, "engines": { diff --git a/packages/integrations/mdx/src/index.ts b/packages/integrations/mdx/src/index.ts index c27abb4d1..fd330625e 100644 --- a/packages/integrations/mdx/src/index.ts +++ b/packages/integrations/mdx/src/index.ts @@ -1,6 +1,4 @@ -import { markdownConfigDefaults } from '@astrojs/markdown-remark'; -import { toRemarkInitializeAstroData } from '@astrojs/markdown-remark/dist/internal.js'; -import { compile as mdxCompile, type CompileOptions } from '@mdx-js/mdx'; +import { markdownConfigDefaults, setVfileFrontmatter } from '@astrojs/markdown-remark'; import type { PluggableList } from '@mdx-js/mdx/lib/core.js'; import type { AstroIntegration, ContentEntryType, HookParameters, SSRError } from 'astro'; import astroJSXRenderer from 'astro/jsx/renderer.js'; @@ -8,11 +6,15 @@ import { parse as parseESM } from 'es-module-lexer'; import fs from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import type { Options as RemarkRehypeOptions } from 'remark-rehype'; -import { SourceMapGenerator } from 'source-map'; import { VFile } from 'vfile'; import type { Plugin as VitePlugin } from 'vite'; -import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from './plugins.js'; +import { createMdxProcessor } from './plugins.js'; import type { OptimizeOptions } from './rehype-optimize-static.js'; +import { + ASTRO_IMAGE_ELEMENT, + ASTRO_IMAGE_IMPORT, + USES_ASTRO_IMAGE_FLAG, +} from './remark-images-to-component.js'; import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from './utils.js'; export type MdxOptions = Omit & { @@ -79,21 +81,7 @@ export default function mdx(partialMdxOptions: Partial = {}): AstroI ), }); - const mdxPluginOpts: CompileOptions = { - remarkPlugins: await getRemarkPlugins(mdxOptions), - rehypePlugins: getRehypePlugins(mdxOptions), - recmaPlugins: mdxOptions.recmaPlugins, - remarkRehypeOptions: mdxOptions.remarkRehype, - jsx: true, - jsxImportSource: 'astro', - // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support - format: 'mdx', - mdExtensions: [], - }; - - let importMetaEnv: Record = { - SITE: config.site, - }; + let processor: ReturnType; updateConfig({ vite: { @@ -102,7 +90,10 @@ export default function mdx(partialMdxOptions: Partial = {}): AstroI name: '@mdx-js/rollup', enforce: 'pre', configResolved(resolved) { - importMetaEnv = { ...importMetaEnv, ...resolved.env }; + processor = createMdxProcessor(mdxOptions, { + sourcemap: !!resolved.build.sourcemap, + importMetaEnv: { SITE: config.site, ...resolved.env }, + }); // HACK: move ourselves before Astro's JSX plugin to transform things in the right order const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === 'astro:jsx'); @@ -129,23 +120,13 @@ export default function mdx(partialMdxOptions: Partial = {}): AstroI const code = await fs.readFile(fileId, 'utf-8'); const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id); + + const vfile = new VFile({ value: pageContent, path: id }); + // Ensure `data.astro` is available to all remark plugins + setVfileFrontmatter(vfile, frontmatter); + try { - const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), { - ...mdxPluginOpts, - elementAttributeNameCase: 'html', - remarkPlugins: [ - // Ensure `data.astro` is available to all remark plugins - toRemarkInitializeAstroData({ userFrontmatter: frontmatter }), - ...(mdxPluginOpts.remarkPlugins ?? []), - ], - recmaPlugins: [ - ...(mdxPluginOpts.recmaPlugins ?? []), - () => recmaInjectImportMetaEnvPlugin({ importMetaEnv }), - ], - SourceMapGenerator: config.vite.build?.sourcemap - ? SourceMapGenerator - : undefined, - }); + const compiled = await processor.process(vfile); return { code: escapeViteEnvReferences(String(compiled.value)), @@ -194,12 +175,25 @@ export default function mdx(partialMdxOptions: Partial = {}): AstroI if (!moduleExports.find(({ n }) => n === 'Content')) { // If have `export const components`, pass that as props to `Content` as fallback const hasComponents = moduleExports.find(({ n }) => n === 'components'); + const usesAstroImage = moduleExports.find( + ({ n }) => n === USES_ASTRO_IMAGE_FLAG + ); + + let componentsCode = `{ Fragment${ + hasComponents ? ', ...components' : '' + }, ...props.components,`; + if (usesAstroImage) { + componentsCode += ` ${JSON.stringify(ASTRO_IMAGE_ELEMENT)}: ${ + hasComponents ? 'components.img ?? ' : '' + } props.components?.img ?? ${ASTRO_IMAGE_IMPORT}`; + } + componentsCode += ' }'; // Make `Content` the default export so we can wrap `MDXContent` and pass in `Fragment` code = code.replace('export default MDXContent;', ''); code += `\nexport const Content = (props = {}) => MDXContent({ ...props, - components: { Fragment${hasComponents ? ', ...components' : ''}, ...props.components }, + components: ${componentsCode}, }); export default Content;`; } diff --git a/packages/integrations/mdx/src/plugins.ts b/packages/integrations/mdx/src/plugins.ts index a3d9e4ff3..3286a9fd8 100644 --- a/packages/integrations/mdx/src/plugins.ts +++ b/packages/integrations/mdx/src/plugins.ts @@ -4,101 +4,49 @@ import { remarkPrism, remarkShiki, } from '@astrojs/markdown-remark'; -import { - InvalidAstroDataError, - safelyGetAstroData, -} from '@astrojs/markdown-remark/dist/internal.js'; -import { nodeTypes } from '@mdx-js/mdx'; +import { createProcessor, nodeTypes } from '@mdx-js/mdx'; import type { PluggableList } from '@mdx-js/mdx/lib/core.js'; -import type { Literal, MemberExpression } from 'estree'; -import { visit as estreeVisit } from 'estree-util-visit'; import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; import remarkSmartypants from 'remark-smartypants'; -import type { VFile } from 'vfile'; +import { SourceMapGenerator } from 'source-map'; +import type { Processor } from 'unified'; import type { MdxOptions } from './index.js'; +import { recmaInjectImportMetaEnv } from './recma-inject-import-meta-env.js'; +import { rehypeApplyFrontmatterExport } from './rehype-apply-frontmatter-export.js'; import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js'; import rehypeMetaString from './rehype-meta-string.js'; import { rehypeOptimizeStatic } from './rehype-optimize-static.js'; import { remarkImageToComponent } from './remark-images-to-component.js'; -import { jsToTreeNode } from './utils.js'; // Skip nonessential plugins during performance benchmark runs const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK); -export function recmaInjectImportMetaEnvPlugin({ - importMetaEnv, -}: { +interface MdxProcessorExtraOptions { + sourcemap: boolean; importMetaEnv: Record; -}) { - return (tree: any) => { - estreeVisit(tree, (node) => { - if (node.type === 'MemberExpression') { - // attempt to get "import.meta.env" variable name - const envVarName = getImportMetaEnvVariableName(node); - if (typeof envVarName === 'string') { - // clear object keys to replace with envVarLiteral - for (const key in node) { - delete (node as any)[key]; - } - const envVarLiteral: Literal = { - type: 'Literal', - value: importMetaEnv[envVarName], - raw: JSON.stringify(importMetaEnv[envVarName]), - }; - Object.assign(node, envVarLiteral); - } - } - }); - }; } -export function rehypeApplyFrontmatterExport() { - return function (tree: any, vfile: VFile) { - const astroData = safelyGetAstroData(vfile.data); - if (astroData instanceof InvalidAstroDataError) - throw new Error( - // Copied from Astro core `errors-data` - // TODO: find way to import error data from core - '[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.' - ); - const { frontmatter } = astroData; - const exportNodes = [ - jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`), - ]; - if (frontmatter.layout) { - // NOTE(bholmesdev) 08-22-2022 - // Using an async layout import (i.e. `const Layout = (await import...)`) - // Preserves the dev server import cache when globbing a large set of MDX files - // Full explanation: 'https://github.com/withastro/astro/pull/4428' - exportNodes.unshift( - jsToTreeNode( - /** @see 'vite-plugin-markdown' for layout props reference */ - `import { jsx as layoutJsx } from 'astro/jsx-runtime'; - - export default async function ({ children }) { - const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default; - const { layout, ...content } = frontmatter; - content.file = file; - content.url = url; - return layoutJsx(Layout, { - file, - url, - content, - frontmatter: content, - headings: getHeadings(), - 'server:root': true, - children, - }); - };` - ) - ); - } - tree.children = exportNodes.concat(tree.children); - }; +export function createMdxProcessor( + mdxOptions: MdxOptions, + extraOptions: MdxProcessorExtraOptions +): Processor { + return createProcessor({ + remarkPlugins: getRemarkPlugins(mdxOptions), + rehypePlugins: getRehypePlugins(mdxOptions), + recmaPlugins: getRecmaPlugins(mdxOptions, extraOptions.importMetaEnv), + remarkRehypeOptions: mdxOptions.remarkRehype, + jsx: true, + jsxImportSource: 'astro', + // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support + format: 'mdx', + mdExtensions: [], + elementAttributeNameCase: 'html', + SourceMapGenerator: extraOptions.sourcemap ? SourceMapGenerator : undefined, + }); } -export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise { +function getRemarkPlugins(mdxOptions: MdxOptions): PluggableList { let remarkPlugins: PluggableList = [remarkCollectImages, remarkImageToComponent]; if (!isPerformanceBenchmark) { @@ -125,7 +73,7 @@ export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise +): PluggableList { + return [...(mdxOptions.recmaPlugins ?? []), [recmaInjectImportMetaEnv, { importMetaEnv }]]; } diff --git a/packages/integrations/mdx/src/recma-inject-import-meta-env.ts b/packages/integrations/mdx/src/recma-inject-import-meta-env.ts new file mode 100644 index 000000000..00578535d --- /dev/null +++ b/packages/integrations/mdx/src/recma-inject-import-meta-env.ts @@ -0,0 +1,65 @@ +import type { Literal, MemberExpression } from 'estree'; +import { visit as estreeVisit } from 'estree-util-visit'; + +export function recmaInjectImportMetaEnv({ + importMetaEnv, +}: { + importMetaEnv: Record; +}) { + return (tree: any) => { + estreeVisit(tree, (node) => { + if (node.type === 'MemberExpression') { + // attempt to get "import.meta.env" variable name + const envVarName = getImportMetaEnvVariableName(node); + if (typeof envVarName === 'string') { + // clear object keys to replace with envVarLiteral + for (const key in node) { + delete (node as any)[key]; + } + const envVarLiteral: Literal = { + type: 'Literal', + value: importMetaEnv[envVarName], + raw: JSON.stringify(importMetaEnv[envVarName]), + }; + Object.assign(node, envVarLiteral); + } + } + }); + }; +} + +/** + * Check if estree entry is "import.meta.env.VARIABLE" + * If it is, return the variable name (i.e. "VARIABLE") + */ +function getImportMetaEnvVariableName(node: MemberExpression): string | Error { + try { + // check for ".[ANYTHING]" + if (node.object.type !== 'MemberExpression' || node.property.type !== 'Identifier') + return new Error(); + + const nestedExpression = node.object; + // check for ".env" + if (nestedExpression.property.type !== 'Identifier' || nestedExpression.property.name !== 'env') + return new Error(); + + const envExpression = nestedExpression.object; + // check for ".meta" + if ( + envExpression.type !== 'MetaProperty' || + envExpression.property.type !== 'Identifier' || + envExpression.property.name !== 'meta' + ) + return new Error(); + + // check for "import" + if (envExpression.meta.name !== 'import') return new Error(); + + return node.property.name; + } catch (e) { + if (e instanceof Error) { + return e; + } + return new Error('Unknown parsing error'); + } +} diff --git a/packages/integrations/mdx/src/rehype-apply-frontmatter-export.ts b/packages/integrations/mdx/src/rehype-apply-frontmatter-export.ts new file mode 100644 index 000000000..3a1098800 --- /dev/null +++ b/packages/integrations/mdx/src/rehype-apply-frontmatter-export.ts @@ -0,0 +1,49 @@ +import { InvalidAstroDataError } from '@astrojs/markdown-remark'; +import { safelyGetAstroData } from '@astrojs/markdown-remark/dist/internal.js'; +import type { VFile } from 'vfile'; +import { jsToTreeNode } from './utils.js'; + +export function rehypeApplyFrontmatterExport() { + return function (tree: any, vfile: VFile) { + const astroData = safelyGetAstroData(vfile.data); + if (astroData instanceof InvalidAstroDataError) + throw new Error( + // Copied from Astro core `errors-data` + // TODO: find way to import error data from core + '[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.' + ); + const { frontmatter } = astroData; + const exportNodes = [ + jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`), + ]; + if (frontmatter.layout) { + // NOTE(bholmesdev) 08-22-2022 + // Using an async layout import (i.e. `const Layout = (await import...)`) + // Preserves the dev server import cache when globbing a large set of MDX files + // Full explanation: 'https://github.com/withastro/astro/pull/4428' + exportNodes.unshift( + jsToTreeNode( + /** @see 'vite-plugin-markdown' for layout props reference */ + `import { jsx as layoutJsx } from 'astro/jsx-runtime'; + + export default async function ({ children }) { + const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default; + const { layout, ...content } = frontmatter; + content.file = file; + content.url = url; + return layoutJsx(Layout, { + file, + url, + content, + frontmatter: content, + headings: getHeadings(), + 'server:root': true, + children, + }); + };` + ) + ); + } + tree.children = exportNodes.concat(tree.children); + }; +} diff --git a/packages/integrations/mdx/src/remark-images-to-component.ts b/packages/integrations/mdx/src/remark-images-to-component.ts index bb9657f42..f83f5d76a 100644 --- a/packages/integrations/mdx/src/remark-images-to-component.ts +++ b/packages/integrations/mdx/src/remark-images-to-component.ts @@ -4,6 +4,10 @@ import type { MdxJsxFlowElement, MdxjsEsm } from 'mdast-util-mdx'; import { visit } from 'unist-util-visit'; import { jsToTreeNode } from './utils.js'; +export const ASTRO_IMAGE_ELEMENT = 'astro-image'; +export const ASTRO_IMAGE_IMPORT = '__AstroImage__'; +export const USES_ASTRO_IMAGE_FLAG = '__usesAstroImage'; + export function remarkImageToComponent() { return function (tree: any, file: MarkdownVFile) { if (!file.data.imagePaths) return; @@ -48,7 +52,7 @@ export function remarkImageToComponent() { // Build a component that's equivalent to {node.alt} const componentElement: MdxJsxFlowElement = { - name: '__AstroImage__', + name: ASTRO_IMAGE_ELEMENT, type: 'mdxJsxFlowElement', attributes: [ { @@ -92,7 +96,11 @@ export function remarkImageToComponent() { // Add all the import statements to the top of the file for the images tree.children.unshift(...importsStatements); - // Add an import statement for the Astro Image component, we rename it to avoid conflicts - tree.children.unshift(jsToTreeNode(`import { Image as __AstroImage__ } from "astro:assets";`)); + tree.children.unshift( + jsToTreeNode(`import { Image as ${ASTRO_IMAGE_IMPORT} } from "astro:assets";`) + ); + // Export `__usesAstroImage` to pick up `astro:assets` usage in the module graph. + // @see the '@astrojs/mdx-postprocess' plugin + tree.children.push(jsToTreeNode(`export const ${USES_ASTRO_IMAGE_FLAG} = true`)); }; } diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/public/favicon.svg b/packages/integrations/mdx/test/fixtures/mdx-images/public/favicon.svg new file mode 100644 index 000000000..f157bd1c5 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/public/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/src/components/Component.mdx b/packages/integrations/mdx/test/fixtures/mdx-images/src/components/Component.mdx new file mode 100644 index 000000000..7463939ba --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/src/components/Component.mdx @@ -0,0 +1,5 @@ +Optimized image: +![Houston](../assets/houston.webp) + +Public image: +![Astro logo](/favicon.svg) diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/src/components/MyImage.astro b/packages/integrations/mdx/test/fixtures/mdx-images/src/components/MyImage.astro new file mode 100644 index 000000000..e3541867c --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/src/components/MyImage.astro @@ -0,0 +1,25 @@ +--- +import type { ImageMetadata } from 'astro'; +import { Image } from 'astro:assets'; + +type Props = { + src: string | ImageMetadata; + alt: string; +}; + +const { src, alt } = Astro.props; +--- + +{ + typeof src === 'string' ? ( + {alt} + ) : ( + + ) +} + + diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/src/content/blog/entry.mdx b/packages/integrations/mdx/test/fixtures/mdx-images/src/content/blog/entry.mdx new file mode 100644 index 000000000..58aebcf54 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/src/content/blog/entry.mdx @@ -0,0 +1,5 @@ +Optimized image: +![Houston](../../assets/houston.webp) + +Public image: +![Astro logo](/favicon.svg) diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/content-collection.astro b/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/content-collection.astro new file mode 100644 index 000000000..63d068b5c --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/content-collection.astro @@ -0,0 +1,19 @@ +--- +import { getEntry } from 'astro:content'; +import MyImage from 'src/components/MyImage.astro'; + +const entry = await getEntry('blog', 'entry'); +const { Content } = await entry.render(); +--- + + + + + + + Renderer + + + + + diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/esm-import.astro b/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/esm-import.astro new file mode 100644 index 000000000..e5f7a61d9 --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/esm-import.astro @@ -0,0 +1,16 @@ +--- +import MDX from '../components/Component.mdx'; +import MyImage from 'src/components/MyImage.astro'; +--- + + + + + + + Renderer + + + + + diff --git a/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/with-components.mdx b/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/with-components.mdx new file mode 100644 index 000000000..763256b1c --- /dev/null +++ b/packages/integrations/mdx/test/fixtures/mdx-images/src/pages/with-components.mdx @@ -0,0 +1,9 @@ +import MyImage from '../components/MyImage.astro'; + +export const components = { img: MyImage }; + +Optimized image: +![Houston](../assets/houston.webp) + +Public image: +![Astro logo](/favicon.svg) diff --git a/packages/integrations/mdx/test/mdx-images.test.js b/packages/integrations/mdx/test/mdx-images.test.js index c9c8e1f7c..950b54581 100644 --- a/packages/integrations/mdx/test/mdx-images.test.js +++ b/packages/integrations/mdx/test/mdx-images.test.js @@ -2,6 +2,8 @@ import { expect } from 'chai'; import { parseHTML } from 'linkedom'; import { loadFixture } from '../../../astro/test/test-utils.js'; +const imageTestRoutes = ['with-components', 'esm-import', 'content-collection']; + describe('MDX Page', () => { let devServer; let fixture; @@ -36,5 +38,26 @@ describe('MDX Page', () => { // Image with spaces in the path expect(imgs.item(3).src.startsWith('/_image')).to.be.true; }); + + for (const route of imageTestRoutes) { + it(`supports img component - ${route}`, async () => { + const res = await fixture.fetch(`/${route}`); + expect(res.status).to.equal(200); + + const html = await res.text(); + const { document } = parseHTML(html); + + const imgs = document.getElementsByTagName('img'); + expect(imgs.length).to.equal(2); + + const assetsImg = imgs.item(0); + expect(assetsImg.src.startsWith('/_image')).to.be.true; + expect(assetsImg.hasAttribute('data-my-image')).to.be.true; + + const publicImg = imgs.item(1); + expect(publicImg.src).to.equal('/favicon.svg'); + expect(publicImg.hasAttribute('data-my-image')).to.be.true; + }); + } }); }); diff --git a/packages/integrations/mdx/tsconfig.json b/packages/integrations/mdx/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/mdx/tsconfig.json +++ b/packages/integrations/mdx/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json index fc5da038f..c477c02e5 100644 --- a/packages/integrations/netlify/package.json +++ b/packages/integrations/netlify/package.json @@ -43,7 +43,7 @@ "esbuild": "^0.19.2" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { "@netlify/edge-functions": "^2.0.0", diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/time.astro b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/time.astro new file mode 100644 index 000000000..873b5c720 --- /dev/null +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/src/pages/time.astro @@ -0,0 +1,5 @@ +--- +const currentTime = new Date().getTime(); +--- + +{currentTime} diff --git a/packages/integrations/netlify/test/hosted/hosted.test.js b/packages/integrations/netlify/test/hosted/hosted.test.js index 0ce531e4d..2dc8c67ce 100644 --- a/packages/integrations/netlify/test/hosted/hosted.test.js +++ b/packages/integrations/netlify/test/hosted/hosted.test.js @@ -10,4 +10,12 @@ describe('Hosted Netlify Tests', () => { expect(image.status).to.equal(200); }); + + it('Server returns fresh content', async () => { + const responseOne = await fetch(NETLIFY_TEST_URL + '/time'); + + const responseTwo = await fetch(NETLIFY_TEST_URL + '/time'); + + expect(responseOne.body).to.not.equal(responseTwo.body); + }); }); diff --git a/packages/integrations/netlify/tsconfig.json b/packages/integrations/netlify/tsconfig.json index 66b0102c7..4095e9b83 100644 --- a/packages/integrations/netlify/tsconfig.json +++ b/packages/integrations/netlify/tsconfig.json @@ -2,11 +2,7 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", "outDir": "./dist", - "target": "ES2022", - "typeRoots": ["node_modules/@types", "node_modules/@netlify"], - "allowImportingTsExtensions": true + "typeRoots": ["node_modules/@types", "node_modules/@netlify"] } } diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index 3dbb7f21d..4f852bdc6 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -37,7 +37,7 @@ "server-destroy": "^1.0.1" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { "@types/node": "^18.17.8", diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index 5afc49f6a..5978371e4 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -1,6 +1,6 @@ import type { AstroAdapter, AstroIntegration } from 'astro'; import { AstroError } from 'astro/errors'; -import type { Options, UserOptions } from './types'; +import type { Options, UserOptions } from './types.js'; export function getAdapter(options: Options): AstroAdapter { return { name: '@astrojs/node', diff --git a/packages/integrations/node/src/nodeMiddleware.ts b/packages/integrations/node/src/nodeMiddleware.ts index 1e0aaea0f..32b8020dc 100644 --- a/packages/integrations/node/src/nodeMiddleware.ts +++ b/packages/integrations/node/src/nodeMiddleware.ts @@ -1,9 +1,9 @@ import type { NodeApp } from 'astro/app/node'; import type { ServerResponse } from 'node:http'; import type { Readable } from 'stream'; -import { createOutgoingHttpHeaders } from './createOutgoingHttpHeaders'; -import { responseIterator } from './response-iterator'; -import type { ErrorHandlerParams, Options, RequestHandlerParams } from './types'; +import { createOutgoingHttpHeaders } from './createOutgoingHttpHeaders.js'; +import { responseIterator } from './response-iterator.js'; +import type { ErrorHandlerParams, Options, RequestHandlerParams } from './types.js'; // Disable no-unused-vars to avoid breaking signature change export default function (app: NodeApp, mode: Options['mode']) { diff --git a/packages/integrations/node/src/preview.ts b/packages/integrations/node/src/preview.ts index 77560d734..70ed54698 100644 --- a/packages/integrations/node/src/preview.ts +++ b/packages/integrations/node/src/preview.ts @@ -4,7 +4,7 @@ import type http from 'node:http'; import { fileURLToPath } from 'node:url'; import { getNetworkAddress } from './get-network-address.js'; import { createServer } from './http-server.js'; -import type { createExports } from './server'; +import type { createExports } from './server.js'; const preview: CreatePreviewServer = async function ({ client, diff --git a/packages/integrations/node/src/server.ts b/packages/integrations/node/src/server.ts index 04c81c2d1..90bf8c44c 100644 --- a/packages/integrations/node/src/server.ts +++ b/packages/integrations/node/src/server.ts @@ -2,7 +2,7 @@ import type { SSRManifest } from 'astro'; import { NodeApp, applyPolyfills } from 'astro/app/node'; import middleware from './nodeMiddleware.js'; import startServer from './standalone.js'; -import type { Options } from './types'; +import type { Options } from './types.js'; applyPolyfills(); export function createExports(manifest: SSRManifest, options: Options) { diff --git a/packages/integrations/node/src/standalone.ts b/packages/integrations/node/src/standalone.ts index 66d1b9c6a..abe40ff5c 100644 --- a/packages/integrations/node/src/standalone.ts +++ b/packages/integrations/node/src/standalone.ts @@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url'; import { getNetworkAddress } from './get-network-address.js'; import { createServer } from './http-server.js'; import middleware from './nodeMiddleware.js'; -import type { Options } from './types'; +import type { Options } from './types.js'; function resolvePaths(options: Options) { const clientURLRaw = new URL(options.client); diff --git a/packages/integrations/node/tsconfig.json b/packages/integrations/node/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/node/tsconfig.json +++ b/packages/integrations/node/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/partytown/tsconfig.json b/packages/integrations/partytown/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/partytown/tsconfig.json +++ b/packages/integrations/partytown/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/preact/src/client.ts b/packages/integrations/preact/src/client.ts index b64431130..050a86f8a 100644 --- a/packages/integrations/preact/src/client.ts +++ b/packages/integrations/preact/src/client.ts @@ -1,6 +1,6 @@ import { h, hydrate, render } from 'preact'; import StaticHtml from './static-html.js'; -import type { SignalLike } from './types'; +import type { SignalLike } from './types.js'; const sharedSignalMap = new Map(); diff --git a/packages/integrations/preact/src/context.ts b/packages/integrations/preact/src/context.ts index c711017c4..4d2398d28 100644 --- a/packages/integrations/preact/src/context.ts +++ b/packages/integrations/preact/src/context.ts @@ -1,4 +1,4 @@ -import type { PropNameToSignalMap, RendererContext, SignalLike } from './types'; +import type { PropNameToSignalMap, RendererContext, SignalLike } from './types.js'; export type Context = { id: string; diff --git a/packages/integrations/preact/src/index.ts b/packages/integrations/preact/src/index.ts index 85c3c66ec..85f9bed0f 100644 --- a/packages/integrations/preact/src/index.ts +++ b/packages/integrations/preact/src/index.ts @@ -1,4 +1,4 @@ -import preact, { type PreactPluginOptions as VitePreactPluginOptions } from '@preact/preset-vite'; +import { preact, type PreactPluginOptions as VitePreactPluginOptions } from '@preact/preset-vite'; import type { AstroIntegration, AstroRenderer, ViteUserConfig } from 'astro'; import { fileURLToPath } from 'node:url'; diff --git a/packages/integrations/preact/src/server.ts b/packages/integrations/preact/src/server.ts index e55d29d1c..a395433c9 100644 --- a/packages/integrations/preact/src/server.ts +++ b/packages/integrations/preact/src/server.ts @@ -1,10 +1,10 @@ import type { AstroComponentMetadata } from 'astro'; import { Component as BaseComponent, h, type VNode } from 'preact'; -import render from 'preact-render-to-string'; +import { render } from 'preact-render-to-string'; import { getContext } from './context.js'; import { restoreSignalsOnProps, serializeSignals } from './signals.js'; import StaticHtml from './static-html.js'; -import type { AstroPreactAttrs, RendererContext } from './types'; +import type { AstroPreactAttrs, RendererContext } from './types.js'; const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase()); diff --git a/packages/integrations/preact/src/signals.ts b/packages/integrations/preact/src/signals.ts index 3fa1529f4..ef3a4b70a 100644 --- a/packages/integrations/preact/src/signals.ts +++ b/packages/integrations/preact/src/signals.ts @@ -1,6 +1,6 @@ -import type { Context } from './context'; +import type { Context } from './context.js'; import { incrementId } from './context.js'; -import type { AstroPreactAttrs, PropNameToSignalMap, SignalLike } from './types'; +import type { AstroPreactAttrs, PropNameToSignalMap, SignalLike } from './types.js'; function isSignal(x: any): x is SignalLike { return x != null && typeof x === 'object' && typeof x.peek === 'function' && 'value' in x; diff --git a/packages/integrations/preact/tsconfig.json b/packages/integrations/preact/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/preact/tsconfig.json +++ b/packages/integrations/preact/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/prefetch/tsconfig.json b/packages/integrations/prefetch/tsconfig.json index 6457dfe8c..dadc37a82 100644 --- a/packages/integrations/prefetch/tsconfig.json +++ b/packages/integrations/prefetch/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src", "@types"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index d5f696522..e4b977880 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -7,6 +7,7 @@ export type ReactIntegrationOptions = Pick str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase()); diff --git a/packages/integrations/solid/tsconfig.json b/packages/integrations/solid/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/solid/tsconfig.json +++ b/packages/integrations/solid/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/svelte/package.json b/packages/integrations/svelte/package.json index 67a1461e9..1d36d5e17 100644 --- a/packages/integrations/svelte/package.json +++ b/packages/integrations/svelte/package.json @@ -48,7 +48,7 @@ "vite": "^4.4.9" }, "peerDependencies": { - "astro": "workspace:^3.0.13", + "astro": "workspace:^3.1.0", "svelte": "^3.55.0 || ^4.0.0" }, "engines": { diff --git a/packages/integrations/svelte/tsconfig.json b/packages/integrations/svelte/tsconfig.json index af1b43564..5742d1f6e 100644 --- a/packages/integrations/svelte/tsconfig.json +++ b/packages/integrations/svelte/tsconfig.json @@ -2,9 +2,7 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", "outDir": "./dist", - "target": "ES2022" + "verbatimModuleSyntax": false } } diff --git a/packages/integrations/tailwind/package.json b/packages/integrations/tailwind/package.json index eb35a8da3..9c0c68a07 100644 --- a/packages/integrations/tailwind/package.json +++ b/packages/integrations/tailwind/package.json @@ -43,7 +43,7 @@ "vite": "^4.4.9" }, "peerDependencies": { - "astro": "workspace:^3.0.13", + "astro": "workspace:^3.1.0", "tailwindcss": "^3.0.24" } } diff --git a/packages/integrations/tailwind/src/index.ts b/packages/integrations/tailwind/src/index.ts index df0f01723..700f16937 100644 --- a/packages/integrations/tailwind/src/index.ts +++ b/packages/integrations/tailwind/src/index.ts @@ -33,6 +33,7 @@ async function getViteConfiguration( const postcssOptions = postcssConfigResult?.options ?? {}; const postcssPlugins = postcssConfigResult?.plugins?.slice() ?? []; + // @ts-expect-error Tailwind plugin types are wrong postcssPlugins.push(tailwindPlugin(tailwindConfigPath) as ResultPlugin); postcssPlugins.push(autoprefixerPlugin()); diff --git a/packages/integrations/tailwind/tsconfig.json b/packages/integrations/tailwind/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/tailwind/tsconfig.json +++ b/packages/integrations/tailwind/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/vercel/CHANGELOG.md b/packages/integrations/vercel/CHANGELOG.md index b720696c8..2c3e74b47 100644 --- a/packages/integrations/vercel/CHANGELOG.md +++ b/packages/integrations/vercel/CHANGELOG.md @@ -1,5 +1,47 @@ # @astrojs/vercel +## 5.0.0 + +### Major Changes + +- [#8445](https://github.com/withastro/astro/pull/8445) [`91380378c`](https://github.com/withastro/astro/commit/91380378cef545656d2c085117fc5f38c9ce4589) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds a configuration option `devImageService` to choose which of the built-in image services to use in development. Defaults to `sharp`. + +- [#8546](https://github.com/withastro/astro/pull/8546) [`b79e11f3c`](https://github.com/withastro/astro/commit/b79e11f3c480e8e165d5b102adb1f2f8a089f29d) Thanks [@matthewp](https://github.com/matthewp)! - Turn off `functionPerRoute` by default + + In the previous version of `@astrojs/vercel`, the default for `functionPerRoute` was changed to `true`. While this option has several advantages, if you're a free tier user you are likely to run into the limit of 12 functions per deployment. This will result in an error when you attempt to deploy. + + For this reason, the `functionPerRoute` option is now back to defaulting to `false`. It's still a useful option if you have a paid plan and have previously run into issues with your single function exceeding the size limits. + +### Minor Changes + +- [#8021](https://github.com/withastro/astro/pull/8021) [`2e8726fee`](https://github.com/withastro/astro/commit/2e8726feec2e0d6ba8bd4db941009986e8e34141) Thanks [@chriswdmr](https://github.com/chriswdmr)! - Enable Vercel Speed Insights and Vercel Web Analytics individually. + Deprecates the `analytics` property in `astro.config.mjs` in favor of `speedInsights` and `webAnalytics`. + + If you're using the `analytics` property, you'll need to update your config to use the new properties: + + ```diff + // astro.config.mjs + export default defineConfig({ + adapter: vercel({ + - analytics: true, + + webAnalytics: { + + enabled: true + + }, + + speedInsights: { + + enabled: true + + } + }) + }); + ``` + + Allow configuration of Web Analytics with all available configuration options. + Bumps @vercel/analytics package to the latest version. + +### Patch Changes + +- Updated dependencies [[`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644), [`ecc65abbf`](https://github.com/withastro/astro/commit/ecc65abbf9e086c5bbd1973cd4a820082b4e0dc5), [`2c4fc878b`](https://github.com/withastro/astro/commit/2c4fc878bece36b7fcf1470419c7ce6f1e1e95d0), [`c92e0acd7`](https://github.com/withastro/astro/commit/c92e0acd715171b3f4c3294099780e21576648c8), [`f95febf96`](https://github.com/withastro/astro/commit/f95febf96bb97babb28d78994332f5e47f5f637d), [`b85c8a78a`](https://github.com/withastro/astro/commit/b85c8a78a116dbbddc901438bc0b7a1917dc0238), [`45364c345`](https://github.com/withastro/astro/commit/45364c345267429e400baecd1fbc290503f8b13a)]: + - astro@3.1.0 + ## 4.0.5 ### Patch Changes diff --git a/packages/integrations/vercel/README.md b/packages/integrations/vercel/README.md index 00c2a18cf..381132d80 100644 --- a/packages/integrations/vercel/README.md +++ b/packages/integrations/vercel/README.md @@ -85,13 +85,13 @@ vercel deploy --prebuilt To configure this adapter, pass an object to the `vercel()` function call in `astro.config.mjs`: -### analytics +### Web Analytics -**Type:** `boolean`
-**Available for:** Serverless, Static
-**Added in:** `@astrojs/vercel@3.1.0` +**Type:** `VercelWebAnalyticsConfig`
+**Available for:** Serverless, Edge, Static
+**Added in:** `@astrojs/vercel@3.8.0` -You can enable [Vercel Analytics](https://vercel.com/analytics) (including Web Vitals and Audiences) by setting `analytics: true`. This will inject Vercel’s tracking scripts into all your pages. +You can enable [Vercel Web Analytics](https://vercel.com/docs/concepts/analytics) by setting `webAnalytics: { enabled: true }`. This will inject Vercel’s tracking scripts into all of your pages. ```js // astro.config.mjs @@ -101,7 +101,32 @@ import vercel from '@astrojs/vercel/serverless'; export default defineConfig({ output: 'server', adapter: vercel({ - analytics: true, + webAnalytics: { + enabled: true, + }, + }), +}); +``` + +### Speed Insights + +You can enable [Vercel Speed Insights](https://vercel.com/docs/concepts/speed-insights) by setting `speedInsights: { enabled: true }`. This will collect and send Web Vital data to Vercel. + +**Type:** `VercelSpeedInsightsConfig`
+**Available for:** Serverless, Edge, Static
+**Added in:** `@astrojs/vercel@3.8.0` + +```js +// astro.config.mjs +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/serverless'; + +export default defineConfig({ + output: 'server', + adapter: vercel({ + speedInsights: { + enabled: true, + }, }), }); ``` @@ -137,7 +162,7 @@ export default defineConfig({ **Available for:** Serverless, Static **Added in:** `@astrojs/vercel@3.3.0` -When enabled, an [Image Service](https://docs.astro.build/en/reference/image-service-reference/) powered by the Vercel Image Optimization API will be automatically configured and used in production. In development, a built-in Squoosh-based service will be used instead. +When enabled, an [Image Service](https://docs.astro.build/en/reference/image-service-reference/) powered by the Vercel Image Optimization API will be automatically configured and used in production. In development, the image service specified by [`devImageService`](#devimageservice) will be used instead. ```js // astro.config.mjs @@ -172,6 +197,30 @@ import astroLogo from '../assets/logo.png'; /> ``` +### devImageService + +**Type:** `'sharp' | 'squoosh' | string`
+**Available for:** Serverless, Static +**Added in:** `@astrojs/vercel@3.3.0` +**Default**: 'sharp' + +Allows you to configure which image service to use in development when [imageService](#imageservice) is enabled. This can be useful if you cannot install Sharp's dependencies on your development machine, but using another image service like Squoosh would allow you to preview images in your dev environment. Build is unaffected and will always use Vercel's Image Optimization. + +It can also be set to any arbitrary value in order to use a custom image service instead of Astro's built-in ones. + +```js +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/serverless'; + +export default defineConfig({ + output: 'server', + adapter: vercel({ + imageService: true, + devImageService: 'squoosh', + }), +}); +``` + ### includeFiles **Type:** `string[]`
@@ -214,9 +263,11 @@ export default defineConfig({ ### Function bundling configuration -The Vercel adapter splits builds into a separate function per route by default. This helps reduce the size of each function, as it only bundles code used on that page. +The Vercel adapter combines all of your routes into a single function by default. -You can disable this and build to a single function by setting the `functionPerRoute` configuration option to `false`: +You also have the option to split builds into a separate function for each route using the `functionPerRoute` option. This reduces the size of each function, meaning you are less likely to exceed the size limit for an individual function. Also, code starts are faster. + +Verify that your Vercel plan includes an appropriate number of functions before enabling `functionPerRoute`. For example, Vercel's free tier limits each deployment to no more than 12 functions. If your Vercel plan is insufficient for the number of routes in your project, you will receive an error message during deployment. ```js // astro.config.mjs @@ -226,7 +277,7 @@ import vercel from '@astrojs/vercel/serverless'; export default defineConfig({ output: 'server', adapter: vercel({ - functionPerRoute: false, + functionPerRoute: true, }), }); ``` diff --git a/packages/integrations/vercel/package.json b/packages/integrations/vercel/package.json index b9ac5aaa0..999181be2 100644 --- a/packages/integrations/vercel/package.json +++ b/packages/integrations/vercel/package.json @@ -1,7 +1,7 @@ { "name": "@astrojs/vercel", "description": "Deploy your site to Vercel", - "version": "4.0.5", + "version": "5.0.0", "type": "module", "author": "withastro", "license": "MIT", @@ -22,9 +22,10 @@ "./serverless": "./dist/serverless/adapter.js", "./serverless/entrypoint": "./dist/serverless/entrypoint.js", "./static": "./dist/static/adapter.js", - "./analytics": "./dist/analytics.js", + "./speed-insights": "./dist/speed-insights.js", "./build-image-service": "./dist/image/build-service.js", "./dev-image-service": "./dist/image/dev-service.js", + "./squoosh-dev-service": "./dist/image/squoosh-dev-service.js", "./package.json": "./package.json" }, "typesVersions": { @@ -60,7 +61,7 @@ "web-vitals": "^3.4.0" }, "peerDependencies": { - "astro": "workspace:^3.0.13" + "astro": "workspace:^3.1.0" }, "devDependencies": { "@types/set-cookie-parser": "^2.4.3", diff --git a/packages/integrations/vercel/src/image/build-service.ts b/packages/integrations/vercel/src/image/build-service.ts index 63a37a5fe..bd58d3af6 100644 --- a/packages/integrations/vercel/src/image/build-service.ts +++ b/packages/integrations/vercel/src/image/build-service.ts @@ -1,5 +1,5 @@ import type { ExternalImageService } from 'astro'; -import { isESMImportedImage, sharedValidateOptions } from './shared'; +import { isESMImportedImage, sharedValidateOptions } from './shared.js'; const service: ExternalImageService = { validateOptions: (options, serviceOptions) => @@ -40,8 +40,9 @@ const service: ExternalImageService = { }; }, getURL(options) { - const fileSrc = - typeof options.src === 'string' ? options.src : removeLeadingForwardSlash(options.src.src); + const fileSrc = isESMImportedImage(options.src) + ? removeLeadingForwardSlash(options.src.src) + : options.src; const searchParams = new URLSearchParams(); searchParams.append('url', fileSrc); diff --git a/packages/integrations/vercel/src/image/dev-service.ts b/packages/integrations/vercel/src/image/dev-service.ts index 72eb7ca0b..c9702cff9 100644 --- a/packages/integrations/vercel/src/image/dev-service.ts +++ b/packages/integrations/vercel/src/image/dev-service.ts @@ -1,10 +1,9 @@ import type { LocalImageService } from 'astro'; -import squooshService from 'astro/assets/services/squoosh'; -import { sharedValidateOptions } from './shared'; +import sharpService from 'astro/assets/services/sharp'; +import { baseDevService } from './shared-dev-service.js'; const service: LocalImageService = { - validateOptions: (options, serviceOptions) => - sharedValidateOptions(options, serviceOptions.service.config, 'development'), + ...baseDevService, getHTMLAttributes(options, serviceOptions) { const { inputtedWidth, ...props } = options; @@ -13,45 +12,19 @@ const service: LocalImageService = { props.width = inputtedWidth; } - return squooshService.getHTMLAttributes - ? squooshService.getHTMLAttributes(props, serviceOptions) + return sharpService.getHTMLAttributes + ? sharpService.getHTMLAttributes(props, serviceOptions) : {}; }, - getURL(options) { - const fileSrc = typeof options.src === 'string' ? options.src : options.src.src; - - const searchParams = new URLSearchParams(); - searchParams.append('href', fileSrc); - - options.width && searchParams.append('w', options.width.toString()); - options.quality && searchParams.append('q', options.quality.toString()); - - return '/_image?' + searchParams; - }, - parseURL(url) { - const params = url.searchParams; - - if (!params.has('href')) { - return undefined; - } - - const transform = { - src: params.get('href')!, - width: params.has('w') ? parseInt(params.get('w')!) : undefined, - quality: params.get('q'), - }; - - return transform; - }, transform(inputBuffer, transform, serviceOptions) { // NOTE: Hardcoding webp here isn't accurate to how the Vercel Image Optimization API works, normally what we should // do is setup a custom endpoint that sniff the user's accept-content header and serve the proper format based on the // user's Vercel config. However, that's: a lot of work for: not much. The dev service is inaccurate to the prod service // in many more ways, this is one of the less offending cases and is, imo, okay, erika - 2023-04-27 - transform.format = 'webp'; + transform.format = transform.src.endsWith('svg') ? 'svg' : 'webp'; - // The base Squoosh service works the same way as the Vercel Image Optimization API, so it's a safe fallback in local - return squooshService.transform(inputBuffer, transform, serviceOptions); + // The base sharp service works the same way as the Vercel Image Optimization API, so it's a safe fallback in local + return sharpService.transform(inputBuffer, transform, serviceOptions); }, }; diff --git a/packages/integrations/vercel/src/image/shared-dev-service.ts b/packages/integrations/vercel/src/image/shared-dev-service.ts new file mode 100644 index 000000000..4251603a7 --- /dev/null +++ b/packages/integrations/vercel/src/image/shared-dev-service.ts @@ -0,0 +1,33 @@ +import type { LocalImageService } from 'astro'; +import { sharedValidateOptions } from './shared.js'; + +export const baseDevService: Omit = { + validateOptions: (options, serviceOptions) => + sharedValidateOptions(options, serviceOptions.service.config, 'development'), + getURL(options) { + const fileSrc = typeof options.src === 'string' ? options.src : options.src.src; + + const searchParams = new URLSearchParams(); + searchParams.append('href', fileSrc); + + options.width && searchParams.append('w', options.width.toString()); + options.quality && searchParams.append('q', options.quality.toString()); + + return '/_image?' + searchParams; + }, + parseURL(url) { + const params = url.searchParams; + + if (!params.has('href')) { + return undefined; + } + + const transform = { + src: params.get('href')!, + width: params.has('w') ? parseInt(params.get('w')!) : undefined, + quality: params.get('q'), + }; + + return transform; + }, +}; diff --git a/packages/integrations/vercel/src/image/shared.ts b/packages/integrations/vercel/src/image/shared.ts index f6cace2a2..079186e18 100644 --- a/packages/integrations/vercel/src/image/shared.ts +++ b/packages/integrations/vercel/src/image/shared.ts @@ -12,6 +12,10 @@ export function getDefaultImageConfig(astroImageConfig: AstroConfig['image']): V export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata { return typeof src === 'object'; } + +// eslint-disable-next-line @typescript-eslint/ban-types +export type DevImageService = 'sharp' | 'squoosh' | (string & {}); + // https://vercel.com/docs/build-output-api/v3/configuration#images type ImageFormat = 'image/avif' | 'image/webp'; @@ -64,16 +68,32 @@ export function getAstroImageConfig( images: boolean | undefined, imagesConfig: VercelImageConfig | undefined, command: string, + devImageService: DevImageService, astroImageConfig: AstroConfig['image'] ) { + let devService = '@astrojs/vercel/dev-image-service'; + + switch (devImageService) { + case 'sharp': + devService = '@astrojs/vercel/dev-image-service'; + break; + case 'squoosh': + devService = '@astrojs/vercel/squoosh-dev-image-service'; + break; + default: + if (typeof devImageService === 'string') { + devService = devImageService; + } else { + devService = '@astrojs/vercel/dev-image-service'; + } + break; + } + if (images) { return { image: { service: { - entrypoint: - command === 'dev' - ? '@astrojs/vercel/dev-image-service' - : '@astrojs/vercel/build-image-service', + entrypoint: command === 'dev' ? devService : '@astrojs/vercel/build-image-service', config: imagesConfig ? imagesConfig : getDefaultImageConfig(astroImageConfig), }, }, diff --git a/packages/integrations/vercel/src/image/squoosh-dev-service.ts b/packages/integrations/vercel/src/image/squoosh-dev-service.ts new file mode 100644 index 000000000..d3b05bb11 --- /dev/null +++ b/packages/integrations/vercel/src/image/squoosh-dev-service.ts @@ -0,0 +1,31 @@ +import type { LocalImageService } from 'astro'; +import squooshService from 'astro/assets/services/squoosh'; +import { baseDevService } from './shared-dev-service.js'; + +const service: LocalImageService = { + ...baseDevService, + getHTMLAttributes(options, serviceOptions) { + const { inputtedWidth, ...props } = options; + + // If `validateOptions` returned a different width than the one of the image, use it for attributes + if (inputtedWidth) { + props.width = inputtedWidth; + } + + return squooshService.getHTMLAttributes + ? squooshService.getHTMLAttributes(props, serviceOptions) + : {}; + }, + transform(inputBuffer, transform, serviceOptions) { + // NOTE: Hardcoding webp here isn't accurate to how the Vercel Image Optimization API works, normally what we should + // do is setup a custom endpoint that sniff the user's accept-content header and serve the proper format based on the + // user's Vercel config. However, that's: a lot of work for: not much. The dev service is inaccurate to the prod service + // in many more ways, this is one of the less offending cases and is, imo, okay, erika - 2023-04-27 + transform.format = transform.src.endsWith('svg') ? 'svg' : 'webp'; + + // The base squoosh service works the same way as the Vercel Image Optimization API, so it's a safe fallback in local + return squooshService.transform(inputBuffer, transform, serviceOptions); + }, +}; + +export default service; diff --git a/packages/integrations/vercel/src/lib/env.ts b/packages/integrations/vercel/src/lib/speed-insights.ts similarity index 68% rename from packages/integrations/vercel/src/lib/env.ts rename to packages/integrations/vercel/src/lib/speed-insights.ts index 01d8c76a5..8e3639536 100644 --- a/packages/integrations/vercel/src/lib/env.ts +++ b/packages/integrations/vercel/src/lib/speed-insights.ts @@ -1,3 +1,17 @@ +export type VercelSpeedInsightsConfig = { + enabled: boolean; +}; + +export function getSpeedInsightsViteConfig(enabled?: boolean) { + if (enabled) { + return { + define: exposeEnv(['VERCEL_ANALYTICS_ID']), + }; + } + + return {}; +} + /** * While Vercel adds the `PUBLIC_` prefix for their `VERCEL_` env vars by default, some env vars * like `VERCEL_ANALYTICS_ID` aren't, so handle them here so that it works correctly in runtime. diff --git a/packages/integrations/vercel/src/lib/web-analytics.ts b/packages/integrations/vercel/src/lib/web-analytics.ts new file mode 100644 index 000000000..d6ee4d78d --- /dev/null +++ b/packages/integrations/vercel/src/lib/web-analytics.ts @@ -0,0 +1,30 @@ +export type VercelWebAnalyticsConfig = { + enabled: boolean; +}; + +export async function getInjectableWebAnalyticsContent({ + mode, +}: { + mode: 'development' | 'production'; +}) { + const base = `window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };`; + + if (mode === 'development') { + return ` + ${base} + var script = document.createElement('script'); + script.defer = true; + script.src = 'https://cdn.vercel-insights.com/v1/script.debug.js'; + var head = document.querySelector('head'); + head.appendChild(script); + `; + } + + return `${base} + var script = document.createElement('script'); + script.defer = true; + script.src = '/_vercel/insights/script.js'; + var head = document.querySelector('head'); + head.appendChild(script); + `; +} diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts index 1c0eb9530..88887fd3a 100644 --- a/packages/integrations/vercel/src/serverless/adapter.ts +++ b/packages/integrations/vercel/src/serverless/adapter.ts @@ -12,12 +12,20 @@ import { fileURLToPath, pathToFileURL } from 'node:url'; import { getAstroImageConfig, getDefaultImageConfig, + type DevImageService, type VercelImageConfig, } from '../image/shared.js'; -import { exposeEnv } from '../lib/env.js'; import { getVercelOutput, removeDir, writeJson } from '../lib/fs.js'; import { copyDependenciesToFunction } from '../lib/nft.js'; import { getRedirects } from '../lib/redirects.js'; +import { + getSpeedInsightsViteConfig, + type VercelSpeedInsightsConfig, +} from '../lib/speed-insights.js'; +import { + getInjectableWebAnalyticsContent, + type VercelWebAnalyticsConfig, +} from '../lib/web-analytics.js'; import { generateEdgeMiddleware } from './middleware.js'; const PACKAGE_NAME = '@astrojs/vercel/serverless'; @@ -63,22 +71,31 @@ function getAdapter({ } export interface VercelServerlessConfig { + /** + * @deprecated + */ + analytics?: boolean; + webAnalytics?: VercelWebAnalyticsConfig; + speedInsights?: VercelSpeedInsightsConfig; includeFiles?: string[]; excludeFiles?: string[]; - analytics?: boolean; imageService?: boolean; imagesConfig?: VercelImageConfig; + devImageService?: DevImageService; edgeMiddleware?: boolean; functionPerRoute?: boolean; } export default function vercelServerless({ + analytics, + webAnalytics, + speedInsights, includeFiles, excludeFiles, - analytics, imageService, imagesConfig, - functionPerRoute = true, + devImageService = 'sharp', + functionPerRoute = false, edgeMiddleware = false, }: VercelServerlessConfig = {}): AstroIntegration { let _config: AstroConfig; @@ -128,12 +145,25 @@ export default function vercelServerless({ return { name: PACKAGE_NAME, hooks: { - 'astro:config:setup': ({ command, config, updateConfig, injectScript }) => { - if (command === 'build' && analytics) { - injectScript('page', 'import "@astrojs/vercel/analytics"'); + 'astro:config:setup': async ({ command, config, updateConfig, injectScript, logger }) => { + if (webAnalytics?.enabled || analytics) { + if (analytics) { + logger.warn( + `The \`analytics\` property is deprecated. Please use the new \`webAnalytics\` and \`speedInsights\` properties instead.` + ); + } + + injectScript( + 'head-inline', + await getInjectableWebAnalyticsContent({ + mode: command === 'dev' ? 'development' : 'production', + }) + ); + } + if (command === 'build' && (speedInsights?.enabled || analytics)) { + injectScript('page', 'import "@astrojs/vercel/speed-insights"'); } const outDir = getVercelOutput(config.root); - const viteDefine = exposeEnv(['VERCEL_ANALYTICS_ID']); updateConfig({ outDir, build: { @@ -142,12 +172,18 @@ export default function vercelServerless({ server: new URL('./dist/', config.root), }, vite: { - define: viteDefine, + ...getSpeedInsightsViteConfig(speedInsights?.enabled || analytics), ssr: { external: ['@vercel/nft'], }, }, - ...getAstroImageConfig(imageService, imagesConfig, command, config.image), + ...getAstroImageConfig( + imageService, + imagesConfig, + command, + devImageService, + config.image + ), }); }, 'astro:config:done': ({ setAdapter, config, logger }) => { diff --git a/packages/integrations/vercel/src/serverless/entrypoint.ts b/packages/integrations/vercel/src/serverless/entrypoint.ts index f132d71f3..7b548dc37 100644 --- a/packages/integrations/vercel/src/serverless/entrypoint.ts +++ b/packages/integrations/vercel/src/serverless/entrypoint.ts @@ -3,8 +3,8 @@ import { App } from 'astro/app'; import { applyPolyfills } from 'astro/app/node'; import type { IncomingMessage, ServerResponse } from 'node:http'; -import { ASTRO_LOCALS_HEADER } from './adapter'; -import { getRequest, setResponse } from './request-transform'; +import { ASTRO_LOCALS_HEADER } from './adapter.js'; +import { getRequest, setResponse } from './request-transform.js'; applyPolyfills(); diff --git a/packages/integrations/vercel/src/analytics.ts b/packages/integrations/vercel/src/speed-insights.ts similarity index 60% rename from packages/integrations/vercel/src/analytics.ts rename to packages/integrations/vercel/src/speed-insights.ts index 95dee83e3..cd2ae7fe8 100644 --- a/packages/integrations/vercel/src/analytics.ts +++ b/packages/integrations/vercel/src/speed-insights.ts @@ -1,8 +1,7 @@ -import { inject } from '@vercel/analytics'; import type { Metric } from 'web-vitals'; -import { getCLS, getFCP, getFID, getLCP, getTTFB } from 'web-vitals'; +import { onCLS, onFCP, onFID, onLCP, onTTFB } from 'web-vitals'; -const vitalsUrl = 'https://vitals.vercel-analytics.com/v1/vitals'; +const SPEED_INSIGHTS_INTAKE = 'https://vitals.vercel-analytics.com/v1/vitals'; type Options = { path: string; analyticsId: string }; @@ -14,7 +13,7 @@ const getConnectionSpeed = () => { : ''; }; -const sendToAnalytics = (metric: Metric, options: Options) => { +const sendToSpeedInsights = (metric: Metric, options: Options) => { const body = { dsn: options.analyticsId, id: metric.id, @@ -28,9 +27,9 @@ const sendToAnalytics = (metric: Metric, options: Options) => { type: 'application/x-www-form-urlencoded', }); if (navigator.sendBeacon) { - navigator.sendBeacon(vitalsUrl, blob); + navigator.sendBeacon(SPEED_INSIGHTS_INTAKE, blob); } else - fetch(vitalsUrl, { + fetch(SPEED_INSIGHTS_INTAKE, { body: blob, method: 'POST', credentials: 'omit', @@ -38,27 +37,29 @@ const sendToAnalytics = (metric: Metric, options: Options) => { }); }; -function webVitals() { +function collectWebVitals() { const analyticsId = (import.meta as any).env.PUBLIC_VERCEL_ANALYTICS_ID; + if (!analyticsId) { - console.error('[Analytics] VERCEL_ANALYTICS_ID not found'); + console.error('[Speed Insights] VERCEL_ANALYTICS_ID not found'); return; } + const options: Options = { path: window.location.pathname, analyticsId }; + try { - getFID((metric) => sendToAnalytics(metric, options)); - getTTFB((metric) => sendToAnalytics(metric, options)); - getLCP((metric) => sendToAnalytics(metric, options)); - getCLS((metric) => sendToAnalytics(metric, options)); - getFCP((metric) => sendToAnalytics(metric, options)); + onFID((metric) => sendToSpeedInsights(metric, options)); + onTTFB((metric) => sendToSpeedInsights(metric, options)); + onLCP((metric) => sendToSpeedInsights(metric, options)); + onCLS((metric) => sendToSpeedInsights(metric, options)); + onFCP((metric) => sendToSpeedInsights(metric, options)); } catch (err) { - console.error('[Analytics]', err); + console.error('[Speed Insights]', err); } } const mode = (import.meta as any).env.MODE as 'development' | 'production'; -inject({ mode }); if (mode === 'production') { - webVitals(); + collectWebVitals(); } diff --git a/packages/integrations/vercel/src/static/adapter.ts b/packages/integrations/vercel/src/static/adapter.ts index 2908dbf58..df2995c37 100644 --- a/packages/integrations/vercel/src/static/adapter.ts +++ b/packages/integrations/vercel/src/static/adapter.ts @@ -3,12 +3,20 @@ import type { AstroAdapter, AstroConfig, AstroIntegration } from 'astro'; import { getAstroImageConfig, getDefaultImageConfig, + type DevImageService, type VercelImageConfig, } from '../image/shared.js'; -import { exposeEnv } from '../lib/env.js'; import { emptyDir, getVercelOutput, writeJson } from '../lib/fs.js'; import { isServerLikeOutput } from '../lib/prerender.js'; import { getRedirects } from '../lib/redirects.js'; +import { + getSpeedInsightsViteConfig, + type VercelSpeedInsightsConfig, +} from '../lib/speed-insights.js'; +import { + getInjectableWebAnalyticsContent, + type VercelWebAnalyticsConfig, +} from '../lib/web-analytics.js'; const PACKAGE_NAME = '@astrojs/vercel/static'; @@ -33,27 +41,49 @@ function getAdapter(): AstroAdapter { } export interface VercelStaticConfig { + /** + * @deprecated + */ analytics?: boolean; + webAnalytics?: VercelWebAnalyticsConfig; + speedInsights?: VercelSpeedInsightsConfig; imageService?: boolean; imagesConfig?: VercelImageConfig; + devImageService?: DevImageService; } export default function vercelStatic({ analytics, + webAnalytics, + speedInsights, imageService, imagesConfig, + devImageService = 'sharp', }: VercelStaticConfig = {}): AstroIntegration { let _config: AstroConfig; return { name: '@astrojs/vercel', hooks: { - 'astro:config:setup': ({ command, config, injectScript, updateConfig }) => { - if (command === 'build' && analytics) { - injectScript('page', 'import "@astrojs/vercel/analytics"'); + 'astro:config:setup': async ({ command, config, injectScript, updateConfig, logger }) => { + if (webAnalytics?.enabled || analytics) { + if (analytics) { + logger.warn( + `The \`analytics\` property is deprecated. Please use the new \`webAnalytics\` and \`speedInsights\` properties instead.` + ); + } + + injectScript( + 'head-inline', + await getInjectableWebAnalyticsContent({ + mode: command === 'dev' ? 'development' : 'production', + }) + ); + } + if (command === 'build' && (speedInsights?.enabled || analytics)) { + injectScript('page', 'import "@astrojs/vercel/speed-insights"'); } const outDir = new URL('./static/', getVercelOutput(config.root)); - const viteDefine = exposeEnv(['VERCEL_ANALYTICS_ID']); updateConfig({ outDir, build: { @@ -61,9 +91,15 @@ export default function vercelStatic({ redirects: false, }, vite: { - define: viteDefine, + ...getSpeedInsightsViteConfig(speedInsights?.enabled || analytics), }, - ...getAstroImageConfig(imageService, imagesConfig, command, config.image), + ...getAstroImageConfig( + imageService, + imagesConfig, + command, + devImageService, + config.image + ), }); }, 'astro:config:done': ({ setAdapter, config }) => { diff --git a/packages/integrations/vercel/src/types.d.ts b/packages/integrations/vercel/src/types.d.ts new file mode 100644 index 000000000..1c5b8d2db --- /dev/null +++ b/packages/integrations/vercel/src/types.d.ts @@ -0,0 +1,3 @@ +import type { AnalyticsProps } from '@vercel/analytics'; + +export type VercelWebAnalyticsBeforeSend = AnalyticsProps['beforeSend']; diff --git a/packages/integrations/vercel/test/fixtures/image/package.json b/packages/integrations/vercel/test/fixtures/image/package.json index ea9d554f5..87fefe2e0 100644 --- a/packages/integrations/vercel/test/fixtures/image/package.json +++ b/packages/integrations/vercel/test/fixtures/image/package.json @@ -2,6 +2,9 @@ "name": "@test/astro-vercel-image", "version": "0.0.0", "private": true, + "scripts": { + "dev": "astro dev" + }, "dependencies": { "@astrojs/vercel": "workspace:*", "astro": "workspace:*" diff --git a/packages/integrations/vercel/test/fixtures/image/src/assets/penguin.svg b/packages/integrations/vercel/test/fixtures/image/src/assets/penguin.svg new file mode 100644 index 000000000..341a0522f --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/image/src/assets/penguin.svg @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/integrations/vercel/test/fixtures/image/src/pages/index.astro b/packages/integrations/vercel/test/fixtures/image/src/pages/index.astro index 0a154874f..db7c22eeb 100644 --- a/packages/integrations/vercel/test/fixtures/image/src/pages/index.astro +++ b/packages/integrations/vercel/test/fixtures/image/src/pages/index.astro @@ -1,6 +1,13 @@ --- import { Image } from "astro:assets"; import astro from "../assets/astro.jpeg"; +import penguin from "../assets/penguin.svg"; --- -Astro +

+ Astro +
+ +
+ Astro +
diff --git a/packages/integrations/vercel/test/fixtures/serverless-with-dynamic-routes/astro.config.mjs b/packages/integrations/vercel/test/fixtures/serverless-with-dynamic-routes/astro.config.mjs index f5a86e609..da708f049 100644 --- a/packages/integrations/vercel/test/fixtures/serverless-with-dynamic-routes/astro.config.mjs +++ b/packages/integrations/vercel/test/fixtures/serverless-with-dynamic-routes/astro.config.mjs @@ -5,6 +5,7 @@ export default defineConfig({ adapter: vercel({ // Pass some value to make sure it doesn't error out includeFiles: ['included.js'], + functionPerRoute: true, }), output: 'server' }); diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/astro.config.mjs b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/astro.config.mjs new file mode 100644 index 000000000..b505034ce --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/serverless'; + +export default defineConfig({ + adapter: vercel({ + speedInsights: { + enabled: true + } + }) +}); diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/package.json b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/package.json new file mode 100644 index 000000000..4c6867fd3 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/astro-vercel-with-speed-insights-enabled-output-as-server", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vercel": "workspace:*", + "astro": "workspace:*" + } +} \ No newline at end of file diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/src/pages/one.astro b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/src/pages/one.astro new file mode 100644 index 000000000..0c7fb90a7 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/src/pages/one.astro @@ -0,0 +1,8 @@ + + + One + + +

One

+ + diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/src/pages/two.astro b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/src/pages/two.astro new file mode 100644 index 000000000..e7ba9910e --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server/src/pages/two.astro @@ -0,0 +1,8 @@ + + + Two + + +

Two

+ + diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/astro.config.mjs b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/astro.config.mjs new file mode 100644 index 000000000..a38f1e939 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/static'; + +export default defineConfig({ + adapter: vercel({ + speedInsights: { + enabled: true + } + }) +}); diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/package.json b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/package.json new file mode 100644 index 000000000..0022e1e92 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/astro-vercel-with-speed-insights-enabled-output-as-static", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vercel": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/src/pages/one.astro b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/src/pages/one.astro new file mode 100644 index 000000000..0c7fb90a7 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/src/pages/one.astro @@ -0,0 +1,8 @@ + + + One + + +

One

+ + diff --git a/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/src/pages/two.astro b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/src/pages/two.astro new file mode 100644 index 000000000..e7ba9910e --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static/src/pages/two.astro @@ -0,0 +1,8 @@ + + + Two + + +

Two

+ + diff --git a/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/astro.config.mjs b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/astro.config.mjs new file mode 100644 index 000000000..395cc9478 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/astro.config.mjs @@ -0,0 +1,10 @@ +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/static'; + +export default defineConfig({ + adapter: vercel({ + webAnalytics: { + enabled: true + } + }) +}); diff --git a/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/package.json b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/package.json new file mode 100644 index 000000000..c54ef16c7 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/astro-vercel-with-web-analytics-enabled-output-as-static", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/vercel": "workspace:*", + "astro": "workspace:*" + } +} diff --git a/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/src/pages/one.astro b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/src/pages/one.astro new file mode 100644 index 000000000..0c7fb90a7 --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/src/pages/one.astro @@ -0,0 +1,8 @@ + + + One + + +

One

+ + diff --git a/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/src/pages/two.astro b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/src/pages/two.astro new file mode 100644 index 000000000..e7ba9910e --- /dev/null +++ b/packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static/src/pages/two.astro @@ -0,0 +1,8 @@ + + + Two + + +

Two

+ + diff --git a/packages/integrations/vercel/test/image.test.js b/packages/integrations/vercel/test/image.test.js index c5153cc6e..b8bc3af95 100644 --- a/packages/integrations/vercel/test/image.test.js +++ b/packages/integrations/vercel/test/image.test.js @@ -20,7 +20,7 @@ describe('Image', () => { it('has link to vercel in build with proper attributes', async () => { const html = await fixture.readFile('../.vercel/output/static/index.html'); const $ = cheerio.load(html); - const img = $('img'); + const img = $('#basic-image img'); expect(img.attr('src').startsWith('/_vercel/image?url=_astr')).to.be.true; expect(img.attr('loading')).to.equal('lazy'); @@ -56,11 +56,22 @@ describe('Image', () => { it('has link to local image in dev with proper attributes', async () => { const html = await fixture.fetch('/').then((res) => res.text()); const $ = cheerio.load(html); - const img = $('img'); + const img = $('#basic-image img'); expect(img.attr('src').startsWith('/_image?href=')).to.be.true; expect(img.attr('loading')).to.equal('lazy'); expect(img.attr('width')).to.equal('225'); }); + + it('supports SVGs', async () => { + const html = await fixture.fetch('/').then((res) => res.text()); + const $ = cheerio.load(html); + const img = $('#svg img'); + const src = img.attr('src'); + + const res = await fixture.fetch(src); + expect(res.status).to.equal(200); + expect(res.headers.get('content-type')).to.equal('image/svg+xml'); + }); }); }); diff --git a/packages/integrations/vercel/test/speed-insights.test.js b/packages/integrations/vercel/test/speed-insights.test.js new file mode 100644 index 000000000..7cf2ae778 --- /dev/null +++ b/packages/integrations/vercel/test/speed-insights.test.js @@ -0,0 +1,46 @@ +import { loadFixture } from './test-utils.js'; +import { expect } from 'chai'; + +describe('Vercel Speed Insights', () => { + describe('output: server', () => { + /** @type {import('./test-utils.js').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/with-speed-insights-enabled/output-as-server/', + output: 'server', + }); + await fixture.build(); + }); + + it('ensures that Vercel Speed Insights is present in the bundle', async () => { + const [page] = await fixture.readdir('../.vercel/output/static/_astro'); + + const bundle = await fixture.readFile(`../.vercel/output/static/_astro/${page}`); + + expect(bundle).to.contain('https://vitals.vercel-analytics.com/v1/vitals'); + }); + }); + + describe('output: static', () => { + /** @type {import('./test-utils.js').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/with-speed-insights-enabled/output-as-static/', + output: 'static', + }); + await fixture.build(); + }); + + it('ensures that Vercel Speed Insights is present in the bundle', async () => { + const [page] = await fixture.readdir('../.vercel/output/static/_astro'); + + const bundle = await fixture.readFile(`../.vercel/output/static/_astro/${page}`); + + expect(bundle).to.contain('https://vitals.vercel-analytics.com/v1/vitals'); + }); + }); +}); diff --git a/packages/integrations/vercel/test/web-analytics.test.js b/packages/integrations/vercel/test/web-analytics.test.js new file mode 100644 index 000000000..b728fae4c --- /dev/null +++ b/packages/integrations/vercel/test/web-analytics.test.js @@ -0,0 +1,25 @@ +import { loadFixture } from './test-utils.js'; +import { expect } from 'chai'; + +describe('Vercel Web Analytics', () => { + describe('output: static', () => { + /** @type {import('./test-utils.js').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/with-web-analytics-enabled/output-as-static/', + output: 'static', + }); + await fixture.build(); + }); + + it('ensures that Vercel Web Analytics is present in the header', async () => { + const pageOne = await fixture.readFile('../.vercel/output/static/one/index.html'); + const pageTwo = await fixture.readFile('../.vercel/output/static/two/index.html'); + + expect(pageOne).to.contain('/_vercel/insights/script.js'); + expect(pageTwo).to.contain('/_vercel/insights/script.js'); + }); + }); +}); diff --git a/packages/integrations/vercel/tsconfig.json b/packages/integrations/vercel/tsconfig.json index af1b43564..1504b4b6d 100644 --- a/packages/integrations/vercel/tsconfig.json +++ b/packages/integrations/vercel/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", - "outDir": "./dist", - "target": "ES2022" + "outDir": "./dist" } } diff --git a/packages/integrations/vue/package.json b/packages/integrations/vue/package.json index 72d15470a..26d0dbe68 100644 --- a/packages/integrations/vue/package.json +++ b/packages/integrations/vue/package.json @@ -56,7 +56,7 @@ "vue": "^3.3.4" }, "peerDependencies": { - "astro": "workspace:^3.0.13", + "astro": "workspace:^3.1.0", "vue": "^3.2.30" }, "engines": { diff --git a/packages/integrations/vue/tsconfig.json b/packages/integrations/vue/tsconfig.json index af1b43564..5742d1f6e 100644 --- a/packages/integrations/vue/tsconfig.json +++ b/packages/integrations/vue/tsconfig.json @@ -2,9 +2,7 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "module": "ES2022", "outDir": "./dist", - "target": "ES2022" + "verbatimModuleSyntax": false } } diff --git a/packages/internal-helpers/tsconfig.json b/packages/internal-helpers/tsconfig.json index fd652e629..18443cddf 100644 --- a/packages/internal-helpers/tsconfig.json +++ b/packages/internal-helpers/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "target": "ES2022", - "module": "ES2022", "outDir": "./dist" } } diff --git a/packages/markdown/remark/CHANGELOG.md b/packages/markdown/remark/CHANGELOG.md index 13d1b95bb..a5a90e2bb 100644 --- a/packages/markdown/remark/CHANGELOG.md +++ b/packages/markdown/remark/CHANGELOG.md @@ -1,5 +1,18 @@ # @astrojs/markdown-remark +## 3.2.0 + +### Minor Changes + +- [#8475](https://github.com/withastro/astro/pull/8475) [`d93987824`](https://github.com/withastro/astro/commit/d93987824d3d6b4f58267be21ab8466ee8d5d5f8) Thanks [@webpro](https://github.com/webpro)! - feat(markdown): Add support for `imageReference` paths when collecting images + +- [#8532](https://github.com/withastro/astro/pull/8532) [`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644) Thanks [@bluwy](https://github.com/bluwy)! - Export `createMarkdownProcessor` and deprecate `renderMarkdown` API + +### Patch Changes + +- Updated dependencies [[`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644), [`ecc65abbf`](https://github.com/withastro/astro/commit/ecc65abbf9e086c5bbd1973cd4a820082b4e0dc5), [`2c4fc878b`](https://github.com/withastro/astro/commit/2c4fc878bece36b7fcf1470419c7ce6f1e1e95d0), [`c92e0acd7`](https://github.com/withastro/astro/commit/c92e0acd715171b3f4c3294099780e21576648c8), [`f95febf96`](https://github.com/withastro/astro/commit/f95febf96bb97babb28d78994332f5e47f5f637d), [`b85c8a78a`](https://github.com/withastro/astro/commit/b85c8a78a116dbbddc901438bc0b7a1917dc0238), [`45364c345`](https://github.com/withastro/astro/commit/45364c345267429e400baecd1fbc290503f8b13a)]: + - astro@3.1.0 + ## 3.1.0 ### Minor Changes diff --git a/packages/markdown/remark/package.json b/packages/markdown/remark/package.json index 8710cce08..d5bd3efae 100644 --- a/packages/markdown/remark/package.json +++ b/packages/markdown/remark/package.json @@ -1,6 +1,6 @@ { "name": "@astrojs/markdown-remark", - "version": "3.1.0", + "version": "3.2.0", "type": "module", "author": "withastro", "license": "MIT", @@ -28,12 +28,13 @@ "test": "mocha --exit --timeout 20000" }, "peerDependencies": { - "astro": "workspace:^3.0.11" + "astro": "workspace:^3.1.0" }, "dependencies": { "@astrojs/prism": "^3.0.0", "github-slugger": "^2.0.0", "import-meta-resolve": "^3.0.0", + "mdast-util-definitions": "^6.0.0", "rehype-raw": "^6.1.1", "rehype-stringify": "^9.0.4", "remark-gfm": "^3.0.1", diff --git a/packages/markdown/remark/src/frontmatter-injection.ts b/packages/markdown/remark/src/frontmatter-injection.ts index db1a2b704..4828873fd 100644 --- a/packages/markdown/remark/src/frontmatter-injection.ts +++ b/packages/markdown/remark/src/frontmatter-injection.ts @@ -27,6 +27,15 @@ export function safelyGetAstroData(vfileData: Data): MarkdownAstroData | Invalid return astro; } +export function setVfileFrontmatter(vfile: VFile, frontmatter: Record) { + vfile.data ??= {}; + vfile.data.astro ??= {}; + (vfile.data.astro as any).frontmatter = frontmatter; +} + +/** + * @deprecated Use `setVfileFrontmatter` instead + */ export function toRemarkInitializeAstroData({ userFrontmatter, }: { diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index c54826bdc..89c9ca8bd 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -1,11 +1,16 @@ import type { AstroMarkdownOptions, + MarkdownProcessor, MarkdownRenderingOptions, MarkdownRenderingResult, MarkdownVFile, -} from './types'; +} from './types.js'; -import { toRemarkInitializeAstroData } from './frontmatter-injection.js'; +import { + InvalidAstroDataError, + safelyGetAstroData, + setVfileFrontmatter, +} from './frontmatter-injection.js'; import { loadPlugins } from './load-plugins.js'; import { rehypeHeadingIds } from './rehype-collect-headings.js'; import { remarkCollectImages } from './remark-collect-images.js'; @@ -15,13 +20,14 @@ import { remarkShiki } from './remark-shiki.js'; import rehypeRaw from 'rehype-raw'; import rehypeStringify from 'rehype-stringify'; import remarkGfm from 'remark-gfm'; -import markdown from 'remark-parse'; -import markdownToHtml from 'remark-rehype'; +import remarkParse from 'remark-parse'; +import remarkRehype from 'remark-rehype'; import remarkSmartypants from 'remark-smartypants'; import { unified } from 'unified'; import { VFile } from 'vfile'; import { rehypeImages } from './rehype-images.js'; +export { InvalidAstroDataError, setVfileFrontmatter } from './frontmatter-injection.js'; export { rehypeHeadingIds } from './rehype-collect-headings.js'; export { remarkCollectImages } from './remark-collect-images.js'; export { remarkPrism } from './remark-prism.js'; @@ -45,30 +51,29 @@ export const markdownConfigDefaults: Omit, 'draft // Skip nonessential plugins during performance benchmark runs const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK); -/** Shared utility for rendering markdown */ -export async function renderMarkdown( - content: string, - opts: MarkdownRenderingOptions -): Promise { - let { - fileURL, +/** + * Create a markdown preprocessor to render multiple markdown files + */ +export async function createMarkdownProcessor( + opts?: AstroMarkdownOptions +): Promise { + const { syntaxHighlight = markdownConfigDefaults.syntaxHighlight, shikiConfig = markdownConfigDefaults.shikiConfig, remarkPlugins = markdownConfigDefaults.remarkPlugins, rehypePlugins = markdownConfigDefaults.rehypePlugins, - remarkRehype = markdownConfigDefaults.remarkRehype, + remarkRehype: remarkRehypeOptions = markdownConfigDefaults.remarkRehype, gfm = markdownConfigDefaults.gfm, smartypants = markdownConfigDefaults.smartypants, - frontmatter: userFrontmatter = {}, - } = opts; - const input = new VFile({ value: content, path: fileURL }); + } = opts ?? {}; - let parser = unified() - .use(markdown) - .use(toRemarkInitializeAstroData({ userFrontmatter })) - .use([]); + const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins)); + const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins)); - if (!isPerformanceBenchmark && gfm) { + const parser = unified().use(remarkParse); + + // gfm and smartypants + if (!isPerformanceBenchmark) { if (gfm) { parser.use(remarkGfm); } @@ -77,14 +82,13 @@ export async function renderMarkdown( } } - const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins)); - const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins)); - - loadedRemarkPlugins.forEach(([plugin, pluginOpts]) => { - parser.use([[plugin, pluginOpts]]); - }); + // User remark plugins + for (const [plugin, pluginOpts] of loadedRemarkPlugins) { + parser.use(plugin, pluginOpts); + } if (!isPerformanceBenchmark) { + // Syntax highlighting if (syntaxHighlight === 'shiki') { parser.use(remarkShiki, shikiConfig); } else if (syntaxHighlight === 'prism') { @@ -95,45 +99,88 @@ export async function renderMarkdown( parser.use(remarkCollectImages); } - parser.use([ - [ - markdownToHtml as any, - { - allowDangerousHtml: true, - passThrough: [], - ...remarkRehype, - }, - ], - ]); - - loadedRehypePlugins.forEach(([plugin, pluginOpts]) => { - parser.use([[plugin, pluginOpts]]); + // Remark -> Rehype + parser.use(remarkRehype as any, { + allowDangerousHtml: true, + passThrough: [], + ...remarkRehypeOptions, }); + // User rehype plugins + for (const [plugin, pluginOpts] of loadedRehypePlugins) { + parser.use(plugin, pluginOpts); + } + + // Images / Assets support parser.use(rehypeImages()); + + // Headings if (!isPerformanceBenchmark) { - parser.use([rehypeHeadingIds]); + parser.use(rehypeHeadingIds); } - parser.use([rehypeRaw]).use(rehypeStringify, { allowDangerousHtml: true }); + // Stringify to HTML + parser.use(rehypeRaw).use(rehypeStringify, { allowDangerousHtml: true }); - let vfile: MarkdownVFile; - try { - vfile = await parser.process(input); - } catch (err) { - // Ensure that the error message contains the input filename - // to make it easier for the user to fix the issue - err = prefixError(err, `Failed to parse Markdown file "${input.path}"`); - // eslint-disable-next-line no-console - console.error(err); - throw err; - } - - const headings = vfile?.data.__astroHeadings || []; return { - metadata: { headings, source: content, html: String(vfile.value) }, - code: String(vfile.value), - vfile, + async render(content, renderOpts) { + const vfile = new VFile({ value: content, path: renderOpts?.fileURL }); + setVfileFrontmatter(vfile, renderOpts?.frontmatter ?? {}); + + const result: MarkdownVFile = await parser.process(vfile).catch((err) => { + // Ensure that the error message contains the input filename + // to make it easier for the user to fix the issue + err = prefixError(err, `Failed to parse Markdown file "${vfile.path}"`); + // eslint-disable-next-line no-console + console.error(err); + throw err; + }); + + const astroData = safelyGetAstroData(result.data); + if (astroData instanceof InvalidAstroDataError) { + throw astroData; + } + + return { + code: String(result.value), + metadata: { + headings: result.data.__astroHeadings ?? [], + imagePaths: result.data.imagePaths ?? new Set(), + frontmatter: astroData.frontmatter ?? {}, + }, + // Compat for `renderMarkdown` only. Do not use! + __renderMarkdownCompat: { + result, + }, + }; + }, + }; +} + +/** + * Shared utility for rendering markdown + * + * @deprecated Use `createMarkdownProcessor` instead for better performance + */ +export async function renderMarkdown( + content: string, + opts: MarkdownRenderingOptions +): Promise { + const processor = await createMarkdownProcessor(opts); + + const result = await processor.render(content, { + fileURL: opts.fileURL, + frontmatter: opts.frontmatter, + }); + + return { + code: result.code, + metadata: { + headings: result.metadata.headings, + source: content, + html: result.code, + }, + vfile: (result as any).__renderMarkdownCompat.result, }; } diff --git a/packages/markdown/remark/src/load-plugins.ts b/packages/markdown/remark/src/load-plugins.ts index de6601e7d..8229ddff2 100644 --- a/packages/markdown/remark/src/load-plugins.ts +++ b/packages/markdown/remark/src/load-plugins.ts @@ -14,7 +14,7 @@ async function importPlugin(p: string | unified.Plugin): Promise } catch {} // Try import from user project - const resolved = await importMetaResolve(p, cwdUrlStr); + const resolved = importMetaResolve(p, cwdUrlStr); const importResult = await import(resolved); return importResult.default; } diff --git a/packages/markdown/remark/src/remark-collect-images.ts b/packages/markdown/remark/src/remark-collect-images.ts index a9f524f7a..cfce51376 100644 --- a/packages/markdown/remark/src/remark-collect-images.ts +++ b/packages/markdown/remark/src/remark-collect-images.ts @@ -1,14 +1,24 @@ -import type { Image } from 'mdast'; +import type { Image, ImageReference } from 'mdast'; +import { definitions } from 'mdast-util-definitions'; import { visit } from 'unist-util-visit'; -import type { MarkdownVFile } from './types'; +import type { MarkdownVFile } from './types.js'; export function remarkCollectImages() { return function (tree: any, vfile: MarkdownVFile) { if (typeof vfile?.path !== 'string') return; + const definition = definitions(tree); const imagePaths = new Set(); - visit(tree, 'image', (node: Image) => { - if (shouldOptimizeImage(node.url)) imagePaths.add(node.url); + 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); + } + } }); vfile.data.imagePaths = imagePaths; diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index caeebec93..bcab97041 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -58,13 +58,33 @@ export interface ImageMetadata { type: string; } -export interface MarkdownRenderingOptions extends AstroMarkdownOptions { +export interface MarkdownProcessor { + render: ( + content: string, + opts?: MarkdownProcessorRenderOptions + ) => Promise; +} + +export interface MarkdownProcessorRenderOptions { /** @internal */ fileURL?: URL; /** Used for frontmatter injection plugins */ frontmatter?: Record; } +export interface MarkdownProcessorRenderResult { + code: string; + metadata: { + headings: MarkdownHeading[]; + imagePaths: Set; + frontmatter: Record; + }; +} + +export interface MarkdownRenderingOptions + extends AstroMarkdownOptions, + MarkdownProcessorRenderOptions {} + export interface MarkdownHeading { depth: number; slug: string; diff --git a/packages/markdown/remark/test/autolinking.test.js b/packages/markdown/remark/test/autolinking.test.js index b1e567bb4..79d3ea767 100644 --- a/packages/markdown/remark/test/autolinking.test.js +++ b/packages/markdown/remark/test/autolinking.test.js @@ -1,14 +1,12 @@ -import { renderMarkdown } from '../dist/index.js'; +import { createMarkdownProcessor } from '../dist/index.js'; import chai from 'chai'; -import { mockRenderMarkdownParams } from './test-utils.js'; describe('autolinking', () => { - describe('plain md', () => { + describe('plain md', async () => { + const processor = await createMarkdownProcessor(); + it('autolinks URLs starting with a protocol in plain text', async () => { - const { code } = await renderMarkdown( - `See https://example.com for more.`, - mockRenderMarkdownParams - ); + const { code } = await processor.render(`See https://example.com for more.`); chai .expect(code.replace(/\n/g, '')) @@ -16,10 +14,7 @@ describe('autolinking', () => { }); it('autolinks URLs starting with "www." in plain text', async () => { - const { code } = await renderMarkdown( - `See www.example.com for more.`, - mockRenderMarkdownParams - ); + const { code } = await processor.render(`See www.example.com for more.`); chai .expect(code.trim()) @@ -27,9 +22,8 @@ describe('autolinking', () => { }); it('does not autolink URLs in code blocks', async () => { - const { code } = await renderMarkdown( - 'See `https://example.com` or `www.example.com` for more.', - mockRenderMarkdownParams + const { code } = await processor.render( + 'See `https://example.com` or `www.example.com` for more.' ); chai diff --git a/packages/markdown/remark/test/entities.test.js b/packages/markdown/remark/test/entities.test.js index acaf71be1..b2dacb79f 100644 --- a/packages/markdown/remark/test/entities.test.js +++ b/packages/markdown/remark/test/entities.test.js @@ -1,13 +1,11 @@ -import { renderMarkdown } from '../dist/index.js'; +import { createMarkdownProcessor } from '../dist/index.js'; import { expect } from 'chai'; -import { mockRenderMarkdownParams } from './test-utils.js'; -describe('entities', () => { +describe('entities', async () => { + const processor = await createMarkdownProcessor(); + it('should not unescape entities in regular Markdown', async () => { - const { code } = await renderMarkdown( - `<i>This should NOT be italic</i>`, - mockRenderMarkdownParams - ); + const { code } = await processor.render(`<i>This should NOT be italic</i>`); expect(code).to.equal(`

<i>This should NOT be italic</i>

`); }); diff --git a/packages/markdown/remark/test/plugins.test.js b/packages/markdown/remark/test/plugins.test.js index 35e5dcaf8..ce2401047 100644 --- a/packages/markdown/remark/test/plugins.test.js +++ b/packages/markdown/remark/test/plugins.test.js @@ -1,5 +1,4 @@ -import { renderMarkdown } from '../dist/index.js'; -import { mockRenderMarkdownParams } from './test-utils.js'; +import { createMarkdownProcessor } from '../dist/index.js'; import chai from 'chai'; import { fileURLToPath } from 'node:url'; @@ -8,9 +7,8 @@ describe('plugins', () => { // https://github.com/withastro/astro/issues/3264 it('should be able to get file path when passing fileURL', async () => { let context; - await renderMarkdown(`test`, { - ...mockRenderMarkdownParams, - fileURL: new URL('virtual.md', import.meta.url), + + const processor = await createMarkdownProcessor({ remarkPlugins: [ function () { const transformer = (tree, file) => { @@ -22,6 +20,10 @@ describe('plugins', () => { ], }); + await processor.render(`test`, { + fileURL: new URL('virtual.md', import.meta.url), + }); + chai.expect(typeof context).to.equal('object'); chai.expect(context.path).to.equal(fileURLToPath(new URL('virtual.md', import.meta.url))); }); diff --git a/packages/markdown/remark/test/remark-collect-images.test.js b/packages/markdown/remark/test/remark-collect-images.test.js new file mode 100644 index 000000000..a55336953 --- /dev/null +++ b/packages/markdown/remark/test/remark-collect-images.test.js @@ -0,0 +1,33 @@ +import { createMarkdownProcessor } from '../dist/index.js'; +import chai from 'chai'; + +describe('collect images', async () => { + const processor = await createMarkdownProcessor(); + + it('should collect inline image paths', async () => { + const { + code, + metadata: { imagePaths }, + } = await processor.render(`Hello ![inline image url](./img.png)`, { + fileURL: 'file.md', + }); + + chai + .expect(code) + .to.equal('

Hello inline image url

'); + + chai.expect(Array.from(imagePaths)).to.deep.equal(['./img.png']); + }); + + it('should add image paths from definition', async () => { + const { + code, + metadata: { imagePaths }, + } = await processor.render(`Hello ![image ref][img-ref]\n\n[img-ref]: ./img.webp`, { + fileURL: 'file.md', + }); + + chai.expect(code).to.equal('

Hello image ref

'); + chai.expect(Array.from(imagePaths)).to.deep.equal(['./img.webp']); + }); +}); diff --git a/packages/markdown/remark/test/test-utils.js b/packages/markdown/remark/test/test-utils.js deleted file mode 100644 index 10b779a7d..000000000 --- a/packages/markdown/remark/test/test-utils.js +++ /dev/null @@ -1,3 +0,0 @@ -export const mockRenderMarkdownParams = { - contentDir: new URL('file:///src/content/'), -}; diff --git a/packages/markdown/remark/tsconfig.json b/packages/markdown/remark/tsconfig.json index 9a8c6d8cb..1504b4b6d 100644 --- a/packages/markdown/remark/tsconfig.json +++ b/packages/markdown/remark/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "target": "ES2022", - "module": "ES2022", "outDir": "./dist" } } diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index 8f8a634bf..d4082091d 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -2,7 +2,7 @@ "name": "@astrojs/telemetry", "version": "3.0.1", "type": "module", - "types": "./dist/types/index.d.ts", + "types": "./dist/index.d.ts", "author": "withastro", "license": "MIT", "repository": { @@ -14,7 +14,7 @@ "homepage": "https://astro.build", "exports": { ".": { - "types": "./dist/types/index.d.ts", + "types": "./dist/index.d.ts", "default": "./dist/index.js" }, "./package.json": "./package.json" diff --git a/packages/telemetry/tsconfig.json b/packages/telemetry/tsconfig.json index 451badc02..18443cddf 100644 --- a/packages/telemetry/tsconfig.json +++ b/packages/telemetry/tsconfig.json @@ -2,10 +2,6 @@ "extends": "../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "target": "ES2022", - "module": "ES2022", - "outDir": "./dist", - "declarationDir": "./dist/types" + "outDir": "./dist" } } diff --git a/packages/underscore-redirects/src/print.ts b/packages/underscore-redirects/src/print.ts index 5d7bd2387..2a9bec257 100644 --- a/packages/underscore-redirects/src/print.ts +++ b/packages/underscore-redirects/src/print.ts @@ -1,4 +1,4 @@ -import type { RedirectDefinition } from './redirects'; +import type { RedirectDefinition } from './redirects.js'; /** * Pretty print a list of definitions into the output format. Keeps diff --git a/packages/underscore-redirects/tsconfig.json b/packages/underscore-redirects/tsconfig.json index fd652e629..18443cddf 100644 --- a/packages/underscore-redirects/tsconfig.json +++ b/packages/underscore-redirects/tsconfig.json @@ -2,9 +2,6 @@ "extends": "../../tsconfig.base.json", "include": ["src"], "compilerOptions": { - "allowJs": true, - "target": "ES2022", - "module": "ES2022", "outDir": "./dist" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 14c65973d..a808d04ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,13 +125,13 @@ importers: examples/basics: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/blog: dependencies: '@astrojs/mdx': - specifier: ^1.0.3 + specifier: ^1.1.0 version: link:../../packages/integrations/mdx '@astrojs/rss': specifier: ^3.0.0 @@ -140,19 +140,19 @@ importers: specifier: ^3.0.0 version: link:../../packages/integrations/sitemap astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/component: devDependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/deno: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro devDependencies: '@astrojs/deno': @@ -171,7 +171,7 @@ importers: specifier: ^3.12.3 version: 3.12.3 astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/framework-lit: @@ -183,7 +183,7 @@ importers: specifier: ^0.2.1 version: 0.2.1 astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro lit: specifier: ^2.8.0 @@ -207,7 +207,7 @@ importers: specifier: ^3.0.0 version: link:../../packages/integrations/vue astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro preact: specifier: ^10.17.1 @@ -237,7 +237,7 @@ importers: specifier: ^1.2.1 version: 1.2.1(preact@10.17.1) astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro preact: specifier: ^10.17.1 @@ -255,7 +255,7 @@ importers: specifier: ^18.2.7 version: 18.2.7 astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro react: specifier: ^18.2.0 @@ -270,7 +270,7 @@ importers: specifier: ^3.0.1 version: link:../../packages/integrations/solid astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro solid-js: specifier: ^1.7.11 @@ -282,7 +282,7 @@ importers: specifier: ^4.0.2 version: link:../../packages/integrations/svelte astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro svelte: specifier: ^4.2.0 @@ -294,7 +294,7 @@ importers: specifier: ^3.0.0 version: link:../../packages/integrations/vue astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro vue: specifier: ^3.3.4 @@ -306,13 +306,13 @@ importers: specifier: ^6.0.0 version: link:../../packages/integrations/node astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/integration: devDependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/middleware: @@ -321,7 +321,7 @@ importers: specifier: ^6.0.0 version: link:../../packages/integrations/node astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro html-minifier: specifier: ^4.0.0 @@ -330,19 +330,19 @@ importers: examples/minimal: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/non-html-pages: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/portfolio: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/ssr: @@ -354,7 +354,7 @@ importers: specifier: ^4.0.2 version: link:../../packages/integrations/svelte astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro svelte: specifier: ^4.2.0 @@ -366,16 +366,16 @@ importers: specifier: ^0.5.0 version: link:../../packages/integrations/markdoc astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/with-markdown-plugins: dependencies: '@astrojs/markdown-remark': - specifier: ^3.1.0 + specifier: ^3.2.0 version: link:../../packages/markdown/remark astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro hast-util-select: specifier: ^5.0.5 @@ -396,19 +396,19 @@ importers: examples/with-markdown-shiki: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro examples/with-mdx: dependencies: '@astrojs/mdx': - specifier: ^1.0.3 + specifier: ^1.1.0 version: link:../../packages/integrations/mdx '@astrojs/preact': specifier: ^3.0.0 version: link:../../packages/integrations/preact astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro preact: specifier: ^10.17.1 @@ -423,7 +423,7 @@ importers: specifier: ^0.5.0 version: 0.5.0(nanostores@0.9.3)(preact@10.17.1) astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro nanostores: specifier: ^0.9.3 @@ -435,7 +435,7 @@ importers: examples/with-tailwindcss: dependencies: '@astrojs/mdx': - specifier: ^1.0.3 + specifier: ^1.1.0 version: link:../../packages/integrations/mdx '@astrojs/tailwind': specifier: ^5.0.0 @@ -444,7 +444,7 @@ importers: specifier: ^1.6.0 version: 1.6.0 astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro autoprefixer: specifier: ^10.4.15 @@ -462,7 +462,7 @@ importers: examples/with-vite-plugin-pwa: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro vite-plugin-pwa: specifier: 0.16.4 @@ -474,7 +474,7 @@ importers: examples/with-vitest: dependencies: astro: - specifier: ^3.0.13 + specifier: ^3.1.0 version: link:../../packages/astro vitest: specifier: ^0.34.2 @@ -596,6 +596,9 @@ importers: preferred-pm: specifier: ^3.1.2 version: 3.1.2 + probe-image-size: + specifier: ^7.2.3 + version: 7.2.3 prompts: specifier: ^2.4.2 version: 2.4.2 @@ -706,6 +709,9 @@ importers: '@types/mocha': specifier: ^10.0.1 version: 10.0.1 + '@types/probe-image-size': + specifier: ^7.2.0 + version: 7.2.0 '@types/prompts': specifier: ^2.4.4 version: 2.4.4 @@ -3566,24 +3572,12 @@ importers: packages/create-astro: dependencies: '@astrojs/cli-kit': - specifier: ^0.2.3 - version: 0.2.3 - execa: - specifier: ^8.0.1 - version: 8.0.1 + specifier: ^0.3.0 + version: 0.3.0 giget: specifier: 1.1.2 version: 1.1.2 - node-fetch-native: - specifier: ^1.4.0 - version: 1.4.0 - which-pm-runs: - specifier: ^1.1.0 - version: 1.1.0 devDependencies: - '@types/which-pm-runs': - specifier: ^1.0.0 - version: 1.0.0 arg: specifier: ^5.0.2 version: 5.0.2 @@ -3647,6 +3641,9 @@ importers: specifier: ^0.2.9 version: 0.2.9 devDependencies: + '@types/iarna__toml': + specifier: ^2.0.2 + version: 2.0.2 astro: specifier: workspace:* version: link:../../astro @@ -4111,6 +4108,9 @@ importers: remark-toc: specifier: ^8.0.1 version: 8.0.1 + unified: + specifier: ^10.1.2 + version: 10.1.2 vite: specifier: ^4.4.9 version: 4.4.9(@types/node@18.17.8)(sass@1.66.1) @@ -4843,6 +4843,33 @@ importers: specifier: workspace:* version: link:../../../../../astro + packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-server: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../../.. + astro: + specifier: workspace:* + version: link:../../../../../../astro + + packages/integrations/vercel/test/fixtures/with-speed-insights-enabled/output-as-static: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../../.. + astro: + specifier: workspace:* + version: link:../../../../../../astro + + packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../../.. + astro: + specifier: workspace:* + version: link:../../../../../../astro + packages/integrations/vercel/test/hosted/hosted-astro-project: dependencies: '@astrojs/vercel': @@ -4921,6 +4948,9 @@ importers: import-meta-resolve: specifier: ^3.0.0 version: 3.0.0 + mdast-util-definitions: + specifier: ^6.0.0 + version: 6.0.0 rehype-raw: specifier: ^6.1.1 version: 6.1.1 @@ -5213,8 +5243,9 @@ packages: - prettier-plugin-astro dev: true - /@astrojs/cli-kit@0.2.3: - resolution: {integrity: sha512-MjB42mpIG/F2rFtdp4f3NylFCILuFSib2yITSq65fRaDFn8+UC8EMh6T7Jr3YqHAbUY5r8V8QWNgH4keOEO2BA==} + /@astrojs/cli-kit@0.3.0: + resolution: {integrity: sha512-nil0Kz2xuzR3xQX+FVHg2W8g+FvbeUeoCeU53duQjAFuHRJrbqWRmgfjYeM6f2780dsSuGiYMXmY+IaJqaqiaw==} + engines: {node: '>=18.14.1'} dependencies: chalk: 5.3.0 log-update: 5.0.1 @@ -8834,6 +8865,12 @@ packages: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: true + /@types/iarna__toml@2.0.2: + resolution: {integrity: sha512-Q3obxKhBLVVbEQ8zsAmsQVobAAZhi8dFFFjF0q5xKXiaHvH8IkSxcbM27e46M9feUMieR03SPpmp5CtaNzpdBg==} + dependencies: + '@types/node': 18.17.8 + dev: true + /@types/is-ci@3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: @@ -8915,6 +8952,12 @@ packages: /@types/ms@0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + /@types/needle@3.2.0: + resolution: {integrity: sha512-6XzvzEyJ2ozFNfPajFmqH9JOt0Hp+9TawaYpJT59iIP/zR0U37cfWCRwosyIeEBBZBi021Osq4jGAD3AOju5fg==} + dependencies: + '@types/node': 18.17.8 + dev: true + /@types/nlcst@1.0.0: resolution: {integrity: sha512-3TGCfOcy8R8mMQ4CNSNOe3PG66HttvjcLzCoOpvXvDtfWOTi+uT/rxeOKm/qEwbM4SNe1O/PjdiBK2YcTjU4OQ==} dependencies: @@ -8956,6 +8999,13 @@ packages: resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==} dev: true + /@types/probe-image-size@7.2.0: + resolution: {integrity: sha512-R5H3vw62gHNHrn+JGZbKejb+Z2D/6E5UNVlhCzIaBBLroMQMOFqy5Pap2gM+ZZHdqBtVU0/cx/M6to+mOJcoew==} + dependencies: + '@types/needle': 3.2.0 + '@types/node': 18.17.8 + dev: true + /@types/prompts@2.4.4: resolution: {integrity: sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A==} dependencies: @@ -10775,6 +10825,17 @@ packages: dependencies: ms: 2.0.0 + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -12537,7 +12598,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: true /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -13268,7 +13328,6 @@ packages: /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true /lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} @@ -13424,6 +13483,14 @@ packages: '@types/unist': 2.0.7 unist-util-visit: 4.1.2 + /mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + dependencies: + '@types/mdast': 4.0.0 + '@types/unist': 3.0.0 + unist-util-visit: 5.0.0 + dev: false + /mdast-util-find-and-replace@2.2.2: resolution: {integrity: sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==} dependencies: @@ -14354,6 +14421,18 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /needle@2.9.1: + resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + dependencies: + debug: 3.2.7 + iconv-lite: 0.4.24 + sax: 1.2.4 + transitivePeerDependencies: + - supports-color + dev: false + /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -15451,6 +15530,16 @@ packages: engines: {node: '>=6'} dev: false + /probe-image-size@7.2.3: + resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==} + dependencies: + lodash.merge: 4.6.2 + needle: 2.9.1 + stream-parser: 0.3.1 + transitivePeerDependencies: + - supports-color + dev: false + /progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -16085,7 +16174,6 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true /sass-formatter@0.7.7: resolution: {integrity: sha512-axtQ7c7Cf4UgHsD8e4okhIkkc90+tdgBIfUMx69+qJuMNq9EOo2k+RH/mDKj0XeA5z3nC1Ca5TCntuxRhI+1MA==} @@ -16505,6 +16593,14 @@ packages: engines: {node: '>=4', npm: '>=6'} dev: true + /stream-parser@0.3.1: + resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + dev: false + /stream-transform@2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: diff --git a/tsconfig.base.json b/tsconfig.base.json index 337005ad4..0349af8a1 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,10 +1,12 @@ { + "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "declaration": true, "emitDeclarationOnly": true, "strict": true, - // All packages are built with ESBuild, so we can use `moduleResolution: 'bundler'` - "moduleResolution": "Bundler", + "moduleResolution": "Node16", + "target": "ES2022", + "module": "Node16", "esModuleInterop": true, "skipLibCheck": true, "verbatimModuleSyntax": true