Skip to content

Commit

Permalink
Update: store meta data about compression savings when cached
Browse files Browse the repository at this point in the history
  • Loading branch information
naranjamecanica committed Nov 21, 2023
1 parent 35e709c commit 887a2d8
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 53 deletions.
89 changes: 58 additions & 31 deletions packages/core/src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,22 @@ import {

import type { ResolvedConfigOptions, StackItem } from './typings'

type CacheFileInfo = {
oldPath: string
newPath: string
oldSize: number
newSize: number
ratio: number
duration: number
oldSizeString: string
newSizeString: string
ratioString: string
durationString: string
}

type CacheValue = {
hash: string
info?: CacheFileInfo
}

let cacheEnabled = false
Expand Down Expand Up @@ -63,21 +77,28 @@ function md5(buffer: BinaryLike): string {
return crypto.createHash('md5').update(buffer).digest('hex')
}

async function getAndUpdateCacheContent(filePath: string | URL) {
async function getAndUpdateCacheContent(
filePath: string,
info?: CacheFileInfo,
) {
try {
const hash = md5(await readFile(filePath))
const normalizedFilePath = filePath.toString()
const cacheValue = fileCacheMap.get(normalizedFilePath) as
| CacheValue
| undefined
const cacheValue = fileCacheMap.get(filePath)

if (cacheValue && cacheValue.hash === hash) {
return {
changed: false,
info: cacheValue.info,
}
}
entryMap.set(normalizedFilePath, { hash })

// save new hash && provided info in entry
const entry = entryMap.get(filePath)
const updatedEntry = { ...entry, hash, info: info ?? entry?.info }
entryMap.set(filePath, updatedEntry)
return {
changed: true,
info: updatedEntry.info,
}
} catch (error) {
return {
Expand Down Expand Up @@ -118,43 +139,49 @@ export const FileCache = {

// Check if input file has changed or there was an error
if (changed || error) {
return false
return
}

// Check if output files are in cache and use them if they haven't changed
const outputFilesExist = await Promise.allSettled(
fileToStack.map(
item =>
new Promise((resolve, reject) =>
getAndUpdateCacheContent(cacheDir + item.toPath)
.then(outputFileCache => {
if (!outputFileCache.error && !outputFileCache.changed) {
copyFileSync(cacheDir + item.toPath, baseDir + item.toPath)
if (existsSync(baseDir + item.toPath)) {
resolve(true)
}
fileToStack.map(item => {
return new Promise((resolve, reject) => {
getAndUpdateCacheContent(cacheDir + filePathFrom)
.then(({ changed, error, info }) => {
if (error || changed || !info) {
return reject(error?.message)
}

try {
copyFileSync(cacheDir + item.toPath, baseDir + item.toPath)

if (existsSync(baseDir + item.toPath)) {
return resolve({ ...info, cached: true })
}
reject(
outputFileCache.error
? `Error while checking cache [${outputFileCache.error.message}]`
: 'Could not copy cached files',
)
})
.catch(reject),
),
),
} catch {
return reject('Could not copy cached file')
}

reject()
})
.catch(reject)
})
}),
)

return outputFilesExist.every(p => p.status === 'fulfilled')
const allFulFilled = outputFilesExist.every(p => p.status === 'fulfilled')

if (allFulFilled) {
return outputFilesExist
}
},

update: async (baseDir: string, filePathTo: string) => {
update: async (baseDir: string, info: CacheFileInfo) => {
if (!cacheEnabled) {
return
}

await copyFile(baseDir + filePathTo, cacheDir + filePathTo)
await getAndUpdateCacheContent(cacheDir + filePathTo)
await copyFile(baseDir + info.newPath, cacheDir + info.newPath)
await getAndUpdateCacheContent(cacheDir + info.newPath, info)
},

reconcile: async () => {
Expand Down
44 changes: 22 additions & 22 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,15 @@ export async function processFile({
}) as Promise<ErroredFile>
}

const hasValidCache = await FileCache.check(
// cached?
const cacheFileInfo = await FileCache.check(
baseDir,
filePathFrom,
fileToStack,
)

if (hasValidCache) {
return Promise.reject({
oldPath: filePathFrom,
newPath: '',
error: '',
errorType: 'cache',
}) as Promise<ErroredFile>
if (cacheFileInfo) {
return Promise.resolve(cacheFileInfo) as Promise<ProcessResultWhenOutput[]>
}

let oldBuffer: Buffer
Expand Down Expand Up @@ -327,12 +323,10 @@ export async function processFile({
return Promise.reject(e)
})
.then(async () => {
// Add to/update in cache
await FileCache.update(baseDir, filePathTo)

const duration = performance.now() - start
const ratio = newSize / oldSize - 1
return Promise.resolve({

const fileInfo = {
oldPath: filePathFrom,
newPath: filePathTo,
oldSize,
Expand All @@ -349,7 +343,12 @@ export async function processFile({
ratio * 100
).toFixed(precisions.ratio)} %`,
durationString: `${duration.toFixed(precisions.duration)} ms`,
})
}

// Add to/update in cache
await FileCache.update(baseDir, fileInfo)

return Promise.resolve(fileInfo)
})
.catch(error => {
let errorType = 'error'
Expand Down Expand Up @@ -578,11 +577,18 @@ export function logResults(
? chalk.red(file.ratioString)
: file.ratioString,
chalk.dim(' │ '),
)

// cached?
if (file.cached) {
logArray.push(chalk.dim(` │ Cached`))
} else {
// Duration
' '.repeat(maxLengths.duration - file.durationString.length),
chalk.dim(file.durationString),
)
logArray.push(
' '.repeat(maxLengths.duration - file.durationString.length),
chalk.dim(file.durationString),
)
}
}

logger.info(logArray.join(''))
Expand Down Expand Up @@ -645,9 +651,6 @@ export function logErrors(
file.error,
)
break
case 'cache':
logArray.push(chalk.black.bgBlue(' CACHED '), ' ', file.error)
break
case 'warning':
logArray.push(
chalk.bgYellow(' WARNING '),
Expand Down Expand Up @@ -689,9 +692,6 @@ export function logErrors(
file.error,
)
break
case 'cache':
logArray.push(chalk.black.bgBlue(' CACHED '), ' ', file.error)
break
case 'warning':
logArray.push(
chalk.bgYellow(' WARNING '),
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export type ProcessedFile = {
newSizeString: string
ratioString: string
durationString: string
cached?: boolean
optimizedDeleted: ResolvedMakeConfigOptions['skipIfLargerThan']
avifDeleted: ResolvedMakeConfigOptions['skipIfLargerThan']
webpDeleted: ResolvedMakeConfigOptions['skipIfLargerThan']
Expand Down

0 comments on commit 887a2d8

Please sign in to comment.