vite-imagetools
Advanced tools
Comparing version 6.2.9 to 7.0.0
import path, { basename, extname } from 'node:path'; | ||
import { join } from 'node:path/posix'; | ||
import { statSync, mkdirSync, createReadStream } from 'node:fs'; | ||
import { writeFile, readFile, opendir, stat, rm } from 'node:fs/promises'; | ||
import { builtins, builtinOutputFormats, parseURL, extractEntries, resolveConfigs, generateTransforms, applyTransforms, urlFormat, getMetadata } from 'imagetools-core'; | ||
@@ -7,3 +10,2 @@ export * from 'imagetools-core'; | ||
import { createHash } from 'node:crypto'; | ||
import { statSync } from 'node:fs'; | ||
@@ -13,7 +15,6 @@ const createBasePath = (base) => { | ||
}; | ||
async function generateImageID(url, config, originalImage) { | ||
async function generateImageID(url, config, imageBuffer) { | ||
if (url.host) { | ||
const baseURL = new URL(url.origin + url.pathname); | ||
const buffer = await originalImage.toBuffer(); | ||
return hash([baseURL.href, JSON.stringify(config), buffer]); | ||
return hash([baseURL.href, JSON.stringify(config), imageBuffer]); | ||
} | ||
@@ -40,3 +41,10 @@ // baseURL isn't a valid URL, but just a string used for an identifier | ||
function imagetools(userOptions = {}) { | ||
var _a, _b, _c, _d, _e; | ||
const pluginOptions = { ...defaultOptions, ...userOptions }; | ||
const cacheOptions = { | ||
enabled: (_b = (_a = pluginOptions.cache) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : true, | ||
dir: (_d = (_c = pluginOptions.cache) === null || _c === void 0 ? void 0 : _c.dir) !== null && _d !== void 0 ? _d : './node_modules/.cache/imagetools', | ||
retention: (_e = pluginOptions.cache) === null || _e === void 0 ? void 0 : _e.retention | ||
}; | ||
mkdirSync(`${cacheOptions.dir}`, { recursive: true }); | ||
const filter = createFilter(pluginOptions.include, pluginOptions.exclude); | ||
@@ -58,6 +66,7 @@ const transformFactories = pluginOptions.extendTransforms ? pluginOptions.extendTransforms(builtins) : builtins; | ||
async load(id) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; | ||
if (!filter(id)) | ||
return null; | ||
const srcURL = parseURL(id); | ||
const pathname = decodeURIComponent(srcURL.pathname); | ||
// lazy loaders so that we can load the metadata in defaultDirectives if needed | ||
@@ -69,3 +78,3 @@ // but if there are no directives then we can just skip loading | ||
return lazyImg; | ||
return (lazyImg = sharp(decodeURIComponent(srcURL.pathname))); | ||
return (lazyImg = sharp(pathname)); | ||
}; | ||
@@ -110,14 +119,34 @@ let lazyMetadata; | ||
}; | ||
const imageBuffer = await img.clone().toBuffer(); | ||
for (const config of imageConfigs) { | ||
const { transforms } = generateTransforms(config, transformFactories, srcURL.searchParams, logger); | ||
const { image, metadata } = await applyTransforms(transforms, img.clone(), pluginOptions.removeMetadata); | ||
if (viteConfig.command === 'serve') { | ||
const id = await generateImageID(srcURL, config, img); | ||
generatedImages.set(id, image); | ||
metadata.src = basePath + id; | ||
const id = await generateImageID(srcURL, config, imageBuffer); | ||
let image; | ||
let metadata; | ||
if (cacheOptions.enabled && ((_d = (_c = statSync(`${cacheOptions.dir}/${id}`, { throwIfNoEntry: false })) === null || _c === void 0 ? void 0 : _c.size) !== null && _d !== void 0 ? _d : 0) > 0) { | ||
metadata = (await sharp(`${cacheOptions.dir}/${id}`).metadata()); | ||
} | ||
else { | ||
const { transforms } = generateTransforms(config, transformFactories, srcURL.searchParams, logger); | ||
const res = await applyTransforms(transforms, img, pluginOptions.removeMetadata); | ||
metadata = res.metadata; | ||
if (cacheOptions.enabled) { | ||
await writeFile(`${cacheOptions.dir}/${id}`, await res.image.toBuffer()); | ||
} | ||
else { | ||
image = res.image; | ||
} | ||
} | ||
generatedImages.set(id, { image, metadata }); | ||
if (directives.has('inline')) { | ||
metadata.src = `data:image/${metadata.format};base64,${(image | ||
? await image.toBuffer() | ||
: await readFile(`${cacheOptions.dir}/${id}`)).toString('base64')}`; | ||
} | ||
else if (viteConfig.command === 'serve') { | ||
metadata.src = join((_f = (_e = viteConfig === null || viteConfig === void 0 ? void 0 : viteConfig.server) === null || _e === void 0 ? void 0 : _e.origin) !== null && _f !== void 0 ? _f : '', basePath) + id; | ||
} | ||
else { | ||
const fileHandle = this.emitFile({ | ||
name: basename(srcURL.pathname, extname(srcURL.pathname)) + `.${metadata.format}`, | ||
source: await image.toBuffer(), | ||
name: basename(pathname, extname(pathname)) + `.${metadata.format}`, | ||
source: image ? await image.toBuffer() : await readFile(`${cacheOptions.dir}/${id}`), | ||
type: 'asset' | ||
@@ -131,3 +160,3 @@ }); | ||
let outputFormat = urlFormat(); | ||
const asParam = (_c = directives.get('as')) === null || _c === void 0 ? void 0 : _c.split(':'); | ||
const asParam = (_g = directives.get('as')) === null || _g === void 0 ? void 0 : _g.split(':'); | ||
const as = asParam ? asParam[0] : undefined; | ||
@@ -141,4 +170,4 @@ for (const [key, format] of Object.entries(outputFormats)) { | ||
return dataToEsm(await outputFormat(outputMetadatas), { | ||
namedExports: (_f = (_d = pluginOptions.namedExports) !== null && _d !== void 0 ? _d : (_e = viteConfig.json) === null || _e === void 0 ? void 0 : _e.namedExports) !== null && _f !== void 0 ? _f : true, | ||
compact: (_g = !!viteConfig.build.minify) !== null && _g !== void 0 ? _g : false, | ||
namedExports: (_k = (_h = pluginOptions.namedExports) !== null && _h !== void 0 ? _h : (_j = viteConfig.json) === null || _j === void 0 ? void 0 : _j.namedExports) !== null && _k !== void 0 ? _k : true, | ||
compact: (_l = !!viteConfig.build.minify) !== null && _l !== void 0 ? _l : false, | ||
preferConst: true | ||
@@ -149,8 +178,12 @@ }); | ||
server.middlewares.use((req, res, next) => { | ||
var _a; | ||
var _a, _b; | ||
if ((_a = req.url) === null || _a === void 0 ? void 0 : _a.startsWith(basePath)) { | ||
const [, id] = req.url.split(basePath); | ||
const image = generatedImages.get(id); | ||
if (!image) | ||
const { image, metadata } = (_b = generatedImages.get(id)) !== null && _b !== void 0 ? _b : {}; | ||
if (!metadata) | ||
throw new Error(`vite-imagetools cannot find image with id "${id}" this is likely an internal error`); | ||
if (!image) { | ||
res.setHeader('Content-Type', `image/${metadata.format}`); | ||
return createReadStream(`${cacheOptions.dir}/${id}`).pipe(res); | ||
} | ||
if (pluginOptions.removeMetadata === false) { | ||
@@ -160,3 +193,2 @@ image.withMetadata(); | ||
res.setHeader('Content-Type', `image/${getMetadata(image, 'format')}`); | ||
res.setHeader('Cache-Control', 'max-age=360000'); | ||
return image.clone().pipe(res); | ||
@@ -166,2 +198,19 @@ } | ||
}); | ||
}, | ||
async buildEnd(error) { | ||
if (!error && cacheOptions.enabled && cacheOptions.retention !== undefined && viteConfig.command !== 'serve') { | ||
const dir = await opendir(cacheOptions.dir); | ||
for await (const dirent of dir) { | ||
if (dirent.isFile()) { | ||
if (generatedImages.has(dirent.name)) | ||
continue; | ||
const imagePath = `${cacheOptions.dir}/${dirent.name}`; | ||
const stats = await stat(imagePath); | ||
if (Date.now() - stats.mtimeMs > cacheOptions.retention * 1000) { | ||
console.debug(`deleting stale cached image ${dirent.name}`); | ||
await rm(imagePath); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -168,0 +217,0 @@ }; |
@@ -77,3 +77,21 @@ import type { TransformFactory, OutputFormat, resolveConfigs } from 'imagetools-core'; | ||
namedExports?: boolean; | ||
/** | ||
* Whether to cache transformed images and options for caching. | ||
*/ | ||
cache?: CacheOptions; | ||
} | ||
export interface CacheOptions { | ||
/** | ||
* Should the image cache be enabled. Default is true | ||
*/ | ||
enabled?: boolean; | ||
/** | ||
* Where should the cached images be stored. Default is './node_modules/.cache/imagetools' | ||
*/ | ||
dir?: string; | ||
/** | ||
* For how many seconds to keep transformed images cached. Default is undefined, which keeps the images forever. | ||
*/ | ||
retention?: number; | ||
} | ||
export {}; |
@@ -0,4 +1,4 @@ | ||
/// <reference types="node" resolution-mode="require"/> | ||
import type { ImageConfig } from 'imagetools-core'; | ||
import type { Sharp } from 'sharp'; | ||
export declare const createBasePath: (base?: string) => string; | ||
export declare function generateImageID(url: URL, config: ImageConfig, originalImage: Sharp): Promise<string>; | ||
export declare function generateImageID(url: URL, config: ImageConfig, imageBuffer: Buffer): Promise<string>; |
{ | ||
"name": "vite-imagetools", | ||
"description": "Load and transform images using a toolbox of import directives!", | ||
"version": "6.2.9", | ||
"version": "7.0.0", | ||
"type": "module", | ||
@@ -29,7 +29,7 @@ "types": "dist/index.d.ts", | ||
"engines": { | ||
"node": ">=12.0.0" | ||
"node": ">=18.0.0" | ||
}, | ||
"dependencies": { | ||
"@rollup/pluginutils": "^5.0.5", | ||
"imagetools-core": "^6.0.4" | ||
"imagetools-core": "^7.0.0" | ||
}, | ||
@@ -41,13 +41,13 @@ "devDependencies": { | ||
"@types/picomatch": "^2.3.0", | ||
"@vitest/coverage-v8": "^0.34.0", | ||
"@vitest/coverage-v8": "^1.4.0", | ||
"jest-image-snapshot": "^6.2.0", | ||
"jsdom": "^23.0.0", | ||
"picomatch": "^3.0.0", | ||
"rollup": "^4.5.0", | ||
"jsdom": "^24.0.0", | ||
"picomatch": "^4.0.0", | ||
"rollup": "^4.13.0", | ||
"sharp": "^0.33.1", | ||
"tslib": "^2.6.1", | ||
"typescript": "^5.1.6", | ||
"vite": "^5.0.5", | ||
"vitest": "^0.34.0", | ||
"imagetools-core": "^6.0.4" | ||
"vite": "^5.2.6", | ||
"vitest": "^1.4.0", | ||
"imagetools-core": "^7.0.0" | ||
}, | ||
@@ -54,0 +54,0 @@ "scripts": { |
Sorry, the diff of this file is not supported yet
43816
312
+ Addedimagetools-core@7.0.2(transitive)
- Removed@emnapi/runtime@1.3.1(transitive)
- Removed@img/sharp-darwin-arm64@0.33.5(transitive)
- Removed@img/sharp-darwin-x64@0.33.5(transitive)
- Removed@img/sharp-libvips-darwin-arm64@1.0.4(transitive)
- Removed@img/sharp-libvips-darwin-x64@1.0.4(transitive)
- Removed@img/sharp-libvips-linux-arm@1.0.5(transitive)
- Removed@img/sharp-libvips-linux-arm64@1.0.4(transitive)
- Removed@img/sharp-libvips-linux-s390x@1.0.4(transitive)
- Removed@img/sharp-libvips-linux-x64@1.0.4(transitive)
- Removed@img/sharp-libvips-linuxmusl-arm64@1.0.4(transitive)
- Removed@img/sharp-libvips-linuxmusl-x64@1.0.4(transitive)
- Removed@img/sharp-linux-arm@0.33.5(transitive)
- Removed@img/sharp-linux-arm64@0.33.5(transitive)
- Removed@img/sharp-linux-s390x@0.33.5(transitive)
- Removed@img/sharp-linux-x64@0.33.5(transitive)
- Removed@img/sharp-linuxmusl-arm64@0.33.5(transitive)
- Removed@img/sharp-linuxmusl-x64@0.33.5(transitive)
- Removed@img/sharp-wasm32@0.33.5(transitive)
- Removed@img/sharp-win32-ia32@0.33.5(transitive)
- Removed@img/sharp-win32-x64@0.33.5(transitive)
- Removedcolor@4.2.3(transitive)
- Removedcolor-convert@2.0.1(transitive)
- Removedcolor-name@1.1.4(transitive)
- Removedcolor-string@1.9.1(transitive)
- Removeddetect-libc@2.0.3(transitive)
- Removedimagetools-core@6.0.4(transitive)
- Removedis-arrayish@0.3.2(transitive)
- Removedsemver@7.7.1(transitive)
- Removedsharp@0.33.5(transitive)
- Removedsimple-swizzle@0.2.2(transitive)
- Removedtslib@2.8.1(transitive)
Updatedimagetools-core@^7.0.0