From 67835a4cae775821208ea980586944975538364a Mon Sep 17 00:00:00 2001 From: Melissa Liu Date: Wed, 15 Jan 2025 12:57:58 -0800 Subject: [PATCH] fix: add cache invalidation when on config change --- .../__tests__/compile-stylex-folder-test.js | 24 +++++++++++++++++++ packages/cli/src/cache.js | 18 +++++++++++++- packages/cli/src/transform.js | 15 ++++++++---- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/cli/__tests__/compile-stylex-folder-test.js b/packages/cli/__tests__/compile-stylex-folder-test.js index 874b3f8e..207890d4 100644 --- a/packages/cli/__tests__/compile-stylex-folder-test.js +++ b/packages/cli/__tests__/compile-stylex-folder-test.js @@ -295,6 +295,7 @@ describe('cache mechanism works as expected', () => { expect(cacheContent).toHaveProperty('inputHash'); expect(cacheContent).toHaveProperty('outputHash'); expect(cacheContent).toHaveProperty('collectedCSS'); + expect(cacheContent).toHaveProperty('configHash'); } }); @@ -306,6 +307,28 @@ describe('cache mechanism works as expected', () => { writeSpy.mockRestore(); }); + test('recompiles when config changes', async () => { + config.styleXBundleName = 'stylex_bundle_new.css'; + await compileDirectory(config); + + // Ensure cache is rewritten due to cache invalidation + expect(writeSpy).toHaveBeenCalledTimes(3); + + const cacheFiles = await fs.readdir(cachePath); + expect(cacheFiles.length).toEqual(3); + + for (const cacheFile of cacheFiles) { + const cacheFilePath = path.join(cachePath, cacheFile); + const cacheContent = JSON.parse( + await fs.readFile(cacheFilePath, 'utf-8'), + ); + expect(cacheContent).toHaveProperty('inputHash'); + expect(cacheContent).toHaveProperty('outputHash'); + expect(cacheContent).toHaveProperty('collectedCSS'); + expect(cacheContent).toHaveProperty('configHash'); + } + }); + test('recompiles when input changes', async () => { const mockFilePath = path.join(config.input, 'index.js'); const mockFileOutputPath = path.join(config.output, 'index.js'); @@ -386,6 +409,7 @@ describe('CLI works with a custom cache path', () => { expect(cacheContent).toHaveProperty('inputHash'); expect(cacheContent).toHaveProperty('outputHash'); expect(cacheContent).toHaveProperty('collectedCSS'); + expect(cacheContent).toHaveProperty('configHash'); } }); diff --git a/packages/cli/src/cache.js b/packages/cli/src/cache.js index 3c0899a4..71886ea3 100644 --- a/packages/cli/src/cache.js +++ b/packages/cli/src/cache.js @@ -60,7 +60,23 @@ export async function deleteCache(cachePath, filePath) { } } -export async function computeHash(filePath) { +export function computeStyleXConfigHash(config) { + // Excluding `input` and `output` paths to hash config settings + const configOptions = Object.fromEntries( + Object.entries(config).filter( + ([key]) => key !== 'input' && key !== 'output', + ), + ); + + const jsonRepresentation = JSON.stringify( + configOptions, + Object.keys(configOptions).sort(), + ); + + return hash(jsonRepresentation); +} + +export async function computeFilePathHash(filePath) { const absoluteFilePath = path.resolve(filePath); const parsedFile = path.parse(absoluteFilePath); diff --git a/packages/cli/src/transform.js b/packages/cli/src/transform.js index 8c957e65..75ee8d7c 100644 --- a/packages/cli/src/transform.js +++ b/packages/cli/src/transform.js @@ -27,7 +27,8 @@ import fs from 'fs'; import { writeCache, readCache, - computeHash, + computeFilePathHash, + computeStyleXConfigHash, getDefaultCachePath, } from './cache'; import { @@ -102,19 +103,22 @@ export async function compileFile( const outputFilePath = path.join(config.output, filePath); const cachePath = config.cachePath || getDefaultCachePath(); - const inputHash = await computeHash(inputFilePath); + const inputHash = await computeFilePathHash(inputFilePath); let oldOutputHash = null; if (fs.existsSync(outputFilePath)) { - oldOutputHash = await computeHash(outputFilePath); + oldOutputHash = await computeFilePathHash(outputFilePath); } + const configHash = computeStyleXConfigHash(config); + const cacheData = await readCache(cachePath, filePath); if ( cacheData && cacheData.inputHash === inputHash && oldOutputHash && - cacheData.outputHash === oldOutputHash + cacheData.outputHash === oldOutputHash && + cacheData.configHash === configHash ) { console.log(`[stylex] Using cached CSS for: ${filePath}`); config.state.styleXRules.set(filePath, cacheData.collectedCSS); @@ -133,12 +137,13 @@ export async function compileFile( writeCompiledJS(outputFilePath, code); - const newOutputHash = await computeHash(outputFilePath); + const newOutputHash = await computeFilePathHash(outputFilePath); await writeCache(cachePath, filePath, { inputHash, outputHash: newOutputHash, collectedCSS: rules, + configHash, }); } }