diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index 4463e4dcbc22a..0be9b77e96fe6 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -30,6 +30,7 @@ "@graphql-tools/load": "^7.5.10", "@jridgewell/trace-mapping": "^0.3.13", "@nodelib/fs.walk": "^1.2.8", + "@parcel/cache": "2.6.2", "@parcel/core": "2.6.2", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", "@types/http-proxy": "^1.17.7", diff --git a/packages/gatsby/src/utils/parcel/__tests__/__snapshots__/compile-gatsby-files.ts.snap b/packages/gatsby/src/utils/parcel/__tests__/__snapshots__/compile-gatsby-files.ts.snap index 15f6a05c0d88e..28b4507270d94 100644 --- a/packages/gatsby/src/utils/parcel/__tests__/__snapshots__/compile-gatsby-files.ts.snap +++ b/packages/gatsby/src/utils/parcel/__tests__/__snapshots__/compile-gatsby-files.ts.snap @@ -2,6 +2,7 @@ exports[`gatsby file compilation constructBundler should construct Parcel relative to passed directory 1`] = ` Object { + "cache": undefined, "cacheDir": "/packages/gatsby/src/utils/parcel/__tests__/fixtures/js/.cache/.parcel-cache", "defaultConfig": "/packages/gatsby-parcel-config/lib/index.json", "entries": Array [ diff --git a/packages/gatsby/src/utils/parcel/compile-gatsby-files.ts b/packages/gatsby/src/utils/parcel/compile-gatsby-files.ts index 2ea07a70ab882..11cd5fc8e1d6f 100644 --- a/packages/gatsby/src/utils/parcel/compile-gatsby-files.ts +++ b/packages/gatsby/src/utils/parcel/compile-gatsby-files.ts @@ -1,4 +1,5 @@ import { Parcel } from "@parcel/core" +import { LMDBCache, Cache } from "@parcel/cache" import path from "path" import type { Diagnostic } from "@parcel/diagnostic" import reporter from "gatsby-cli/lib/reporter" @@ -27,7 +28,7 @@ function exponentialBackoff(retry: number): Promise { * Construct Parcel with config. * @see {@link https://parceljs.org/features/targets/} */ -export function constructParcel(siteRoot: string): Parcel { +export function constructParcel(siteRoot: string, cache?: Cache): Parcel { return new Parcel({ entries: [ `${siteRoot}/${gatsbyFileRegex}`, @@ -35,6 +36,7 @@ export function constructParcel(siteRoot: string): Parcel { ], defaultConfig: require.resolve(`gatsby-parcel-config`), mode: `production`, + cache, targets: { root: { outputFormat: `commonjs`, @@ -100,8 +102,22 @@ export async function compileGatsbyFiles( await exponentialBackoff(retry) - const parcel = constructParcel(siteRoot) + // for whatever reason TS thinks LMDBCache is some browser Cache and not actually Parcel's Cache + // so we force type it to Parcel's Cache + const cache = new LMDBCache(getCacheDir(siteRoot)) as unknown as Cache + const parcel = constructParcel(siteRoot, cache) const { bundleGraph } = await parcel.run() + let cacheClosePromise = Promise.resolve() + try { + // @ts-ignore store is public field on LMDBCache class, but public interface for Cache + // doesn't have it. There doesn't seem to be proper public API for this, so we have to + // resort to reaching into internals. Just in case this is wrapped in try/catch if + // parcel changes internals in future (closing cache is only needed when retrying + // so the if the change happens we shouldn't fail on happy builds) + cacheClosePromise = cache.store.close() + } catch (e) { + reporter.verbose(`Failed to close parcel cache\n${e.toString()}`) + } await exponentialBackoff(retry) @@ -138,8 +154,15 @@ export async function compileGatsbyFiles( ) } - // sometimes parcel cache gets in weird state - await remove(getCacheDir(siteRoot)) + // sometimes parcel cache gets in weird state and we need to clear the cache + await cacheClosePromise + + try { + await remove(getCacheDir(siteRoot)) + } catch { + // in windows we might get "EBUSY" errors if LMDB failed to close, so this try/catch is + // to prevent EBUSY errors from potentially hiding real import errors + } await compileGatsbyFiles(siteRoot, retry + 1) return