Compare commits
49 commits
main
...
fix/conten
Author | SHA1 | Date | |
---|---|---|---|
|
0d57cafd04 | ||
|
0ae1c91b8d | ||
|
5885a7e67c | ||
|
70342a8306 | ||
|
f1b42d81bb | ||
|
ffd09a91aa | ||
|
91b3307b98 | ||
|
d04dbdfa19 | ||
|
f4cb1b70b5 | ||
|
3ec76dc571 | ||
|
331e394ca1 | ||
|
a1966ff1d6 | ||
|
ac487a4ced | ||
|
c8d601ebeb | ||
|
cd425bf448 | ||
|
631a773dbb | ||
|
a342882859 | ||
|
39aae03429 | ||
|
2934c3a9e9 | ||
|
af4dc9ffe2 | ||
|
a84e934d21 | ||
|
e88ea2c7cf | ||
|
095158bb86 | ||
|
b5c6a9355c | ||
|
7944d28482 | ||
|
80dc1a5cbd | ||
|
a784e603a9 | ||
|
1126c750ed | ||
|
7747f0099a | ||
|
262a24b5c3 | ||
|
6386abd30b | ||
|
4f5b224cda | ||
|
6a4262f962 | ||
|
9af39e7628 | ||
|
6daf548688 | ||
|
81f6ece5ca | ||
|
0c3c216ef2 | ||
|
680e235f44 | ||
|
bbe50ec11c | ||
|
31820e4122 | ||
|
c54a115e29 | ||
|
dc37849f1d | ||
|
7de72f3417 | ||
|
7418ce4737 | ||
|
0f007f3d56 | ||
|
7f4529f12f | ||
|
6e904db135 | ||
|
d556df728d | ||
|
0577e4e9e4 |
132 changed files with 1904 additions and 981 deletions
5
.changeset/lemon-flies-clean.md
Normal file
5
.changeset/lemon-flies-clean.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fix sourcemap generation when scanning files
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'@astrojs/cloudflare': patch
|
||||
---
|
||||
|
||||
Cloudflare fix for building to directory mode
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Improve error handling when top-level `return` is present
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"@astrojs/mdx": "^0.15.2",
|
||||
"astro": "^2.0.6",
|
||||
"@astrojs/mdx": "^0.16.0",
|
||||
"@astrojs/rss": "^2.1.0",
|
||||
"@astrojs/sitemap": "^1.0.1"
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^2.0.0-beta.0"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/deno": "^4.0.0"
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"preact": "^10.7.3",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"@astrojs/react": "^2.0.2",
|
||||
"@astrojs/preact": "^2.0.1",
|
||||
"@astrojs/preact": "^2.0.2",
|
||||
"@algolia/client-search": "^4.13.1",
|
||||
"@docsearch/css": "^3.1.0",
|
||||
"@docsearch/react": "^3.1.0",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"alpinejs": "^3.10.2",
|
||||
"@astrojs/alpinejs": "^0.1.3",
|
||||
"@types/alpinejs": "^3.7.0"
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"lit": "^2.2.5",
|
||||
"@astrojs/lit": "^1.1.1",
|
||||
"@astrojs/lit": "^1.1.2",
|
||||
"@webcomponents/template-shadowroot": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,16 +11,16 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"preact": "^10.7.3",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.3",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.37",
|
||||
"@astrojs/preact": "^2.0.1",
|
||||
"@astrojs/preact": "^2.0.2",
|
||||
"@astrojs/react": "^2.0.2",
|
||||
"@astrojs/solid-js": "^2.0.1",
|
||||
"@astrojs/solid-js": "^2.0.2",
|
||||
"@astrojs/svelte": "^2.0.1",
|
||||
"@astrojs/vue": "^2.0.1"
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"preact": "^10.7.3",
|
||||
"@astrojs/preact": "^2.0.1",
|
||||
"@astrojs/preact": "^2.0.2",
|
||||
"@preact/signals": "^1.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"@astrojs/react": "^2.0.2",
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"solid-js": "^1.4.3",
|
||||
"@astrojs/solid-js": "^2.0.1"
|
||||
"@astrojs/solid-js": "^2.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
"dependencies": {
|
||||
"svelte": "^3.48.0",
|
||||
"@astrojs/svelte": "^2.0.1",
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"vue": "^3.2.37",
|
||||
"@astrojs/vue": "^2.0.1"
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^5.0.1",
|
||||
"astro": "^2.0.3"
|
||||
"@astrojs/node": "^5.0.3",
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^2.0.0-beta.0"
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
"server": "node dist/server/entry.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"svelte": "^3.48.0",
|
||||
"@astrojs/svelte": "^2.0.1",
|
||||
"@astrojs/node": "^5.0.1",
|
||||
"@astrojs/node": "^5.0.3",
|
||||
"concurrently": "^7.2.1",
|
||||
"unocss": "^0.15.6",
|
||||
"vite-imagetools": "^4.0.4"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"@astrojs/markdown-remark": "^2.0.1",
|
||||
"hast-util-select": "5.0.1",
|
||||
"rehype-autolink-headings": "^6.1.1",
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3"
|
||||
"astro": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"preact": "^10.6.5",
|
||||
"@astrojs/preact": "^2.0.1",
|
||||
"@astrojs/mdx": "^0.15.2"
|
||||
"@astrojs/preact": "^2.0.2",
|
||||
"@astrojs/mdx": "^0.16.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"preact": "^10.7.3",
|
||||
"@astrojs/preact": "^2.0.1",
|
||||
"@astrojs/preact": "^2.0.2",
|
||||
"nanostores": "^0.5.12",
|
||||
"@nanostores/preact": "^0.1.3"
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^0.15.2",
|
||||
"@astrojs/mdx": "^0.16.0",
|
||||
"@astrojs/tailwind": "^3.0.1",
|
||||
"@types/canvas-confetti": "^1.4.3",
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"canvas-confetti": "^1.5.1",
|
||||
"postcss": "^8.4.14",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"vite-plugin-pwa": "0.11.11",
|
||||
"workbox-window": "^6.5.3"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.0.3",
|
||||
"astro": "^2.0.6",
|
||||
"vitest": "^0.20.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,31 @@
|
|||
# astro
|
||||
|
||||
## 2.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6107](https://github.com/withastro/astro/pull/6107) [`9bec6bc41`](https://github.com/withastro/astro/commit/9bec6bc410f324a41c67e5d185fa86f78d7625f2) Thanks [@matthewp](https://github.com/matthewp)! - Fixes head contents being placed in body in MDX components
|
||||
|
||||
## 2.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6052](https://github.com/withastro/astro/pull/6052) [`9793f19ec`](https://github.com/withastro/astro/commit/9793f19ecd4e64cbf3140454fe52aeee2c22c8c9) Thanks [@mayank99](https://github.com/mayank99)! - Error overlay will now show the error's `cause` if available.
|
||||
|
||||
- [#6070](https://github.com/withastro/astro/pull/6070) [`f91615f5c`](https://github.com/withastro/astro/commit/f91615f5c04fde36f115dad9110dd75254efd61d) Thanks [@AirBorne04](https://github.com/AirBorne04)! - \* safe guard against TextEncode.encode(HTMLString) [errors on vercel edge]
|
||||
|
||||
- safe guard against html.replace when html is undefined
|
||||
|
||||
- [#6064](https://github.com/withastro/astro/pull/6064) [`2fb72c887`](https://github.com/withastro/astro/commit/2fb72c887f71c0a69ab512870d65b8c867774766) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Apply MDX `components` export when rendering as a content collection entry
|
||||
|
||||
## 2.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6045](https://github.com/withastro/astro/pull/6045) [`41e97158b`](https://github.com/withastro/astro/commit/41e97158ba90d23d346b6e3ff6c7c14b5ecbe903) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improve error handling when an Astro component is rendered manually
|
||||
|
||||
- [#6036](https://github.com/withastro/astro/pull/6036) [`e779c6242`](https://github.com/withastro/astro/commit/e779c6242418d1d4102e683ca5b851b764c89688) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improve error handling when top-level `return` is present
|
||||
|
||||
## 2.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import { LitElement, html } from 'lit';
|
||||
|
||||
export default class NonDeferredCounter extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
count: {
|
||||
type: Number,
|
||||
// All set properties are reflected to attributes so its hydration is
|
||||
// not deferred.
|
||||
reflect: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
increment() {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div>
|
||||
<p>Count: ${this.count}</p>
|
||||
|
||||
<button type="button" @click=${this.increment}>Increment</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('non-deferred-counter', NonDeferredCounter);
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
import MyCounter from '../components/Counter.js';
|
||||
import NonDeferredCounter from '../components/NonDeferredCounter.js';
|
||||
|
||||
const someProps = {
|
||||
count: 0,
|
||||
count: 10,
|
||||
};
|
||||
---
|
||||
|
||||
|
@ -15,6 +16,9 @@ const someProps = {
|
|||
<h1>Hello, client:idle!</h1>
|
||||
</MyCounter>
|
||||
|
||||
<NonDeferredCounter id="non-deferred" client:idle {...someProps}>
|
||||
</NonDeferredCounter>
|
||||
|
||||
<MyCounter id="client-load" {...someProps} client:load>
|
||||
<h1>Hello, client:load!</h1>
|
||||
</MyCounter>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import MyCounter from '../components/Counter.js';
|
||||
|
||||
const someProps = {
|
||||
count: 0,
|
||||
count: 10,
|
||||
};
|
||||
---
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import MyCounter from '../components/Counter.js';
|
||||
|
||||
const someProps = {
|
||||
count: 0,
|
||||
count: 10,
|
||||
};
|
||||
---
|
||||
|
||||
|
|
|
@ -32,12 +32,25 @@ test.describe('Lit components', () => {
|
|||
await expect(counter).toHaveCount(1);
|
||||
|
||||
const count = counter.locator('p');
|
||||
await expect(count, 'initial count is 0').toHaveText('Count: 0');
|
||||
await expect(count, 'initial count is 10').toHaveText('Count: 10');
|
||||
|
||||
const inc = counter.locator('button');
|
||||
await inc.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 1');
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 11');
|
||||
});
|
||||
|
||||
t('non-deferred attribute serialization', async ({ page, astro }) => {
|
||||
await page.goto(astro.resolveUrl('/'));
|
||||
|
||||
const counter = page.locator('#non-deferred');
|
||||
const count = counter.locator('p');
|
||||
await expect(count, 'initial count is 10').toHaveText('Count: 10');
|
||||
|
||||
const inc = counter.locator('button');
|
||||
await inc.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 11');
|
||||
});
|
||||
|
||||
t('client:load', async ({ page, astro }) => {
|
||||
|
@ -47,12 +60,12 @@ test.describe('Lit components', () => {
|
|||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = counter.locator('p');
|
||||
await expect(count, 'initial count is 0').toHaveText('Count: 0');
|
||||
await expect(count, 'initial count is 10').toHaveText('Count: 10');
|
||||
|
||||
const inc = counter.locator('button');
|
||||
await inc.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 1');
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 11');
|
||||
});
|
||||
|
||||
t('client:visible', async ({ page, astro }) => {
|
||||
|
@ -64,12 +77,12 @@ test.describe('Lit components', () => {
|
|||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = counter.locator('p');
|
||||
await expect(count, 'initial count is 0').toHaveText('Count: 0');
|
||||
await expect(count, 'initial count is 10').toHaveText('Count: 10');
|
||||
|
||||
const inc = counter.locator('button');
|
||||
await inc.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 1');
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 11');
|
||||
});
|
||||
|
||||
t('client:media', async ({ page, astro }) => {
|
||||
|
@ -79,18 +92,18 @@ test.describe('Lit components', () => {
|
|||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = counter.locator('p');
|
||||
await expect(count, 'initial count is 0').toHaveText('Count: 0');
|
||||
await expect(count, 'initial count is 10').toHaveText('Count: 10');
|
||||
|
||||
const inc = counter.locator('button');
|
||||
await inc.click();
|
||||
|
||||
await expect(count, 'component not hydrated yet').toHaveText('Count: 0');
|
||||
await expect(count, 'component not hydrated yet').toHaveText('Count: 10');
|
||||
|
||||
// Reset the viewport to hydrate the component (max-width: 50rem)
|
||||
await page.setViewportSize({ width: 414, height: 1124 });
|
||||
|
||||
await inc.click();
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 1');
|
||||
await expect(count, 'count incremented by 1').toHaveText('Count: 11');
|
||||
});
|
||||
|
||||
t.skip('HMR', async ({ page, astro }) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "astro",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.6",
|
||||
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
||||
"type": "module",
|
||||
"author": "withastro",
|
||||
|
|
|
@ -1449,6 +1449,10 @@ export interface SSRResult {
|
|||
): AstroGlobal;
|
||||
resolve: (s: string) => Promise<string>;
|
||||
response: ResponseInit;
|
||||
// Bits 1 = astro, 2 = jsx, 4 = slot
|
||||
// As rendering occurs these bits are manipulated to determine where content
|
||||
// is within a slot. This is used for head injection.
|
||||
scope: number;
|
||||
_metadata: SSRMetadata;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ export { createContentTypesGenerator } from './types-generator.js';
|
|||
export { contentObservable, getContentPaths, getDotAstroTypeReference } from './utils.js';
|
||||
export {
|
||||
astroContentAssetPropagationPlugin,
|
||||
astroContentProdBundlePlugin,
|
||||
} from './vite-plugin-content-assets.js';
|
||||
export { astroContentServerPlugin } from './vite-plugin-content-server.js';
|
||||
export { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||
import { prependForwardSlash } from '../core/path.js';
|
||||
|
||||
import {
|
||||
|
@ -120,21 +121,32 @@ async function render({
|
|||
id: string;
|
||||
collectionToRenderEntryMap: CollectionToEntryMap;
|
||||
}) {
|
||||
const lazyImport = collectionToRenderEntryMap[collection]?.[id];
|
||||
if (!lazyImport) throw new Error(`${String(collection)} → ${String(id)} does not exist.`);
|
||||
const UnexpectedRenderError = new AstroError({
|
||||
...AstroErrorData.UnknownContentCollectionError,
|
||||
message: `Unexpected error while rendering ${String(collection)} → ${String(id)}.`,
|
||||
});
|
||||
|
||||
const mod = await lazyImport();
|
||||
const lazyImport = collectionToRenderEntryMap[collection]?.[id];
|
||||
if (typeof lazyImport !== 'function') throw UnexpectedRenderError;
|
||||
|
||||
const baseMod = await lazyImport();
|
||||
if (baseMod == null || typeof baseMod !== 'object') throw UnexpectedRenderError;
|
||||
|
||||
const { collectedStyles, collectedLinks, collectedScripts, getMod } = baseMod;
|
||||
if (typeof getMod !== 'function') throw UnexpectedRenderError;
|
||||
const mod = await getMod();
|
||||
if (mod == null || typeof mod !== 'object') throw UnexpectedRenderError;
|
||||
|
||||
const Content = createComponent({
|
||||
factory(result, props, slots) {
|
||||
factory(result, baseProps, slots) {
|
||||
let styles = '',
|
||||
links = '',
|
||||
scripts = '';
|
||||
if (Array.isArray(mod?.collectedStyles)) {
|
||||
styles = mod.collectedStyles.map((style: any) => renderStyleElement(style)).join('');
|
||||
if (Array.isArray(collectedStyles)) {
|
||||
styles = collectedStyles.map((style: any) => renderStyleElement(style)).join('');
|
||||
}
|
||||
if (Array.isArray(mod?.collectedLinks)) {
|
||||
links = mod.collectedLinks
|
||||
if (Array.isArray(collectedLinks)) {
|
||||
links = collectedLinks
|
||||
.map((link: any) => {
|
||||
return renderUniqueStylesheet(result, {
|
||||
href: prependForwardSlash(link),
|
||||
|
@ -142,8 +154,17 @@ async function render({
|
|||
})
|
||||
.join('');
|
||||
}
|
||||
if (Array.isArray(mod?.collectedScripts)) {
|
||||
scripts = mod.collectedScripts.map((script: any) => renderScriptElement(script)).join('');
|
||||
if (Array.isArray(collectedScripts)) {
|
||||
scripts = collectedScripts.map((script: any) => renderScriptElement(script)).join('');
|
||||
}
|
||||
|
||||
let props = baseProps;
|
||||
// Auto-apply MDX components export
|
||||
if (id.endsWith('mdx')) {
|
||||
props = {
|
||||
components: mod.components ?? {},
|
||||
...baseProps,
|
||||
};
|
||||
}
|
||||
|
||||
return createHeadAndContent(
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { pathToFileURL } from 'url';
|
||||
import npath from 'node:path';
|
||||
import type { Plugin } from 'vite';
|
||||
import { moduleIsTopLevelPage, walkParentInfos } from '../core/build/graph.js';
|
||||
import { BuildInternals, getPageDataByViteID } from '../core/build/internal.js';
|
||||
import { AstroBuildPlugin } from '../core/build/plugin.js';
|
||||
import type { ModuleLoader } from '../core/module-loader/loader.js';
|
||||
import { createViteLoader } from '../core/module-loader/vite.js';
|
||||
import { getStylesForURL } from '../core/render/dev/css.js';
|
||||
|
@ -13,6 +15,8 @@ import {
|
|||
SCRIPTS_PLACEHOLDER,
|
||||
STYLES_PLACEHOLDER,
|
||||
} from './consts.js';
|
||||
import type { RollupOutput, OutputChunk, StaticBuildOptions } from '../core/build/types';
|
||||
import { prependForwardSlash } from '../core/path.js';
|
||||
|
||||
function isPropagatedAsset(viteId: string): boolean {
|
||||
const url = new URL(viteId, 'file://');
|
||||
|
@ -36,7 +40,9 @@ export function astroContentAssetPropagationPlugin({ mode }: { mode: string }):
|
|||
if (isPropagatedAsset(id)) {
|
||||
const basePath = id.split('?')[0];
|
||||
const code = `
|
||||
export { Content, getHeadings, frontmatter } from ${JSON.stringify(basePath)};
|
||||
export async function getMod() {
|
||||
return import(${JSON.stringify(basePath)});
|
||||
}
|
||||
export const collectedLinks = ${JSON.stringify(LINKS_PLACEHOLDER)};
|
||||
export const collectedStyles = ${JSON.stringify(STYLES_PLACEHOLDER)};
|
||||
export const collectedScripts = ${JSON.stringify(SCRIPTS_PLACEHOLDER)};
|
||||
|
@ -70,26 +76,92 @@ export function astroContentAssetPropagationPlugin({ mode }: { mode: string }):
|
|||
};
|
||||
}
|
||||
|
||||
export function astroContentProdBundlePlugin({ internals }: { internals: BuildInternals }): Plugin {
|
||||
export function astroConfigBuildPlugin(options: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
|
||||
let ssrPluginContext: any = undefined;
|
||||
return {
|
||||
name: 'astro:content-prod-bundle',
|
||||
async generateBundle(_options, bundle) {
|
||||
for (const [_, chunk] of Object.entries(bundle)) {
|
||||
if (chunk.type === 'chunk' && chunk.code.includes(LINKS_PLACEHOLDER)) {
|
||||
for (const id of Object.keys(chunk.modules)) {
|
||||
for (const [pageInfo, depth, order] of walkParentInfos(id, this)) {
|
||||
if (moduleIsTopLevelPage(pageInfo)) {
|
||||
const pageViteID = pageInfo.id;
|
||||
const pageData = getPageDataByViteID(internals, pageViteID);
|
||||
if (!pageData) continue;
|
||||
const entryCss = pageData.contentCollectionCss?.get(id);
|
||||
if (!entryCss) continue;
|
||||
chunk.code = chunk.code.replace(
|
||||
JSON.stringify(LINKS_PLACEHOLDER),
|
||||
JSON.stringify([...entryCss])
|
||||
);
|
||||
build: 'ssr',
|
||||
hooks: {
|
||||
'build:before': ({ build }) => {
|
||||
return {
|
||||
vitePlugin: {
|
||||
name: 'astro:content-build-plugin',
|
||||
generateBundle() {
|
||||
if(build === 'ssr') {
|
||||
ssrPluginContext = this;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
'build:post': ({ ssrOutputs, clientOutputs, mutate }) => {
|
||||
const outputs = ssrOutputs.flatMap(o => o.output);
|
||||
for (const chunk of outputs) {
|
||||
if (
|
||||
chunk.type === 'chunk' &&
|
||||
(chunk.code.includes(LINKS_PLACEHOLDER) || chunk.code.includes(SCRIPTS_PLACEHOLDER))
|
||||
) {
|
||||
let entryCSS = new Set<string>();
|
||||
let entryScripts = new Set<string>();
|
||||
|
||||
for (const id of Object.keys(chunk.modules)) {
|
||||
for (const [pageInfo] of walkParentInfos(id, ssrPluginContext)) {
|
||||
if (moduleIsTopLevelPage(pageInfo)) {
|
||||
const pageViteID = pageInfo.id;
|
||||
const pageData = getPageDataByViteID(internals, pageViteID);
|
||||
if (!pageData) continue;
|
||||
|
||||
const _entryCss = pageData.contentCollectionCss?.get(id);
|
||||
const _entryScripts = pageData.propagatedScripts?.get(id);
|
||||
if(_entryCss) {
|
||||
for(const value of _entryCss) {
|
||||
entryCSS.add(value);
|
||||
}
|
||||
}
|
||||
if(_entryScripts) {
|
||||
for(const value of _entryScripts) {
|
||||
entryScripts.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let newCode = chunk.code;
|
||||
if (entryCSS.size) {
|
||||
newCode = newCode.replace(
|
||||
JSON.stringify(LINKS_PLACEHOLDER),
|
||||
JSON.stringify([...entryCSS])
|
||||
);
|
||||
}
|
||||
if (entryScripts.size) {
|
||||
const entryFileNames = new Set<string>();
|
||||
for(const output of clientOutputs) {
|
||||
for(const clientChunk of output.output) {
|
||||
if(clientChunk.type !== 'chunk') continue;
|
||||
for(const [id] of Object.entries(clientChunk.modules)) {
|
||||
if(entryScripts.has(id)) {
|
||||
entryFileNames.add(clientChunk.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newCode = newCode.replace(
|
||||
JSON.stringify(SCRIPTS_PLACEHOLDER),
|
||||
JSON.stringify(
|
||||
[...entryFileNames].map((src) => ({
|
||||
props: {
|
||||
src: prependForwardSlash(npath.posix.join(
|
||||
options.settings.config.base,
|
||||
src
|
||||
)),
|
||||
type: 'module'
|
||||
},
|
||||
children: '',
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
mutate(chunk, 'server', newCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,9 +40,10 @@ export function moduleIsTopLevelPage(info: ModuleInfo): boolean {
|
|||
// This could be a .astro page, a .markdown or a .md (or really any file extension for markdown files) page.
|
||||
export function* getTopLevelPages(
|
||||
id: string,
|
||||
ctx: { getModuleInfo: GetModuleInfo }
|
||||
ctx: { getModuleInfo: GetModuleInfo },
|
||||
walkUntil?: (importer: string) => boolean
|
||||
): Generator<[ModuleInfo, number, number], void, unknown> {
|
||||
for (const res of walkParentInfos(id, ctx)) {
|
||||
for (const res of walkParentInfos(id, ctx, walkUntil)) {
|
||||
if (moduleIsTopLevelPage(res[0])) {
|
||||
yield res;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ export async function collectPagesData(
|
|||
moduleSpecifier: '',
|
||||
css: new Map(),
|
||||
contentCollectionCss: new Map(),
|
||||
propagatedScripts: new Map(),
|
||||
hoistedScript: undefined,
|
||||
};
|
||||
|
||||
|
@ -77,6 +78,7 @@ export async function collectPagesData(
|
|||
moduleSpecifier: '',
|
||||
css: new Map(),
|
||||
contentCollectionCss: new Map(),
|
||||
propagatedScripts: new Map(),
|
||||
hoistedScript: undefined,
|
||||
};
|
||||
}
|
||||
|
|
120
packages/astro/src/core/build/plugin.ts
Normal file
120
packages/astro/src/core/build/plugin.ts
Normal file
|
@ -0,0 +1,120 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from './internal';
|
||||
import type { StaticBuildOptions, ViteBuildReturn } from './types';
|
||||
|
||||
type RollupOutputArray = Extract<ViteBuildReturn, Array<any>>;
|
||||
type OutputChunkorAsset = RollupOutputArray[number]['output'][number];
|
||||
type OutputChunk = Extract<OutputChunkorAsset, { type: 'chunk' }>;
|
||||
|
||||
type MutateChunk = (chunk: OutputChunk, build: 'server' | 'client', newCode: string) => void;
|
||||
|
||||
export type AstroBuildPlugin = {
|
||||
build: 'ssr' | 'client' | 'both';
|
||||
hooks?: {
|
||||
'build:before'?: (opts: { build: 'ssr' | 'client'; input: Set<string> }) => {
|
||||
enforce?: 'after-user-plugins';
|
||||
vitePlugin: VitePlugin | VitePlugin[] | undefined;
|
||||
};
|
||||
'build:post'?: (opts: {
|
||||
ssrOutputs: RollupOutputArray;
|
||||
clientOutputs: RollupOutputArray;
|
||||
mutate: MutateChunk;
|
||||
}) => void | Promise<void>;
|
||||
};
|
||||
};
|
||||
|
||||
export function createPluginContainer(options: StaticBuildOptions, internals: BuildInternals) {
|
||||
const clientPlugins: AstroBuildPlugin[] = [];
|
||||
const ssrPlugins: AstroBuildPlugin[] = [];
|
||||
const allPlugins = new Set<AstroBuildPlugin>();
|
||||
|
||||
return {
|
||||
options,
|
||||
internals,
|
||||
register(plugin: AstroBuildPlugin) {
|
||||
allPlugins.add(plugin);
|
||||
switch (plugin.build) {
|
||||
case 'client': {
|
||||
clientPlugins.push(plugin);
|
||||
break;
|
||||
}
|
||||
case 'ssr': {
|
||||
ssrPlugins.push(plugin);
|
||||
break;
|
||||
}
|
||||
case 'both': {
|
||||
clientPlugins.push(plugin);
|
||||
ssrPlugins.push(plugin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Hooks
|
||||
runBeforeHook(build: 'ssr' | 'client', input: Set<string>) {
|
||||
let plugins = build === 'ssr' ? ssrPlugins : clientPlugins;
|
||||
let vitePlugins: Array<VitePlugin | VitePlugin[]> = [];
|
||||
let lastVitePlugins: Array<VitePlugin | VitePlugin[]> = [];
|
||||
for (const plugin of plugins) {
|
||||
if (plugin.hooks?.['build:before']) {
|
||||
let result = plugin.hooks['build:before']({ build, input });
|
||||
if (result.vitePlugin) {
|
||||
vitePlugins.push(result.vitePlugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
vitePlugins,
|
||||
lastVitePlugins,
|
||||
};
|
||||
},
|
||||
|
||||
async runPostHook(ssrReturn: ViteBuildReturn, clientReturn: ViteBuildReturn | null) {
|
||||
const mutations = new Map<
|
||||
string,
|
||||
{
|
||||
build: 'server' | 'client';
|
||||
code: string;
|
||||
}
|
||||
>();
|
||||
const ssrOutputs: RollupOutputArray = [];
|
||||
const clientOutputs: RollupOutputArray = [];
|
||||
|
||||
if (Array.isArray(ssrReturn)) {
|
||||
ssrOutputs.push(...ssrReturn);
|
||||
} else if ('output' in ssrReturn) {
|
||||
ssrOutputs.push(ssrReturn);
|
||||
}
|
||||
|
||||
if (Array.isArray(clientReturn)) {
|
||||
clientOutputs.push(...clientReturn);
|
||||
} else if (clientReturn && 'output' in clientReturn) {
|
||||
clientOutputs.push(clientReturn);
|
||||
}
|
||||
|
||||
const mutate: MutateChunk = (chunk, build, newCode) => {
|
||||
chunk.code = newCode;
|
||||
mutations.set(chunk.fileName, {
|
||||
build,
|
||||
code: newCode,
|
||||
});
|
||||
};
|
||||
|
||||
for (const plugin of allPlugins) {
|
||||
const postHook = plugin.hooks?.['build:post'];
|
||||
if (postHook) {
|
||||
await postHook({
|
||||
ssrOutputs,
|
||||
clientOutputs,
|
||||
mutate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return mutations;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export type AstroBuildPluginContainer = ReturnType<typeof createPluginContainer>;
|
22
packages/astro/src/core/build/plugins/index.ts
Normal file
22
packages/astro/src/core/build/plugins/index.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { astroConfigBuildPlugin } from '../../../content/vite-plugin-content-assets.js';
|
||||
import type { AstroBuildPluginContainer } from '../plugin';
|
||||
import { pluginAliasResolve } from './plugin-alias-resolve.js';
|
||||
import { pluginAnalyzer } from './plugin-analyzer.js';
|
||||
import { pluginCSS } from './plugin-css.js';
|
||||
import { pluginHoistedScripts } from './plugin-hoisted-scripts.js';
|
||||
import { pluginInternals } from './plugin-internals.js';
|
||||
import { pluginPages } from './plugin-pages.js';
|
||||
import { pluginPrerender } from './plugin-prerender.js';
|
||||
import { pluginSSR } from './plugin-ssr.js';
|
||||
|
||||
export function registerAllPlugins({ internals, options, register }: AstroBuildPluginContainer) {
|
||||
register(pluginAliasResolve(internals));
|
||||
register(pluginAnalyzer(internals));
|
||||
register(pluginInternals(internals));
|
||||
register(pluginPages(options, internals));
|
||||
register(pluginCSS(options, internals));
|
||||
register(pluginPrerender(options, internals));
|
||||
register(astroConfigBuildPlugin(options, internals));
|
||||
register(pluginHoistedScripts(options, internals));
|
||||
register(pluginSSR(options, internals));
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import type { Alias, Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from '../../core/build/internal.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import { AstroBuildPlugin } from '../plugin.js';
|
||||
|
||||
/**
|
||||
* `@rollup/plugin-alias` doesn't resolve aliases in Rollup input by default. This plugin fixes it
|
||||
|
@ -48,3 +49,16 @@ function matches(pattern: string | RegExp, importee: string) {
|
|||
}
|
||||
return importee.startsWith(pattern + '/');
|
||||
}
|
||||
|
||||
export function pluginAliasResolve(internals: BuildInternals): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'client',
|
||||
hooks: {
|
||||
'build:before': () => {
|
||||
return {
|
||||
vitePlugin: vitePluginAliasResolve(internals),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,16 +1,28 @@
|
|||
import type { PluginContext } from 'rollup';
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from '../../core/build/internal.js';
|
||||
import type { PluginMetadata as AstroPluginMetadata } from '../../vite-plugin-astro/types';
|
||||
import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
|
||||
import { prependForwardSlash } from '../../core/path.js';
|
||||
import { getTopLevelPages } from './graph.js';
|
||||
import { getPageDataByViteID, trackClientOnlyPageDatas } from './internal.js';
|
||||
import { prependForwardSlash } from '../../../core/path.js';
|
||||
import { getTopLevelPages, moduleIsTopLevelPage, walkParentInfos } from '../graph.js';
|
||||
import { getPageDataByViteID, trackClientOnlyPageDatas } from '../internal.js';
|
||||
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
||||
|
||||
function isPropagatedAsset(id: string) {
|
||||
return new URL('file://' + id).searchParams.has(PROPAGATED_ASSET_FLAG);
|
||||
}
|
||||
|
||||
export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
||||
function hoistedScriptScanner() {
|
||||
const uniqueHoistedIds = new Map<string, string>();
|
||||
const pageScripts = new Map<string, Set<string>>();
|
||||
const pageScripts = new Map<
|
||||
string,
|
||||
{
|
||||
hoistedSet: Set<string>;
|
||||
propagatedMapByImporter: Map<string, Set<string>>;
|
||||
}
|
||||
>();
|
||||
|
||||
return {
|
||||
scan(this: PluginContext, scripts: AstroPluginMetadata['astro']['scripts'], from: string) {
|
||||
|
@ -21,13 +33,36 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
|||
}
|
||||
|
||||
if (hoistedScripts.size) {
|
||||
for (const [pageInfo] of getTopLevelPages(from, this)) {
|
||||
const pageId = pageInfo.id;
|
||||
for (const hid of hoistedScripts) {
|
||||
if (pageScripts.has(pageId)) {
|
||||
pageScripts.get(pageId)?.add(hid);
|
||||
} else {
|
||||
pageScripts.set(pageId, new Set([hid]));
|
||||
for (const [parentInfo] of walkParentInfos(from, this, function until(importer) {
|
||||
return isPropagatedAsset(importer);
|
||||
})) {
|
||||
if (isPropagatedAsset(parentInfo.id)) {
|
||||
for (const [nestedParentInfo] of walkParentInfos(from, this)) {
|
||||
if (moduleIsTopLevelPage(nestedParentInfo)) {
|
||||
for (const hid of hoistedScripts) {
|
||||
if (!pageScripts.has(nestedParentInfo.id)) {
|
||||
pageScripts.set(nestedParentInfo.id, {
|
||||
hoistedSet: new Set(),
|
||||
propagatedMapByImporter: new Map(),
|
||||
});
|
||||
}
|
||||
const entry = pageScripts.get(nestedParentInfo.id)!;
|
||||
if (!entry.propagatedMapByImporter.has(parentInfo.id)) {
|
||||
entry.propagatedMapByImporter.set(parentInfo.id, new Set());
|
||||
}
|
||||
entry.propagatedMapByImporter.get(parentInfo.id)!.add(hid);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (moduleIsTopLevelPage(parentInfo)) {
|
||||
for (const hid of hoistedScripts) {
|
||||
if (!pageScripts.has(parentInfo.id)) {
|
||||
pageScripts.set(parentInfo.id, {
|
||||
hoistedSet: new Set(),
|
||||
propagatedMapByImporter: new Map(),
|
||||
});
|
||||
}
|
||||
pageScripts.get(parentInfo.id)?.hoistedSet.add(hid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,14 +70,14 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
|||
},
|
||||
|
||||
finalize() {
|
||||
for (const [pageId, hoistedScripts] of pageScripts) {
|
||||
for (const [pageId, { hoistedSet, propagatedMapByImporter }] of pageScripts) {
|
||||
const pageData = getPageDataByViteID(internals, pageId);
|
||||
if (!pageData) continue;
|
||||
|
||||
const { component } = pageData;
|
||||
const astroModuleId = prependForwardSlash(component);
|
||||
|
||||
const uniqueHoistedId = JSON.stringify(Array.from(hoistedScripts).sort());
|
||||
const uniqueHoistedId = JSON.stringify(Array.from(hoistedSet).sort());
|
||||
let moduleId: string;
|
||||
|
||||
// If we're already tracking this set of hoisted scripts, get the unique id
|
||||
|
@ -55,13 +90,26 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
|||
}
|
||||
internals.discoveredScripts.add(moduleId);
|
||||
|
||||
// TODO: map raw URL (?type=script) to client build ready URL
|
||||
// This will inject the raw URL as a script tag as-is,
|
||||
// which will fail to map with the client build output.
|
||||
pageData.propagatedScripts = propagatedMapByImporter;
|
||||
|
||||
// Add propagated scripts to client build,
|
||||
// but DON'T add to pages -> hoisted script map.
|
||||
for (const propagatedScripts of propagatedMapByImporter.values()) {
|
||||
for (const propagatedScript of propagatedScripts) {
|
||||
internals.discoveredScripts.add(propagatedScript);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to track that this page uses this set of hoisted scripts
|
||||
if (internals.hoistedScriptIdToPagesMap.has(moduleId)) {
|
||||
const pages = internals.hoistedScriptIdToPagesMap.get(moduleId);
|
||||
pages!.add(astroModuleId);
|
||||
} else {
|
||||
internals.hoistedScriptIdToPagesMap.set(moduleId, new Set([astroModuleId]));
|
||||
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedScripts);
|
||||
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedSet);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -122,3 +170,16 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pluginAnalyzer(internals: BuildInternals): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'ssr',
|
||||
hooks: {
|
||||
'build:before': () => {
|
||||
return {
|
||||
vitePlugin: vitePluginAnalyzer(internals),
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
|
@ -2,20 +2,22 @@ import * as crypto from 'node:crypto';
|
|||
import * as npath from 'node:path';
|
||||
import type { GetModuleInfo } from 'rollup';
|
||||
import { Plugin as VitePlugin, ResolvedConfig, transformWithEsbuild } from 'vite';
|
||||
import { isCSSRequest } from '../render/util.js';
|
||||
import type { BuildInternals } from './internal';
|
||||
import type { PageBuildData, StaticBuildOptions } from './types';
|
||||
import { isCSSRequest } from '../../render/util.js';
|
||||
import type { BuildInternals } from '../internal';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { PageBuildData, StaticBuildOptions } from '../types';
|
||||
|
||||
import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
|
||||
import * as assetName from './css-asset-name.js';
|
||||
import { moduleIsTopLevelPage, walkParentInfos } from './graph.js';
|
||||
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
||||
import * as assetName from '../css-asset-name.js';
|
||||
import { moduleIsTopLevelPage, walkParentInfos } from '../graph.js';
|
||||
import {
|
||||
eachPageData,
|
||||
getPageDataByViteID,
|
||||
getPageDatasByClientOnlyID,
|
||||
getPageDatasByHoistedScriptId,
|
||||
isHoistedScript,
|
||||
} from './internal.js';
|
||||
} from '../internal.js';
|
||||
import { extendManualChunks } from './util.js';
|
||||
|
||||
interface PluginOptions {
|
||||
internals: BuildInternals;
|
||||
|
@ -54,40 +56,30 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
|
|||
name: 'astro:rollup-plugin-build-css',
|
||||
|
||||
outputOptions(outputOptions) {
|
||||
const manualChunks = outputOptions.manualChunks || Function.prototype;
|
||||
const assetFileNames = outputOptions.assetFileNames;
|
||||
const namingIncludesHash = assetFileNames?.toString().includes('[hash]');
|
||||
const createNameForParentPages = namingIncludesHash
|
||||
? assetName.shortHashedName
|
||||
: assetName.createSlugger(settings);
|
||||
outputOptions.manualChunks = function (id, ...args) {
|
||||
// Defer to user-provided `manualChunks`, if it was provided.
|
||||
if (typeof manualChunks == 'object') {
|
||||
if (id in manualChunks) {
|
||||
return manualChunks[id];
|
||||
}
|
||||
} else if (typeof manualChunks === 'function') {
|
||||
const outid = manualChunks.call(this, id, ...args);
|
||||
if (outid) {
|
||||
return outid;
|
||||
}
|
||||
}
|
||||
|
||||
// For CSS, create a hash of all of the pages that use it.
|
||||
// This causes CSS to be built into shared chunks when used by multiple pages.
|
||||
if (isCSSRequest(id)) {
|
||||
for (const [pageInfo] of walkParentInfos(id, {
|
||||
getModuleInfo: args[0].getModuleInfo,
|
||||
})) {
|
||||
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
|
||||
// Split delayed assets to separate modules
|
||||
// so they can be injected where needed
|
||||
return createNameHash(id, [id]);
|
||||
extendManualChunks(outputOptions, {
|
||||
after(id, meta) {
|
||||
// For CSS, create a hash of all of the pages that use it.
|
||||
// This causes CSS to be built into shared chunks when used by multiple pages.
|
||||
if (isCSSRequest(id)) {
|
||||
for (const [pageInfo] of walkParentInfos(id, {
|
||||
getModuleInfo: meta.getModuleInfo,
|
||||
})) {
|
||||
if (new URL(pageInfo.id, 'file://').searchParams.has(PROPAGATED_ASSET_FLAG)) {
|
||||
// Split delayed assets to separate modules
|
||||
// so they can be injected where needed
|
||||
return createNameHash(id, [id]);
|
||||
}
|
||||
}
|
||||
return createNameForParentPages(id, meta);
|
||||
}
|
||||
return createNameForParentPages(id, args[0]);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async generateBundle(_outputOptions, bundle) {
|
||||
|
@ -272,3 +264,25 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
|
|||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function pluginCSS(
|
||||
options: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'both',
|
||||
hooks: {
|
||||
'build:before': ({ build }) => {
|
||||
let plugins = rollupPluginAstroBuildCSS({
|
||||
buildOptions: options,
|
||||
internals,
|
||||
target: build === 'ssr' ? 'server' : 'client',
|
||||
});
|
||||
|
||||
return {
|
||||
vitePlugin: plugins,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { AstroSettings } from '../../@types/astro';
|
||||
import type { BuildInternals } from '../../core/build/internal.js';
|
||||
import { viteID } from '../util.js';
|
||||
import { getPageDataByViteID } from './internal.js';
|
||||
import type { AstroSettings } from '../../../@types/astro';
|
||||
import { viteID } from '../../util.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import { getPageDataByViteID } from '../internal.js';
|
||||
import { AstroBuildPlugin } from '../plugin';
|
||||
import { StaticBuildOptions } from '../types';
|
||||
|
||||
function virtualHoistedEntry(id: string) {
|
||||
return id.startsWith('/astro/hoisted.js?q=');
|
||||
|
@ -91,3 +93,19 @@ export function vitePluginHoistedScripts(
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pluginHoistedScripts(
|
||||
options: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'client',
|
||||
hooks: {
|
||||
'build:before': () => {
|
||||
return {
|
||||
vitePlugin: vitePluginHoistedScripts(options.settings, internals),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import type { Plugin as VitePlugin, UserConfig } from 'vite';
|
||||
import type { BuildInternals } from './internal.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
|
||||
export function vitePluginInternals(input: Set<string>, internals: BuildInternals): VitePlugin {
|
||||
return {
|
||||
|
@ -60,3 +61,16 @@ export function vitePluginInternals(input: Set<string>, internals: BuildInternal
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pluginInternals(internals: BuildInternals): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'both',
|
||||
hooks: {
|
||||
'build:before': ({ input }) => {
|
||||
return {
|
||||
vitePlugin: vitePluginInternals(input, internals),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import { pagesVirtualModuleId, resolvedPagesVirtualModuleId } from '../app/index.js';
|
||||
import { addRollupInput } from './add-rollup-input.js';
|
||||
import { BuildInternals, eachPageData, hasPrerenderedPages } from './internal.js';
|
||||
import type { StaticBuildOptions } from './types';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
|
||||
import { pagesVirtualModuleId, resolvedPagesVirtualModuleId } from '../../app/index.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import { BuildInternals, eachPageData, hasPrerenderedPages } from '../internal.js';
|
||||
|
||||
export function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin {
|
||||
return {
|
||||
|
@ -53,3 +55,16 @@ export const renderers = [${rendererItems}];`;
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pluginPages(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'ssr',
|
||||
hooks: {
|
||||
'build:before': () => {
|
||||
return {
|
||||
vitePlugin: vitePluginPages(opts, internals),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
51
packages/astro/src/core/build/plugins/plugin-prerender.ts
Normal file
51
packages/astro/src/core/build/plugins/plugin-prerender.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import { extendManualChunks } from './util.js';
|
||||
|
||||
export function vitePluginPrerender(
|
||||
opts: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): VitePlugin {
|
||||
return {
|
||||
name: 'astro:rollup-plugin-prerender',
|
||||
|
||||
outputOptions(outputOptions) {
|
||||
extendManualChunks(outputOptions, {
|
||||
after(id, meta) {
|
||||
// Split the Astro runtime into a separate chunk for readability
|
||||
if (id.includes('astro/dist')) {
|
||||
return 'astro';
|
||||
}
|
||||
const pageInfo = internals.pagesByViteID.get(id);
|
||||
if (pageInfo) {
|
||||
// prerendered pages should be split into their own chunk
|
||||
// Important: this can't be in the `pages/` directory!
|
||||
if (meta.getModuleInfo(id)?.meta.astro?.pageOptions?.prerender) {
|
||||
return 'prerender';
|
||||
}
|
||||
// dynamic pages should all go in their own chunk in the pages/* directory
|
||||
return `pages/all`;
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pluginPrerender(
|
||||
opts: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): AstroBuildPlugin {
|
||||
return {
|
||||
build: 'ssr',
|
||||
hooks: {
|
||||
'build:before': () => {
|
||||
return {
|
||||
vitePlugin: vitePluginPrerender(opts, internals),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,21 +1,21 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { AstroAdapter } from '../../@types/astro';
|
||||
import type { SerializedRouteInfo, SerializedSSRManifest } from '../app/types';
|
||||
import type { BuildInternals } from './internal.js';
|
||||
import type { StaticBuildOptions } from './types';
|
||||
import type { AstroAdapter } from '../../../@types/astro';
|
||||
import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
|
||||
import glob from 'fast-glob';
|
||||
import * as fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { getContentPaths } from '../../content/index.js';
|
||||
import { runHookBuildSsr } from '../../integrations/index.js';
|
||||
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
||||
import { pagesVirtualModuleId } from '../app/index.js';
|
||||
import { removeLeadingForwardSlash, removeTrailingForwardSlash } from '../path.js';
|
||||
import { serializeRouteData } from '../routing/index.js';
|
||||
import { addRollupInput } from './add-rollup-input.js';
|
||||
import { getOutFile, getOutFolder } from './common.js';
|
||||
import { eachPrerenderedPageData, eachServerPageData, sortedCSS } from './internal.js';
|
||||
import { getContentPaths } from '../../../content/index.js';
|
||||
import { runHookBuildSsr } from '../../../integrations/index.js';
|
||||
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js';
|
||||
import { pagesVirtualModuleId } from '../../app/index.js';
|
||||
import { removeLeadingForwardSlash, removeTrailingForwardSlash } from '../../path.js';
|
||||
import { serializeRouteData } from '../../routing/index.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import { getOutFile, getOutFolder } from '../common.js';
|
||||
import { eachPrerenderedPageData, eachServerPageData, sortedCSS } from '../internal.js';
|
||||
import { AstroBuildPlugin } from '../plugin';
|
||||
|
||||
export const virtualModuleId = '@astrojs-ssr-virtual-entry';
|
||||
const resolvedVirtualModuleId = '\0' + virtualModuleId;
|
||||
|
@ -29,7 +29,7 @@ export function vitePluginSSR(internals: BuildInternals, adapter: AstroAdapter):
|
|||
options(opts) {
|
||||
return addRollupInput(opts, [virtualModuleId]);
|
||||
},
|
||||
resolveId(id) {
|
||||
resolveId(id, parent) {
|
||||
if (id === virtualModuleId) {
|
||||
return resolvedVirtualModuleId;
|
||||
}
|
||||
|
@ -114,12 +114,10 @@ export async function injectManifest(buildOpts: StaticBuildOptions, internals: B
|
|||
|
||||
const chunk = internals.ssrEntryChunk;
|
||||
const code = chunk.code;
|
||||
chunk.code = code.replace(replaceExp, () => {
|
||||
|
||||
return code.replace(replaceExp, () => {
|
||||
return JSON.stringify(manifest);
|
||||
});
|
||||
const serverEntryURL = new URL(buildOpts.buildConfig.serverEntry, buildOpts.buildConfig.server);
|
||||
await fs.promises.mkdir(new URL('./', serverEntryURL), { recursive: true });
|
||||
await fs.promises.writeFile(serverEntryURL, chunk.code, 'utf-8');
|
||||
}
|
||||
|
||||
function buildManifest(
|
||||
|
@ -220,3 +218,37 @@ function buildManifest(
|
|||
|
||||
return ssrManifest;
|
||||
}
|
||||
|
||||
export function pluginSSR(
|
||||
options: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): AstroBuildPlugin {
|
||||
const ssr = options.settings.config.output === 'server';
|
||||
return {
|
||||
build: 'ssr',
|
||||
hooks: {
|
||||
'build:before': () => {
|
||||
let vitePlugin = ssr ? vitePluginSSR(internals, options.settings.adapter!) : undefined;
|
||||
|
||||
return {
|
||||
enforce: 'after-user-plugins',
|
||||
vitePlugin,
|
||||
};
|
||||
},
|
||||
'build:post': async ({ mutate }) => {
|
||||
if (!ssr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!internals.ssrEntryChunk) {
|
||||
throw new Error(`Did not generate an entry chunk for SSR`);
|
||||
}
|
||||
// Mutate the filename
|
||||
internals.ssrEntryChunk.fileName = options.settings.config.build.serverEntry;
|
||||
|
||||
const code = await injectManifest(options, internals);
|
||||
mutate(internals.ssrEntryChunk, 'server', code);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
40
packages/astro/src/core/build/plugins/util.ts
Normal file
40
packages/astro/src/core/build/plugins/util.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type OutputOptionsHook = Extract<VitePlugin['outputOptions'], Function>;
|
||||
type OutputOptions = Parameters<OutputOptionsHook>[0];
|
||||
|
||||
type ExtendManualChunksHooks = {
|
||||
before?: (id: string, meta: any) => string | undefined;
|
||||
after?: (id: string, meta: any) => string | undefined;
|
||||
};
|
||||
|
||||
export function extendManualChunks(outputOptions: OutputOptions, hooks: ExtendManualChunksHooks) {
|
||||
const manualChunks = outputOptions.manualChunks;
|
||||
outputOptions.manualChunks = function (id, meta) {
|
||||
if (hooks.before) {
|
||||
let value = hooks.before(id, meta);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Defer to user-provided `manualChunks`, if it was provided.
|
||||
if (typeof manualChunks == 'object') {
|
||||
if (id in manualChunks) {
|
||||
let value = manualChunks[id];
|
||||
return value[0];
|
||||
}
|
||||
} else if (typeof manualChunks === 'function') {
|
||||
const outid = manualChunks.call(this, id, meta);
|
||||
if (outid) {
|
||||
return outid;
|
||||
}
|
||||
}
|
||||
|
||||
if (hooks.after) {
|
||||
return hooks.after(id, meta) || null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
|
@ -4,7 +4,6 @@ import fs from 'fs';
|
|||
import { bgGreen, bgMagenta, black, dim } from 'kleur/colors';
|
||||
import { fileURLToPath } from 'url';
|
||||
import * as vite from 'vite';
|
||||
import { astroContentProdBundlePlugin } from '../../content/index.js';
|
||||
import {
|
||||
BuildInternals,
|
||||
createBuildInternals,
|
||||
|
@ -21,16 +20,10 @@ import { info } from '../logger/core.js';
|
|||
import { getOutDirWithinCwd } from './common.js';
|
||||
import { generatePages } from './generate.js';
|
||||
import { trackPageData } from './internal.js';
|
||||
import { AstroBuildPluginContainer, createPluginContainer } from './plugin.js';
|
||||
import { registerAllPlugins } from './plugins/index.js';
|
||||
import type { PageBuildData, StaticBuildOptions } from './types';
|
||||
import { getTimeStat } from './util.js';
|
||||
import { vitePluginAliasResolve } from './vite-plugin-alias-resolve.js';
|
||||
import { vitePluginAnalyzer } from './vite-plugin-analyzer.js';
|
||||
import { rollupPluginAstroBuildCSS } from './vite-plugin-css.js';
|
||||
import { vitePluginHoistedScripts } from './vite-plugin-hoisted-scripts.js';
|
||||
import { vitePluginInternals } from './vite-plugin-internals.js';
|
||||
import { vitePluginPages } from './vite-plugin-pages.js';
|
||||
import { vitePluginPrerender } from './vite-plugin-prerender.js';
|
||||
import { injectManifest, vitePluginSSR } from './vite-plugin-ssr.js';
|
||||
|
||||
export async function staticBuild(opts: StaticBuildOptions) {
|
||||
const { allPages, settings } = opts;
|
||||
|
@ -70,10 +63,14 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
|||
// condition, so we are doing it ourselves
|
||||
emptyDir(settings.config.outDir, new Set('.git'));
|
||||
|
||||
// Register plugins
|
||||
const container = createPluginContainer(opts, internals);
|
||||
registerAllPlugins(container);
|
||||
|
||||
// Build your project (SSR application code, assets, client JS, etc.)
|
||||
timer.ssr = performance.now();
|
||||
info(opts.logging, 'build', `Building ${settings.config.output} entrypoints...`);
|
||||
await ssrBuild(opts, internals, pageInput);
|
||||
const ssrOutput = await ssrBuild(opts, internals, pageInput, container);
|
||||
info(opts.logging, 'build', dim(`Completed in ${getTimeStat(timer.ssr, performance.now())}.`));
|
||||
|
||||
const rendererClientEntrypoints = settings.renderers
|
||||
|
@ -93,9 +90,11 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
|||
|
||||
// Run client build first, so the assets can be fed into the SSR rendered version.
|
||||
timer.clientBuild = performance.now();
|
||||
await clientBuild(opts, internals, clientInput);
|
||||
const clientOutput = await clientBuild(opts, internals, clientInput, container);
|
||||
|
||||
timer.generate = performance.now();
|
||||
await runPostBuildHooks(container, ssrOutput, clientOutput);
|
||||
|
||||
switch (settings.config.output) {
|
||||
case 'static': {
|
||||
await generatePages(opts, internals);
|
||||
|
@ -103,7 +102,6 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
|||
return;
|
||||
}
|
||||
case 'server': {
|
||||
await injectManifest(opts, internals);
|
||||
await generatePages(opts, internals);
|
||||
await cleanStaticOutput(opts, internals);
|
||||
info(opts.logging, null, `\n${bgMagenta(black(' finalizing server assets '))}\n`);
|
||||
|
@ -113,11 +111,18 @@ export async function staticBuild(opts: StaticBuildOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
|
||||
async function ssrBuild(
|
||||
opts: StaticBuildOptions,
|
||||
internals: BuildInternals,
|
||||
input: Set<string>,
|
||||
container: AstroBuildPluginContainer
|
||||
) {
|
||||
const { settings, viteConfig } = opts;
|
||||
const ssr = settings.config.output === 'server';
|
||||
const out = ssr ? opts.buildConfig.server : getOutDirWithinCwd(settings.config.outDir);
|
||||
|
||||
const { lastVitePlugins, vitePlugins } = container.runBeforeHook('ssr', input);
|
||||
|
||||
const viteBuildConfig: vite.InlineConfig = {
|
||||
...viteConfig,
|
||||
mode: viteConfig.mode || 'production',
|
||||
|
@ -154,21 +159,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
|
|||
modulePreload: { polyfill: false },
|
||||
reportCompressedSize: false,
|
||||
},
|
||||
plugins: [
|
||||
vitePluginAnalyzer(internals),
|
||||
vitePluginInternals(input, internals),
|
||||
vitePluginPages(opts, internals),
|
||||
rollupPluginAstroBuildCSS({
|
||||
buildOptions: opts,
|
||||
internals,
|
||||
target: 'server',
|
||||
}),
|
||||
vitePluginPrerender(opts, internals),
|
||||
...(viteConfig.plugins || []),
|
||||
astroContentProdBundlePlugin({ internals }),
|
||||
// SSR needs to be last
|
||||
ssr && vitePluginSSR(internals, settings.adapter!),
|
||||
],
|
||||
plugins: [...vitePlugins, ...(viteConfig.plugins || []), ...lastVitePlugins],
|
||||
envPrefix: viteConfig.envPrefix ?? 'PUBLIC_',
|
||||
base: settings.config.base,
|
||||
};
|
||||
|
@ -187,7 +178,8 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
|
|||
async function clientBuild(
|
||||
opts: StaticBuildOptions,
|
||||
internals: BuildInternals,
|
||||
input: Set<string>
|
||||
input: Set<string>,
|
||||
container: AstroBuildPluginContainer
|
||||
) {
|
||||
const { settings, viteConfig } = opts;
|
||||
const timer = performance.now();
|
||||
|
@ -204,6 +196,7 @@ async function clientBuild(
|
|||
return null;
|
||||
}
|
||||
|
||||
const { lastVitePlugins, vitePlugins } = container.runBeforeHook('client', input);
|
||||
info(opts.logging, null, `\n${bgGreen(black(' building client '))}`);
|
||||
|
||||
const viteBuildConfig: vite.InlineConfig = {
|
||||
|
@ -228,17 +221,7 @@ async function clientBuild(
|
|||
preserveEntrySignatures: 'exports-only',
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
vitePluginAliasResolve(internals),
|
||||
vitePluginInternals(input, internals),
|
||||
vitePluginHoistedScripts(settings, internals),
|
||||
rollupPluginAstroBuildCSS({
|
||||
buildOptions: opts,
|
||||
internals,
|
||||
target: 'client',
|
||||
}),
|
||||
...(viteConfig.plugins || []),
|
||||
],
|
||||
plugins: [...vitePlugins, ...(viteConfig.plugins || []), ...lastVitePlugins],
|
||||
envPrefix: viteConfig.envPrefix ?? 'PUBLIC_',
|
||||
base: settings.config.base,
|
||||
};
|
||||
|
@ -256,6 +239,24 @@ async function clientBuild(
|
|||
return buildResult;
|
||||
}
|
||||
|
||||
async function runPostBuildHooks(
|
||||
container: AstroBuildPluginContainer,
|
||||
ssrReturn: Awaited<ReturnType<typeof ssrBuild>>,
|
||||
clientReturn: Awaited<ReturnType<typeof clientBuild>>
|
||||
) {
|
||||
const mutations = await container.runPostHook(ssrReturn, clientReturn);
|
||||
const config = container.options.settings.config;
|
||||
const buildConfig = container.options.settings.config.build;
|
||||
for (const [fileName, mutation] of mutations) {
|
||||
const root = config.output === 'server' ?
|
||||
mutation.build === 'server' ? buildConfig.server : buildConfig.client :
|
||||
config.outDir;
|
||||
const fileURL = new URL(fileName, root);
|
||||
await fs.promises.mkdir(new URL('./', fileURL), { recursive: true });
|
||||
await fs.promises.writeFile(fileURL, mutation.code, 'utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For each statically prerendered page, replace their SSR file with a noop.
|
||||
* This allows us to run the SSR build only once, but still remove dependencies for statically rendered routes.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { InlineConfig } from 'vite';
|
||||
import type { default as vite, InlineConfig } from 'vite';
|
||||
import type {
|
||||
AstroConfig,
|
||||
AstroSettings,
|
||||
|
@ -22,6 +22,7 @@ export interface PageBuildData {
|
|||
moduleSpecifier: string;
|
||||
css: Map<string, { depth: number; order: number }>;
|
||||
contentCollectionCss: Map<string, Set<string>>;
|
||||
propagatedScripts: Map<string, Set<string>>;
|
||||
hoistedScript: { type: 'inline' | 'external'; value: string } | undefined;
|
||||
}
|
||||
export type AllPagesData = Record<ComponentPath, PageBuildData>;
|
||||
|
@ -44,3 +45,10 @@ export interface SingleFileBuiltModule {
|
|||
pageMap: Map<ComponentPath, ComponentInstance>;
|
||||
renderers: SSRLoadedRenderer[];
|
||||
}
|
||||
|
||||
export type ViteBuildReturn = Awaited<ReturnType<typeof vite.build>>;
|
||||
export type RollupOutput = Extract<
|
||||
Extract<ViteBuildReturn, Exclude<ViteBuildReturn, Array<any>>>,
|
||||
{ output: any }
|
||||
>;
|
||||
export type OutputChunk = Extract<RollupOutput['output'][number], { type: 'chunk' }>;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from './internal.js';
|
||||
import type { StaticBuildOptions } from './types';
|
||||
|
||||
export function vitePluginPrerender(
|
||||
opts: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): VitePlugin {
|
||||
return {
|
||||
name: 'astro:rollup-plugin-prerender',
|
||||
|
||||
outputOptions(outputOptions) {
|
||||
const manualChunks = outputOptions.manualChunks || Function.prototype;
|
||||
outputOptions.manualChunks = function (id, api, ...args) {
|
||||
// Defer to user-provided `manualChunks`, if it was provided.
|
||||
if (typeof manualChunks == 'object') {
|
||||
if (id in manualChunks) {
|
||||
return manualChunks[id];
|
||||
}
|
||||
} else if (typeof manualChunks === 'function') {
|
||||
const outid = manualChunks.call(this, id, api, ...args);
|
||||
if (outid) {
|
||||
return outid;
|
||||
}
|
||||
}
|
||||
// Split the Astro runtime into a separate chunk for readability
|
||||
if (id.includes('astro/dist')) {
|
||||
return 'astro';
|
||||
}
|
||||
const pageInfo = internals.pagesByViteID.get(id);
|
||||
if (pageInfo) {
|
||||
// prerendered pages should be split into their own chunk
|
||||
// Important: this can't be in the `pages/` directory!
|
||||
if (api.getModuleInfo(id)?.meta.astro?.pageOptions?.prerender) {
|
||||
return `prerender`;
|
||||
}
|
||||
// dynamic pages should all go in their own chunk in the pages/* directory
|
||||
return `pages/all`;
|
||||
}
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
|
@ -118,6 +118,7 @@ export interface AstroErrorPayload {
|
|||
line?: number;
|
||||
column?: number;
|
||||
};
|
||||
cause?: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -174,6 +175,7 @@ export async function getViteErrorPayload(err: ErrorWithMetadata): Promise<Astro
|
|||
},
|
||||
plugin,
|
||||
stack: err.stack,
|
||||
cause: err.cause,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -415,6 +415,20 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
|
|||
},
|
||||
hint: 'Mutable values declared at runtime are not supported. Please make sure to use exactly `export const prerender = true`.',
|
||||
},
|
||||
/**
|
||||
* @docs
|
||||
* @message
|
||||
* **Example error messages:**<br/>
|
||||
* InvalidComponentArgs: Invalid arguments passed to `<MyAstroComponent>` component.
|
||||
* @description
|
||||
* Astro components cannot be rendered manually via a function call, such as `Component()` or `{items.map(Component)}`. Prefer the component syntax `<Component />` or `{items.map(item => <Component {...item} />)}`.
|
||||
*/
|
||||
InvalidComponentArgs: {
|
||||
title: 'Invalid component arguments.',
|
||||
code: 3020,
|
||||
message: (name: string) => `Invalid arguments passed to${name ? ` <${name}>` : ''} component.`,
|
||||
hint: 'Astro components cannot be rendered directly via function call, such as `Component()` or `{items.map(Component)}`.',
|
||||
},
|
||||
// Vite Errors - 4xxx
|
||||
UnknownViteError: {
|
||||
title: 'Unknown Vite Error.',
|
||||
|
@ -615,6 +629,7 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
|
|||
},
|
||||
/**
|
||||
* @docs
|
||||
* @message `COLLECTION_NAME` → `ENTRY_ID` has an invalid slug. `slug` must be a string.
|
||||
* @see
|
||||
* - [The reserved entry `slug` field](https://docs.astro.build/en/guides/content-collections/)
|
||||
* @description
|
||||
|
@ -632,6 +647,7 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
|
|||
},
|
||||
/**
|
||||
* @docs
|
||||
* @message A content collection schema should not contain `slug` since it is reserved for slug generation. Remove this from your `COLLECTION_NAME` collection schema.
|
||||
* @see
|
||||
* - [The reserved entry `slug` field](https://docs.astro.build/en/guides/content-collections/)
|
||||
* @description
|
||||
|
|
|
@ -321,7 +321,8 @@ const style = /* css */ `
|
|||
|
||||
#message-hints,
|
||||
#stack,
|
||||
#code {
|
||||
#code,
|
||||
#cause {
|
||||
border-radius: var(--roundiness);
|
||||
background-color: var(--box-background);
|
||||
}
|
||||
|
@ -471,7 +472,8 @@ const style = /* css */ `
|
|||
color: var(--error-text);
|
||||
}
|
||||
|
||||
#stack h2 {
|
||||
#stack h2,
|
||||
#cause h2 {
|
||||
color: var(--title-text);
|
||||
font-family: var(--font-normal);
|
||||
font-size: 22px;
|
||||
|
@ -480,7 +482,8 @@ const style = /* css */ `
|
|||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
#stack-content {
|
||||
#stack-content,
|
||||
#cause-content {
|
||||
font-size: 14px;
|
||||
white-space: pre;
|
||||
line-height: 21px;
|
||||
|
@ -488,6 +491,10 @@ const style = /* css */ `
|
|||
padding: 24px;
|
||||
color: var(--stack-text);
|
||||
}
|
||||
|
||||
#cause {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const overlayTemplate = /* html */ `
|
||||
|
@ -552,6 +559,11 @@ ${style.trim()}
|
|||
<h2>Stack Trace</h2>
|
||||
<div id="stack-content"></div>
|
||||
</section>
|
||||
|
||||
<section id="cause">
|
||||
<h2>Cause</h2>
|
||||
<div id="cause-content"></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -593,6 +605,17 @@ class ErrorOverlay extends HTMLElement {
|
|||
this.text('#title', err.title);
|
||||
this.text('#message-content', err.message, true);
|
||||
|
||||
const cause = this.root.querySelector<HTMLElement>('#cause');
|
||||
if (cause && err.cause) {
|
||||
if (typeof err.cause === 'string') {
|
||||
this.text('#cause-content', err.cause);
|
||||
cause.style.display = 'block';
|
||||
} else {
|
||||
this.text('#cause-content', JSON.stringify(err.cause, null, 2));
|
||||
cause.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
const hint = this.root.querySelector<HTMLElement>('#hint');
|
||||
if (hint && err.hint) {
|
||||
this.text('#hint-content', err.hint, true);
|
||||
|
|
|
@ -156,6 +156,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
|
|||
propagation: args.propagation ?? new Map(),
|
||||
propagators: new Map(),
|
||||
extraHead: [],
|
||||
scope: 0,
|
||||
cookies,
|
||||
/** This function returns the `Astro` faux-global */
|
||||
createAstro(
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
import type { PropagationHint } from '../../@types/astro';
|
||||
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
||||
import type { AstroComponentFactory } from './render/index.js';
|
||||
|
||||
function baseCreateComponent(cb: AstroComponentFactory, moduleId?: string) {
|
||||
function validateArgs(args: unknown[]): args is Parameters<AstroComponentFactory> {
|
||||
if (args.length !== 3) return false;
|
||||
if (!args[0] || typeof args[0] !== 'object') return false;
|
||||
return true;
|
||||
}
|
||||
function baseCreateComponent(cb: AstroComponentFactory, moduleId?: string): AstroComponentFactory {
|
||||
const name = moduleId?.split('/').pop()?.replace('.astro', '') ?? '';
|
||||
const fn = (...args: Parameters<AstroComponentFactory>) => {
|
||||
if (!validateArgs(args)) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.InvalidComponentArgs,
|
||||
message: AstroErrorData.InvalidComponentArgs.message(name),
|
||||
});
|
||||
}
|
||||
return cb(...args);
|
||||
};
|
||||
Object.defineProperty(fn, 'name', { value: name, writable: false });
|
||||
// Add a flag to this callback to mark it as an Astro component
|
||||
cb.isAstroComponentFactory = true;
|
||||
cb.moduleId = moduleId;
|
||||
return cb;
|
||||
fn.isAstroComponentFactory = true;
|
||||
fn.moduleId = moduleId;
|
||||
return fn;
|
||||
}
|
||||
|
||||
interface CreateComponentOptions {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from './index.js';
|
||||
import { HTMLParts } from './render/common.js';
|
||||
import type { ComponentIterable } from './render/component';
|
||||
import { ScopeFlags } from './render/util.js';
|
||||
|
||||
const ClientOnlyPlaceholder = 'astro-client-only';
|
||||
|
||||
|
@ -94,6 +95,7 @@ Did you forget to import the component or is it possible there is a typo?`);
|
|||
props[key] = value;
|
||||
}
|
||||
}
|
||||
result.scope |= ScopeFlags.JSX;
|
||||
return markHTMLString(await renderToString(result, vnode.type as any, props, slots));
|
||||
}
|
||||
case !vnode.type && (vnode.type as any) !== 0:
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { HeadAndContent } from './head-and-content';
|
|||
import type { RenderTemplateResult } from './render-template';
|
||||
|
||||
import { HTMLParts } from '../common.js';
|
||||
import { ScopeFlags } from '../util.js';
|
||||
import { isHeadAndContent } from './head-and-content.js';
|
||||
import { renderAstroTemplateResult } from './render-template.js';
|
||||
|
||||
|
@ -27,6 +28,7 @@ export async function renderToString(
|
|||
props: any,
|
||||
children: any
|
||||
): Promise<string> {
|
||||
result.scope |= ScopeFlags.Astro;
|
||||
const factoryResult = await componentFactory(result, props, children);
|
||||
|
||||
if (factoryResult instanceof Response) {
|
||||
|
|
|
@ -93,5 +93,7 @@ export function chunkToByteArray(
|
|||
if (chunk instanceof Uint8Array) {
|
||||
return chunk as Uint8Array;
|
||||
}
|
||||
return encoder.encode(stringifyChunk(result, chunk));
|
||||
// stringify chunk might return a HTMLString
|
||||
let stringified = stringifyChunk(result, chunk);
|
||||
return encoder.encode(stringified.toString());
|
||||
}
|
||||
|
|
|
@ -261,8 +261,10 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
|
|||
|
||||
if (isPage || renderer?.name === 'astro:jsx') {
|
||||
yield html;
|
||||
} else {
|
||||
} else if (html && html.length > 0) {
|
||||
yield markHTMLString(html.replace(/\<\/?astro-slot\>/g, ''));
|
||||
} else {
|
||||
yield '';
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { SSRResult } from '../../../@types/astro';
|
||||
|
||||
import { markHTMLString } from '../escape.js';
|
||||
import { renderElement } from './util.js';
|
||||
import { renderElement, ScopeFlags } from './util.js';
|
||||
|
||||
// Filter out duplicate elements in our set
|
||||
const uniqueElements = (item: any, index: number, all: any[]) => {
|
||||
|
@ -52,6 +52,14 @@ export function* maybeRenderHead(result: SSRResult) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Don't render the head inside of a JSX component that's inside of an Astro component
|
||||
// as the Astro component will be the one to render the head.
|
||||
switch (result.scope) {
|
||||
case ScopeFlags.JSX | ScopeFlags.Slot | ScopeFlags.Astro: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This is an instruction informing the page rendering that head might need rendering.
|
||||
// This allows the page to deduplicate head injections.
|
||||
yield { type: 'head', result } as const;
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { RenderInstruction } from './types.js';
|
|||
|
||||
import { HTMLString, markHTMLString } from '../escape.js';
|
||||
import { renderChild } from './any.js';
|
||||
import { ScopeFlags } from './util.js';
|
||||
|
||||
const slotString = Symbol.for('astro:slot-string');
|
||||
|
||||
|
@ -20,8 +21,13 @@ export function isSlotString(str: string): str is any {
|
|||
return !!(str as any)[slotString];
|
||||
}
|
||||
|
||||
export async function renderSlot(_result: any, slotted: string, fallback?: any): Promise<string> {
|
||||
export async function renderSlot(
|
||||
result: SSRResult,
|
||||
slotted: string,
|
||||
fallback?: any
|
||||
): Promise<string> {
|
||||
if (slotted) {
|
||||
result.scope |= ScopeFlags.Slot;
|
||||
let iterator = renderChild(slotted);
|
||||
let content = '';
|
||||
let instructions: null | RenderInstruction[] = null;
|
||||
|
@ -35,6 +41,8 @@ export async function renderSlot(_result: any, slotted: string, fallback?: any):
|
|||
content += chunk;
|
||||
}
|
||||
}
|
||||
// Remove the flag since we are now outside of the scope.
|
||||
result.scope &= ~ScopeFlags.Slot;
|
||||
return markHTMLString(new SlotString(content, instructions));
|
||||
}
|
||||
return fallback;
|
||||
|
|
|
@ -128,3 +128,9 @@ export function renderElement(
|
|||
}
|
||||
return `<${name}${internalSpreadAttributes(props, shouldEscape)}>${children}</${name}>`;
|
||||
}
|
||||
|
||||
export const ScopeFlags = {
|
||||
Astro: 1 << 0,
|
||||
JSX: 1 << 1,
|
||||
Slot: 1 << 2,
|
||||
};
|
||||
|
|
|
@ -29,6 +29,7 @@ export default function astroScannerPlugin({ settings }: { settings: AstroSettin
|
|||
const { meta = {} } = this.getModuleInfo(id) ?? {};
|
||||
return {
|
||||
code,
|
||||
map: null,
|
||||
meta: {
|
||||
...meta,
|
||||
astro: {
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('Content Collections - render()', () => {
|
|||
// Includes hoisted script
|
||||
expect(
|
||||
[...allScripts].find((script) =>
|
||||
$(script).text().includes('document.querySelector("#update-me")')
|
||||
$(script).attr('src')?.includes('WithScripts')
|
||||
),
|
||||
'`WithScripts.astro` hoisted script missing from head.'
|
||||
).to.not.be.undefined;
|
||||
|
@ -55,9 +55,7 @@ describe('Content Collections - render()', () => {
|
|||
expect($('script[data-is-inline]')).to.have.a.lengthOf(1);
|
||||
});
|
||||
|
||||
// TODO: Script bleed isn't solved for prod builds.
|
||||
// Tackling in separate PR.
|
||||
it.skip('Excludes component scripts for non-rendered entries', async () => {
|
||||
it('Excludes component scripts for non-rendered entries', async () => {
|
||||
const html = await fixture.readFile('/index.html');
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
|
@ -71,6 +69,15 @@ describe('Content Collections - render()', () => {
|
|||
'`WithScripts.astro` hoisted script included unexpectedly.'
|
||||
).to.be.undefined;
|
||||
});
|
||||
|
||||
it('Applies MDX components export', async () => {
|
||||
const html = await fixture.readFile('/launch-week-components-export/index.html');
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
const h2 = $('h2');
|
||||
expect(h2).to.have.a.lengthOf(1);
|
||||
expect(h2.attr('data-components-export-applied')).to.equal('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Build - SSR', () => {
|
||||
|
@ -110,6 +117,18 @@ describe('Content Collections - render()', () => {
|
|||
// Includes styles
|
||||
expect($('link[rel=stylesheet]')).to.have.a.lengthOf(0);
|
||||
});
|
||||
|
||||
it('Applies MDX components export', async () => {
|
||||
const app = await fixture.loadTestAdapterApp();
|
||||
const request = new Request('http://example.com/launch-week-components-export');
|
||||
const response = await app.render(request);
|
||||
const html = await response.text();
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
const h2 = $('h2');
|
||||
expect(h2).to.have.a.lengthOf(1);
|
||||
expect(h2.attr('data-components-export-applied')).to.equal('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dev - SSG', () => {
|
||||
|
@ -162,5 +181,17 @@ describe('Content Collections - render()', () => {
|
|||
// Includes inline script
|
||||
expect($('script[data-is-inline]')).to.have.a.lengthOf(1);
|
||||
});
|
||||
|
||||
it('Applies MDX components export', async () => {
|
||||
const response = await fixture.fetch('/launch-week-components-export', { method: 'GET' });
|
||||
expect(response.status).to.equal(200);
|
||||
|
||||
const html = await response.text();
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
const h2 = $('h2');
|
||||
expect(h2).to.have.a.lengthOf(1);
|
||||
expect(h2.attr('data-components-export-applied')).to.equal('true');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('Custom Elements', () => {
|
|||
expect($('my-element')).to.have.lengthOf(1);
|
||||
|
||||
// test 2: shadow rendered
|
||||
expect($('my-element template[shadowroot=open]')).to.have.lengthOf(1);
|
||||
expect($('my-element template[shadowroot=open][shadowrootmode=open]')).to.have.lengthOf(1);
|
||||
});
|
||||
|
||||
it('Works with exported tagName', async () => {
|
||||
|
@ -34,7 +34,7 @@ describe('Custom Elements', () => {
|
|||
expect($('my-element')).to.have.lengthOf(1);
|
||||
|
||||
// test 2: shadow rendered
|
||||
expect($('my-element template[shadowroot=open]')).to.have.lengthOf(1);
|
||||
expect($('my-element template[shadowroot=open][shadowrootmode=open]')).to.have.lengthOf(1);
|
||||
});
|
||||
|
||||
it.skip('Hydration works with exported tagName', async () => {
|
||||
|
@ -46,7 +46,7 @@ describe('Custom Elements', () => {
|
|||
expect($('my-element')).to.have.lengthOf(1);
|
||||
|
||||
// test 2: shadow rendered
|
||||
expect($('my-element template[shadowroot=open]')).to.have.lengthOf(1);
|
||||
expect($('my-element template[shadowroot=open][shadowrootmode=open]')).to.have.lengthOf(1);
|
||||
|
||||
// Hydration
|
||||
// test 3: Component and polyfill scripts bundled separately
|
||||
|
|
4
packages/astro/test/fixtures/content/src/components/H2.astro
vendored
Normal file
4
packages/astro/test/fixtures/content/src/components/H2.astro
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
---
|
||||
|
||||
<h2 data-components-export-applied="true"><slot /></h2>
|
18
packages/astro/test/fixtures/content/src/content/blog/promo/launch-week-components-export.mdx
vendored
Normal file
18
packages/astro/test/fixtures/content/src/content/blog/promo/launch-week-components-export.mdx
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
title: 'Launch week!'
|
||||
description: 'Join us for the exciting launch of SPACE BLOG'
|
||||
publishedDate: 'Sat May 21 2022 00:00:00 GMT-0400 (Eastern Daylight Time)'
|
||||
tags: ['announcement']
|
||||
---
|
||||
|
||||
import H2 from '../../../components/H2.astro';
|
||||
|
||||
export const components = { h2: H2 };
|
||||
|
||||
Join us for the space blog launch!
|
||||
|
||||
## Details
|
||||
|
||||
- THIS THURSDAY
|
||||
- Houston, TX
|
||||
- Dress code: **interstellar casual** ✨
|
14
packages/astro/test/fixtures/content/src/pages/launch-week-components-export.astro
vendored
Normal file
14
packages/astro/test/fixtures/content/src/pages/launch-week-components-export.astro
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
import { getEntryBySlug } from 'astro:content';
|
||||
|
||||
const entry = await getEntryBySlug('blog', 'promo/launch-week-components-export');
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
<html>
|
||||
<head>
|
||||
<title>Launch Week</title>
|
||||
</head>
|
||||
<body>
|
||||
<Content />
|
||||
</body>
|
||||
</html>
|
|
@ -18,7 +18,7 @@ function renderToStaticMarkup(component, props, innerHTML) {
|
|||
const Component = getConstructor(component);
|
||||
const el = new Component();
|
||||
el.connectedCallback();
|
||||
const html = `<${el.localName}><template shadowroot="open">${el.shadowRoot.innerHTML}</template>${el.innerHTML}</${el.localName}>`
|
||||
const html = `<${el.localName}><template shadowroot="open" shadowrootmode="open">${el.shadowRoot.innerHTML}</template>${el.innerHTML}</${el.localName}>`
|
||||
return {
|
||||
html
|
||||
};
|
||||
|
|
23
packages/astro/test/fixtures/lit-element/src/components/non-deferred-element.ts
vendored
Normal file
23
packages/astro/test/fixtures/lit-element/src/components/non-deferred-element.ts
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { LitElement, html } from 'lit';
|
||||
import { property, customElement } from 'lit/decorators.js';
|
||||
|
||||
@customElement('non-deferred-counter')
|
||||
export class NonDeferredCounter extends LitElement {
|
||||
// All set properties are reflected to attributes so its hydration is not
|
||||
// hydration-deferred should always be set.
|
||||
@property({ type: Number, reflect: true }) count = 0;
|
||||
|
||||
increment() {
|
||||
this.count++;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div>
|
||||
<p>Count: ${this.count}</p>
|
||||
|
||||
<button type="button" @click=${this.increment}>Increment</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,25 @@
|
|||
---
|
||||
import {MyElement} from '../components/my-element.js';
|
||||
import {NonDeferredCounter} from '../components/non-deferred-element.js';
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>LitElements</title>
|
||||
<title>LitElements</title>
|
||||
</head>
|
||||
<body>
|
||||
<MyElement
|
||||
foo="bar"
|
||||
str-attr={'initialized'}
|
||||
bool={false}
|
||||
obj={{data: 1}}
|
||||
reflectedStrProp={'initialized reflected'}>
|
||||
</MyElement>
|
||||
<MyElement
|
||||
id="default"
|
||||
foo="bar"
|
||||
str-attr={'initialized'}
|
||||
bool={false}
|
||||
obj={{data: 1}}
|
||||
reflectedStrProp={'initialized reflected'}>
|
||||
</MyElement>
|
||||
<NonDeferredCounter
|
||||
id="non-deferred"
|
||||
count={10}
|
||||
foo="bar">
|
||||
</NonDeferredCounter>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,36 +30,57 @@ describe('LitElement test', function () {
|
|||
const $ = cheerio.load(html);
|
||||
|
||||
// test 1: attributes rendered – non reactive properties
|
||||
expect($('my-element').attr('foo')).to.equal('bar');
|
||||
expect($('#default').attr('foo')).to.equal('bar');
|
||||
|
||||
// test 2: shadow rendered
|
||||
expect($('my-element').html()).to.include(`<div>Testing...</div>`);
|
||||
expect($('#default').html()).to.include(`<div>Testing...</div>`);
|
||||
|
||||
// test 3: string reactive property set
|
||||
expect(stripExpressionMarkers($('my-element').html())).to.include(
|
||||
expect(stripExpressionMarkers($('#default').html())).to.include(
|
||||
`<div id="str">initialized</div>`
|
||||
);
|
||||
|
||||
// test 4: boolean reactive property correctly set
|
||||
// <my-element bool="false"> Lit will equate to true because it uses
|
||||
// this.hasAttribute to determine its value
|
||||
expect(stripExpressionMarkers($('my-element').html())).to.include(`<div id="bool">B</div>`);
|
||||
expect(stripExpressionMarkers($('#default').html())).to.include(`<div id="bool">B</div>`);
|
||||
|
||||
// test 5: object reactive property set
|
||||
// by default objects will be stringified to [object Object]
|
||||
expect(stripExpressionMarkers($('my-element').html())).to.include(
|
||||
`<div id="data">data: 1</div>`
|
||||
);
|
||||
expect(stripExpressionMarkers($('#default').html())).to.include(`<div id="data">data: 1</div>`);
|
||||
|
||||
// test 6: reactive properties are not rendered as attributes
|
||||
expect($('my-element').attr('obj')).to.equal(undefined);
|
||||
expect($('my-element').attr('bool')).to.equal(undefined);
|
||||
expect($('my-element').attr('str')).to.equal(undefined);
|
||||
expect($('#default').attr('obj')).to.equal(undefined);
|
||||
expect($('#default').attr('bool')).to.equal(undefined);
|
||||
expect($('#default').attr('str')).to.equal(undefined);
|
||||
|
||||
// test 7: reflected reactive props are rendered as attributes
|
||||
expect($('my-element').attr('reflectedbool')).to.equal('');
|
||||
expect($('my-element').attr('reflected-str')).to.equal('default reflected string');
|
||||
expect($('my-element').attr('reflected-str-prop')).to.equal('initialized reflected');
|
||||
expect($('#default').attr('reflectedbool')).to.equal('');
|
||||
expect($('#default').attr('reflected-str')).to.equal('default reflected string');
|
||||
expect($('#default').attr('reflected-str-prop')).to.equal('initialized reflected');
|
||||
});
|
||||
|
||||
it('Sets defer-hydration on element only when necessary', async () => {
|
||||
// @lit-labs/ssr/ requires Node 13.9 or higher
|
||||
if (NODE_VERSION < 13.9) {
|
||||
return;
|
||||
}
|
||||
const html = await fixture.readFile('/index.html');
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
// test 1: reflected reactive props are rendered as attributes
|
||||
expect($('#non-deferred').attr('count')).to.equal('10');
|
||||
|
||||
// test 2: non-reactive props are set as attributes
|
||||
expect($('#non-deferred').attr('foo')).to.equal('bar');
|
||||
|
||||
// test 3: components with only reflected reactive props set are not
|
||||
// deferred because their state can be completely serialized via attributes
|
||||
expect($('#non-deferred').attr('defer-hydration')).to.equal(undefined);
|
||||
|
||||
// test 4: components with non-reflected reactive props set are deferred because
|
||||
// their state needs to be synced with the server on the client.
|
||||
expect($('#default').attr('defer-hydration')).to.equal('');
|
||||
});
|
||||
|
||||
it('Correctly passes child slots', async () => {
|
||||
|
@ -74,7 +95,7 @@ describe('LitElement test', function () {
|
|||
const $slottedMyElement = $('#slotted');
|
||||
const $slottedSlottedMyElement = $('#slotted-slotted');
|
||||
|
||||
expect($('my-element').length).to.equal(3);
|
||||
expect($('#default').length).to.equal(3);
|
||||
|
||||
// Root my-element
|
||||
expect($rootMyElement.children('.default').length).to.equal(2);
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
# @astrojs/cloudflare
|
||||
|
||||
## 6.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6046](https://github.com/withastro/astro/pull/6046) [`df3201165`](https://github.com/withastro/astro/commit/df320116528e00ab082396531b4deffbb0707b78) Thanks [@matthewp](https://github.com/matthewp)! - Cloudflare fix for building to directory mode
|
||||
|
||||
- Updated dependencies [[`41e97158b`](https://github.com/withastro/astro/commit/41e97158ba90d23d346b6e3ff6c7c14b5ecbe903), [`e779c6242`](https://github.com/withastro/astro/commit/e779c6242418d1d4102e683ca5b851b764c89688)]:
|
||||
- astro@2.0.4
|
||||
|
||||
## 6.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@astrojs/cloudflare",
|
||||
"description": "Deploy your site to cloudflare workers or cloudflare pages",
|
||||
"version": "6.1.0",
|
||||
"version": "6.1.1",
|
||||
"type": "module",
|
||||
"types": "./dist/index.d.ts",
|
||||
"author": "withastro",
|
||||
|
@ -38,7 +38,7 @@
|
|||
"tiny-glob": "^0.2.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "workspace:^2.0.3"
|
||||
"astro": "workspace:^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "workspace:*",
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
"esbuild": "^0.15.18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "workspace:^2.0.3"
|
||||
"astro": "workspace:^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "workspace:*",
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
# @astrojs/image
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5932](https://github.com/withastro/astro/pull/5932) [`b3e65991f`](https://github.com/withastro/astro/commit/b3e65991f731f5320ba5826c731934a8e8482493) Thanks [@rasendubi](https://github.com/rasendubi)! - Allow images from outside srcDir
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5894](https://github.com/withastro/astro/pull/5894) [`ca91976ed`](https://github.com/withastro/astro/commit/ca91976edbfd34adbb31096516a266f31d8f6216) Thanks [@ralacerda](https://github.com/ralacerda)! - `getPicture()` return object with the correct image type
|
||||
|
||||
- Updated dependencies [[`9793f19ec`](https://github.com/withastro/astro/commit/9793f19ecd4e64cbf3140454fe52aeee2c22c8c9), [`f91615f5c`](https://github.com/withastro/astro/commit/f91615f5c04fde36f115dad9110dd75254efd61d), [`2fb72c887`](https://github.com/withastro/astro/commit/2fb72c887f71c0a69ab512870d65b8c867774766)]:
|
||||
- astro@2.0.5
|
||||
|
||||
## 0.13.1
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -259,7 +259,7 @@ color representation with 3 or 6 hexadecimal characters in the form `#123[abc]`,
|
|||
**Default:** `'cover'`
|
||||
</p>
|
||||
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead.
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead. Read more about [how `sharp` resizes images](https://sharp.pixelplumbing.com/api-resize).
|
||||
|
||||
How the image should be resized to fit both `height` and `width`.
|
||||
|
||||
|
@ -271,7 +271,7 @@ How the image should be resized to fit both `height` and `width`.
|
|||
**Default:** `'centre'`
|
||||
</p>
|
||||
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead.
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead. Read more about [how `sharp` resizes images](https://sharp.pixelplumbing.com/api-resize).
|
||||
|
||||
Position of the crop when fit is `cover` or `contain`.
|
||||
|
||||
|
@ -333,7 +333,7 @@ The list of sizes that should be built for responsive images. This is combined w
|
|||
|
||||
```astro
|
||||
// Builds three images: 400x400, 800x800, and 1200x1200
|
||||
<Picture src={...} widths={[400, 800, 1200]} aspectRatio="1:1" />
|
||||
<Picture src={...} widths={[400, 800, 1200]} aspectRatio="1:1" alt="descriptive text" />
|
||||
```
|
||||
|
||||
#### aspectRatio
|
||||
|
@ -392,7 +392,7 @@ color representation with 3 or 6 hexadecimal characters in the form `#123[abc]`,
|
|||
**Default:** `'cover'`
|
||||
</p>
|
||||
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead.
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead. Read more about [how `sharp` resizes images](https://sharp.pixelplumbing.com/api-resize).
|
||||
|
||||
How the image should be resized to fit both `height` and `width`.
|
||||
|
||||
|
@ -406,7 +406,7 @@ How the image should be resized to fit both `height` and `width`.
|
|||
**Default:** `'centre'`
|
||||
</p>
|
||||
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead.
|
||||
> This is not supported by the default Squoosh service. See the [installation section](#installing-sharp-optional) for details on using the `sharp` service instead. Read more about [how `sharp` resizes images](https://sharp.pixelplumbing.com/api-resize).
|
||||
|
||||
Position of the crop when fit is `cover` or `contain`.
|
||||
|
||||
|
@ -422,7 +422,10 @@ This can be helpful if you need to add preload links to a page's `<head>`.
|
|||
---
|
||||
import { getImage } from '@astrojs/image';
|
||||
|
||||
const { src } = await getImage({src: '../assets/hero.png'});
|
||||
const { src } = await getImage({
|
||||
src: import('../assets/hero.png'),
|
||||
alt: "My hero image"
|
||||
});
|
||||
---
|
||||
|
||||
<html>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@astrojs/image",
|
||||
"description": "Load and transform images in your Astro site.",
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.0",
|
||||
"type": "module",
|
||||
"types": "./dist/index.d.ts",
|
||||
"author": "withastro",
|
||||
|
@ -47,8 +47,7 @@
|
|||
"image-size": "^1.0.2",
|
||||
"kleur": "^4.1.5",
|
||||
"magic-string": "^0.27.0",
|
||||
"mime": "^3.0.0",
|
||||
"slash": "^4.0.0"
|
||||
"mime": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/http-cache-semantics": "^4.0.1",
|
||||
|
@ -64,7 +63,7 @@
|
|||
"vite": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "workspace:^2.0.3",
|
||||
"astro": "workspace:^2.0.6",
|
||||
"sharp": ">=0.31.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
|
|
|
@ -17,7 +17,7 @@ export interface GetPictureParams {
|
|||
}
|
||||
|
||||
export interface GetPictureResult {
|
||||
image: astroHTML.JSX.HTMLAttributes;
|
||||
image: astroHTML.JSX.ImgHTMLAttributes;
|
||||
sources: { type: string; srcset: string }[];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import type { AstroConfig } from 'astro';
|
||||
import MagicString from 'magic-string';
|
||||
import fs from 'node:fs/promises';
|
||||
import path, { basename, extname, join } from 'node:path';
|
||||
import { basename, extname } from 'node:path';
|
||||
import { Readable } from 'node:stream';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import slash from 'slash';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import type { Plugin, ResolvedConfig } from 'vite';
|
||||
import type { IntegrationOptions } from './index.js';
|
||||
import type { InputFormat } from './loaders/index.js';
|
||||
|
@ -65,12 +64,7 @@ export function createPlugin(config: AstroConfig, options: Required<IntegrationO
|
|||
|
||||
meta.src = `__ASTRO_IMAGE_ASSET__${handle}__`;
|
||||
} else {
|
||||
const relId = path.relative(fileURLToPath(config.srcDir), id);
|
||||
|
||||
meta.src = join('/@astroimage', relId);
|
||||
|
||||
// Windows compat
|
||||
meta.src = slash(meta.src);
|
||||
meta.src = '/@astroimage' + url.pathname;
|
||||
}
|
||||
|
||||
return `export default ${JSON.stringify(meta)}`;
|
||||
|
@ -78,9 +72,9 @@ export function createPlugin(config: AstroConfig, options: Required<IntegrationO
|
|||
configureServer(server) {
|
||||
server.middlewares.use(async (req, res, next) => {
|
||||
if (req.url?.startsWith('/@astroimage/')) {
|
||||
const [, id] = req.url.split('/@astroimage/');
|
||||
// Reconstructing URL to get rid of query parameters in path
|
||||
const url = new URL(req.url.slice('/@astroimage'.length), 'file:');
|
||||
|
||||
const url = new URL(id, config.srcDir);
|
||||
const file = await fs.readFile(url);
|
||||
|
||||
const meta = await metadata(url);
|
||||
|
|
BIN
packages/integrations/image/test/fixtures/basic-image/social.png
vendored
Normal file
BIN
packages/integrations/image/test/fixtures/basic-image/social.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
import socialJpg from '../assets/social.jpg';
|
||||
import introJpg from '../assets/blog/introducing astro.jpg';
|
||||
import outsideSrc from '../../social.png';
|
||||
import { Image } from '@astrojs/image/components';
|
||||
const publicImage = new URL('./hero.jpg', Astro.url);
|
||||
---
|
||||
|
@ -18,6 +19,8 @@ const publicImage = new URL('./hero.jpg', Astro.url);
|
|||
<br />
|
||||
<Image id="no-transforms" src={socialJpg} alt="no-transforms" />
|
||||
<br />
|
||||
<Image id="outside-src" src={outsideSrc} alt="outside-src" />
|
||||
<br />
|
||||
<Image id="google" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" width={544} height={184} format="webp" alt="Google" />
|
||||
<br />
|
||||
<Image id="inline" src={import('../assets/social.jpg')} width={506} alt="inline" />
|
||||
|
|
BIN
packages/integrations/image/test/fixtures/basic-picture/social.png
vendored
Normal file
BIN
packages/integrations/image/test/fixtures/basic-picture/social.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
import socialJpg from '../assets/social.jpg';
|
||||
import introJpg from '../assets/blog/introducing astro.jpg';
|
||||
import outsideSrc from '../../social.png';
|
||||
import { Picture } from '@astrojs/image/components';
|
||||
const publicImage = new URL('./hero.jpg', Astro.url);
|
||||
---
|
||||
|
@ -14,6 +15,8 @@ const publicImage = new URL('./hero.jpg', Astro.url);
|
|||
<br />
|
||||
<Picture id="spaces" src={introJpg} sizes="100vw" widths={[384, 768]} aspectRatio={768/414} alt="spaces" />
|
||||
<br />
|
||||
<Picture id="outside-src" src={outsideSrc} sizes="100vw" widths={[384, 768]} aspectRatio={768/414} alt="outside-src" />
|
||||
<br />
|
||||
<Picture id="social-jpg" src={socialJpg} sizes="(min-width: 640px) 50vw, 100vw" widths={[253, 506]} alt="Social image" />
|
||||
<br />
|
||||
<Picture id="google" src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" sizes="(min-width: 640px) 50vw, 100vw" widths={[272, 544]} aspectRatio={544/184} alt="Google logo" formats={["avif", "webp", "png"]} />
|
||||
|
|
|
@ -2,9 +2,14 @@ import { expect } from 'chai';
|
|||
import * as cheerio from 'cheerio';
|
||||
import sizeOf from 'image-size';
|
||||
import fs from 'fs/promises';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { join } from 'node:path';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const toAstroImage = (relpath) =>
|
||||
'/@astroimage' + pathToFileURL(join(__dirname, 'fixtures/basic-image', relpath)).pathname;
|
||||
|
||||
describe('SSG images - dev', function () {
|
||||
let fixture;
|
||||
let devServer;
|
||||
|
@ -25,25 +30,32 @@ describe('SSG images - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
},
|
||||
{
|
||||
title: 'Local image no transforms',
|
||||
id: '#no-transforms',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: {},
|
||||
},
|
||||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { f: 'webp', w: '768', h: '414' },
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '2024', h: '1012' },
|
||||
contentType: 'image/png',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
},
|
||||
{
|
||||
|
@ -123,19 +135,32 @@ describe('SSG images with subpath - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
},
|
||||
{
|
||||
title: 'Local image no transforms',
|
||||
id: '#no-transforms',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: {},
|
||||
},
|
||||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { f: 'webp', w: '768', h: '414' },
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '2024', h: '1012' },
|
||||
contentType: 'image/png',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
},
|
||||
{
|
||||
|
@ -210,8 +235,11 @@ describe('SSG images - build', function () {
|
|||
});
|
||||
|
||||
function verifyImage(pathname, expected) {
|
||||
const url = new URL('./fixtures/basic-image/dist/' + pathname, import.meta.url);
|
||||
const dist = fileURLToPath(url);
|
||||
const dist = join(
|
||||
fileURLToPath(new URL('.', import.meta.url)),
|
||||
'fixtures/basic-image/dist',
|
||||
pathname
|
||||
);
|
||||
const result = sizeOf(dist);
|
||||
expect(result).to.deep.equal(expected);
|
||||
}
|
||||
|
@ -229,6 +257,12 @@ describe('SSG images - build', function () {
|
|||
regex: /^\/_astro\/introducing astro.\w{8}_\w{4,10}.webp/,
|
||||
size: { width: 768, height: 414, type: 'webp' },
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
regex: /^\/_astro\/social.\w{8}_\w{4,10}.png/,
|
||||
size: { type: 'png', width: 2024, height: 1012 },
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
|
@ -311,6 +345,12 @@ describe('SSG images with subpath - build', function () {
|
|||
regex: /^\/docs\/_astro\/introducing astro.\w{8}_\w{4,10}.webp/,
|
||||
size: { width: 768, height: 414, type: 'webp' },
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
regex: /^\/docs\/_astro\/social.\w{8}_\w{4,10}.png/,
|
||||
size: { type: 'png', width: 2024, height: 1012 },
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import { expect } from 'chai';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { join } from 'node:path';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
import testAdapter from '../../../astro/test/test-adapter.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const toAstroImage = (relpath) =>
|
||||
'/@astroimage' + pathToFileURL(join(__dirname, 'fixtures/basic-image', relpath)).pathname;
|
||||
|
||||
describe('SSR images - dev', function () {
|
||||
let fixture;
|
||||
let devServer;
|
||||
|
@ -28,28 +34,35 @@ describe('SSR images - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
},
|
||||
{
|
||||
title: 'Local image no transforms',
|
||||
id: '#no-transforms',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: {},
|
||||
contentType: 'image/jpeg',
|
||||
},
|
||||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { f: 'webp', w: '768', h: '414' },
|
||||
contentType: 'image/webp',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '2024', h: '1012' },
|
||||
contentType: 'image/png',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
},
|
||||
|
@ -150,21 +163,28 @@ describe('SSR images with subpath - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
},
|
||||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { f: 'webp', w: '768', h: '414' },
|
||||
contentType: 'image/webp',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '2024', h: '1012' },
|
||||
contentType: 'image/png',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
},
|
||||
|
|
|
@ -3,9 +3,14 @@ import * as cheerio from 'cheerio';
|
|||
import fs from 'fs';
|
||||
import sizeOf from 'image-size';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { join } from 'node:path';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const toAstroImage = (relpath) =>
|
||||
'/@astroimage' + pathToFileURL(join(__dirname, 'fixtures/basic-picture', relpath)).pathname;
|
||||
|
||||
describe('SSG pictures - dev', function () {
|
||||
let fixture;
|
||||
let devServer;
|
||||
|
@ -26,21 +31,28 @@ describe('SSG pictures - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
alt: 'Social image',
|
||||
},
|
||||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { f: 'jpg', w: '768', h: '414' },
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '768', h: '414' },
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
alt: 'Inline social image',
|
||||
},
|
||||
|
@ -120,21 +132,28 @@ describe('SSG pictures with subpath - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
alt: 'Social image',
|
||||
},
|
||||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { f: 'jpg', w: '768', h: '414' },
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '768', h: '414' },
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
alt: 'Inline social image',
|
||||
},
|
||||
|
@ -222,6 +241,13 @@ describe('SSG pictures - build', function () {
|
|||
size: { width: 768, height: 414, type: 'jpg' },
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
regex: /^\/_astro\/social.\w{8}_\w{4,10}.png/,
|
||||
size: { type: 'png', width: 768, height: 414 },
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline images',
|
||||
id: '#inline',
|
||||
|
@ -322,6 +348,13 @@ describe('SSG pictures with subpath - build', function () {
|
|||
size: { width: 506, height: 253, type: 'jpg' },
|
||||
alt: 'Social image',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
regex: /^\/docs\/_astro\/social.\w{8}_\w{4,10}.png/,
|
||||
size: { type: 'png', width: 768, height: 414 },
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline images',
|
||||
id: '#inline',
|
||||
|
|
|
@ -30,6 +30,13 @@ describe('SSR pictures - build', function () {
|
|||
query: { w: '768', h: '414', f: 'jpg', href: /^\/_astro\/introducing astro.\w{8}.jpg/ },
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: '/_image',
|
||||
query: { w: '768', h: '414', f: 'png', href: /^\/_astro\/social.\w{8}.png/ },
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
|
@ -141,6 +148,13 @@ describe('SSR pictures with subpath - build', function () {
|
|||
query: { w: '768', h: '414', f: 'jpg', href: /^\/docs\/_astro\/introducing astro.\w{8}.jpg/ },
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: '/_image',
|
||||
query: { w: '768', h: '414', f: 'png', href: /^\/docs\/_astro\/social.\w{8}.png/ },
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import { expect } from 'chai';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { join } from 'node:path';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
import testAdapter from '../../../astro/test/test-adapter.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const toAstroImage = (relpath) =>
|
||||
'/@astroimage' + pathToFileURL(join(__dirname, 'fixtures/basic-picture', relpath)).pathname;
|
||||
|
||||
describe('SSR pictures - dev', function () {
|
||||
let fixture;
|
||||
let devServer;
|
||||
|
@ -28,7 +34,7 @@ describe('SSR pictures - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
alt: 'Social image',
|
||||
|
@ -36,15 +42,23 @@ describe('SSR pictures - dev', function () {
|
|||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { w: '768', h: '414', f: 'jpg' },
|
||||
contentType: 'image/jpeg',
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '768', h: '414' },
|
||||
contentType: 'image/png',
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
alt: 'Inline social image',
|
||||
|
@ -157,7 +171,7 @@ describe('SSR pictures with subpath - dev', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
alt: 'Social image',
|
||||
|
@ -165,15 +179,23 @@ describe('SSR pictures with subpath - dev', function () {
|
|||
{
|
||||
title: 'Filename with spaces',
|
||||
id: '#spaces',
|
||||
url: '/@astroimage/assets/blog/introducing astro.jpg',
|
||||
url: toAstroImage('src/assets/blog/introducing astro.jpg'),
|
||||
query: { w: '768', h: '414', f: 'jpg' },
|
||||
contentType: 'image/jpeg',
|
||||
alt: 'spaces',
|
||||
},
|
||||
{
|
||||
title: 'File outside src',
|
||||
id: '#outside-src',
|
||||
url: toAstroImage('social.png'),
|
||||
query: { f: 'png', w: '768', h: '414' },
|
||||
contentType: 'image/png',
|
||||
alt: 'outside-src',
|
||||
},
|
||||
{
|
||||
title: 'Inline imports',
|
||||
id: '#inline',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
contentType: 'image/jpeg',
|
||||
alt: 'Inline social image',
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import { expect } from 'chai';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { join } from 'node:path';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const toAstroImage = (relpath) =>
|
||||
'/@astroimage' + pathToFileURL(join(__dirname, 'fixtures/squoosh-service', relpath)).pathname;
|
||||
|
||||
describe('Squoosh service', function () {
|
||||
let fixture;
|
||||
let devServer;
|
||||
|
@ -22,7 +28,7 @@ describe('Squoosh service', function () {
|
|||
{
|
||||
title: 'Local images',
|
||||
id: '#social-jpg',
|
||||
url: '/@astroimage/assets/social.jpg',
|
||||
url: toAstroImage('src/assets/social.jpg'),
|
||||
query: { f: 'jpg', w: '506', h: '253' },
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
# @astrojs/lit
|
||||
|
||||
## 1.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6080](https://github.com/withastro/astro/pull/6080) [`0db220415`](https://github.com/withastro/astro/commit/0db22041531d981a813a07f4c4e00cfb7ebddd51) Thanks [@e111077](https://github.com/e111077)! - Fixes Lit hydration not having the same reactive values as server (losing state upon hydration)
|
||||
|
||||
- [#6055](https://github.com/withastro/astro/pull/6055) [`2567aa48b`](https://github.com/withastro/astro/commit/2567aa48bba8751cf7e10429555f1e85830c9169) Thanks [@e111077](https://github.com/e111077)! - Add forwards compatibility for streaming Declarative Shadow DOM
|
||||
|
||||
## 1.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -8,9 +8,13 @@ async function polyfill() {
|
|||
}
|
||||
|
||||
const polyfillCheckEl = new DOMParser()
|
||||
.parseFromString(`<p><template shadowroot="open"></template></p>`, 'text/html', {
|
||||
includeShadowRoots: true,
|
||||
})
|
||||
.parseFromString(
|
||||
`<p><template shadowroot="open" shadowrootmode="open"></template></p>`,
|
||||
'text/html',
|
||||
{
|
||||
includeShadowRoots: true,
|
||||
}
|
||||
)
|
||||
.querySelector('p');
|
||||
|
||||
if (!polyfillCheckEl || !polyfillCheckEl.shadowRoot) {
|
||||
|
|
12
packages/integrations/lit/client-shim.min.js
vendored
12
packages/integrations/lit/client-shim.min.js
vendored
|
@ -8,7 +8,7 @@ var b = (t, n) => {
|
|||
function s() {
|
||||
if (d === void 0) {
|
||||
let t = document.createElement('div');
|
||||
(t.innerHTML = '<div><template shadowroot="open"></template></div>'),
|
||||
(t.innerHTML = '<div><template shadowroot="open" shadowrootmode="open"></template></div>'),
|
||||
(d = !!t.firstElementChild.shadowRoot);
|
||||
}
|
||||
return d;
|
||||
|
@ -80,8 +80,12 @@ async function g() {
|
|||
window.addEventListener('DOMContentLoaded', () => t(document.body), { once: true });
|
||||
}
|
||||
var x = new DOMParser()
|
||||
.parseFromString('<p><template shadowroot="open"></template></p>', 'text/html', {
|
||||
includeShadowRoots: !0,
|
||||
})
|
||||
.parseFromString(
|
||||
'<p><template shadowroot="open" shadowrootmode="open"></template></p>',
|
||||
'text/html',
|
||||
{
|
||||
includeShadowRoots: !0,
|
||||
}
|
||||
)
|
||||
.querySelector('p');
|
||||
(!x || !x.shadowRoot) && g();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@astrojs/lit",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"description": "Use Lit components within Astro",
|
||||
"type": "module",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
@ -23,6 +23,7 @@
|
|||
".": "./dist/index.js",
|
||||
"./server.js": "./server.js",
|
||||
"./client-shim.js": "./client-shim.js",
|
||||
"./dist/client.js": "./dist/client.js",
|
||||
"./hydration-support.js": "./hydration-support.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue