Skip to content

Commit

Permalink
Merge pull request #6 from vHeemstra/feature-cache
Browse files Browse the repository at this point in the history
Feature cache
  • Loading branch information
vHeemstra authored Nov 14, 2023
2 parents 6329148 + 464c06c commit 5b61839
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 85 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ Default: `true`

> Ignore the optimized output if it is larger than the original file.
### cache

Type: `boolean`<br>
Default: `true`

> Skip optimizing the input if it did not change since the last run.
### makeAvif / makeWebp

Type: `object`<br>
Expand Down
235 changes: 169 additions & 66 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@
"postversion": "git push --follow-tags"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.11.0",
"@vheemstra/imagemin-avifenc": "^2.1.0",
"@vheemstra/imagemin-oxipng": "^1.0.0",
"@vitest/coverage-c8": "^0.32.2",
"@vitest/coverage-istanbul": "^0.34.6",
"cross-env": "^7.0.3",
"cross-var": "^1.1.0",
"eslint": "^8.52.0",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-vitest-globals": "^1.4.0",
Expand All @@ -77,7 +77,7 @@
"imagemin-svgo": "^10.0.1",
"imagemin-webp": "^8.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"prettier": "^3.1.0",
"serve": "^14.2.1",
"typescript": "^5.2.2",
"vite": "^4.5.0",
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"node": ">=16.0.0"
},
"dependencies": {
"@file-cache/core": "^1.1.4",
"chalk": "^5.2.0",
"fast-glob": "^3.2.12",
"fs-extra": "^11.1.1",
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1368,6 +1368,7 @@ describe('logErrors', () => {
* dist/images/opaque-1.png.avif
*/

// TODO: add tests using cache
// TODO: expand after-build checks

describe.skipIf(skipBuilds)('viteImagemin', () => {
Expand Down Expand Up @@ -1452,6 +1453,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
// skipIfLargerThan: 'optimized',
// skipIfLargerThan: 'smallest',
},
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down Expand Up @@ -1518,6 +1520,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
skipIfLargerThan: 'smallest' as const,
},
logger: mockLogger,
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down Expand Up @@ -1574,6 +1577,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
],
},
logger: mockLogger,
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down Expand Up @@ -1619,6 +1623,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
plugins: {
gif: [mockPlugin],
},
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down Expand Up @@ -1649,6 +1654,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
plugins: {
gif: [mockPlugin],
},
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down Expand Up @@ -1684,6 +1690,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
}),
],
},
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down Expand Up @@ -1714,6 +1721,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
plugins: {
none: [mockPlugin],
},
cache: false,
}

const testConfig = getBuildConfig(viteImagemin(options), {
Expand Down
83 changes: 68 additions & 15 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import path from 'node:path'
import { lstatSync, readdirSync, unlinkSync /*, rmSync */ } from 'node:fs'
import {
existsSync,
lstatSync,
readdirSync,
unlinkSync /*, rmSync */,
} from 'node:fs'
import { readFile, writeFile } from 'node:fs/promises'
import { Buffer } from 'node:buffer'
import { performance } from 'node:perf_hooks'
import chalk from 'chalk'
import { normalizePath, createFilter } from 'vite'
import imagemin from 'imagemin'
import isAPNG from 'is-apng'
import { createCache } from '@file-cache/core'

import {
isFunction,
isBoolean,
Expand Down Expand Up @@ -34,6 +41,7 @@ import type {
ProcessResult,
ProcessFileReturn,
} from './typings'
import { CacheInterface } from '@file-cache/core/mjs/CacheInterface'

export const parsePlugins = (rawPlugins: PluginsConfig) => {
let plugins: false | ResolvedPluginsConfig = false
Expand Down Expand Up @@ -84,8 +92,8 @@ export const parseOptions = (
false === _options.makeAvif.skipIfLargerThan
? _options.makeAvif.skipIfLargerThan
: isString(_options.makeAvif.skipIfLargerThan)
? _options.makeAvif.skipIfLargerThan
: 'optimized',
? _options.makeAvif.skipIfLargerThan
: 'optimized',
}
}
}
Expand All @@ -104,8 +112,8 @@ export const parseOptions = (
false === _options.makeWebp.skipIfLargerThan
? _options.makeWebp.skipIfLargerThan
: isString(_options.makeWebp.skipIfLargerThan)
? _options.makeWebp.skipIfLargerThan
: 'optimized',
? _options.makeWebp.skipIfLargerThan
: 'optimized',
}
}
}
Expand All @@ -131,6 +139,7 @@ export const parseOptions = (
skipIfLarger: isBoolean(_options?.skipIfLarger)
? _options.skipIfLarger
: true,
cache: isBoolean(_options?.cache) ? _options.cache : true,
plugins,
makeAvif,
makeWebp,
Expand Down Expand Up @@ -179,6 +188,7 @@ export async function processFile({
precisions,
bytesDivider,
sizeUnit,
cache,
}: ProcessFileParams): ProcessFileReturn {
// const start = performance.now()

Expand All @@ -200,6 +210,24 @@ export async function processFile({
}) as Promise<ErroredFile>
}

if (cache) {
const result = await cache.getAndUpdateCache(baseDir + filePathFrom)
if (!result.changed) {
const outputsStillExist = fileToStack.every(item => {
return existsSync(baseDir + item.toPath)
})

if (outputsStillExist) {
return Promise.reject({
oldPath: filePathFrom,
newPath: '',
error: '',
errorType: 'cache',
}) as Promise<ErroredFile>
}
}
}

let oldBuffer: Buffer
let oldSize = 0

Expand Down Expand Up @@ -526,8 +554,8 @@ export function logResults(
file.ratio < 0
? chalk.green(basenameTo)
: file.ratio > 0
? chalk.yellow(basenameTo)
: basenameTo,
? chalk.yellow(basenameTo)
: basenameTo,
' '.repeat(
maxPathLength - bulletLength - file.newPath.length + spaceLength,
),
Expand All @@ -542,8 +570,8 @@ export function logResults(
file.ratio < 0
? chalk.green(file.ratioString)
: file.ratio > 0
? chalk.red(file.ratioString)
: file.ratioString,
? chalk.red(file.ratioString)
: file.ratioString,
chalk.dim(' │ '),

// Duration
Expand Down Expand Up @@ -612,6 +640,9 @@ 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 @@ -653,6 +684,9 @@ 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 @@ -716,6 +750,8 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
let hadFilesToProcess = false
// const mtimeCache = new Map<string, number>()

let cache: CacheInterface

return {
name: 'vite-plugin-imagemin',
enforce: 'post',
Expand Down Expand Up @@ -746,6 +782,17 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
const baseDir = `${root}/`
const rootRE = new RegExp(`^${escapeRegExp(baseDir)}`)

// Create cache for this run
cache = (await createCache({
noCache: options.cache === false,
mode: 'content',
keys: [
() => {
return JSON.stringify(options)
},
],
})) as CacheInterface

// Get all input files to (potentially) process
const files = getAllFiles(processDir, logger)
.filter(filter)
Expand Down Expand Up @@ -852,6 +899,7 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
precisions,
bytesDivider,
sizeUnit,
cache,
}),
),
) as Promise<ProcessResult[]>
Expand Down Expand Up @@ -965,6 +1013,9 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
logResults(processedFiles[k], logger, maxLengths)
})

// Write cache state to file for persistence
await cache.reconcile()

Object.keys(erroredFiles)
.sort((a, b) => a.localeCompare(b)) // TODO: sort by (sub)folder and depth?
.forEach(k => {
Expand All @@ -989,16 +1040,18 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
totalDuration.length,
) + 2
const totalRatio = (totalSize.to / totalSize.from - 1) * 100
const totalRatioString =
totalRatio < 0

const totalRatioString = isNaN(totalRatio)
? '0 %'
: totalRatio < 0
? chalk.green(
`-${Math.abs(totalRatio).toFixed(precisions.ratio)} %`,
)
: totalRatio > 0
? chalk.red(
`+${Math.abs(totalRatio).toFixed(precisions.ratio)} %`,
)
: `${Math.abs(totalRatio).toFixed(precisions.ratio)} %`
? chalk.red(
`+${Math.abs(totalRatio).toFixed(precisions.ratio)} %`,
)
: `${Math.abs(totalRatio).toFixed(precisions.ratio)} %`

logger.info('')

Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Logger as ViteLogger, FilterPattern } from 'vite'
import type { Plugin as ImageminPlugin } from 'imagemin'
import { CacheInterface } from '@file-cache/core/mjs/CacheInterface'

// type Required<T> = {
// [P in keyof T]-?: T[P]
Expand Down Expand Up @@ -79,6 +80,12 @@ export interface ConfigOptions {
*/
verbose?: boolean

/**
* Only optimize contents if it was updated.
* @default true
*/
cache?: boolean

/**
* Only use optimized contents if smaller than original.
* @default true
Expand Down Expand Up @@ -128,6 +135,7 @@ export interface ResolvedConfigOptions {
onlyAssets: boolean
verbose: boolean
skipIfLarger: boolean
cache: boolean
plugins: ResolvedPluginsConfig
makeAvif: false | ResolvedMakeConfigOptions
makeWebp: false | ResolvedMakeConfigOptions
Expand Down Expand Up @@ -162,6 +170,7 @@ export type ProcessFileParams = {
}
bytesDivider: number
sizeUnit: string
cache: CacheInterface
}

export type ProcessedFile = {
Expand Down
1 change: 1 addition & 0 deletions packages/playground/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default defineConfig({
// skipIfLargerThan: 'optimized', // default
// skipIfLargerThan: 'smallest',
},
// cache: false,
}),
],
})

0 comments on commit 5b61839

Please sign in to comment.