diff --git a/.changeset/eight-taxis-wash.md b/.changeset/eight-taxis-wash.md new file mode 100644 index 000000000..40b42303f --- /dev/null +++ b/.changeset/eight-taxis-wash.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': minor +--- + +Reduced cache usage, share css cache between SSR and client diff --git a/packages/vite-plugin-svelte/src/handleHotUpdate.ts b/packages/vite-plugin-svelte/src/handleHotUpdate.ts index 8f42e57d8..085e4d79a 100644 --- a/packages/vite-plugin-svelte/src/handleHotUpdate.ts +++ b/packages/vite-plugin-svelte/src/handleHotUpdate.ts @@ -1,8 +1,9 @@ import { ModuleNode, HmrContext } from 'vite'; -import { CompileData } from './utils/compile'; +import { Code, CompileData } from './utils/compile'; import { log } from './utils/log'; import { SvelteRequest } from './utils/id'; import { VitePluginSvelteCache } from './utils/VitePluginSvelteCache'; +import { ResolvedOptions } from './utils/options'; /** * Vite-specific HMR handling @@ -11,34 +12,33 @@ export async function handleHotUpdate( compileSvelte: Function, ctx: HmrContext, svelteRequest: SvelteRequest, - cache: VitePluginSvelteCache + cache: VitePluginSvelteCache, + options: Partial ): Promise { const { read, server } = ctx; - const cachedCompileData = cache.getCompileData(svelteRequest, false); - if (!cachedCompileData) { + + const cachedJS = cache.getJS(svelteRequest); + if (!cachedJS) { // file hasn't been requested yet (e.g. async component) log.debug(`handleHotUpdate first call ${svelteRequest.id}`); return; } + const cachedCss = cache.getCSS(svelteRequest); const content = await read(); - const compileData: CompileData = await compileSvelte( - svelteRequest, - content, - cachedCompileData.options - ); - cache.setCompileData(compileData); + const compileData: CompileData = await compileSvelte(svelteRequest, content, options); + cache.update(compileData); const affectedModules = new Set(); const cssModule = server.moduleGraph.getModuleById(svelteRequest.cssId); const mainModule = server.moduleGraph.getModuleById(svelteRequest.id); - if (cssModule && cssChanged(cachedCompileData, compileData)) { + if (cssModule && cssChanged(cachedCss, compileData.compiled.css)) { log.debug('handleHotUpdate css changed'); affectedModules.add(cssModule); } - if (mainModule && jsChanged(cachedCompileData, compileData)) { + if (mainModule && jsChanged(cachedJS, compileData.compiled.js, svelteRequest.filename)) { log.debug('handleHotUpdate js changed'); affectedModules.add(mainModule); } @@ -56,13 +56,13 @@ export async function handleHotUpdate( return result; } -function cssChanged(prev: CompileData, next: CompileData): boolean { - return !isCodeEqual(prev.compiled.css?.code, next.compiled.css?.code); +function cssChanged(prev?: Code, next?: Code): boolean { + return !isCodeEqual(prev?.code, next?.code); } -function jsChanged(prev: CompileData, next: CompileData): boolean { - const prevJs = prev.compiled.js.code; - const nextJs = next.compiled.js.code; +function jsChanged(prev?: Code, next?: Code, filename?: string): boolean { + const prevJs = prev?.code; + const nextJs = next?.code; const isStrictEqual = isCodeEqual(prevJs, nextJs); if (isStrictEqual) { return false; @@ -70,13 +70,13 @@ function jsChanged(prev: CompileData, next: CompileData): boolean { const isLooseEqual = isCodeEqual(normalizeJsCode(prevJs), normalizeJsCode(nextJs)); if (!isStrictEqual && isLooseEqual) { log.warn( - `ignoring compiler output js change for ${next.filename} as it is equal to previous output after normalization` + `ignoring compiler output js change for ${filename} as it is equal to previous output after normalization` ); } return !isLooseEqual; } -function isCodeEqual(prev: string, next: string): boolean { +function isCodeEqual(prev?: string, next?: string): boolean { if (!prev && !next) { return true; } @@ -93,7 +93,7 @@ function isCodeEqual(prev: string, next: string): boolean { * 2) ... maybe more (or less) in the future * @param code */ -function normalizeJsCode(code: string): string { +function normalizeJsCode(code?: string): string | undefined { if (!code) { return code; } diff --git a/packages/vite-plugin-svelte/src/index.ts b/packages/vite-plugin-svelte/src/index.ts index 2f7fb461a..541ae2580 100644 --- a/packages/vite-plugin-svelte/src/index.ts +++ b/packages/vite-plugin-svelte/src/index.ts @@ -115,10 +115,10 @@ export default function vitePluginSvelte(inlineOptions?: Partial): Plug // if (query.svelte) { if (query.type === 'style') { - const compileData = cache.getCompileData(svelteRequest, false); - if (compileData?.compiled?.css) { + const css = cache.getCSS(svelteRequest); + if (css) { log.debug(`load returns css for ${filename}`); - return compileData.compiled.css; + return css; } } } @@ -183,26 +183,21 @@ export default function vitePluginSvelte(inlineOptions?: Partial): Plug } log.debug('transform', svelteRequest); const { filename, query } = svelteRequest; - const cachedCompileData = cache.getCompileData(svelteRequest, false); if (query.svelte) { - // tagged svelte request, use cache - if (query.type === 'style' && cachedCompileData?.compiled?.css) { - log.debug(`transform returns css for ${filename}`); - return cachedCompileData.compiled.css; + if (query.type === 'style') { + const css = cache.getCSS(svelteRequest); + if (css) { + log.debug(`transform returns css for ${filename}`); + return css; // TODO return code arg instead? it's the code from load hook. + } } log.error('failed to transform tagged svelte request', svelteRequest); throw new Error(`failed to transform tagged svelte request for id ${id}`); } - - if (cachedCompileData && !options.disableTransformCache) { - log.debug(`transform returns cached js for ${filename}`); - return cachedCompileData.compiled.js; - } - - // first request, compile here const compileData = await compileSvelte(svelteRequest, code, options); - cache.setCompileData(compileData); + cache.update(compileData); + log.debug(`transform returns compiled js for ${filename}`); return compileData.compiled.js; }, @@ -216,7 +211,7 @@ export default function vitePluginSvelte(inlineOptions?: Partial): Plug return; } log.debug('handleHotUpdate', svelteRequest); - return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache); + return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options); }, // eslint-disable-next-line no-unused-vars diff --git a/packages/vite-plugin-svelte/src/utils/VitePluginSvelteCache.ts b/packages/vite-plugin-svelte/src/utils/VitePluginSvelteCache.ts index 7298b6ab4..c7145d0f4 100644 --- a/packages/vite-plugin-svelte/src/utils/VitePluginSvelteCache.ts +++ b/packages/vite-plugin-svelte/src/utils/VitePluginSvelteCache.ts @@ -1,37 +1,27 @@ import { SvelteRequest } from './id'; -import { CompileData } from './compile'; +import { Code, CompileData } from './compile'; export class VitePluginSvelteCache { - private _compile = new Map(); - private _compileSSR = new Map(); + private _css = new Map(); + private _js = new Map(); - private selectCache(ssr: boolean): Map { - return ssr ? this._compileSSR : this._compile; - } - - public getCompileData( - svelteRequest: SvelteRequest, - errorOnMissing = true - ): CompileData | undefined { - const cache = this.selectCache(svelteRequest.ssr); - const id = svelteRequest.normalizedFilename; - if (cache.has(id)) { - return cache.get(id)!; - } - if (errorOnMissing) { - throw new Error( - `${id} has no corresponding entry in the ${svelteRequest.ssr ? 'ssr' : ''}cache. ` + - `This is a @sveltejs/vite-plugin-svelte internal error, please open an issue.` - ); + public update(compileData: CompileData) { + const id = compileData.normalizedFilename; + this._css.set(id, compileData.compiled.css); + if (!compileData.ssr) { + // do not cache SSR js + this._js.set(id, compileData.compiled.js); } } - public setCompileData(compileData: CompileData) { - const cache = this.selectCache(!!compileData.ssr); - const id = compileData.normalizedFilename; - cache.set(id, compileData); + public getCSS(svelteRequest: SvelteRequest) { + return this._css.get(svelteRequest.normalizedFilename); } - // TODO accessors by id/url? - // TODO expose on plugin instance? + public getJS(svelteRequest: SvelteRequest) { + if (!svelteRequest.ssr) { + // SSR js isn't cached + return this._js.get(svelteRequest.normalizedFilename); + } + } } diff --git a/packages/vite-plugin-svelte/src/utils/compile.ts b/packages/vite-plugin-svelte/src/utils/compile.ts index da15b6455..3a7ee0265 100644 --- a/packages/vite-plugin-svelte/src/utils/compile.ts +++ b/packages/vite-plugin-svelte/src/utils/compile.ts @@ -1,4 +1,4 @@ -import { CompileOptions, PreprocessorGroup, Processed, ResolvedOptions } from './options'; +import { CompileOptions, PreprocessorGroup, ResolvedOptions } from './options'; import { compile, preprocess, walk } from 'svelte/compiler'; // @ts-ignore import { createMakeHot } from 'svelte-hmr'; @@ -74,20 +74,11 @@ const _createCompileSvelte = (makeHot: Function, extraPreprocessors: Preprocesso compiled.js.dependencies = dependencies; - // return everything that was created during preprocess/compile - const result = { - filename, + return { normalizedFilename, - cssId, - code, - preprocessed, compiled, - compilerOptions: finalCompilerOptions, - options, ssr }; - - return result; }; function buildMakeHot(options: ResolvedOptions) { @@ -142,13 +133,7 @@ export interface Compiled { } export interface CompileData { - filename: string; normalizedFilename: string; - cssId: string; - code: string; - preprocessed?: Processed; compiled: Compiled; - compilerOptions: CompileOptions; - options: Partial; ssr: boolean | undefined; } diff --git a/packages/vite-plugin-svelte/src/utils/options.ts b/packages/vite-plugin-svelte/src/utils/options.ts index b60280d42..29cdc03c2 100644 --- a/packages/vite-plugin-svelte/src/utils/options.ts +++ b/packages/vite-plugin-svelte/src/utils/options.ts @@ -11,7 +11,6 @@ const knownOptions = new Set([ 'compilerOptions', 'preprocess', 'hot', - 'disableTransformCache', 'disableCssHmr', 'useVitePreprocess' ]); @@ -300,12 +299,6 @@ export interface Options { */ disableCssHmr?: boolean; - /** - * do not return cached transform data - * @default false - */ - disableTransformCache?: boolean; - /** * use vite as extra css preprocessor EXPERIMENTAL! * @default false