-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Content Collection cache (experimental) #8854
Conversation
🦋 Changeset detectedLatest commit: 3d61b49 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is blocked because it contains a minor
changeset. A reviewer will merge this at the next release if approved.
af787e4
to
ba83398
Compare
6636df2
to
aba219d
Compare
!preview content-cache |
|
f38cdb9
to
b1f127e
Compare
!preview content-cache |
|
f97ffa7
to
7870d0c
Compare
Working on a refactor to be stacked against this PR refactor/content-collections...refactor/collections-build |
7b52b92
to
5466fb6
Compare
/preview content-cache |
Snapshots have been released for the following packages:
Publish Log
Build Log
|
84dd3a2
to
b14a2bc
Compare
/preview content-cache |
Snapshots have been released for the following packages:
Publish Log
Build Log
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Happy to see this one squeak in! 🙌 Tiny suggestion for your consideration below!
Co-authored-by: Sarah Rainsberger <[email protected]>
configResolved(config) { | ||
IS_DEV = config.mode === 'development' | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
settings
already contains the config
; why do we need configResolved
in this case?
return; | ||
} | ||
if (code.includes(RESOLVED_VIRTUAL_MODULE_ID)) { | ||
const depth = chunk.fileName.split('/').length - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work on Windows?
function getStringifiedCollectionFromLookup(wantedType: 'content' | 'data' | 'render', relContentDir: string, lookupMap: ContentLookupMap) { | ||
let str = '{'; | ||
// In dev, we don't need to normalize the import specifier at all. Vite handles it. | ||
let normalize = (slug: string) => slug; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be let normalize
because if/else
both reach the point where we do normalize =
let suffix = ''; | ||
if (wantedType === 'content') suffix = CONTENT_FLAG; | ||
else if (wantedType === 'data') suffix = DATA_FLAG; | ||
else if (wantedType === 'render') suffix = CONTENT_RENDER_FLAG; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be else
because we checked all types
`lookupMap = ${stringifiedLookupMap};` | ||
), | ||
}; | ||
function getStringifiedCollectionFromLookup(wantedType: 'content' | 'data' | 'render', relContentDir: string, lookupMap: ContentLookupMap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we introduced some new logic: 'content' | 'data' | 'render'
. Maybe it's worth having a comment that explains what we do.
If you think it's too technical, we could also have a README.md
await fsMod.promises.mkdir(contentCacheDir, { recursive: true }); | ||
await fsMod.promises.writeFile(contentManifestFile, JSON.stringify(newManifest), { encoding: 'utf8' }); | ||
|
||
const cacheExists = fsMod.existsSync(cache); | ||
fsMod.mkdirSync(cache, { recursive: true }) | ||
await fsMod.promises.mkdir(cacheTmp, { recursive: true }); | ||
await copyFiles(distContentRoot, cacheTmp, true); | ||
if (cacheExists) { | ||
await copyFiles(contentCacheDir, distContentRoot, false); | ||
} | ||
await copyFiles(cacheTmp, contentCacheDir); | ||
await fsMod.promises.rm(cacheTmp, { recursive: true, force: true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we enclose all these FS operations in a try/catch
block? There might be remote situations where we don't have write access
]); | ||
newManifest.serverEntries = Array.from(serverComponents); | ||
newManifest.clientEntries = Array.from(clientComponents); | ||
await fsMod.promises.mkdir(contentCacheDir, { recursive: true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check if contentCacheDir
exists already?
|
||
async function generateContentManifest(opts: StaticBuildOptions, lookupMap: ContentLookupMap): Promise<ContentManifest> { | ||
let manifest: ContentManifest = { version: CONTENT_MANIFEST_VERSION, entries: [], serverEntries: [], clientEntries: [] }; | ||
const limit = pLimit(10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an arbitrary number?
const key: ContentManifestKey = { collection, type, entry }; | ||
const fileURL = new URL(encodeURI(joinPaths(opts.settings.config.root.toString(), entry))); | ||
promises.push(limit(async () => { | ||
const data = await fsMod.promises.readFile(fileURL, { encoding: 'utf8' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this operation safe? Should we check if fileURL
exists and if we can read the file?
@@ -36,3 +36,19 @@ export function i18nHasFallback(config: AstroConfig): boolean { | |||
|
|||
return false; | |||
} | |||
|
|||
export function encodeName(name: string): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should at least explain what kind of encoding this function does. Or maybe an example.
Co-authored-by: Sarah Rainsberger <[email protected]> Co-authored-by: Matthew Phillips <[email protected]>
Changes
experimental.contentCollectionCache
flag. This flag changes a few things about our build process, which allows us to share Content Collection assets between the build.astro build --force
flag to clear the cache if needed.import.meta.glob
, which will invalidate a collection every time one of the modules it references changes, this implements a custom build for content collections where individual modules can be built separately.In order to try this PR out locally, run:
Real-world results from this PR:
Note that the build still renders every page, which can take a significant time with large projects.
2.5K items
Uncached 33.31s
Cached 10.53s
5K items
Uncached 86.70s
Cached 44.17s
Docs Repo (Real World)
Uncached 133.20s
Cached 10.46s
Testing
Added a few initial test suites for the experimental behavior. To remove the experimental flag, we'll need more comprehensive test coverage.
Docs
For review:
.changeset/lovely-pianos-build.md
packages/astro/src/@types/astro.ts