-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[@astrojs/image] adding caching support for SSG builds (#4909)
* adds a caching feature for SSG builds * chore: add changeset * nit: eslint fix * chore: add readme docs for caching * adding basic test coverage for cached images
- Loading branch information
Tony Sullivan
authored
Sep 29, 2022
1 parent
d08093f
commit 9892989
Showing
8 changed files
with
240 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
'@astrojs/image': patch | ||
--- | ||
|
||
Adds caching support for transformed images :tada: | ||
|
||
Local images will be cached for 1 year and invalidated when the original image file is changed. | ||
|
||
Remote images will be cached based on the `fetch()` response's cache headers, similar to how a CDN would manage the cache. | ||
|
||
**cacheDir** | ||
|
||
By default, transformed images will be cached to `./node_modules/.astro/image`. This can be configured in the integration's config options. | ||
|
||
``` | ||
export default defineConfig({ | ||
integrations: [image({ | ||
// may be useful if your hosting provider allows caching between CI builds | ||
cacheDir: "./.cache/image" | ||
})] | ||
}); | ||
``` | ||
|
||
Caching can also be disabled by using `cacheDir: false`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import fs from 'node:fs/promises'; | ||
import path from 'node:path'; | ||
import { fileURLToPath } from 'node:url'; | ||
import { debug, error, warn } from '../utils/logger.js'; | ||
import type { LoggerLevel } from '../utils/logger.js'; | ||
|
||
const CACHE_FILE = `cache.json`; | ||
|
||
interface Cache { | ||
[filename: string]: { expires: number } | ||
} | ||
|
||
export class ImageCache { | ||
#cacheDir: URL; | ||
#cacheFile: URL; | ||
#cache: Cache = { } | ||
#logLevel: LoggerLevel; | ||
|
||
constructor(dir: URL, logLevel: LoggerLevel) { | ||
this.#logLevel = logLevel; | ||
this.#cacheDir = dir; | ||
this.#cacheFile = this.#toAbsolutePath(CACHE_FILE); | ||
} | ||
|
||
#toAbsolutePath(file: string) { | ||
return new URL(path.join(this.#cacheDir.toString(), file)); | ||
} | ||
|
||
async init() { | ||
try { | ||
const str = await fs.readFile(this.#cacheFile, 'utf-8'); | ||
this.#cache = JSON.parse(str) as Cache; | ||
} catch { | ||
// noop | ||
debug({ message: 'no cache file found', level: this.#logLevel }); | ||
} | ||
} | ||
|
||
async finalize() { | ||
try { | ||
await fs.mkdir(path.dirname(fileURLToPath(this.#cacheFile)), { recursive: true }); | ||
await fs.writeFile(this.#cacheFile, JSON.stringify(this.#cache)); | ||
} catch { | ||
// noop | ||
warn({ message: 'could not save the cache file', level: this.#logLevel }); | ||
} | ||
} | ||
|
||
async get(file: string): Promise<Buffer | undefined> { | ||
if (!this.has(file)) { | ||
return undefined; | ||
} | ||
|
||
try { | ||
const filepath = this.#toAbsolutePath(file); | ||
return await fs.readFile(filepath); | ||
} catch { | ||
warn({ message: `could not load cached file for "${file}"`, level: this.#logLevel }); | ||
return undefined; | ||
} | ||
} | ||
|
||
async set(file: string, buffer: Buffer, opts: Cache['string']): Promise<void> { | ||
try { | ||
const filepath = this.#toAbsolutePath(file); | ||
await fs.mkdir(path.dirname(fileURLToPath(filepath)), { recursive: true }); | ||
await fs.writeFile(filepath, buffer); | ||
|
||
this.#cache[file] = opts; | ||
} catch { | ||
// noop | ||
warn({ message: `could not save cached copy of "${file}"`, level: this.#logLevel }); | ||
} | ||
} | ||
|
||
has(file: string): boolean { | ||
if (!(file in this.#cache)) { | ||
return false; | ||
} | ||
|
||
const { expires } = this.#cache[file]; | ||
|
||
return expires > Date.now(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.