Compare commits
13 commits
main
...
feat/pictu
Author | SHA1 | Date | |
---|---|---|---|
|
bfe8e09ba6 | ||
|
fc86fdf0c3 | ||
|
73a06292bc | ||
|
2022ce5b87 | ||
|
dc21d085ec | ||
|
db0c862440 | ||
|
7398d63331 | ||
|
3809a452ae | ||
|
050143da64 | ||
|
207edd65ec | ||
|
83eac94b38 | ||
|
cccd165d75 | ||
|
77f7774010 |
99 changed files with 693 additions and 572 deletions
8
.Dockerfile
Normal file
8
.Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
FROM gitpod/workspace-node
|
||||||
|
|
||||||
|
# Install latest pnpm
|
||||||
|
RUN curl -fsSL https://get.pnpm.io/install.sh | SHELL=`which bash` bash -
|
||||||
|
|
||||||
|
# Install deno in gitpod
|
||||||
|
RUN curl -fsSL https://deno.land/x/install/install.sh | sh
|
||||||
|
RUN /home/gitpod/.deno/bin/deno completions bash > /home/gitpod/.bashrc.d/90-deno && echo 'export DENO_INSTALL="/home/gitpod/.deno"' >> /home/gitpod/.bashrc.d/90-deno && echo 'export PATH="$DENO_INSTALL/bin:$PATH"' >> /home/gitpod/.bashrc.d/90-deno
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
'astro': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Fixed an issue where the transitions router did not work within framework components.
|
|
49
.changeset/smooth-goats-agree.md
Normal file
49
.changeset/smooth-goats-agree.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
'astro': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add support for generating multiple widths when using the Image component and a Picture component for supporting multiple formats.
|
||||||
|
|
||||||
|
## `srcset` support
|
||||||
|
|
||||||
|
Two new properties have been added to `Image` and `getImage`: `densities` and `widths`.
|
||||||
|
|
||||||
|
These props can be used to generate a `srcset` attribute with multiple sources. For example:
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import { Image } from "astro";
|
||||||
|
import myImage from "./my-image.jpg";
|
||||||
|
---
|
||||||
|
|
||||||
|
<Image src={myImage} width={myImage.width / 2} densities={[2]} alt="My cool image" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<img src="..." srcset="... 2x, ... 3x" alt="My cool image" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Picture component
|
||||||
|
|
||||||
|
The `Picture` component can be used to generate a `<picture>` element with multiple sources. It can be used as follow:
|
||||||
|
|
||||||
|
```astro
|
||||||
|
---
|
||||||
|
import { Picture } from "astro:assets";
|
||||||
|
import myImage from "./my-image.jpg";
|
||||||
|
---
|
||||||
|
|
||||||
|
<Picture src={myImage} formats={["avif", "webp"]} alt="My super image in multiple formats!" />
|
||||||
|
```
|
||||||
|
|
||||||
|
The above code will generate the following:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<picture>
|
||||||
|
<source srcset="..." type="image/avif" />
|
||||||
|
<source srcset="..." type="image/webp" />
|
||||||
|
<img src="..." alt="My super image in multiple formats!" />
|
||||||
|
</picture>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Picture` component takes all the same props as the `Image` component, including the new `densities` and `widths` properties.
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
'@astrojs/cloudflare': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
fixes `AdvancedRuntime` & `DirectoryRuntime` types to work woth Cloudflare caches
|
|
|
@ -6,6 +6,10 @@ RUN npm install -g @playwright/test
|
||||||
# Install latest pnpm
|
# Install latest pnpm
|
||||||
RUN npm install -g pnpm
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Install deno
|
||||||
|
ENV DENO_INSTALL=/usr/local
|
||||||
|
RUN curl -fsSL https://deno.land/x/install/install.sh | sh
|
||||||
|
|
||||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
&& curl -sSL https://dl.google.com/linux/direct/google-chrome-stable_current_$(dpkg --print-architecture).deb -o /tmp/chrome.deb \
|
&& curl -sSL https://dl.google.com/linux/direct/google-chrome-stable_current_$(dpkg --print-architecture).deb -o /tmp/chrome.deb \
|
||||||
&& apt-get -y install /tmp/chrome.deb
|
&& apt-get -y install /tmp/chrome.deb
|
||||||
|
|
34
.devcontainer/deno/devcontainer.json
Normal file
34
.devcontainer/deno/devcontainer.json
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"name": "Deno",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "../examples.deno.Dockerfile"
|
||||||
|
},
|
||||||
|
|
||||||
|
"workspaceFolder": "/workspaces/astro/examples/deno",
|
||||||
|
|
||||||
|
"portsAttributes": {
|
||||||
|
"4321": {
|
||||||
|
"label": "Application",
|
||||||
|
"onAutoForward": "openPreview"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"forwardPorts": [4321],
|
||||||
|
|
||||||
|
"postCreateCommand": "pnpm install && cd /workspaces/astro && pnpm run build",
|
||||||
|
|
||||||
|
"waitFor": "postCreateCommand",
|
||||||
|
|
||||||
|
"postAttachCommand": {
|
||||||
|
"Server": "pnpm start --host"
|
||||||
|
},
|
||||||
|
|
||||||
|
"customizations": {
|
||||||
|
"codespaces": {
|
||||||
|
"openFiles": ["src/pages/index.astro"]
|
||||||
|
},
|
||||||
|
"vscode": {
|
||||||
|
"extensions": ["astro-build.astro-vscode", "esbenp.prettier-vscode"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
.devcontainer/examples.deno.Dockerfile
Normal file
10
.devcontainer/examples.deno.Dockerfile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
FROM mcr.microsoft.com/devcontainers/javascript-node:0-18
|
||||||
|
|
||||||
|
# Install latest pnpm
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Install deno
|
||||||
|
ENV DENO_INSTALL=/usr/local
|
||||||
|
RUN curl -fsSL https://deno.land/x/install/install.sh | sh
|
||||||
|
|
||||||
|
COPY example-welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt
|
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
|
@ -133,6 +133,11 @@ jobs:
|
||||||
node-version: ${{ matrix.NODE_VERSION }}
|
node-version: ${{ matrix.NODE_VERSION }}
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: Use Deno
|
||||||
|
uses: denoland/setup-deno@v1
|
||||||
|
with:
|
||||||
|
deno-version: v1.35.0
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
|
|
||||||
|
|
5
.github/workflows/snapshot-release.yml
vendored
5
.github/workflows/snapshot-release.yml
vendored
|
@ -19,11 +19,6 @@ jobs:
|
||||||
name: Create a snapshot release of a pull request
|
name: Create a snapshot release of a pull request
|
||||||
if: ${{ github.repository_owner == 'withastro' && github.event.issue.pull_request && startsWith(github.event.comment.body, '!preview') }}
|
if: ${{ github.repository_owner == 'withastro' && github.event.issue.pull_request && startsWith(github.event.comment.body, '!preview') }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
id-token: write
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Check if user has admin access (only admins can publish snapshot releases)."
|
- name: "Check if user has admin access (only admins can publish snapshot releases)."
|
||||||
uses: "lannonbr/repo-permission-check-action@2.0.0"
|
uses: "lannonbr/repo-permission-check-action@2.0.0"
|
||||||
|
|
18
.github/workflows/test-hosts.yml
vendored
18
.github/workflows/test-hosts.yml
vendored
|
@ -11,6 +11,8 @@ env:
|
||||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_TEST_ORG_ID }}
|
VERCEL_ORG_ID: ${{ secrets.VERCEL_TEST_ORG_ID }}
|
||||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_TEST_PROJECT_ID }}
|
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_TEST_PROJECT_ID }}
|
||||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
|
VERCEL_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
|
||||||
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_TEST_SITE_ID }}
|
||||||
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TEST_AUTH_TOKEN }}
|
||||||
FORCE_COLOR: true
|
FORCE_COLOR: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -33,19 +35,21 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
|
|
||||||
- name: Build Astro
|
- name: Install Hosts CLIs
|
||||||
run: pnpm turbo build --filter astro --filter @astrojs/vercel
|
run: pnpm install --global netlify-cli vercel
|
||||||
|
|
||||||
- name: Build test project
|
- name: Deploy Vercel
|
||||||
working-directory: ./packages/integrations/vercel/test/hosted/hosted-astro-project
|
working-directory: ./packages/integrations/vercel/test/hosted/hosted-astro-project
|
||||||
run:
|
run:
|
||||||
pnpm run build
|
pnpm run build
|
||||||
|
vercel --prod --prebuilt
|
||||||
|
|
||||||
- name: Deploy to Vercel
|
- name: Deploy Netlify
|
||||||
working-directory: ./packages/integrations/vercel/test/hosted/hosted-astro-project
|
working-directory: ./packages/integrations/netlify/test/hosted/hosted-astro-project
|
||||||
run:
|
run:
|
||||||
pnpm dlx vercel --prod --prebuilt
|
pnpm run build
|
||||||
|
netlify deploy --prod
|
||||||
|
|
||||||
- name: Test
|
- name: Test both hosts
|
||||||
run:
|
run:
|
||||||
pnpm run test:e2e:hosts
|
pnpm run test:e2e:hosts
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
---
|
---
|
||||||
|
image:
|
||||||
|
file: .Dockerfile
|
||||||
# Commands to start on workspace startup
|
# Commands to start on workspace startup
|
||||||
tasks:
|
tasks:
|
||||||
- before: |
|
- before: |
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
# Convert context URL to an array
|
# Convert context URL to an array
|
||||||
mapfile -t CONTEXT_URL_ITEMS < <(echo "$GITPOD_WORKSPACE_CONTEXT_URL" | tr '/' '\n')
|
mapfile -t CONTEXT_URL_ITEMS < <(echo "$GITPOD_WORKSPACE_CONTEXT_URL" | tr '/' '\n')
|
||||||
|
|
||||||
# Install latest pnpm
|
|
||||||
curl -fsSL https://get.pnpm.io/install.sh | SHELL=`which bash` bash -
|
|
||||||
|
|
||||||
# Check if Gitpod started from a specific example directory in the repository
|
# Check if Gitpod started from a specific example directory in the repository
|
||||||
if [ "${CONTEXT_URL_ITEMS[7]}" = "examples" ]; then
|
if [ "${CONTEXT_URL_ITEMS[7]}" = "examples" ]; then
|
||||||
EXAMPLE_PROJECT=${CONTEXT_URL_ITEMS[8]}
|
EXAMPLE_PROJECT=${CONTEXT_URL_ITEMS[8]}
|
||||||
|
|
|
@ -52,6 +52,8 @@ Join us on [Discord](https://astro.build/chat) to meet other maintainers. We'll
|
||||||
| [@astrojs/svelte](packages/integrations/svelte) | [![astro version](https://img.shields.io/npm/v/@astrojs/svelte.svg?label=%20)](packages/integrations/svelte/CHANGELOG.md) |
|
| [@astrojs/svelte](packages/integrations/svelte) | [![astro version](https://img.shields.io/npm/v/@astrojs/svelte.svg?label=%20)](packages/integrations/svelte/CHANGELOG.md) |
|
||||||
| [@astrojs/vue](packages/integrations/vue) | [![astro version](https://img.shields.io/npm/v/@astrojs/vue.svg?label=%20)](packages/integrations/vue/CHANGELOG.md) |
|
| [@astrojs/vue](packages/integrations/vue) | [![astro version](https://img.shields.io/npm/v/@astrojs/vue.svg?label=%20)](packages/integrations/vue/CHANGELOG.md) |
|
||||||
| [@astrojs/lit](packages/integrations/lit) | [![astro version](https://img.shields.io/npm/v/@astrojs/lit.svg?label=%20)](packages/integrations/lit/CHANGELOG.md) |
|
| [@astrojs/lit](packages/integrations/lit) | [![astro version](https://img.shields.io/npm/v/@astrojs/lit.svg?label=%20)](packages/integrations/lit/CHANGELOG.md) |
|
||||||
|
| [@astrojs/deno](packages/integrations/deno) | [![astro version](https://img.shields.io/npm/v/@astrojs/deno.svg?label=%20)](packages/integrations/deno/CHANGELOG.md) |
|
||||||
|
| [@astrojs/netlify](packages/integrations/netlify) | [![astro version](https://img.shields.io/npm/v/@astrojs/netlify.svg?label=%20)](packages/integrations/netlify/CHANGELOG.md) |
|
||||||
| [@astrojs/node](packages/integrations/node) | [![astro version](https://img.shields.io/npm/v/@astrojs/node.svg?label=%20)](packages/integrations/node/CHANGELOG.md) |
|
| [@astrojs/node](packages/integrations/node) | [![astro version](https://img.shields.io/npm/v/@astrojs/node.svg?label=%20)](packages/integrations/node/CHANGELOG.md) |
|
||||||
| [@astrojs/vercel](packages/integrations/vercel) | [![astro version](https://img.shields.io/npm/v/@astrojs/vercel.svg?label=%20)](packages/integrations/vercel/CHANGELOG.md) |
|
| [@astrojs/vercel](packages/integrations/vercel) | [![astro version](https://img.shields.io/npm/v/@astrojs/vercel.svg?label=%20)](packages/integrations/vercel/CHANGELOG.md) |
|
||||||
| [@astrojs/cloudflare](packages/integrations/cloudflare) | [![astro version](https://img.shields.io/npm/v/@astrojs/cloudflare.svg?label=%20)](packages/integrations/cloudflare/CHANGELOG.md) |
|
| [@astrojs/cloudflare](packages/integrations/cloudflare) | [![astro version](https://img.shields.io/npm/v/@astrojs/cloudflare.svg?label=%20)](packages/integrations/cloudflare/CHANGELOG.md) |
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,6 @@
|
||||||
"@astrojs/mdx": "^1.1.1",
|
"@astrojs/mdx": "^1.1.1",
|
||||||
"@astrojs/rss": "^3.0.0",
|
"@astrojs/rss": "^3.0.0",
|
||||||
"@astrojs/sitemap": "^3.0.1",
|
"@astrojs/sitemap": "^3.0.1",
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
],
|
],
|
||||||
"scripts": {},
|
"scripts": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "^2.0.0-beta.0"
|
"astro": "^2.0.0-beta.0"
|
||||||
|
|
|
@ -14,6 +14,6 @@
|
||||||
"@astrojs/alpinejs": "^0.3.1",
|
"@astrojs/alpinejs": "^0.3.1",
|
||||||
"@types/alpinejs": "^3.7.2",
|
"@types/alpinejs": "^3.7.2",
|
||||||
"alpinejs": "^3.12.3",
|
"alpinejs": "^3.12.3",
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/lit": "^3.0.1",
|
"@astrojs/lit": "^3.0.1",
|
||||||
"@webcomponents/template-shadowroot": "^0.2.1",
|
"@webcomponents/template-shadowroot": "^0.2.1",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"lit": "^2.8.0"
|
"lit": "^2.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"@astrojs/solid-js": "^3.0.2",
|
"@astrojs/solid-js": "^3.0.2",
|
||||||
"@astrojs/svelte": "^4.0.3",
|
"@astrojs/svelte": "^4.0.3",
|
||||||
"@astrojs/vue": "^3.0.1",
|
"@astrojs/vue": "^3.0.1",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"preact": "^10.17.1",
|
"preact": "^10.17.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/preact": "^3.0.1",
|
"@astrojs/preact": "^3.0.1",
|
||||||
"@preact/signals": "^1.2.1",
|
"@preact/signals": "^1.2.1",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"preact": "^10.17.1"
|
"preact": "^10.17.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"@astrojs/react": "^3.0.3",
|
"@astrojs/react": "^3.0.3",
|
||||||
"@types/react": "^18.2.21",
|
"@types/react": "^18.2.21",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/solid-js": "^3.0.2",
|
"@astrojs/solid-js": "^3.0.2",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"solid-js": "^1.7.11"
|
"solid-js": "^1.7.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/svelte": "^4.0.3",
|
"@astrojs/svelte": "^4.0.3",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"svelte": "^4.2.0"
|
"svelte": "^4.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/vue": "^3.0.1",
|
"@astrojs/vue": "^3.0.1",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"vue": "^3.3.4"
|
"vue": "^3.3.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^6.0.3",
|
"@astrojs/node": "^6.0.3",
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ export default function createIntegration(): AstroIntegration {
|
||||||
// See the @astrojs/react integration for an example
|
// See the @astrojs/react integration for an example
|
||||||
// https://github.com/withastro/astro/blob/main/packages/integrations/react/src/index.ts
|
// https://github.com/withastro/astro/blob/main/packages/integrations/react/src/index.ts
|
||||||
},
|
},
|
||||||
'astro:build:setup': ({ pages, updateConfig }) => {
|
'astro:build:setup': ({ config, updateConfig }) => {
|
||||||
// See the @astrojs/lit integration for an example
|
// See the @astrojs/netlify integration for an example
|
||||||
// https://github.com/withastro/astro/blob/main/packages/integrations/lit/src/index.ts
|
// https://github.com/withastro/astro/blob/main/packages/integrations/netlify/src/integration-functions.ts
|
||||||
},
|
},
|
||||||
'astro:build:done': ({ dir, routes }) => {
|
'astro:build:done': ({ dir, routes }) => {
|
||||||
// See the @astrojs/partytown integration for an example
|
// See the @astrojs/partytown integration for an example
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
],
|
],
|
||||||
"scripts": {},
|
"scripts": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "^2.0.0-beta.0"
|
"astro": "^2.0.0-beta.0"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^6.0.3",
|
"@astrojs/node": "^6.0.3",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"html-minifier": "^4.0.0"
|
"html-minifier": "^4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^6.0.3",
|
"@astrojs/node": "^6.0.3",
|
||||||
"@astrojs/svelte": "^4.0.3",
|
"@astrojs/svelte": "^4.0.3",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"svelte": "^4.2.0"
|
"svelte": "^4.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/tailwind": "^5.0.2",
|
"@astrojs/tailwind": "^5.0.1",
|
||||||
"@astrojs/node": "^6.0.3",
|
"@astrojs/node": "^6.0.3",
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/markdoc": "^0.5.2",
|
"@astrojs/markdoc": "^0.5.2",
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/markdown-remark": "^3.2.1",
|
"@astrojs/markdown-remark": "^3.2.1",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"hast-util-select": "^5.0.5",
|
"hast-util-select": "^5.0.5",
|
||||||
"rehype-autolink-headings": "^6.1.1",
|
"rehype-autolink-headings": "^6.1.1",
|
||||||
"rehype-slug": "^5.1.0",
|
"rehype-slug": "^5.1.0",
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4"
|
"astro": "^3.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^1.1.1",
|
"@astrojs/mdx": "^1.1.1",
|
||||||
"@astrojs/preact": "^3.0.1",
|
"@astrojs/preact": "^3.0.1",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"preact": "^10.17.1"
|
"preact": "^10.17.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/preact": "^3.0.1",
|
"@astrojs/preact": "^3.0.1",
|
||||||
"@nanostores/preact": "^0.5.0",
|
"@nanostores/preact": "^0.5.0",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"nanostores": "^0.9.3",
|
"nanostores": "^0.9.3",
|
||||||
"preact": "^10.17.1"
|
"preact": "^10.17.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^1.1.1",
|
"@astrojs/mdx": "^1.1.1",
|
||||||
"@astrojs/tailwind": "^5.0.2",
|
"@astrojs/tailwind": "^5.0.1",
|
||||||
"@types/canvas-confetti": "^1.6.0",
|
"@types/canvas-confetti": "^1.6.0",
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"autoprefixer": "^10.4.15",
|
"autoprefixer": "^10.4.15",
|
||||||
"canvas-confetti": "^1.6.0",
|
"canvas-confetti": "^1.6.0",
|
||||||
"postcss": "^8.4.28",
|
"postcss": "^8.4.28",
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"vite-plugin-pwa": "0.16.4",
|
"vite-plugin-pwa": "0.16.4",
|
||||||
"workbox-window": "^7.0.0"
|
"workbox-window": "^7.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"test": "vitest"
|
"test": "vitest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^3.2.4",
|
"astro": "^3.2.3",
|
||||||
"vitest": "^0.34.2"
|
"vitest": "^0.34.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,5 @@
|
||||||
# astro
|
# astro
|
||||||
|
|
||||||
## 3.2.4
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#8638](https://github.com/withastro/astro/pull/8638) [`160d1cd75`](https://github.com/withastro/astro/commit/160d1cd755e70af1d8ec294d01dd2cb32d60db50) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - The `@astrojs/tailwind` integration now creates a `tailwind.config.mjs` file by default
|
|
||||||
|
|
||||||
- [#8767](https://github.com/withastro/astro/pull/8767) [`30de32436`](https://github.com/withastro/astro/commit/30de324361bc261956eb9fc08fe60a82ff602a9b) Thanks [@martrapp](https://github.com/martrapp)! - Revert fix #8472
|
|
||||||
|
|
||||||
[#8472](https://github.com/withastro/astro/pull/8472) caused some style files from previous pages to not be cleanly deleted on view transitions. For a discussion of a future fix for the original issue [#8144](https://github.com/withastro/astro/issues/8114) see [#8745](https://github.com/withastro/astro/pull/8745).
|
|
||||||
|
|
||||||
- [#8741](https://github.com/withastro/astro/pull/8741) [`c4a7ec425`](https://github.com/withastro/astro/commit/c4a7ec4255e7acb9555cb8bb74ea13c5fbb2ac17) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixed an issue on Windows where lowercase drive letters in current working directory led to missing scripts and styles.
|
|
||||||
|
|
||||||
- [#8772](https://github.com/withastro/astro/pull/8772) [`c24f70d91`](https://github.com/withastro/astro/commit/c24f70d91601dd3a6b5a84f04d61824e775e9b44) Thanks [@martrapp](https://github.com/martrapp)! - Fix flickering during view transitions
|
|
||||||
|
|
||||||
- [#8754](https://github.com/withastro/astro/pull/8754) [`93b092266`](https://github.com/withastro/astro/commit/93b092266febfad16a48575f8eee12d5910bf071) Thanks [@bluwy](https://github.com/bluwy)! - Make CSS chunk names less confusing
|
|
||||||
|
|
||||||
- [#8776](https://github.com/withastro/astro/pull/8776) [`29cdfa024`](https://github.com/withastro/astro/commit/29cdfa024886dd581cb207586f7dfec6966bdd4e) Thanks [@martrapp](https://github.com/martrapp)! - Fix transition attributes on islands
|
|
||||||
|
|
||||||
- [#8773](https://github.com/withastro/astro/pull/8773) [`eaed844ea`](https://github.com/withastro/astro/commit/eaed844ea8f2f52e0c9caa40bb3ec7377e10595f) Thanks [@sumimakito](https://github.com/sumimakito)! - Fix an issue where HTML attributes do not render if getHTMLAttributes in an image service returns a Promise
|
|
||||||
|
|
||||||
## 3.2.3
|
## 3.2.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -32,13 +32,6 @@ async function main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// windows drive letters can sometimes be lowercase, which vite cannot process
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
const cwd = process.cwd();
|
|
||||||
const correctedCwd = cwd.slice(0, 1).toUpperCase() + cwd.slice(1);
|
|
||||||
if (correctedCwd !== cwd) process.chdir(correctedCwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return import('./dist/cli/index.js')
|
return import('./dist/cli/index.js')
|
||||||
.then(({ cli }) => cli(process.argv))
|
.then(({ cli }) => cli(process.argv))
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
12
packages/astro/client.d.ts
vendored
12
packages/astro/client.d.ts
vendored
|
@ -53,6 +53,7 @@ declare module 'astro:assets' {
|
||||||
imageConfig: import('./dist/@types/astro.js').AstroConfig['image'];
|
imageConfig: import('./dist/@types/astro.js').AstroConfig['image'];
|
||||||
getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
|
getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
|
||||||
Image: typeof import('./components/Image.astro').default;
|
Image: typeof import('./components/Image.astro').default;
|
||||||
|
Picture: typeof import('./components/Picture.astro').default;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ImgAttributes = import('./dist/type-utils.js').WithRequired<
|
type ImgAttributes = import('./dist/type-utils.js').WithRequired<
|
||||||
|
@ -66,17 +67,10 @@ declare module 'astro:assets' {
|
||||||
export type RemoteImageProps = import('./dist/type-utils.js').Simplify<
|
export type RemoteImageProps = import('./dist/type-utils.js').Simplify<
|
||||||
import('./dist/assets/types.js').RemoteImageProps<ImgAttributes>
|
import('./dist/assets/types.js').RemoteImageProps<ImgAttributes>
|
||||||
>;
|
>;
|
||||||
export const { getImage, getConfiguredImageService, imageConfig, Image }: AstroAssets;
|
export const { getImage, getConfiguredImageService, imageConfig, Image, Picture }: AstroAssets;
|
||||||
}
|
}
|
||||||
|
|
||||||
type InputFormat = import('./dist/assets/types.js').ImageInputFormat;
|
type ImageMetadata = import('./dist/assets/types.js').ImageMetadata;
|
||||||
|
|
||||||
interface ImageMetadata {
|
|
||||||
src: string;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
format: InputFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.gif' {
|
declare module '*.gif' {
|
||||||
const metadata: ImageMetadata;
|
const metadata: ImageMetadata;
|
||||||
|
|
|
@ -23,6 +23,12 @@ if (typeof props.height === 'string') {
|
||||||
}
|
}
|
||||||
|
|
||||||
const image = await getImage(props);
|
const image = await getImage(props);
|
||||||
|
|
||||||
|
const additionalAttributes: Record<string, any> = {};
|
||||||
|
|
||||||
|
if (image.srcSet.values.length > 0) {
|
||||||
|
additionalAttributes.srcset = image.srcSet.attribute;
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<img src={image.src} {...image.attributes} />
|
<img src={image.src} {...additionalAttributes} {...image.attributes} />
|
||||||
|
|
57
packages/astro/components/Picture.astro
Normal file
57
packages/astro/components/Picture.astro
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
import { getImage, type LocalImageProps, type RemoteImageProps } from 'astro:assets';
|
||||||
|
import type { GetImageResult, ImageOutputFormat } from '../dist/@types/astro';
|
||||||
|
import { isESMImportedImage } from '../dist/assets/internal';
|
||||||
|
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
|
||||||
|
import type { HTMLAttributes } from '../types';
|
||||||
|
|
||||||
|
type Props = (LocalImageProps | RemoteImageProps) & {
|
||||||
|
formats?: ImageOutputFormat[];
|
||||||
|
fallbackFormat?: ImageOutputFormat;
|
||||||
|
pictureAttributes?: HTMLAttributes<'picture'>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { formats = ['webp'], pictureAttributes = {}, ...props } = Astro.props;
|
||||||
|
|
||||||
|
if (props.alt === undefined || props.alt === null) {
|
||||||
|
throw new AstroError(AstroErrorData.ImageMissingAlt);
|
||||||
|
}
|
||||||
|
|
||||||
|
const optimizedImages: GetImageResult[] = await Promise.all(
|
||||||
|
formats.map(
|
||||||
|
async (format) =>
|
||||||
|
await getImage({ ...props, format: format, widths: props.widths, densities: props.densities })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const fallbackFormat =
|
||||||
|
props.fallbackFormat ?? isESMImportedImage(props.src)
|
||||||
|
? ['svg', 'gif'].includes(props.src.format)
|
||||||
|
? props.src.format
|
||||||
|
: 'png'
|
||||||
|
: 'png';
|
||||||
|
|
||||||
|
const fallbackImage = await getImage({
|
||||||
|
...props,
|
||||||
|
format: fallbackFormat,
|
||||||
|
widths: props.widths,
|
||||||
|
densities: props.densities,
|
||||||
|
});
|
||||||
|
|
||||||
|
const additionalAttributes: Record<string, any> = {};
|
||||||
|
if (fallbackImage.srcSet.values.length > 0) {
|
||||||
|
additionalAttributes.srcset = fallbackImage.srcSet.attribute;
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<picture {...pictureAttributes}>
|
||||||
|
{
|
||||||
|
Object.entries(optimizedImages).map(([_, image]) => (
|
||||||
|
<source
|
||||||
|
srcset={`${image.src}, ` + image.srcSet.attribute}
|
||||||
|
type={image.srcSet.values[0].attributes?.type}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
<img src={fallbackImage.src} {...additionalAttributes} {...fallbackImage.attributes} />
|
||||||
|
</picture>
|
|
@ -1,5 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { navigate } from "astro:transitions/client";
|
|
||||||
export default function ClickToNavigate({ to, id }) {
|
|
||||||
return <button id={id} onClick={() => navigate(to)}>Navigate to `{to}`</button>;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
import { ViewTransitions } from 'astro:transitions';
|
|
||||||
---
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<ViewTransitions/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>Local transitions</p>
|
|
||||||
<slot/>
|
|
||||||
<script>
|
|
||||||
document.addEventListener("astro:after-swap", () => {
|
|
||||||
document.querySelector("p").addEventListener("transitionstart", () => {
|
|
||||||
console.info("transitionstart");
|
|
||||||
});
|
|
||||||
document.documentElement.setAttribute("class", "blue");
|
|
||||||
});
|
|
||||||
document.dispatchEvent(new Event("astro:after-swap"));
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
<style>
|
|
||||||
p {
|
|
||||||
transition: background-color 1s;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
background-color: #0ee;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
.blue p {
|
|
||||||
background-color: #ee0;
|
|
||||||
color: blue;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</html>
|
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
import ClickToNavigate from "../components/ClickToNavigate.jsx"
|
|
||||||
import { ViewTransitions } from "astro:transitions";
|
|
||||||
---
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<ViewTransitions />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<ClickToNavigate id="react-client-load-navigate-button" to="/two" client:load/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
import ListenerLayout from '../components/listener-layout.astro';
|
|
||||||
---
|
|
||||||
<ListenerLayout>
|
|
||||||
<a id="totwo" href="/listener-two">Go to listener two</a>
|
|
||||||
</ListenerLayout>
|
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
import ListenerLayout from '../components/listener-layout.astro';
|
|
||||||
---
|
|
||||||
<ListenerLayout>
|
|
||||||
<a id="toone" href="/listener-one">Go to listener one</a>
|
|
||||||
</ListenerLayout>
|
|
|
@ -230,28 +230,6 @@ test.describe('View Transitions', () => {
|
||||||
await expect(h, 'imported CSS updated').toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
await expect(h, 'imported CSS updated').toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('No page rendering during swap()', async ({ page, astro }) => {
|
|
||||||
let transitions = 0;
|
|
||||||
page.on('console', (msg) => {
|
|
||||||
if (msg.type() === 'info' && msg.text() === 'transitionstart') ++transitions;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Go to page 1
|
|
||||||
await page.goto(astro.resolveUrl('/listener-one'));
|
|
||||||
let p = page.locator('#totwo');
|
|
||||||
await expect(p, 'should have content').toHaveText('Go to listener two');
|
|
||||||
// on load a CSS transition is started triggered by a class on the html element
|
|
||||||
expect(transitions).toEqual(1);
|
|
||||||
|
|
||||||
// go to page 2
|
|
||||||
await page.click('#totwo');
|
|
||||||
p = page.locator('#toone');
|
|
||||||
await expect(p, 'should have content').toHaveText('Go to listener one');
|
|
||||||
// swap() resets that class, the after-swap listener sets it again.
|
|
||||||
// the temporarily missing class must not trigger page rendering
|
|
||||||
expect(transitions).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('click hash links does not do navigation', async ({ page, astro }) => {
|
test('click hash links does not do navigation', async ({ page, astro }) => {
|
||||||
// Go to page 1
|
// Go to page 1
|
||||||
await page.goto(astro.resolveUrl('/one'));
|
await page.goto(astro.resolveUrl('/one'));
|
||||||
|
@ -670,7 +648,7 @@ test.describe('View Transitions', () => {
|
||||||
expect(loads.length, 'There should be 2 page loads').toEqual(2);
|
expect(loads.length, 'There should be 2 page loads').toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('client:only styles are retained on transition', async ({ page, astro }) => {
|
test('client:only styles are retained on transition', async ({ page, astro }) => {
|
||||||
const totalExpectedStyles = 7;
|
const totalExpectedStyles = 7;
|
||||||
|
|
||||||
// Go to page 1
|
// Go to page 1
|
||||||
|
@ -753,21 +731,6 @@ test.describe('View Transitions', () => {
|
||||||
await expect(p, 'should have content').toHaveText('Page 1');
|
await expect(p, 'should have content').toHaveText('Page 1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Use the client side router in framework components', async ({ page, astro }) => {
|
|
||||||
await page.goto(astro.resolveUrl('/client-load'));
|
|
||||||
|
|
||||||
// the button is set to naviagte() to /two
|
|
||||||
const button = page.locator('#react-client-load-navigate-button');
|
|
||||||
|
|
||||||
await expect(button, 'should have content').toHaveText('Navigate to `/two`');
|
|
||||||
|
|
||||||
await button.click();
|
|
||||||
|
|
||||||
const p = page.locator('#two');
|
|
||||||
|
|
||||||
await expect(p, 'should have content').toHaveText('Page 2');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('body inline scripts do not re-execute on navigation', async ({ page, astro }) => {
|
test('body inline scripts do not re-execute on navigation', async ({ page, astro }) => {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
page.addListener('pageerror', (err) => {
|
page.addListener('pageerror', (err) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "astro",
|
"name": "astro",
|
||||||
"version": "3.2.4",
|
"version": "3.2.3",
|
||||||
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "withastro",
|
"author": "withastro",
|
||||||
|
@ -213,6 +213,7 @@
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"network-information-types": "^0.1.1",
|
"network-information-types": "^0.1.1",
|
||||||
"node-mocks-http": "^1.13.0",
|
"node-mocks-http": "^1.13.0",
|
||||||
|
"parse-srcset": "^1.0.2",
|
||||||
"rehype-autolink-headings": "^6.1.1",
|
"rehype-autolink-headings": "^6.1.1",
|
||||||
"rehype-slug": "^5.0.1",
|
"rehype-slug": "^5.0.1",
|
||||||
"rehype-toc": "^3.0.2",
|
"rehype-toc": "^3.0.2",
|
||||||
|
|
|
@ -24,4 +24,5 @@ export const VALID_SUPPORTED_FORMATS = [
|
||||||
'svg',
|
'svg',
|
||||||
'avif',
|
'avif',
|
||||||
] as const;
|
] as const;
|
||||||
|
export const DEFAULT_OUTPUT_FORMAT = 'webp' as const;
|
||||||
export const VALID_OUTPUT_FORMATS = ['avif', 'png', 'webp', 'jpeg', 'jpg', 'svg'] as const;
|
export const VALID_OUTPUT_FORMATS = ['avif', 'png', 'webp', 'jpeg', 'jpg', 'svg'] as const;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import type {
|
||||||
GetImageResult,
|
GetImageResult,
|
||||||
ImageMetadata,
|
ImageMetadata,
|
||||||
ImageTransform,
|
ImageTransform,
|
||||||
|
SrcSetValue,
|
||||||
UnresolvedImageTransform,
|
UnresolvedImageTransform,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
import { matchHostname, matchPattern } from './utils/remotePattern.js';
|
import { matchHostname, matchPattern } from './utils/remotePattern.js';
|
||||||
|
@ -93,25 +94,44 @@ export async function getImage(
|
||||||
? await service.validateOptions(resolvedOptions, imageConfig)
|
? await service.validateOptions(resolvedOptions, imageConfig)
|
||||||
: resolvedOptions;
|
: resolvedOptions;
|
||||||
|
|
||||||
let imageURL = await service.getURL(validatedOptions, imageConfig);
|
// Get all the options for the different srcSets
|
||||||
|
const srcSetTransforms = service.getSrcSet
|
||||||
|
? await service.getSrcSet(validatedOptions, imageConfig)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
let imageURL = await service.getURL(validatedOptions, imageConfig);
|
||||||
|
let srcSets: SrcSetValue[] = await Promise.all(
|
||||||
|
srcSetTransforms.map(async (srcSet) => ({
|
||||||
|
url: await service.getURL(srcSet.transform, imageConfig),
|
||||||
|
descriptor: srcSet.descriptor,
|
||||||
|
attributes: srcSet.attributes,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
// In build and for local services, we need to collect the requested parameters so we can generate the final images
|
|
||||||
if (
|
if (
|
||||||
isLocalService(service) &&
|
isLocalService(service) &&
|
||||||
globalThis.astroAsset.addStaticImage &&
|
globalThis.astroAsset.addStaticImage &&
|
||||||
// If `getURL` returned the same URL as the user provided, it means the service doesn't need to do anything
|
|
||||||
!(isRemoteImage(validatedOptions.src) && imageURL === validatedOptions.src)
|
!(isRemoteImage(validatedOptions.src) && imageURL === validatedOptions.src)
|
||||||
) {
|
) {
|
||||||
imageURL = globalThis.astroAsset.addStaticImage(validatedOptions);
|
imageURL = globalThis.astroAsset.addStaticImage(validatedOptions);
|
||||||
|
srcSets = srcSetTransforms.map((srcSet) => ({
|
||||||
|
url: globalThis.astroAsset.addStaticImage!(srcSet.transform),
|
||||||
|
descriptor: srcSet.descriptor,
|
||||||
|
attributes: srcSet.attributes,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
rawOptions: resolvedOptions,
|
rawOptions: resolvedOptions,
|
||||||
options: validatedOptions,
|
options: validatedOptions,
|
||||||
src: imageURL,
|
src: imageURL,
|
||||||
|
srcSet: {
|
||||||
|
values: srcSets,
|
||||||
|
attribute: srcSets.map((srcSet) => `${srcSet.url} ${srcSet.descriptor}`).join(', '),
|
||||||
|
},
|
||||||
attributes:
|
attributes:
|
||||||
service.getHTMLAttributes !== undefined
|
service.getHTMLAttributes !== undefined
|
||||||
? await service.getHTMLAttributes(validatedOptions, imageConfig)
|
? service.getHTMLAttributes(validatedOptions, imageConfig)
|
||||||
: {},
|
: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { AstroConfig } from '../../@types/astro.js';
|
import type { AstroConfig } from '../../@types/astro.js';
|
||||||
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
||||||
import { isRemotePath, joinPaths } from '../../core/path.js';
|
import { isRemotePath, joinPaths } from '../../core/path.js';
|
||||||
import { VALID_SUPPORTED_FORMATS } from '../consts.js';
|
import { DEFAULT_OUTPUT_FORMAT, VALID_SUPPORTED_FORMATS } from '../consts.js';
|
||||||
import { isESMImportedImage, isRemoteAllowed } from '../internal.js';
|
import { isESMImportedImage, isRemoteAllowed } from '../internal.js';
|
||||||
import type { ImageOutputFormat, ImageTransform } from '../types.js';
|
import type { ImageOutputFormat, ImageTransform } from '../types.js';
|
||||||
|
|
||||||
|
@ -28,6 +28,12 @@ type ImageConfig<T> = Omit<AstroConfig['image'], 'service'> & {
|
||||||
service: { entrypoint: string; config: T };
|
service: { entrypoint: string; config: T };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type SrcSetValue = {
|
||||||
|
transform: ImageTransform;
|
||||||
|
descriptor?: string;
|
||||||
|
attributes?: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
interface SharedServiceProps<T extends Record<string, any> = Record<string, any>> {
|
interface SharedServiceProps<T extends Record<string, any> = Record<string, any>> {
|
||||||
/**
|
/**
|
||||||
* Return the URL to the endpoint or URL your images are generated from.
|
* Return the URL to the endpoint or URL your images are generated from.
|
||||||
|
@ -38,6 +44,16 @@ interface SharedServiceProps<T extends Record<string, any> = Record<string, any>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
getURL: (options: ImageTransform, imageConfig: ImageConfig<T>) => string | Promise<string>;
|
getURL: (options: ImageTransform, imageConfig: ImageConfig<T>) => string | Promise<string>;
|
||||||
|
/**
|
||||||
|
* Generate additional `srcset` values for the image.
|
||||||
|
*
|
||||||
|
* While in most cases this is exclusively used for `srcset`, it can also be used in a more generic way to generate
|
||||||
|
* multiple variants of the same image. For instance, you can use this to generate multiple aspect ratios or multiple formats.
|
||||||
|
*/
|
||||||
|
getSrcSet?: (
|
||||||
|
options: ImageTransform,
|
||||||
|
imageConfig: ImageConfig<T>
|
||||||
|
) => SrcSetValue[] | Promise<SrcSetValue[]>;
|
||||||
/**
|
/**
|
||||||
* Return any additional HTML attributes separate from `src` that your service requires to show the image properly.
|
* Return any additional HTML attributes separate from `src` that your service requires to show the image properly.
|
||||||
*
|
*
|
||||||
|
@ -174,6 +190,10 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.widths && options.densities) {
|
||||||
|
throw new AstroError(AstroErrorData.IncompatibleDescriptorOptions);
|
||||||
|
}
|
||||||
|
|
||||||
// We currently do not support processing SVGs, so whenever the input format is a SVG, force the output to also be one
|
// We currently do not support processing SVGs, so whenever the input format is a SVG, force the output to also be one
|
||||||
if (options.src.format === 'svg') {
|
if (options.src.format === 'svg') {
|
||||||
options.format = 'svg';
|
options.format = 'svg';
|
||||||
|
@ -183,30 +203,15 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
// If the user didn't specify a format, we'll default to `webp`. It offers the best ratio of compatibility / quality
|
// If the user didn't specify a format, we'll default to `webp`. It offers the best ratio of compatibility / quality
|
||||||
// In the future, hopefully we can replace this with `avif`, alas, Edge. See https://caniuse.com/avif
|
// In the future, hopefully we can replace this with `avif`, alas, Edge. See https://caniuse.com/avif
|
||||||
if (!options.format) {
|
if (!options.format) {
|
||||||
options.format = 'webp';
|
options.format = DEFAULT_OUTPUT_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
getHTMLAttributes(options) {
|
getHTMLAttributes(options) {
|
||||||
let targetWidth = options.width;
|
const { targetWidth, targetHeight } = getTargetDimensions(options);
|
||||||
let targetHeight = options.height;
|
const { src, width, height, format, quality, densities, widths, formats, ...attributes } =
|
||||||
if (isESMImportedImage(options.src)) {
|
options;
|
||||||
const aspectRatio = options.src.width / options.src.height;
|
|
||||||
if (targetHeight && !targetWidth) {
|
|
||||||
// If we have a height but no width, use height to calculate the width
|
|
||||||
targetWidth = Math.round(targetHeight * aspectRatio);
|
|
||||||
} else if (targetWidth && !targetHeight) {
|
|
||||||
// If we have a width but no height, use width to calculate the height
|
|
||||||
targetHeight = Math.round(targetWidth / aspectRatio);
|
|
||||||
} else if (!targetWidth && !targetHeight) {
|
|
||||||
// If we have neither width or height, use the original image's dimensions
|
|
||||||
targetWidth = options.src.width;
|
|
||||||
targetHeight = options.src.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { src, width, height, format, quality, ...attributes } = options;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...attributes,
|
...attributes,
|
||||||
|
@ -216,6 +221,89 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
decoding: attributes.decoding ?? 'async',
|
decoding: attributes.decoding ?? 'async',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
getSrcSet(options) {
|
||||||
|
const srcSet: SrcSetValue[] = [];
|
||||||
|
const { targetWidth, targetHeight } = getTargetDimensions(options);
|
||||||
|
const { widths, densities } = options;
|
||||||
|
const targetFormat = options.format ?? DEFAULT_OUTPUT_FORMAT;
|
||||||
|
|
||||||
|
const aspectRatio = targetWidth / targetHeight;
|
||||||
|
const imageWidth = isESMImportedImage(options.src) ? options.src.width : options.width;
|
||||||
|
const maxWidth = imageWidth ?? Infinity;
|
||||||
|
|
||||||
|
// REFACTOR: Could we merge these two blocks?
|
||||||
|
if (densities) {
|
||||||
|
const densityValues = densities.map((density) => {
|
||||||
|
if (typeof density === 'number') {
|
||||||
|
return density;
|
||||||
|
} else {
|
||||||
|
return parseFloat(density);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const densityWidths = densityValues
|
||||||
|
.sort()
|
||||||
|
.map((density) => Math.round(targetWidth * density));
|
||||||
|
|
||||||
|
densityWidths.forEach((width, index) => {
|
||||||
|
const maxTargetWidth = Math.min(width, maxWidth);
|
||||||
|
|
||||||
|
// If the user passed dimensions, we don't want to add it to the srcset
|
||||||
|
const { width: transformWidth, height: transformHeight, ...rest } = options;
|
||||||
|
|
||||||
|
const srcSetValue = {
|
||||||
|
transform: {
|
||||||
|
...rest,
|
||||||
|
},
|
||||||
|
descriptor: `${densityValues[index]}x`,
|
||||||
|
attributes: {
|
||||||
|
type: `image/${targetFormat}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only set width and height if they are different from the original image, to avoid duplicated final images
|
||||||
|
if (maxTargetWidth !== imageWidth) {
|
||||||
|
srcSetValue.transform.width = maxTargetWidth;
|
||||||
|
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetFormat !== options.format) {
|
||||||
|
srcSetValue.transform.format = targetFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcSet.push(srcSetValue);
|
||||||
|
});
|
||||||
|
} else if (widths) {
|
||||||
|
widths.forEach((width) => {
|
||||||
|
const maxTargetWidth = Math.min(width, maxWidth);
|
||||||
|
|
||||||
|
const { width: transformWidth, height: transformHeight, ...rest } = options;
|
||||||
|
|
||||||
|
const srcSetValue = {
|
||||||
|
transform: {
|
||||||
|
...rest,
|
||||||
|
},
|
||||||
|
descriptor: `${width}w`,
|
||||||
|
attributes: {
|
||||||
|
type: `image/${targetFormat}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (maxTargetWidth !== imageWidth) {
|
||||||
|
srcSetValue.transform.width = maxTargetWidth;
|
||||||
|
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetFormat !== options.format) {
|
||||||
|
srcSetValue.transform.format = targetFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcSet.push(srcSetValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return srcSet;
|
||||||
|
},
|
||||||
getURL(options, imageConfig) {
|
getURL(options, imageConfig) {
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
|
|
||||||
|
@ -260,3 +348,28 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
||||||
return transform;
|
return transform;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getTargetDimensions(options: ImageTransform) {
|
||||||
|
let targetWidth = options.width;
|
||||||
|
let targetHeight = options.height;
|
||||||
|
if (isESMImportedImage(options.src)) {
|
||||||
|
const aspectRatio = options.src.width / options.src.height;
|
||||||
|
if (targetHeight && !targetWidth) {
|
||||||
|
// If we have a height but no width, use height to calculate the width
|
||||||
|
targetWidth = Math.round(targetHeight * aspectRatio);
|
||||||
|
} else if (targetWidth && !targetHeight) {
|
||||||
|
// If we have a width but no height, use width to calculate the height
|
||||||
|
targetHeight = Math.round(targetWidth / aspectRatio);
|
||||||
|
} else if (!targetWidth && !targetHeight) {
|
||||||
|
// If we have neither width or height, use the original image's dimensions
|
||||||
|
targetWidth = options.src.width;
|
||||||
|
targetHeight = options.src.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeScript doesn't know this, but because of previous hooks we always know that targetWidth and targetHeight are defined
|
||||||
|
return {
|
||||||
|
targetWidth: targetWidth!,
|
||||||
|
targetHeight: targetHeight!,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ const sharpService: LocalImageService = {
|
||||||
getURL: baseService.getURL,
|
getURL: baseService.getURL,
|
||||||
parseURL: baseService.parseURL,
|
parseURL: baseService.parseURL,
|
||||||
getHTMLAttributes: baseService.getHTMLAttributes,
|
getHTMLAttributes: baseService.getHTMLAttributes,
|
||||||
|
getSrcSet: baseService.getSrcSet,
|
||||||
async transform(inputBuffer, transformOptions) {
|
async transform(inputBuffer, transformOptions) {
|
||||||
if (!sharp) sharp = await loadSharp();
|
if (!sharp) sharp = await loadSharp();
|
||||||
|
|
||||||
|
@ -49,9 +50,9 @@ const sharpService: LocalImageService = {
|
||||||
|
|
||||||
// Never resize using both width and height at the same time, prioritizing width.
|
// Never resize using both width and height at the same time, prioritizing width.
|
||||||
if (transform.height && !transform.width) {
|
if (transform.height && !transform.width) {
|
||||||
result.resize({ height: transform.height });
|
result.resize({ height: Math.round(transform.height) });
|
||||||
} else if (transform.width) {
|
} else if (transform.width) {
|
||||||
result.resize({ width: transform.width });
|
result.resize({ width: Math.round(transform.width) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transform.format) {
|
if (transform.format) {
|
||||||
|
|
|
@ -56,6 +56,7 @@ const service: LocalImageService = {
|
||||||
getURL: baseService.getURL,
|
getURL: baseService.getURL,
|
||||||
parseURL: baseService.parseURL,
|
parseURL: baseService.parseURL,
|
||||||
getHTMLAttributes: baseService.getHTMLAttributes,
|
getHTMLAttributes: baseService.getHTMLAttributes,
|
||||||
|
getSrcSet: baseService.getSrcSet,
|
||||||
async transform(inputBuffer, transformOptions) {
|
async transform(inputBuffer, transformOptions) {
|
||||||
const transform: BaseServiceTransform = transformOptions as BaseServiceTransform;
|
const transform: BaseServiceTransform = transformOptions as BaseServiceTransform;
|
||||||
|
|
||||||
|
@ -76,12 +77,12 @@ const service: LocalImageService = {
|
||||||
if (transform.height && !transform.width) {
|
if (transform.height && !transform.width) {
|
||||||
operations.push({
|
operations.push({
|
||||||
type: 'resize',
|
type: 'resize',
|
||||||
height: transform.height,
|
height: Math.round(transform.height),
|
||||||
});
|
});
|
||||||
} else if (transform.width) {
|
} else if (transform.width) {
|
||||||
operations.push({
|
operations.push({
|
||||||
type: 'resize',
|
type: 'resize',
|
||||||
width: transform.width,
|
width: Math.round(transform.width),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,12 @@ export interface ImageMetadata {
|
||||||
orientation?: number;
|
orientation?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SrcSetValue {
|
||||||
|
url: string;
|
||||||
|
descriptor?: string;
|
||||||
|
attributes?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A yet to be resolved image transform. Used by `getImage`
|
* A yet to be resolved image transform. Used by `getImage`
|
||||||
*/
|
*/
|
||||||
|
@ -41,6 +47,8 @@ export type UnresolvedImageTransform = Omit<ImageTransform, 'src'> & {
|
||||||
export type ImageTransform = {
|
export type ImageTransform = {
|
||||||
src: ImageMetadata | string;
|
src: ImageMetadata | string;
|
||||||
width?: number | undefined;
|
width?: number | undefined;
|
||||||
|
widths?: number[] | undefined;
|
||||||
|
densities?: (number | `${number}x`)[] | undefined;
|
||||||
height?: number | undefined;
|
height?: number | undefined;
|
||||||
quality?: ImageQuality | undefined;
|
quality?: ImageQuality | undefined;
|
||||||
format?: ImageOutputFormat | undefined;
|
format?: ImageOutputFormat | undefined;
|
||||||
|
@ -51,6 +59,10 @@ export interface GetImageResult {
|
||||||
rawOptions: ImageTransform;
|
rawOptions: ImageTransform;
|
||||||
options: ImageTransform;
|
options: ImageTransform;
|
||||||
src: string;
|
src: string;
|
||||||
|
srcSet: {
|
||||||
|
values: SrcSetValue[];
|
||||||
|
attribute: string;
|
||||||
|
};
|
||||||
attributes: Record<string, any>;
|
attributes: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +70,7 @@ type ImageSharedProps<T> = T & {
|
||||||
/**
|
/**
|
||||||
* Width of the image, the value of this property will be used to assign the `width` property on the final `img` element.
|
* Width of the image, the value of this property will be used to assign the `width` property on the final `img` element.
|
||||||
*
|
*
|
||||||
* For local images, this value will additionally be used to resize the image to the desired width, taking into account the original aspect ratio of the image.
|
* This value will additionally be used to resize the image to the desired width, taking into account the original aspect ratio of the image.
|
||||||
*
|
*
|
||||||
* **Example**:
|
* **Example**:
|
||||||
* ```astro
|
* ```astro
|
||||||
|
@ -85,7 +97,26 @@ type ImageSharedProps<T> = T & {
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
height?: number | `${number}`;
|
height?: number | `${number}`;
|
||||||
};
|
} & (
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* A list of widths to generate images for. The value of this property will be used to assign the `srcset` property on the final `img` element.
|
||||||
|
*
|
||||||
|
* This attribute is incompatible with `densities`.
|
||||||
|
*/
|
||||||
|
widths?: number[];
|
||||||
|
densities?: never;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* A list of densities to generate images for. The value of this property will be used to assign the `srcset` property on the final `img` element.
|
||||||
|
*
|
||||||
|
* This attribute is incompatible with `widths`.
|
||||||
|
*/
|
||||||
|
densities?: (number | `${number}x`)[];
|
||||||
|
widths?: never;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export type LocalImageProps<T> = ImageSharedProps<T> & {
|
export type LocalImageProps<T> = ImageSharedProps<T> & {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,8 +16,8 @@ export function propsToFilename(transform: ImageTransform, hash: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hashTransform(transform: ImageTransform, imageService: string) {
|
export function hashTransform(transform: ImageTransform, imageService: string) {
|
||||||
// take everything from transform except alt, which is not used in the hash
|
// Extract the fields we want to hash
|
||||||
const { alt, ...rest } = transform;
|
const { alt, class: className, style, widths, densities, ...rest } = transform;
|
||||||
const hashFields = { ...rest, imageService };
|
const hashFields = { ...rest, imageService };
|
||||||
return shorthash(JSON.stringify(hashFields));
|
return shorthash(JSON.stringify(hashFields));
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ export default function assets({
|
||||||
export { getConfiguredImageService, isLocalService } from "astro/assets";
|
export { getConfiguredImageService, isLocalService } from "astro/assets";
|
||||||
import { getImage as getImageInternal } from "astro/assets";
|
import { getImage as getImageInternal } from "astro/assets";
|
||||||
export { default as Image } from "astro/components/Image.astro";
|
export { default as Image } from "astro/components/Image.astro";
|
||||||
|
export { default as Picture } from "astro/components/Picture.astro";
|
||||||
|
|
||||||
export const imageConfig = ${JSON.stringify(settings.config.image)};
|
export const imageConfig = ${JSON.stringify(settings.config.image)};
|
||||||
export const assetsDir = new URL(${JSON.stringify(
|
export const assetsDir = new URL(${JSON.stringify(
|
||||||
|
|
|
@ -50,7 +50,7 @@ const ALIASES = new Map([
|
||||||
]);
|
]);
|
||||||
const ASTRO_CONFIG_STUB = `import { defineConfig } from 'astro/config';\n\nexport default defineConfig({});`;
|
const ASTRO_CONFIG_STUB = `import { defineConfig } from 'astro/config';\n\nexport default defineConfig({});`;
|
||||||
const TAILWIND_CONFIG_STUB = `/** @type {import('tailwindcss').Config} */
|
const TAILWIND_CONFIG_STUB = `/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
module.exports = {
|
||||||
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
|
@ -74,6 +74,7 @@ const OFFICIAL_ADAPTER_TO_IMPORT_MAP: Record<string, string> = {
|
||||||
vercel: '@astrojs/vercel/serverless',
|
vercel: '@astrojs/vercel/serverless',
|
||||||
cloudflare: '@astrojs/cloudflare',
|
cloudflare: '@astrojs/cloudflare',
|
||||||
node: '@astrojs/node',
|
node: '@astrojs/node',
|
||||||
|
deno: '@astrojs/deno',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Users might lack access to the global npm registry, this function
|
// Users might lack access to the global npm registry, this function
|
||||||
|
@ -159,7 +160,7 @@ export async function add(names: string[], { flags }: AddOptions) {
|
||||||
'./tailwind.config.mjs',
|
'./tailwind.config.mjs',
|
||||||
'./tailwind.config.js',
|
'./tailwind.config.js',
|
||||||
],
|
],
|
||||||
defaultConfigFile: './tailwind.config.mjs',
|
defaultConfigFile: './tailwind.config.cjs',
|
||||||
defaultConfigContent: TAILWIND_CONFIG_STUB,
|
defaultConfigContent: TAILWIND_CONFIG_STUB,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ type RawContentEvent = { name: ChokidarEvent; entry: string };
|
||||||
type ContentEvent = { name: ChokidarEvent; entry: URL };
|
type ContentEvent = { name: ChokidarEvent; entry: URL };
|
||||||
|
|
||||||
type DataEntryMetadata = Record<string, never>;
|
type DataEntryMetadata = Record<string, never>;
|
||||||
type ContentEntryMetadata = { slug: string, path: string };
|
type ContentEntryMetadata = { slug: string };
|
||||||
type CollectionEntryMap = {
|
type CollectionEntryMap = {
|
||||||
[collection: string]:
|
[collection: string]:
|
||||||
| {
|
| {
|
||||||
|
@ -276,7 +276,7 @@ export async function createContentTypesGenerator({
|
||||||
if (!(entryKey in collectionEntryMap[collectionKey].entries)) {
|
if (!(entryKey in collectionEntryMap[collectionKey].entries)) {
|
||||||
collectionEntryMap[collectionKey] = {
|
collectionEntryMap[collectionKey] = {
|
||||||
type: 'content',
|
type: 'content',
|
||||||
entries: { ...collectionInfo.entries, [entryKey]: { slug: addedSlug, path: event.entry.toString() } },
|
entries: { ...collectionInfo.entries, [entryKey]: { slug: addedSlug } },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { shouldGenerateTypes: true };
|
return { shouldGenerateTypes: true };
|
||||||
|
@ -453,15 +453,7 @@ async function writeContentFiles({
|
||||||
)}] }`;
|
)}] }`;
|
||||||
|
|
||||||
const slugType = JSON.stringify(entryMetadata.slug);
|
const slugType = JSON.stringify(entryMetadata.slug);
|
||||||
contentTypesStr += [
|
contentTypesStr += `${entryKey}: {\n id: ${entryKey};\n slug: ${slugType};\n body: string;\n collection: ${collectionKey};\n data: ${dataType}\n} & ${renderType};\n`;
|
||||||
`${entryKey}: {`,
|
|
||||||
` id: ${entryKey};`,
|
|
||||||
` slug: ${slugType};`,
|
|
||||||
` path: ${JSON.stringify(entryMetadata.path)};`,
|
|
||||||
` body: string;`,
|
|
||||||
` collection: ${collectionKey};`,
|
|
||||||
` data: ${dataType}`,
|
|
||||||
`} & ${renderType};`].join("\n");
|
|
||||||
}
|
}
|
||||||
contentTypesStr += `};\n`;
|
contentTypesStr += `};\n`;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { GetModuleInfo, ModuleInfo } from 'rollup';
|
import type { GetModuleInfo } from 'rollup';
|
||||||
|
|
||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
import npath from 'node:path';
|
import npath from 'node:path';
|
||||||
|
@ -6,29 +6,20 @@ import type { AstroSettings } from '../../@types/astro.js';
|
||||||
import { viteID } from '../util.js';
|
import { viteID } from '../util.js';
|
||||||
import { getTopLevelPages } from './graph.js';
|
import { getTopLevelPages } from './graph.js';
|
||||||
|
|
||||||
// These pages could be used as base names for the chunk hashed name, but they are confusing
|
|
||||||
// and should be avoided it possible
|
|
||||||
const confusingBaseNames = ['404', '500'];
|
|
||||||
|
|
||||||
// The short name for when the hash can be included
|
// The short name for when the hash can be included
|
||||||
// We could get rid of this and only use the createSlugger implementation, but this creates
|
// We could get rid of this and only use the createSlugger implementation, but this creates
|
||||||
// slightly prettier names.
|
// slightly prettier names.
|
||||||
export function shortHashedName(id: string, ctx: { getModuleInfo: GetModuleInfo }): string {
|
export function shortHashedName(id: string, ctx: { getModuleInfo: GetModuleInfo }): string {
|
||||||
const parents = Array.from(getTopLevelPages(id, ctx));
|
const parents = Array.from(getTopLevelPages(id, ctx));
|
||||||
return createNameHash(
|
const firstParentId = parents[0]?.[0].id;
|
||||||
getFirstParentId(parents),
|
const firstParentName = firstParentId ? npath.parse(firstParentId).name : 'index';
|
||||||
parents.map(([page]) => page.id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createNameHash(baseId: string | undefined, hashIds: string[]): string {
|
|
||||||
const baseName = baseId ? prettifyBaseName(npath.parse(baseId).name) : 'index';
|
|
||||||
const hash = crypto.createHash('sha256');
|
const hash = crypto.createHash('sha256');
|
||||||
for (const id of hashIds) {
|
for (const [page] of parents) {
|
||||||
hash.update(id, 'utf-8');
|
hash.update(page.id, 'utf-8');
|
||||||
}
|
}
|
||||||
const h = hash.digest('hex').slice(0, 8);
|
const h = hash.digest('hex').slice(0, 8);
|
||||||
const proposedName = baseName + '.' + h;
|
const proposedName = firstParentName + '.' + h;
|
||||||
return proposedName;
|
return proposedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +34,7 @@ export function createSlugger(settings: AstroSettings) {
|
||||||
.map(([page]) => page.id)
|
.map(([page]) => page.id)
|
||||||
.sort()
|
.sort()
|
||||||
.join('-');
|
.join('-');
|
||||||
const firstParentId = getFirstParentId(parents) || indexPage;
|
const firstParentId = parents[0]?.[0].id || indexPage;
|
||||||
|
|
||||||
// Use the last two segments, for ex /docs/index
|
// Use the last two segments, for ex /docs/index
|
||||||
let dir = firstParentId;
|
let dir = firstParentId;
|
||||||
|
@ -54,7 +45,7 @@ export function createSlugger(settings: AstroSettings) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = prettifyBaseName(npath.parse(npath.basename(dir)).name);
|
const name = npath.parse(npath.basename(dir)).name;
|
||||||
key = key.length ? name + sep + key : name;
|
key = key.length ? name + sep + key : name;
|
||||||
dir = npath.dirname(dir);
|
dir = npath.dirname(dir);
|
||||||
i++;
|
i++;
|
||||||
|
@ -85,32 +76,3 @@ export function createSlugger(settings: AstroSettings) {
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the first parent id from `parents` where its name is not confusing.
|
|
||||||
* Returns undefined if there's no parents.
|
|
||||||
*/
|
|
||||||
function getFirstParentId(parents: [ModuleInfo, number, number][]) {
|
|
||||||
for (const parent of parents) {
|
|
||||||
const id = parent[0].id;
|
|
||||||
const baseName = npath.parse(id).name;
|
|
||||||
if (!confusingBaseNames.includes(baseName)) {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If all parents are confusing, just use the first one. Or if there's no
|
|
||||||
// parents, this will return undefined.
|
|
||||||
return parents[0]?.[0].id;
|
|
||||||
}
|
|
||||||
|
|
||||||
const charsToReplaceRe = /[.\[\]]/g;
|
|
||||||
const underscoresRe = /_+/g;
|
|
||||||
/**
|
|
||||||
* Prettify base names so they're easier to read:
|
|
||||||
* - index -> index
|
|
||||||
* - [slug] -> _slug_
|
|
||||||
* - [...spread] -> _spread_
|
|
||||||
*/
|
|
||||||
function prettifyBaseName(str: string) {
|
|
||||||
return str.replace(charsToReplaceRe, '_').replace(underscoresRe, '_');
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import * as crypto from 'node:crypto';
|
||||||
|
import * as npath from 'node:path';
|
||||||
import type { GetModuleInfo } from 'rollup';
|
import type { GetModuleInfo } from 'rollup';
|
||||||
import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite';
|
import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite';
|
||||||
import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
|
import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
|
||||||
|
@ -91,7 +93,7 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
|
||||||
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
|
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
|
||||||
// Split delayed assets to separate modules
|
// Split delayed assets to separate modules
|
||||||
// so they can be injected where needed
|
// so they can be injected where needed
|
||||||
const chunkId = assetName.createNameHash(id, [id]);
|
const chunkId = createNameHash(id, [id]);
|
||||||
internals.cssModuleToChunkIdMap.set(id, chunkId);
|
internals.cssModuleToChunkIdMap.set(id, chunkId);
|
||||||
return chunkId;
|
return chunkId;
|
||||||
}
|
}
|
||||||
|
@ -270,6 +272,17 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
|
||||||
|
|
||||||
/***** UTILITY FUNCTIONS *****/
|
/***** UTILITY FUNCTIONS *****/
|
||||||
|
|
||||||
|
function createNameHash(baseId: string, hashIds: string[]): string {
|
||||||
|
const baseName = baseId ? npath.parse(baseId).name : 'index';
|
||||||
|
const hash = crypto.createHash('sha256');
|
||||||
|
for (const id of hashIds) {
|
||||||
|
hash.update(id, 'utf-8');
|
||||||
|
}
|
||||||
|
const h = hash.digest('hex').slice(0, 8);
|
||||||
|
const proposedName = baseName + '.' + h;
|
||||||
|
return proposedName;
|
||||||
|
}
|
||||||
|
|
||||||
function* getParentClientOnlys(
|
function* getParentClientOnlys(
|
||||||
id: string,
|
id: string,
|
||||||
ctx: { getModuleInfo: GetModuleInfo },
|
ctx: { getModuleInfo: GetModuleInfo },
|
||||||
|
|
|
@ -621,6 +621,21 @@ export const ExpectedImageOptions = {
|
||||||
`Expected getImage() parameter to be an object. Received \`${options}\`.`,
|
`Expected getImage() parameter to be an object. Received \`${options}\`.`,
|
||||||
} satisfies ErrorData;
|
} satisfies ErrorData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @docs
|
||||||
|
* @see
|
||||||
|
* - [Images](https://docs.astro.build/en/guides/images/)
|
||||||
|
* @description
|
||||||
|
* Only one of `densities` or `widths` can be specified. Those attributes are used to construct a `srcset` attribute, which cannot have both `x` and `w` descriptors.
|
||||||
|
*/
|
||||||
|
export const IncompatibleDescriptorOptions = {
|
||||||
|
name: 'IncompatibleDescriptorOptions',
|
||||||
|
title: 'Cannot set both `densities` and `widths`',
|
||||||
|
message:
|
||||||
|
"Only one of `densities` or `widths` can be specified. In most cases, you'll probably want to use only `widths` if you require specific widths.",
|
||||||
|
hint: 'Those attributes are used to construct a `srcset` attribute, which cannot have both `x` and `w` descriptors.',
|
||||||
|
} satisfies ErrorData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @see
|
* @see
|
||||||
|
|
|
@ -15,13 +15,10 @@ export interface HydrationMetadata {
|
||||||
componentExport: { value: string };
|
componentExport: { value: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = Record<string | number | symbol, any>;
|
|
||||||
|
|
||||||
interface ExtractedProps {
|
interface ExtractedProps {
|
||||||
isPage: boolean;
|
isPage: boolean;
|
||||||
hydration: HydrationMetadata | null;
|
hydration: HydrationMetadata | null;
|
||||||
props: Props;
|
props: Record<string | number | symbol, any>;
|
||||||
propsWithoutTransitionAttributes: Props;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const transitionDirectivesToCopyOnIsland = Object.freeze([
|
const transitionDirectivesToCopyOnIsland = Object.freeze([
|
||||||
|
@ -32,14 +29,13 @@ const transitionDirectivesToCopyOnIsland = Object.freeze([
|
||||||
// Used to extract the directives, aka `client:load` information about a component.
|
// Used to extract the directives, aka `client:load` information about a component.
|
||||||
// Finds these special props and removes them from what gets passed into the component.
|
// Finds these special props and removes them from what gets passed into the component.
|
||||||
export function extractDirectives(
|
export function extractDirectives(
|
||||||
inputProps: Props,
|
inputProps: Record<string | number | symbol, any>,
|
||||||
clientDirectives: SSRResult['clientDirectives']
|
clientDirectives: SSRResult['clientDirectives']
|
||||||
): ExtractedProps {
|
): ExtractedProps {
|
||||||
let extracted: ExtractedProps = {
|
let extracted: ExtractedProps = {
|
||||||
isPage: false,
|
isPage: false,
|
||||||
hydration: null,
|
hydration: null,
|
||||||
props: {},
|
props: {},
|
||||||
propsWithoutTransitionAttributes: {},
|
|
||||||
};
|
};
|
||||||
for (const [key, value] of Object.entries(inputProps)) {
|
for (const [key, value] of Object.entries(inputProps)) {
|
||||||
if (key.startsWith('server:')) {
|
if (key.startsWith('server:')) {
|
||||||
|
@ -100,14 +96,10 @@ export function extractDirectives(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
extracted.props[key] = value;
|
extracted.props[key] = value;
|
||||||
if (!transitionDirectivesToCopyOnIsland.includes(key)) {
|
|
||||||
extracted.propsWithoutTransitionAttributes[key] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const sym of Object.getOwnPropertySymbols(inputProps)) {
|
for (const sym of Object.getOwnPropertySymbols(inputProps)) {
|
||||||
extracted.props[sym] = inputProps[sym];
|
extracted.props[sym] = inputProps[sym];
|
||||||
extracted.propsWithoutTransitionAttributes[sym] = inputProps[sym];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return extracted;
|
return extracted;
|
||||||
|
|
|
@ -92,10 +92,7 @@ async function renderFrameworkComponent(
|
||||||
displayName,
|
displayName,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { hydration, isPage, props, propsWithoutTransitionAttributes } = extractDirectives(
|
const { hydration, isPage, props } = extractDirectives(_props, clientDirectives);
|
||||||
_props,
|
|
||||||
clientDirectives
|
|
||||||
);
|
|
||||||
let html = '';
|
let html = '';
|
||||||
let attrs: Record<string, string> | undefined = undefined;
|
let attrs: Record<string, string> | undefined = undefined;
|
||||||
|
|
||||||
|
@ -220,7 +217,7 @@ async function renderFrameworkComponent(
|
||||||
({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
|
({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
|
||||||
{ result },
|
{ result },
|
||||||
Component,
|
Component,
|
||||||
propsWithoutTransitionAttributes,
|
props,
|
||||||
children,
|
children,
|
||||||
metadata
|
metadata
|
||||||
));
|
));
|
||||||
|
@ -245,7 +242,7 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
|
||||||
({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
|
({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
|
||||||
{ result },
|
{ result },
|
||||||
Component,
|
Component,
|
||||||
propsWithoutTransitionAttributes,
|
props,
|
||||||
children,
|
children,
|
||||||
metadata
|
metadata
|
||||||
));
|
));
|
||||||
|
|
|
@ -13,14 +13,9 @@ type Events = 'astro:page-load' | 'astro:after-swap';
|
||||||
// only update history entries that are managed by us
|
// only update history entries that are managed by us
|
||||||
// leave other entries alone and do not accidently add state.
|
// leave other entries alone and do not accidently add state.
|
||||||
const persistState = (state: State) => history.state && history.replaceState(state, '');
|
const persistState = (state: State) => history.state && history.replaceState(state, '');
|
||||||
|
export const supportsViewTransitions = !!document.startViewTransition;
|
||||||
const inBrowser = import.meta.env.SSR === false;
|
|
||||||
|
|
||||||
export const supportsViewTransitions = inBrowser && !!document.startViewTransition;
|
|
||||||
|
|
||||||
export const transitionEnabledOnThisPage = () =>
|
export const transitionEnabledOnThisPage = () =>
|
||||||
inBrowser && !!document.querySelector('[name="astro-view-transitions-enabled"]');
|
!!document.querySelector('[name="astro-view-transitions-enabled"]');
|
||||||
|
|
||||||
const samePage = (otherLocation: URL) =>
|
const samePage = (otherLocation: URL) =>
|
||||||
location.pathname === otherLocation.pathname && location.search === otherLocation.search;
|
location.pathname === otherLocation.pathname && location.search === otherLocation.search;
|
||||||
const triggerEvent = (name: Events) => document.dispatchEvent(new Event(name));
|
const triggerEvent = (name: Events) => document.dispatchEvent(new Event(name));
|
||||||
|
@ -45,17 +40,18 @@ const announce = () => {
|
||||||
60
|
60
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const PERSIST_ATTR = 'data-astro-transition-persist';
|
const PERSIST_ATTR = 'data-astro-transition-persist';
|
||||||
|
const parser = new DOMParser();
|
||||||
let parser: DOMParser;
|
// explained at its usage
|
||||||
|
let noopEl: HTMLDivElement;
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
noopEl = document.createElement('div');
|
||||||
|
}
|
||||||
|
|
||||||
// The History API does not tell you if navigation is forward or back, so
|
// The History API does not tell you if navigation is forward or back, so
|
||||||
// you can figure it using an index. On pushState the index is incremented so you
|
// you can figure it using an index. On pushState the index is incremented so you
|
||||||
// can use that to determine popstate if going forward or back.
|
// can use that to determine popstate if going forward or back.
|
||||||
let currentHistoryIndex = 0;
|
let currentHistoryIndex = 0;
|
||||||
|
|
||||||
if (inBrowser) {
|
|
||||||
if (history.state) {
|
if (history.state) {
|
||||||
// we reloaded a page with history state
|
// we reloaded a page with history state
|
||||||
// (e.g. history navigation from non-transition page or browser reload)
|
// (e.g. history navigation from non-transition page or browser reload)
|
||||||
|
@ -64,8 +60,6 @@ if (inBrowser) {
|
||||||
} else if (transitionEnabledOnThisPage()) {
|
} else if (transitionEnabledOnThisPage()) {
|
||||||
history.replaceState({ index: currentHistoryIndex, scrollX, scrollY, intraPage: false }, '');
|
history.replaceState({ index: currentHistoryIndex, scrollX, scrollY, intraPage: false }, '');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const throttle = (cb: (...args: any[]) => any, delay: number) => {
|
const throttle = (cb: (...args: any[]) => any, delay: number) => {
|
||||||
let wait = false;
|
let wait = false;
|
||||||
// During the waiting time additional events are lost.
|
// During the waiting time additional events are lost.
|
||||||
|
@ -157,24 +151,18 @@ function isInfinite(animation: Animation) {
|
||||||
|
|
||||||
const updateHistoryAndScrollPosition = (toLocation: URL, replace: boolean, intraPage: boolean) => {
|
const updateHistoryAndScrollPosition = (toLocation: URL, replace: boolean, intraPage: boolean) => {
|
||||||
const fresh = !samePage(toLocation);
|
const fresh = !samePage(toLocation);
|
||||||
let scrolledToTop = false;
|
|
||||||
if (toLocation.href !== location.href) {
|
if (toLocation.href !== location.href) {
|
||||||
if (replace) {
|
if (replace) {
|
||||||
history.replaceState({ ...history.state }, '', toLocation.href);
|
history.replaceState({ ...history.state }, '', toLocation.href);
|
||||||
} else {
|
} else {
|
||||||
history.replaceState({ ...history.state, intraPage }, '');
|
history.replaceState({ ...history.state, intraPage }, '');
|
||||||
history.pushState(
|
history.pushState({ index: ++currentHistoryIndex, scrollX, scrollY }, '', toLocation.href);
|
||||||
{ index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 },
|
|
||||||
'',
|
|
||||||
toLocation.href
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// now we are on the new page for non-history navigations!
|
// now we are on the new page for non-history navigations!
|
||||||
// (with history navigation page change happens before popstate is fired)
|
// (with history navigation page change happens before popstate is fired)
|
||||||
// freshly loaded pages start from the top
|
// freshly loaded pages start from the top
|
||||||
if (fresh) {
|
if (fresh) {
|
||||||
scrollTo({ left: 0, top: 0, behavior: 'instant' });
|
scrollTo({ left: 0, top: 0, behavior: 'instant' });
|
||||||
scrolledToTop = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (toLocation.hash) {
|
if (toLocation.hash) {
|
||||||
|
@ -183,10 +171,8 @@ const updateHistoryAndScrollPosition = (toLocation: URL, replace: boolean, intra
|
||||||
// that won't reload the page but instead scroll to the fragment
|
// that won't reload the page but instead scroll to the fragment
|
||||||
location.href = toLocation.href;
|
location.href = toLocation.href;
|
||||||
} else {
|
} else {
|
||||||
if (!scrolledToTop) {
|
|
||||||
scrollTo({ left: 0, top: 0, behavior: 'instant' });
|
scrollTo({ left: 0, top: 0, behavior: 'instant' });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// replace head and body of the windows document with contents from newDocument
|
// replace head and body of the windows document with contents from newDocument
|
||||||
|
@ -212,6 +198,22 @@ async function updateDOM(
|
||||||
const href = el.getAttribute('href');
|
const href = el.getAttribute('href');
|
||||||
return newDocument.head.querySelector(`link[rel=stylesheet][href="${href}"]`);
|
return newDocument.head.querySelector(`link[rel=stylesheet][href="${href}"]`);
|
||||||
}
|
}
|
||||||
|
// What follows is a fix for an issue (#8472) with missing client:only styles after transition.
|
||||||
|
// That problem exists only in dev mode where styles are injected into the page by Vite.
|
||||||
|
// Returning a noop element ensures that the styles are not removed from the old document.
|
||||||
|
// Guarding the code below with the dev mode check
|
||||||
|
// allows tree shaking to remove this code in production.
|
||||||
|
if (import.meta.env.DEV) {
|
||||||
|
if (el.tagName === 'STYLE' && el.dataset.viteDevId) {
|
||||||
|
const devId = el.dataset.viteDevId;
|
||||||
|
// If this same style tag exists, remove it from the new page
|
||||||
|
return (
|
||||||
|
newDocument.querySelector(`style[data-vite-dev-id="${devId}"]`) ||
|
||||||
|
// Otherwise, keep it anyways. This is client:only styles.
|
||||||
|
noopEl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -347,8 +349,6 @@ async function transition(
|
||||||
toLocation = new URL(response.redirected);
|
toLocation = new URL(response.redirected);
|
||||||
}
|
}
|
||||||
|
|
||||||
parser ??= new DOMParser();
|
|
||||||
|
|
||||||
const newDocument = parser.parseFromString(response.html, response.mediaType);
|
const newDocument = parser.parseFromString(response.html, response.mediaType);
|
||||||
// The next line might look like a hack,
|
// The next line might look like a hack,
|
||||||
// but it is actually necessary as noscript elements
|
// but it is actually necessary as noscript elements
|
||||||
|
@ -385,22 +385,7 @@ async function transition(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let navigateOnServerWarned = false;
|
|
||||||
|
|
||||||
export function navigate(href: string, options?: Options) {
|
export function navigate(href: string, options?: Options) {
|
||||||
if (inBrowser === false) {
|
|
||||||
if (!navigateOnServerWarned) {
|
|
||||||
// instantiate an error for the stacktrace to show to user.
|
|
||||||
const warning = new Error(
|
|
||||||
'The view transtions client API was called during a server side render. This may be unintentional as the navigate() function is expected to be called in response to user interactions. Please make sure that your usage is correct.'
|
|
||||||
);
|
|
||||||
warning.name = 'Warning';
|
|
||||||
console.warn(warning);
|
|
||||||
navigateOnServerWarned = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not ours
|
// not ours
|
||||||
if (!transitionEnabledOnThisPage()) {
|
if (!transitionEnabledOnThisPage()) {
|
||||||
location.href = href;
|
location.href = href;
|
||||||
|
@ -418,7 +403,8 @@ export function navigate(href: string, options?: Options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPopState(ev: PopStateEvent) {
|
if (supportsViewTransitions || getFallback() !== 'none') {
|
||||||
|
addEventListener('popstate', (ev) => {
|
||||||
if (!transitionEnabledOnThisPage() && ev.state) {
|
if (!transitionEnabledOnThisPage() && ev.state) {
|
||||||
// The current page doesn't have View Transitions enabled
|
// The current page doesn't have View Transitions enabled
|
||||||
// but the page we navigate to does (because it set the state).
|
// but the page we navigate to does (because it set the state).
|
||||||
|
@ -458,11 +444,8 @@ function onPopState(ev: PopStateEvent) {
|
||||||
currentHistoryIndex = nextIndex;
|
currentHistoryIndex = nextIndex;
|
||||||
transition(direction, new URL(location.href), {}, state);
|
transition(direction, new URL(location.href), {}, state);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if (inBrowser) {
|
|
||||||
if (supportsViewTransitions || getFallback() !== 'none') {
|
|
||||||
addEventListener('popstate', onPopState);
|
|
||||||
addEventListener('load', onPageLoad);
|
addEventListener('load', onPageLoad);
|
||||||
// There's not a good way to record scroll position before a back button.
|
// There's not a good way to record scroll position before a back button.
|
||||||
// So the way we do it is by listening to scrollend if supported, and if not continuously record the scroll position.
|
// So the way we do it is by listening to scrollend if supported, and if not continuously record the scroll position.
|
||||||
|
@ -475,4 +458,3 @@ if (inBrowser) {
|
||||||
|
|
||||||
markScriptsExec();
|
markScriptsExec();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { expect } from 'chai';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import { basename } from 'node:path';
|
import { basename } from 'node:path';
|
||||||
import { Writable } from 'node:stream';
|
import { Writable } from 'node:stream';
|
||||||
|
import parseSrcset from 'parse-srcset';
|
||||||
import { removeDir } from '../dist/core/fs/index.js';
|
import { removeDir } from '../dist/core/fs/index.js';
|
||||||
import { Logger } from '../dist/core/logger/core.js';
|
import { Logger } from '../dist/core/logger/core.js';
|
||||||
import testAdapter from './test-adapter.js';
|
import testAdapter from './test-adapter.js';
|
||||||
|
@ -188,6 +189,36 @@ describe('astro:image', () => {
|
||||||
expect(res.status).to.equal(200);
|
expect(res.status).to.equal(200);
|
||||||
expect(res.headers.get('content-type')).to.equal('image/avif');
|
expect(res.headers.get('content-type')).to.equal('image/avif');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('has a working Picture component', async () => {
|
||||||
|
let res = await fixture.fetch('/picturecomponent');
|
||||||
|
let html = await res.text();
|
||||||
|
$ = cheerio.load(html);
|
||||||
|
|
||||||
|
// Densities
|
||||||
|
let $img = $('#picture-density-2-format img');
|
||||||
|
let $picture = $('#picture-density-2-format picture');
|
||||||
|
let $source = $('#picture-density-2-format source');
|
||||||
|
expect($img).to.have.a.lengthOf(1);
|
||||||
|
expect($picture).to.have.a.lengthOf(1);
|
||||||
|
expect($source).to.have.a.lengthOf(2);
|
||||||
|
|
||||||
|
const srcset = parseSrcset($source.attr('srcset'));
|
||||||
|
expect(srcset.every((src) => src.url.startsWith('/_image'))).to.equal(true);
|
||||||
|
expect(srcset.map((src) => src.d)).to.deep.equal([undefined, 2]);
|
||||||
|
|
||||||
|
// Widths
|
||||||
|
$img = $('#picture-widths img');
|
||||||
|
$picture = $('#picture-widths picture');
|
||||||
|
$source = $('#picture-widths source');
|
||||||
|
expect($img).to.have.a.lengthOf(1);
|
||||||
|
expect($picture).to.have.a.lengthOf(1);
|
||||||
|
expect($source).to.have.a.lengthOf(1);
|
||||||
|
|
||||||
|
const srcset2 = parseSrcset($source.attr('srcset'));
|
||||||
|
expect(srcset2.every((src) => src.url.startsWith('/_image'))).to.equal(true);
|
||||||
|
expect(srcset2.map((src) => src.w)).to.deep.equal([undefined, 207]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('vite-isms', () => {
|
describe('vite-isms', () => {
|
||||||
|
@ -702,6 +733,26 @@ describe('astro:image', () => {
|
||||||
expect(data).to.be.an.instanceOf(Buffer);
|
expect(data).to.be.an.instanceOf(Buffer);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Picture component images are written', async () => {
|
||||||
|
const html = await fixture.readFile('/picturecomponent/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
let $img = $('img');
|
||||||
|
let $source = $('source');
|
||||||
|
|
||||||
|
expect($img).to.have.a.lengthOf(1);
|
||||||
|
expect($source).to.have.a.lengthOf(2);
|
||||||
|
|
||||||
|
const srcset = parseSrcset($source.attr('srcset'));
|
||||||
|
let hasExistingSrc = await Promise.all(
|
||||||
|
srcset.map(async (src) => {
|
||||||
|
const data = await fixture.readFile(src.url, null);
|
||||||
|
return data instanceof Buffer;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(hasExistingSrc.every((src) => src === true)).to.deep.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('markdown images are written', async () => {
|
it('markdown images are written', async () => {
|
||||||
const html = await fixture.readFile('/post/index.html');
|
const html = await fixture.readFile('/post/index.html');
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
6
packages/astro/test/fixtures/core-image-ssg/src/pages/picturecomponent.astro
vendored
Normal file
6
packages/astro/test/fixtures/core-image-ssg/src/pages/picturecomponent.astro
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
import { Picture } from "astro:assets";
|
||||||
|
import myImage from "../assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
|
||||||
|
<Picture src={myImage} width={Math.round(myImage.width / 2)} alt="A penguin" densities={[2]} formats={['avif', 'webp']} />
|
12
packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro
vendored
Normal file
12
packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
import { Picture } from "astro:assets";
|
||||||
|
import myImage from "../assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
|
||||||
|
<div id="picture-density-2-format">
|
||||||
|
<Picture src={myImage} width={Math.round(myImage.width / 2)} alt="A penguin" densities={[2]} formats={['avif', 'webp']} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="picture-widths">
|
||||||
|
<Picture src={myImage} width={Math.round(myImage.width / 2)} alt="A penguin" widths={[myImage.width]} />
|
||||||
|
</div>
|
|
@ -1,7 +0,0 @@
|
||||||
import { defineConfig } from 'astro/config';
|
|
||||||
import react from '@astrojs/react';
|
|
||||||
|
|
||||||
// https://astro.build/config
|
|
||||||
export default defineConfig({
|
|
||||||
integrations: [react()],
|
|
||||||
});
|
|
|
@ -3,9 +3,6 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "workspace:*",
|
"astro": "workspace:*"
|
||||||
"@astrojs/react": "workspace:*",
|
|
||||||
"react": "^18.1.0",
|
|
||||||
"react-dom": "^18.1.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
.counter {
|
|
||||||
display: grid;
|
|
||||||
font-size: 2em;
|
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
||||||
margin-top: 2em;
|
|
||||||
place-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.counter-message {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import React, { useState } from 'react';
|
|
||||||
import './Island.css';
|
|
||||||
|
|
||||||
export default function Counter({ children, count: initialCount, id }) {
|
|
||||||
const [count, setCount] = useState(initialCount);
|
|
||||||
const add = () => setCount((i) => i + 1);
|
|
||||||
const subtract = () => setCount((i) => i - 1);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div id={id} className="counter">
|
|
||||||
<button className="decrement" onClick={subtract}>-</button>
|
|
||||||
<pre>{count}</pre>
|
|
||||||
<button className="increment" onClick={add}>+</button>
|
|
||||||
</div>
|
|
||||||
<div className="counter-message">{children}</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
---
|
|
||||||
import Island from '../components/Island.jsx';
|
|
||||||
---
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<Island id="1" count="{1}" children="Greetings!" transition:persist="here" client:load/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -22,14 +22,4 @@ describe('View Transitions styles', () => {
|
||||||
|
|
||||||
expect($('head style')).to.have.a.lengthOf(3);
|
expect($('head style')).to.have.a.lengthOf(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not duplicate transition attributes on island contents', async () => {
|
|
||||||
let res = await fixture.fetch('/hasIsland');
|
|
||||||
let html = await res.text();
|
|
||||||
let $ = cheerio.load(html);
|
|
||||||
expect($('astro-island[data-astro-transition-persist]')).to.have.a.lengthOf(1);
|
|
||||||
expect(
|
|
||||||
$('astro-island[data-astro-transition-persist] > [data-astro-transition-persist]')
|
|
||||||
).to.have.a.lengthOf(0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,17 +1,5 @@
|
||||||
# @astrojs/cloudflare
|
# @astrojs/cloudflare
|
||||||
|
|
||||||
## 7.5.2
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#8766](https://github.com/withastro/astro/pull/8766) [`054c5c644`](https://github.com/withastro/astro/commit/054c5c6447d79dd4ea7ab6ce0f9ec836abebd211) Thanks [@jadbox](https://github.com/jadbox)! - Adds `cloudflare:sockets` compile support
|
|
||||||
|
|
||||||
- [#8788](https://github.com/withastro/astro/pull/8788) [`0ab6bad7d`](https://github.com/withastro/astro/commit/0ab6bad7dffd413c975ab00e545f8bc150f6a92f) Thanks [@alexanderniebuhr](https://github.com/alexanderniebuhr)! - Adds support for `node:crypto`
|
|
||||||
|
|
||||||
- Updated dependencies [[`160d1cd75`](https://github.com/withastro/astro/commit/160d1cd755e70af1d8ec294d01dd2cb32d60db50), [`30de32436`](https://github.com/withastro/astro/commit/30de324361bc261956eb9fc08fe60a82ff602a9b), [`c4a7ec425`](https://github.com/withastro/astro/commit/c4a7ec4255e7acb9555cb8bb74ea13c5fbb2ac17), [`c24f70d91`](https://github.com/withastro/astro/commit/c24f70d91601dd3a6b5a84f04d61824e775e9b44), [`93b092266`](https://github.com/withastro/astro/commit/93b092266febfad16a48575f8eee12d5910bf071), [`29cdfa024`](https://github.com/withastro/astro/commit/29cdfa024886dd581cb207586f7dfec6966bdd4e), [`eaed844ea`](https://github.com/withastro/astro/commit/eaed844ea8f2f52e0c9caa40bb3ec7377e10595f)]:
|
|
||||||
- astro@3.2.4
|
|
||||||
- @astrojs/underscore-redirects@0.3.1
|
|
||||||
|
|
||||||
## 7.5.1
|
## 7.5.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -169,7 +169,7 @@ default: `false`
|
||||||
|
|
||||||
Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration) using the `.wasm?module` import syntax.
|
Whether or not to import `.wasm` files [directly as ES modules](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration) using the `.wasm?module` import syntax.
|
||||||
|
|
||||||
Add `wasmModuleImports: true` to `astro.config.mjs` to enable this functionality in both the Cloudflare build and the Astro dev server. Read more about [using Wasm modules](#use-wasm-modules).
|
Add `wasmModuleImports: true` to `astro.config.mjs` to enable this functionality in both the Cloudflare build and the Astro dev server. Read more about [using Wasm modules](#use-wasm-modules)
|
||||||
|
|
||||||
```diff lang="js"
|
```diff lang="js"
|
||||||
// astro.config.mjs
|
// astro.config.mjs
|
||||||
|
@ -221,7 +221,7 @@ Currently supported bindings:
|
||||||
- [Cloudflare Workers KV](https://developers.cloudflare.com/kv/)
|
- [Cloudflare Workers KV](https://developers.cloudflare.com/kv/)
|
||||||
- [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/)
|
- [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/)
|
||||||
|
|
||||||
You can access the runtime from Astro components through `Astro.locals` inside any `.astro` file.
|
You can access the runtime from Astro components through `Astro.locals` inside any .astro` file.
|
||||||
|
|
||||||
```astro
|
```astro
|
||||||
---
|
---
|
||||||
|
@ -339,7 +339,6 @@ Astro's Cloudflare adapter allows you to use any Node.js runtime API supported b
|
||||||
- assert
|
- assert
|
||||||
- AsyncLocalStorage
|
- AsyncLocalStorage
|
||||||
- Buffer
|
- Buffer
|
||||||
- Crypto
|
|
||||||
- Diagnostics Channel
|
- Diagnostics Channel
|
||||||
- EventEmitter
|
- EventEmitter
|
||||||
- path
|
- path
|
||||||
|
@ -358,10 +357,6 @@ import { Buffer } from 'node:buffer';
|
||||||
|
|
||||||
Additionally, you'll need to enable the Compatibility Flag in Cloudflare. The configuration for this flag may vary based on where you deploy your Astro site. For detailed guidance, please refer to the [Cloudflare documentation on enabling Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs).
|
Additionally, you'll need to enable the Compatibility Flag in Cloudflare. The configuration for this flag may vary based on where you deploy your Astro site. For detailed guidance, please refer to the [Cloudflare documentation on enabling Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs).
|
||||||
|
|
||||||
## Cloudflare module support
|
|
||||||
|
|
||||||
All Cloudflare namespaced packages (e.g. `cloudflare:sockets`) are allowlisted for use. Note that the package `cloudflare:sockets` does not work locally without using Wrangler dev mode.
|
|
||||||
|
|
||||||
## Preview with Wrangler
|
## Preview with Wrangler
|
||||||
|
|
||||||
To use [`wrangler`](https://developers.cloudflare.com/workers/wrangler/) to run your application locally, update the preview script:
|
To use [`wrangler`](https://developers.cloudflare.com/workers/wrangler/) to run your application locally, update the preview script:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@astrojs/cloudflare",
|
"name": "@astrojs/cloudflare",
|
||||||
"description": "Deploy your site to Cloudflare Workers/Pages",
|
"description": "Deploy your site to Cloudflare Workers/Pages",
|
||||||
"version": "7.5.2",
|
"version": "7.5.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"author": "withastro",
|
"author": "withastro",
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.9"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4"
|
"astro": "workspace:^3.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/iarna__toml": "^2.0.2",
|
"@types/iarna__toml": "^2.0.2",
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import type {
|
import type { Request as CFRequest, ExecutionContext } from '@cloudflare/workers-types';
|
||||||
Request as CFRequest,
|
|
||||||
CacheStorage,
|
|
||||||
ExecutionContext,
|
|
||||||
} from '@cloudflare/workers-types';
|
|
||||||
import type { SSRManifest } from 'astro';
|
import type { SSRManifest } from 'astro';
|
||||||
import { App } from 'astro/app';
|
import { App } from 'astro/app';
|
||||||
import { getProcessEnvProxy, isNode } from '../util.js';
|
import { getProcessEnvProxy, isNode } from '../util.js';
|
||||||
|
@ -20,7 +16,7 @@ export interface AdvancedRuntime<T extends object = object> {
|
||||||
waitUntil: (promise: Promise<any>) => void;
|
waitUntil: (promise: Promise<any>) => void;
|
||||||
env: Env & T;
|
env: Env & T;
|
||||||
cf: CFRequest['cf'];
|
cf: CFRequest['cf'];
|
||||||
caches: CacheStorage;
|
caches: typeof caches;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +50,7 @@ export function createExports(manifest: SSRManifest) {
|
||||||
},
|
},
|
||||||
env: env,
|
env: env,
|
||||||
cf: request.cf,
|
cf: request.cf,
|
||||||
caches: caches as unknown as CacheStorage,
|
caches: caches,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Request as CFRequest, CacheStorage, EventContext } from '@cloudflare/workers-types';
|
import type { Request as CFRequest, EventContext } from '@cloudflare/workers-types';
|
||||||
import type { SSRManifest } from 'astro';
|
import type { SSRManifest } from 'astro';
|
||||||
import { App } from 'astro/app';
|
import { App } from 'astro/app';
|
||||||
import { getProcessEnvProxy, isNode } from '../util.js';
|
import { getProcessEnvProxy, isNode } from '../util.js';
|
||||||
|
@ -6,12 +6,13 @@ import { getProcessEnvProxy, isNode } from '../util.js';
|
||||||
if (!isNode) {
|
if (!isNode) {
|
||||||
process.env = getProcessEnvProxy();
|
process.env = getProcessEnvProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DirectoryRuntime<T extends object = object> {
|
export interface DirectoryRuntime<T extends object = object> {
|
||||||
runtime: {
|
runtime: {
|
||||||
waitUntil: (promise: Promise<any>) => void;
|
waitUntil: (promise: Promise<any>) => void;
|
||||||
env: EventContext<unknown, string, unknown>['env'] & T;
|
env: EventContext<unknown, string, unknown>['env'] & T;
|
||||||
cf: CFRequest['cf'];
|
cf: CFRequest['cf'];
|
||||||
caches: CacheStorage;
|
caches: typeof caches;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ export function createExports(manifest: SSRManifest) {
|
||||||
},
|
},
|
||||||
env: context.env,
|
env: context.env,
|
||||||
cf: request.cf,
|
cf: request.cf,
|
||||||
caches: caches as unknown as CacheStorage,
|
caches: caches,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,6 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
'node:assert',
|
'node:assert',
|
||||||
'node:async_hooks',
|
'node:async_hooks',
|
||||||
'node:buffer',
|
'node:buffer',
|
||||||
'node:crypto',
|
|
||||||
'node:diagnostics_channel',
|
'node:diagnostics_channel',
|
||||||
'node:events',
|
'node:events',
|
||||||
'node:path',
|
'node:path',
|
||||||
|
@ -291,7 +290,6 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
'node:stream',
|
'node:stream',
|
||||||
'node:string_decoder',
|
'node:string_decoder',
|
||||||
'node:util',
|
'node:util',
|
||||||
'cloudflare:*',
|
|
||||||
],
|
],
|
||||||
entryPoints: pathsGroup,
|
entryPoints: pathsGroup,
|
||||||
outbase: absolutePagesDirname,
|
outbase: absolutePagesDirname,
|
||||||
|
@ -366,7 +364,6 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
'node:assert',
|
'node:assert',
|
||||||
'node:async_hooks',
|
'node:async_hooks',
|
||||||
'node:buffer',
|
'node:buffer',
|
||||||
'node:crypto',
|
|
||||||
'node:diagnostics_channel',
|
'node:diagnostics_channel',
|
||||||
'node:events',
|
'node:events',
|
||||||
'node:path',
|
'node:path',
|
||||||
|
@ -374,7 +371,6 @@ export default function createIntegration(args?: Options): AstroIntegration {
|
||||||
'node:stream',
|
'node:stream',
|
||||||
'node:string_decoder',
|
'node:string_decoder',
|
||||||
'node:util',
|
'node:util',
|
||||||
'cloudflare:*',
|
|
||||||
],
|
],
|
||||||
entryPoints: [entryPath],
|
entryPoints: [entryPath],
|
||||||
outfile: buildPath,
|
outfile: buildPath,
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
"zod": "3.21.1"
|
"zod": "3.21.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4"
|
"astro": "workspace:^3.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/markdown-remark": "workspace:*",
|
"@astrojs/markdown-remark": "workspace:*",
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
"vfile": "^5.3.7"
|
"vfile": "^5.3.7"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4"
|
"astro": "workspace:^3.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^4.3.5",
|
"@types/chai": "^4.3.5",
|
||||||
|
|
|
@ -116,14 +116,14 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
||||||
if (!id.endsWith('.mdx')) return;
|
if (!id.endsWith('.mdx')) return;
|
||||||
|
|
||||||
// Read code from file manually to prevent Vite from parsing `import.meta.env` expressions
|
// Read code from file manually to prevent Vite from parsing `import.meta.env` expressions
|
||||||
const { fileId, fileUrl } = getFileInfo(id, config);
|
const { fileId } = getFileInfo(id, config);
|
||||||
const code = await fs.readFile(fileId, 'utf-8');
|
const code = await fs.readFile(fileId, 'utf-8');
|
||||||
|
|
||||||
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
||||||
|
|
||||||
const vfile = new VFile({ value: pageContent, path: id });
|
const vfile = new VFile({ value: pageContent, path: id });
|
||||||
// Ensure `data.astro` is available to all remark plugins
|
// Ensure `data.astro` is available to all remark plugins
|
||||||
setVfileFrontmatter(vfile, frontmatter, { fileURL: new URL(fileUrl) });
|
setVfileFrontmatter(vfile, frontmatter);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const compiled = await processor.process(vfile);
|
const compiled = await processor.process(vfile);
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
"server-destroy": "^1.0.1"
|
"server-destroy": "^1.0.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4"
|
"astro": "workspace:^3.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.17.8",
|
"@types/node": "^18.17.8",
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.9"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4",
|
"astro": "workspace:^3.2.3",
|
||||||
"svelte": "^3.55.0 || ^4.0.0"
|
"svelte": "^3.55.0 || ^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
# @astrojs/tailwind
|
# @astrojs/tailwind
|
||||||
|
|
||||||
## 5.0.2
|
|
||||||
|
|
||||||
### Patch Changes
|
|
||||||
|
|
||||||
- [#8638](https://github.com/withastro/astro/pull/8638) [`160d1cd75`](https://github.com/withastro/astro/commit/160d1cd755e70af1d8ec294d01dd2cb32d60db50) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - The `@astrojs/tailwind` integration now creates a `tailwind.config.mjs` file by default
|
|
||||||
|
|
||||||
- Updated dependencies [[`160d1cd75`](https://github.com/withastro/astro/commit/160d1cd755e70af1d8ec294d01dd2cb32d60db50), [`30de32436`](https://github.com/withastro/astro/commit/30de324361bc261956eb9fc08fe60a82ff602a9b), [`c4a7ec425`](https://github.com/withastro/astro/commit/c4a7ec4255e7acb9555cb8bb74ea13c5fbb2ac17), [`c24f70d91`](https://github.com/withastro/astro/commit/c24f70d91601dd3a6b5a84f04d61824e775e9b44), [`93b092266`](https://github.com/withastro/astro/commit/93b092266febfad16a48575f8eee12d5910bf071), [`29cdfa024`](https://github.com/withastro/astro/commit/29cdfa024886dd581cb207586f7dfec6966bdd4e), [`eaed844ea`](https://github.com/withastro/astro/commit/eaed844ea8f2f52e0c9caa40bb3ec7377e10595f)]:
|
|
||||||
- astro@3.2.4
|
|
||||||
|
|
||||||
## 5.0.1
|
## 5.0.1
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -94,7 +94,7 @@ https://user-images.githubusercontent.com/4033662/169918388-8ed153b2-0ba0-4b24-b
|
||||||
|
|
||||||
### Configuring Tailwind
|
### Configuring Tailwind
|
||||||
|
|
||||||
If you used the Quick Install instructions and said yes to each prompt, you'll see a `tailwind.config.mjs` file in your project's root directory. Use this file for your Tailwind configuration changes. You can learn how to customize Tailwind using this file [in the Tailwind docs](https://tailwindcss.com/docs/configuration).
|
If you used the Quick Install instructions and said yes to each prompt, you'll see a `tailwind.config.cjs` file in your project's root directory. Use this file for your Tailwind configuration changes. You can learn how to customize Tailwind using this file [in the Tailwind docs](https://tailwindcss.com/docs/configuration).
|
||||||
|
|
||||||
If it isn't there, you add your own `tailwind.config.(js|cjs|mjs)` file to the root directory and the integration will use its configurations. This can be great if you already have Tailwind configured in another project and want to bring those settings over to this one.
|
If it isn't there, you add your own `tailwind.config.(js|cjs|mjs)` file to the root directory and the integration will use its configurations. This can be great if you already have Tailwind configured in another project and want to bring those settings over to this one.
|
||||||
|
|
||||||
|
@ -178,8 +178,8 @@ error The `text-special` class does not exist. If `text-special` is a custom c
|
||||||
[Instead of using `@layer` directives in a global stylesheet](https://tailwindcss.com/docs/functions-and-directives#using-apply-with-per-component-css), define your custom styles by adding a plugin to your Tailwind config to fix it:
|
[Instead of using `@layer` directives in a global stylesheet](https://tailwindcss.com/docs/functions-and-directives#using-apply-with-per-component-css), define your custom styles by adding a plugin to your Tailwind config to fix it:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// tailwind.config.mjs
|
// tailwind.config.cjs
|
||||||
export default {
|
module.exports = {
|
||||||
// ...
|
// ...
|
||||||
plugins: [
|
plugins: [
|
||||||
function ({ addComponents, theme }) {
|
function ({ addComponents, theme }) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@astrojs/tailwind",
|
"name": "@astrojs/tailwind",
|
||||||
"description": "Use Tailwind CSS to style your Astro site",
|
"description": "Use Tailwind CSS to style your Astro site",
|
||||||
"version": "5.0.2",
|
"version": "5.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"author": "withastro",
|
"author": "withastro",
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.9"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4",
|
"astro": "workspace:^3.2.3",
|
||||||
"tailwindcss": "^3.0.24"
|
"tailwindcss": "^3.0.24"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|
|
@ -50,7 +50,7 @@ async function getViteConfiguration(
|
||||||
type TailwindOptions = {
|
type TailwindOptions = {
|
||||||
/**
|
/**
|
||||||
* Path to your tailwind config file
|
* Path to your tailwind config file
|
||||||
* @default 'tailwind.config.mjs'
|
* @default 'tailwind.config.js'
|
||||||
*/
|
*/
|
||||||
configFile?: string;
|
configFile?: string;
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
"web-vitals": "^3.4.0"
|
"web-vitals": "^3.4.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4"
|
"astro": "workspace:^3.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/set-cookie-parser": "^2.4.3",
|
"@types/set-cookie-parser": "^2.4.3",
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
/// <reference types="astro/client" />
|
/// <reference types="astro/client-image" />
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
"vue": "^3.3.4"
|
"vue": "^3.3.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"astro": "workspace:^3.2.4",
|
"astro": "workspace:^3.2.3",
|
||||||
"vue": "^3.2.30"
|
"vue": "^3.2.30"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { VFileData as Data, VFile } from 'vfile';
|
import type { VFileData as Data, VFile } from 'vfile';
|
||||||
import type { MarkdownAstroData, MarkdownProcessorRenderOptions } from './types.js';
|
import type { MarkdownAstroData } from './types.js';
|
||||||
|
|
||||||
function isValidAstroData(obj: unknown): obj is MarkdownAstroData {
|
function isValidAstroData(obj: unknown): obj is MarkdownAstroData {
|
||||||
if (typeof obj === 'object' && obj !== null && obj.hasOwnProperty('frontmatter')) {
|
if (typeof obj === 'object' && obj !== null && obj.hasOwnProperty('frontmatter')) {
|
||||||
|
@ -27,15 +27,10 @@ export function safelyGetAstroData(vfileData: Data): MarkdownAstroData | Invalid
|
||||||
return astro;
|
return astro;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setVfileFrontmatter(
|
export function setVfileFrontmatter(vfile: VFile, frontmatter: Record<string, any>) {
|
||||||
vfile: VFile,
|
|
||||||
frontmatter: Record<string, any>,
|
|
||||||
renderOpts: MarkdownProcessorRenderOptions | undefined
|
|
||||||
) {
|
|
||||||
vfile.data ??= {};
|
vfile.data ??= {};
|
||||||
vfile.data.astro ??= {};
|
vfile.data.astro ??= {};
|
||||||
(vfile.data.astro as any).frontmatter = frontmatter;
|
(vfile.data.astro as any).frontmatter = frontmatter;
|
||||||
(vfile.data.astro as any).fileURL = renderOpts?.fileURL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -124,9 +124,8 @@ export async function createMarkdownProcessor(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async render(content, renderOpts) {
|
async render(content, renderOpts) {
|
||||||
console.log('url', renderOpts?.fileURL);
|
|
||||||
const vfile = new VFile({ value: content, path: renderOpts?.fileURL });
|
const vfile = new VFile({ value: content, path: renderOpts?.fileURL });
|
||||||
setVfileFrontmatter(vfile, renderOpts?.frontmatter ?? {}, renderOpts);
|
setVfileFrontmatter(vfile, renderOpts?.frontmatter ?? {});
|
||||||
|
|
||||||
const result: MarkdownVFile = await parser.process(vfile).catch((err) => {
|
const result: MarkdownVFile = await parser.process(vfile).catch((err) => {
|
||||||
// Ensure that the error message contains the input filename
|
// Ensure that the error message contains the input filename
|
||||||
|
|
|
@ -125,7 +125,7 @@ importers:
|
||||||
examples/basics:
|
examples/basics:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/blog:
|
examples/blog:
|
||||||
|
@ -140,13 +140,13 @@ importers:
|
||||||
specifier: ^3.0.1
|
specifier: ^3.0.1
|
||||||
version: link:../../packages/integrations/sitemap
|
version: link:../../packages/integrations/sitemap
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/component:
|
examples/component:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/framework-alpine:
|
examples/framework-alpine:
|
||||||
|
@ -161,7 +161,7 @@ importers:
|
||||||
specifier: ^3.12.3
|
specifier: ^3.12.3
|
||||||
version: 3.12.3
|
version: 3.12.3
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/framework-lit:
|
examples/framework-lit:
|
||||||
|
@ -173,7 +173,7 @@ importers:
|
||||||
specifier: ^0.2.1
|
specifier: ^0.2.1
|
||||||
version: 0.2.1
|
version: 0.2.1
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
lit:
|
lit:
|
||||||
specifier: ^2.8.0
|
specifier: ^2.8.0
|
||||||
|
@ -197,7 +197,7 @@ importers:
|
||||||
specifier: ^3.0.1
|
specifier: ^3.0.1
|
||||||
version: link:../../packages/integrations/vue
|
version: link:../../packages/integrations/vue
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
preact:
|
preact:
|
||||||
specifier: ^10.17.1
|
specifier: ^10.17.1
|
||||||
|
@ -227,7 +227,7 @@ importers:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1(preact@10.17.1)
|
version: 1.2.1(preact@10.17.1)
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
preact:
|
preact:
|
||||||
specifier: ^10.17.1
|
specifier: ^10.17.1
|
||||||
|
@ -245,7 +245,7 @@ importers:
|
||||||
specifier: ^18.2.7
|
specifier: ^18.2.7
|
||||||
version: 18.2.7
|
version: 18.2.7
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
react:
|
react:
|
||||||
specifier: ^18.2.0
|
specifier: ^18.2.0
|
||||||
|
@ -260,7 +260,7 @@ importers:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: link:../../packages/integrations/solid
|
version: link:../../packages/integrations/solid
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
solid-js:
|
solid-js:
|
||||||
specifier: ^1.7.11
|
specifier: ^1.7.11
|
||||||
|
@ -272,7 +272,7 @@ importers:
|
||||||
specifier: ^4.0.3
|
specifier: ^4.0.3
|
||||||
version: link:../../packages/integrations/svelte
|
version: link:../../packages/integrations/svelte
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
svelte:
|
svelte:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
|
@ -284,7 +284,7 @@ importers:
|
||||||
specifier: ^3.0.1
|
specifier: ^3.0.1
|
||||||
version: link:../../packages/integrations/vue
|
version: link:../../packages/integrations/vue
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.3.4
|
specifier: ^3.3.4
|
||||||
|
@ -296,13 +296,13 @@ importers:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: link:../../packages/integrations/node
|
version: link:../../packages/integrations/node
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/integration:
|
examples/integration:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/middleware:
|
examples/middleware:
|
||||||
|
@ -311,7 +311,7 @@ importers:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: link:../../packages/integrations/node
|
version: link:../../packages/integrations/node
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
html-minifier:
|
html-minifier:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
|
@ -320,19 +320,19 @@ importers:
|
||||||
examples/minimal:
|
examples/minimal:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/non-html-pages:
|
examples/non-html-pages:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/portfolio:
|
examples/portfolio:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/ssr:
|
examples/ssr:
|
||||||
|
@ -344,7 +344,7 @@ importers:
|
||||||
specifier: ^4.0.3
|
specifier: ^4.0.3
|
||||||
version: link:../../packages/integrations/svelte
|
version: link:../../packages/integrations/svelte
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
svelte:
|
svelte:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
|
@ -356,10 +356,10 @@ importers:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: link:../../packages/integrations/node
|
version: link:../../packages/integrations/node
|
||||||
'@astrojs/tailwind':
|
'@astrojs/tailwind':
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.1
|
||||||
version: link:../../packages/integrations/tailwind
|
version: link:../../packages/integrations/tailwind
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/with-markdoc:
|
examples/with-markdoc:
|
||||||
|
@ -368,7 +368,7 @@ importers:
|
||||||
specifier: ^0.5.2
|
specifier: ^0.5.2
|
||||||
version: link:../../packages/integrations/markdoc
|
version: link:../../packages/integrations/markdoc
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/with-markdown-plugins:
|
examples/with-markdown-plugins:
|
||||||
|
@ -377,7 +377,7 @@ importers:
|
||||||
specifier: ^3.2.1
|
specifier: ^3.2.1
|
||||||
version: link:../../packages/markdown/remark
|
version: link:../../packages/markdown/remark
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
hast-util-select:
|
hast-util-select:
|
||||||
specifier: ^5.0.5
|
specifier: ^5.0.5
|
||||||
|
@ -398,7 +398,7 @@ importers:
|
||||||
examples/with-markdown-shiki:
|
examples/with-markdown-shiki:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
|
|
||||||
examples/with-mdx:
|
examples/with-mdx:
|
||||||
|
@ -410,7 +410,7 @@ importers:
|
||||||
specifier: ^3.0.1
|
specifier: ^3.0.1
|
||||||
version: link:../../packages/integrations/preact
|
version: link:../../packages/integrations/preact
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
preact:
|
preact:
|
||||||
specifier: ^10.17.1
|
specifier: ^10.17.1
|
||||||
|
@ -425,7 +425,7 @@ importers:
|
||||||
specifier: ^0.5.0
|
specifier: ^0.5.0
|
||||||
version: 0.5.0(nanostores@0.9.3)(preact@10.17.1)
|
version: 0.5.0(nanostores@0.9.3)(preact@10.17.1)
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
nanostores:
|
nanostores:
|
||||||
specifier: ^0.9.3
|
specifier: ^0.9.3
|
||||||
|
@ -440,13 +440,13 @@ importers:
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.1
|
||||||
version: link:../../packages/integrations/mdx
|
version: link:../../packages/integrations/mdx
|
||||||
'@astrojs/tailwind':
|
'@astrojs/tailwind':
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.1
|
||||||
version: link:../../packages/integrations/tailwind
|
version: link:../../packages/integrations/tailwind
|
||||||
'@types/canvas-confetti':
|
'@types/canvas-confetti':
|
||||||
specifier: ^1.6.0
|
specifier: ^1.6.0
|
||||||
version: 1.6.0
|
version: 1.6.0
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.15
|
specifier: ^10.4.15
|
||||||
|
@ -464,7 +464,7 @@ importers:
|
||||||
examples/with-vite-plugin-pwa:
|
examples/with-vite-plugin-pwa:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
vite-plugin-pwa:
|
vite-plugin-pwa:
|
||||||
specifier: 0.16.4
|
specifier: 0.16.4
|
||||||
|
@ -476,7 +476,7 @@ importers:
|
||||||
examples/with-vitest:
|
examples/with-vitest:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.3
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^0.34.2
|
specifier: ^0.34.2
|
||||||
|
@ -753,6 +753,9 @@ importers:
|
||||||
node-mocks-http:
|
node-mocks-http:
|
||||||
specifier: ^1.13.0
|
specifier: ^1.13.0
|
||||||
version: 1.13.0
|
version: 1.13.0
|
||||||
|
parse-srcset:
|
||||||
|
specifier: ^1.0.2
|
||||||
|
version: 1.0.2
|
||||||
rehype-autolink-headings:
|
rehype-autolink-headings:
|
||||||
specifier: ^6.1.1
|
specifier: ^6.1.1
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
|
@ -3531,18 +3534,9 @@ importers:
|
||||||
|
|
||||||
packages/astro/test/fixtures/view-transitions:
|
packages/astro/test/fixtures/view-transitions:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/react':
|
|
||||||
specifier: workspace:*
|
|
||||||
version: link:../../../../integrations/react
|
|
||||||
astro:
|
astro:
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../..
|
version: link:../../..
|
||||||
react:
|
|
||||||
specifier: ^18.1.0
|
|
||||||
version: 18.2.0
|
|
||||||
react-dom:
|
|
||||||
specifier: ^18.1.0
|
|
||||||
version: 18.2.0(react@18.2.0)
|
|
||||||
|
|
||||||
packages/astro/test/fixtures/virtual-astro-file:
|
packages/astro/test/fixtures/virtual-astro-file:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -14747,6 +14741,10 @@ packages:
|
||||||
resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==}
|
resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/parse-srcset@1.0.2:
|
||||||
|
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/parse5-htmlparser2-tree-adapter@7.0.0:
|
/parse5-htmlparser2-tree-adapter@7.0.0:
|
||||||
resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
|
resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Reference in a new issue