mirror of
https://github.com/withastro/astro.git
synced 2025-01-20 22:12:38 -05:00
fix(astro): always return cloned content collection (#11228)
* fix: always return cloned content collection * Update .changeset/early-melons-thank.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> --------- Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
parent
28ee6e7f85
commit
1e293a1b81
12 changed files with 139 additions and 3 deletions
5
.changeset/early-melons-thank.md
Normal file
5
.changeset/early-melons-thank.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Updates `getCollection()` to always return a cloned array
|
|
@ -79,8 +79,7 @@ export function createGetCollection({
|
|||
// Cache `getCollection()` calls in production only
|
||||
// prevents stale cache in development
|
||||
if (!import.meta.env?.DEV && cacheEntriesByCollection.has(collection)) {
|
||||
// Always return a new instance so consumers can safely mutate it
|
||||
entries = [...cacheEntriesByCollection.get(collection)!];
|
||||
entries = cacheEntriesByCollection.get(collection)!;
|
||||
} else {
|
||||
const limit = pLimit(10);
|
||||
entries = await Promise.all(
|
||||
|
@ -115,7 +114,9 @@ export function createGetCollection({
|
|||
if (typeof filter === 'function') {
|
||||
return entries.filter(filter);
|
||||
} else {
|
||||
return entries;
|
||||
// Clone the array so users can safely mutate it.
|
||||
// slice() is faster than ...spread for large arrays.
|
||||
return entries.slice();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -370,4 +370,26 @@ describe('Content Collections', () => {
|
|||
assert.equal($('script').attr('src').startsWith('/docs'), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Mutation', () => {
|
||||
let fixture;
|
||||
|
||||
before(async () => {
|
||||
fixture = await loadFixture({
|
||||
root: './fixtures/content-collections-mutation/',
|
||||
});
|
||||
await fixture.build();
|
||||
});
|
||||
|
||||
it('Does not mutate cached collection', async () => {
|
||||
const html = await fixture.readFile('/index.html');
|
||||
const index = cheerio.load(html)('h2:first').text();
|
||||
const html2 = await fixture.readFile('/another_page/index.html');
|
||||
const anotherPage = cheerio.load(html2)('h2:first').text();
|
||||
|
||||
assert.equal(index, anotherPage);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
6
packages/astro/test/fixtures/content-collections-mutation/astro.config.mjs
vendored
Normal file
6
packages/astro/test/fixtures/content-collections-mutation/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
import mdx from '@astrojs/mdx';
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
export default defineConfig({
|
||||
integrations: [mdx()],
|
||||
});
|
9
packages/astro/test/fixtures/content-collections-mutation/package.json
vendored
Normal file
9
packages/astro/test/fixtures/content-collections-mutation/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@test/content-collections-mutation",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"astro": "workspace:*",
|
||||
"@astrojs/mdx": "workspace:*"
|
||||
}
|
||||
}
|
6
packages/astro/test/fixtures/content-collections-mutation/src/content/blog/first.md
vendored
Normal file
6
packages/astro/test/fixtures/content-collections-mutation/src/content/blog/first.md
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "First Blog"
|
||||
date: 2024-04-05
|
||||
---
|
||||
|
||||
First blog content.
|
6
packages/astro/test/fixtures/content-collections-mutation/src/content/blog/second.md
vendored
Normal file
6
packages/astro/test/fixtures/content-collections-mutation/src/content/blog/second.md
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "Second Blog"
|
||||
date: 2024-04-06
|
||||
---
|
||||
|
||||
Second blog content.
|
6
packages/astro/test/fixtures/content-collections-mutation/src/content/blog/third.md
vendored
Normal file
6
packages/astro/test/fixtures/content-collections-mutation/src/content/blog/third.md
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: "Third Blog"
|
||||
date: 2024-04-07
|
||||
---
|
||||
|
||||
Third blog content.
|
16
packages/astro/test/fixtures/content-collections-mutation/src/content/config.ts
vendored
Normal file
16
packages/astro/test/fixtures/content-collections-mutation/src/content/config.ts
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 1. Import utilities from `astro:content`
|
||||
import { z, defineCollection } from "astro:content";
|
||||
|
||||
// 2. Define a `type` and `schema` for each collection
|
||||
const blogCollection = defineCollection({
|
||||
type: "content", // v2.5.0 and later
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
date: z.date(),
|
||||
}),
|
||||
});
|
||||
|
||||
// 3. Export a single `collections` object to register your collection(s)
|
||||
export const collections = {
|
||||
blog: blogCollection,
|
||||
};
|
25
packages/astro/test/fixtures/content-collections-mutation/src/pages/another_page.astro
vendored
Normal file
25
packages/astro/test/fixtures/content-collections-mutation/src/pages/another_page.astro
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
const blogs = await getCollection("blog");
|
||||
blogs.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf()); // sort by date most recent first
|
||||
const latestBlog = blogs.splice(0, 1)[0]; // modifies the collection
|
||||
---
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<a href="/">home</a>
|
||||
<h1>Latest Blog</h1>
|
||||
<h2>{latestBlog.data.title}</h2>
|
||||
<p>posted: {latestBlog.data.date.toLocaleString()}</p>
|
||||
<br />
|
||||
<h2>Older blogs</h2>
|
||||
{
|
||||
blogs.map((b) => (
|
||||
<>
|
||||
<h3>{b.data.title}</h3>
|
||||
<p>posted: {b.data.date.toLocaleString()}</p>
|
||||
</>
|
||||
))
|
||||
}
|
||||
</body>
|
||||
</html>
|
25
packages/astro/test/fixtures/content-collections-mutation/src/pages/index.astro
vendored
Normal file
25
packages/astro/test/fixtures/content-collections-mutation/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
const blogs = await getCollection("blog");
|
||||
blogs.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf()); // sort by date most recent first
|
||||
const latestBlog = blogs.splice(0, 1)[0]; // modifies the collection
|
||||
---
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<a href="/another_page">other page</a>
|
||||
<h1>Latest Blog</h1>
|
||||
<h2>{latestBlog.data.title}</h2>
|
||||
<p>posted: {latestBlog.data.date.toLocaleString()}</p>
|
||||
<br />
|
||||
<h2>Older blogs</h2>
|
||||
{
|
||||
blogs.map((b) => (
|
||||
<>
|
||||
<h3>{b.data.title}</h3>
|
||||
<p>posted: {b.data.date.toLocaleString()}</p>
|
||||
</>
|
||||
))
|
||||
}
|
||||
</body>
|
||||
</html>
|
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
|
@ -2599,6 +2599,15 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/content-collections-mutation:
|
||||
dependencies:
|
||||
'@astrojs/mdx':
|
||||
specifier: workspace:*
|
||||
version: link:../../../../integrations/mdx
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/content-collections-with-config-mjs:
|
||||
dependencies:
|
||||
astro:
|
||||
|
|
Loading…
Add table
Reference in a new issue