From 1e0a50861efa780b3c7f27a0e869fe52b108afdb Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Fri, 24 Jan 2025 14:55:50 +0400 Subject: [PATCH] refactor: use Vite official API for building sw.js (#20894) * fix: fix service worker build * fix PwaTestIT * exclude sw.js from manifest * generate service worker at closeBundle stage * clean up service worker build config * generate service worker at different stages depending on mode * do not use lib mode to allow for minification in es format * clean up plugin code * add inlineDynamicImports: true option * revert some changes to minimize diff * add exports option for backward compatibility --------- Co-authored-by: Teppo Kurki --- .../src/main/resources/vite.generated.ts | 111 ++++++------------ .../com/vaadin/flow/pwatest/ui/PwaTestIT.java | 2 +- 2 files changed, 40 insertions(+), 73 deletions(-) diff --git a/flow-server/src/main/resources/vite.generated.ts b/flow-server/src/main/resources/vite.generated.ts index fc9d52f095e..de3b69c6ac1 100644 --- a/flow-server/src/main/resources/vite.generated.ts +++ b/flow-server/src/main/resources/vite.generated.ts @@ -16,18 +16,18 @@ import settings from '#settingsImport#'; import { AssetInfo, ChunkInfo, + build, defineConfig, mergeConfig, OutputOptions, PluginOption, - ResolvedConfig, + InlineConfig, UserConfigFn } from 'vite'; import { getManifest, type ManifestTransform } from 'workbox-build'; import * as rollup from 'rollup'; import brotli from 'rollup-plugin-brotli'; -import replace from '@rollup/plugin-replace'; import checker from 'vite-plugin-checker'; import postcssLit from '#buildFolder#/plugins/rollup-plugin-postcss-lit-custom/rollup-plugin-postcss-lit.js'; @@ -106,7 +106,7 @@ function injectManifestToSWPlugin(): rollup.Plugin { const { manifestEntries } = await getManifest({ globDirectory: buildOutputFolder, globPatterns: ['**/*'], - globIgnores: ['**/*.br'], + globIgnores: ['**/*.br', 'pwa-icons/**', 'sw.js'], manifestTransforms: [rewriteManifestIndexHtmlUrl], maximumFileSizeToCacheInBytes: 100 * 1024 * 1024 // 100mb, }); @@ -118,87 +118,54 @@ function injectManifestToSWPlugin(): rollup.Plugin { } function buildSWPlugin(opts: { devMode: boolean }): PluginOption { - let config: ResolvedConfig; + let buildConfig: InlineConfig; const devMode = opts.devMode; - const swObj: { code?: string, map?: rollup.SourceMap | null } = {}; - - async function build(action: 'generate' | 'write', additionalPlugins: rollup.Plugin[] = []) { - const includedPluginNames = [ - 'vite:esbuild', - 'rollup-plugin-dynamic-import-variables', - 'vite:esbuild-transpile', - 'vite:terser' - ]; - const plugins: rollup.Plugin[] = config.plugins.filter((p) => { - return includedPluginNames.includes(p.name); - }); - const resolver = config.createResolver(); - const resolvePlugin: rollup.Plugin = { - name: 'resolver', - resolveId(source, importer, _options) { - return resolver(source, importer); - } - }; - plugins.unshift(resolvePlugin); // Put resolve first - plugins.push( - replace({ - values: { - 'process.env.NODE_ENV': JSON.stringify(config.mode), - ...config.define - }, - preventAssignment: true - }) - ); - if (additionalPlugins) { - plugins.push(...additionalPlugins); - } - const bundle = await rollup.rollup({ - input: path.resolve(settings.clientServiceWorkerSource), - plugins - }); - - try { - return await bundle[action]({ - file: path.resolve(buildOutputFolder, 'sw.js'), - format: 'es', - exports: 'none', - sourcemap: config.command === 'serve' || config.build.sourcemap, - inlineDynamicImports: true - }); - } finally { - await bundle.close(); - } - } - return { name: 'vaadin:build-sw', enforce: 'post', - async configResolved(resolvedConfig) { - config = resolvedConfig; + async configResolved(viteConfig) { + buildConfig = { + base: viteConfig.base, + root: viteConfig.root, + mode: viteConfig.mode, + resolve: viteConfig.resolve, + define: { + ...viteConfig.define, + 'process.env.NODE_ENV': JSON.stringify(viteConfig.mode), + }, + build: { + minify: viteConfig.build.minify, + outDir: viteConfig.build.outDir, + sourcemap: viteConfig.command === 'serve' || viteConfig.build.sourcemap, + emptyOutDir: false, + modulePreload: false, + rollupOptions: { + input: { + sw: settings.clientServiceWorkerSource + }, + output: { + exports: 'none', + entryFileNames: 'sw.js', + inlineDynamicImports: true, + }, + }, + }, + }; }, async buildStart() { if (devMode) { - const { output } = await build('generate'); - swObj.code = output[0].code; - swObj.map = output[0].map; - } - }, - async load(id) { - if (id.endsWith('sw.js')) { - return ''; - } - }, - async transform(_code, id) { - if (id.endsWith('sw.js')) { - return swObj; + await build(buildConfig); } }, async closeBundle() { if (!devMode) { - await build('write', [injectManifestToSWPlugin(), brotli()]); + await build({ + ...buildConfig, + plugins: [injectManifestToSWPlugin(), brotli()] + }); } - } + }, }; } @@ -299,7 +266,7 @@ function statsExtracterPlugin(): PluginOption { const frontendFiles: Record = {}; frontendFiles['index.html'] = createHash('sha256').update(customIndexData.replace(/\r\n/g, '\n'), 'utf8').digest('hex'); - const projectFileExtensions = ['.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map']; + const projectFileExtensions = ['.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map'#frontendExtraFileExtensions#]; const isThemeComponentsResource = (id: string) => id.startsWith(themeOptions.frontendGeneratedFolder.replace(/\\/g, '/')) diff --git a/flow-tests/test-pwa/src/test/java/com/vaadin/flow/pwatest/ui/PwaTestIT.java b/flow-tests/test-pwa/src/test/java/com/vaadin/flow/pwatest/ui/PwaTestIT.java index af6eba7a3b0..010f2433a4a 100644 --- a/flow-tests/test-pwa/src/test/java/com/vaadin/flow/pwatest/ui/PwaTestIT.java +++ b/flow-tests/test-pwa/src/test/java/com/vaadin/flow/pwatest/ui/PwaTestIT.java @@ -129,7 +129,7 @@ public void testPwaResources() throws IOException { Assert.assertTrue( "Expected sw-runtime-resources-precache.js to be imported, but was not", serviceWorkerJS.contains( - "importScripts(\"sw-runtime-resources-precache.js\");")); + "importScripts(\"sw-runtime-resources-precache.js\")")); serviceWorkerUrl = getRootURL() + "/sw-runtime-resources-precache.js"; serviceWorkerJS = readStringFromUrl(serviceWorkerUrl);