From e4b3a57cd83a8fecf56e496e854499514a1fb887 Mon Sep 17 00:00:00 2001 From: robinvandermolen Date: Wed, 19 Feb 2025 18:05:51 +0100 Subject: [PATCH] :bug: Define vite build dir based on build version For release builds we want to the assets to be placed in `/dist/[release number]`. This logic was present in the previous build setup, with CRA. In the re-structure of the SDK project, #724, the build process of CRA was replaced with vite. But this logic rule was lost in the process --- vite.config.mts | 360 +++++++++++++++++++++++++----------------------- 1 file changed, 187 insertions(+), 173 deletions(-) diff --git a/vite.config.mts b/vite.config.mts index 78079e3fc..6d6294a6a 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -6,7 +6,7 @@ import {sentryVitePlugin} from '@sentry/vite-plugin'; import react from '@vitejs/plugin-react'; import path from 'path'; import type {OutputOptions} from 'rollup'; -import {defineConfig} from 'vite'; +import {defineConfig, loadEnv} from 'vite'; import jsconfigPaths from 'vite-jsconfig-paths'; import eslint from 'vite-plugin-eslint2'; import {coverageConfigDefaults} from 'vitest/config'; @@ -35,33 +35,35 @@ const buildTargetDefined = process.env.BUILD_TARGET !== undefined; * * - the react-intl translations are not distributed yet (also broken in CRA/babel build!) */ -const esmOutput = { - dir: 'dist/esm', - format: 'esm', - preserveModules: true, - preserveModulesRoot: 'src', - entryFileNames: '[name].js', - assetFileNames: ({name}) => { - if (name?.endsWith('.css')) { - return '[name].[ext]'; - } - return 'static/media/[name].[hash:8].[ext]'; - }, -} satisfies OutputOptions; +const esmOutput = (buildDist: string) => + ({ + dir: `${buildDist}/esm`, + format: 'esm', + preserveModules: true, + preserveModulesRoot: 'src', + entryFileNames: '[name].js', + assetFileNames: ({name}) => { + if (name?.endsWith('.css')) { + return '[name].[ext]'; + } + return 'static/media/[name].[hash:8].[ext]'; + }, + }) satisfies OutputOptions; -const esmBundleOutput = { - dir: 'dist', - format: 'esm', - preserveModules: false, - entryFileNames: 'open-forms-sdk.mjs', - assetFileNames: ({name}) => { - if (name === 'style.css') { - return 'open-forms-sdk.css'; - } - return 'static/media/[name].[hash:8].[ext]'; - }, - inlineDynamicImports: false, -} satisfies OutputOptions; +const esmBundleOutput = (buildDist: string) => + ({ + dir: buildDist, + format: 'esm', + preserveModules: false, + entryFileNames: 'open-forms-sdk.mjs', + assetFileNames: ({name}) => { + if (name === 'style.css') { + return 'open-forms-sdk.css'; + } + return 'static/media/[name].[hash:8].[ext]'; + }, + inlineDynamicImports: false, + }) satisfies OutputOptions; /** * Rollup output options for UMD bundle, included in the NPM package but @@ -69,170 +71,182 @@ const esmBundleOutput = { * * @deprecated - it's better to use the ESM bundle which has separate chunks. */ -const umdOutput = { - dir: 'dist', - format: 'umd', - exports: 'named', - name: 'OpenForms', - generatedCode: 'es2015', - entryFileNames: 'open-forms-sdk.js', - assetFileNames: ({name}) => { - if (name === 'style.css') { - return 'open-forms-sdk.css'; - } - return 'static/media/[name].[hash:8].[ext]'; - }, - inlineDynamicImports: true, -} satisfies OutputOptions; +const umdOutput = (buildDist: string) => + ({ + dir: buildDist, + format: 'umd', + exports: 'named', + name: 'OpenForms', + generatedCode: 'es2015', + entryFileNames: 'open-forms-sdk.js', + assetFileNames: ({name}) => { + if (name === 'style.css') { + return 'open-forms-sdk.css'; + } + return 'static/media/[name].[hash:8].[ext]'; + }, + inlineDynamicImports: true, + }) satisfies OutputOptions; -const getOutput = (buildTarget: typeof process.env.BUILD_TARGET): OutputOptions => { +const getOutput = ( + buildTarget: typeof process.env.BUILD_TARGET, + buildDist: string +): OutputOptions => { switch (buildTarget) { case 'esm-bundle': { - return esmBundleOutput; + return esmBundleOutput(buildDist); } case 'esm': { - return esmOutput; + return esmOutput(buildDist); } case 'umd': default: { - return umdOutput; + return umdOutput(buildDist); } } }; -export default defineConfig(({mode}) => ({ - base: './', - publicDir: false, - server: { - port: 3000, - }, - plugins: [ - // BIG DISCLAIMER - Vite only processes files with the .jsx or .tsx extension with - // babel, and changing this configuration is... cumbersome and comes with a performance - // penalty. This manifests if you're using react-intl in .js/.mjs/.ts files etc., as - // they don't get transformed to inject the message ID. The solution is to rename the - // file extension to .jsx/.tsx - react({babel: {babelrc: true}}), - jsconfigPaths(), - eslint({ - build: true, - emitErrorAsWarning: mode === 'development', - }), - cjsTokens(), - ejsPlugin(), - // @formio/protected-eval requires js-interpeter (a forked version), which includes - // this['Interpreter'] = Interpreter. When this is bundled, it becomes a strict module - // and 'this' doesn't point to the window object, but is undefined, and causes the SDK - // to crash. - replace({ - preventAssignment: false, - include: ['**/node_modules/js-interpreter/interpreter.js'], - delimiters: ['', ''], - values: { - "this\['Interpreter'\]": "window['Interpreter']", - }, - }), - /** - * Plugin to ignore (S)CSS when bundling to UMD bundle target, since we use the ESM - * bundle to generate these. - * - * @todo Remove this when we drop the UMD bundle entirely (in 4.0?) - */ - { - name: 'ignore-styles-esm-bundle', - transform(code, id) { - if (!buildTargetDefined) return; - if (buildTarget === 'umd' && (id.endsWith('.css') || id.endsWith('scss'))) { - // skip processing - return {code: '', map: null}; - } - }, +export default defineConfig(({mode}) => { + const env = loadEnv(mode, process.cwd(), ''); + let buildDist = 'dist'; + if (env.SDK_VERSION && env.SDK_VERSION !== 'latest') { + buildDist = `${buildDist}/${env.SDK_VERSION}`; + } + + return { + base: './', + publicDir: false, + server: { + port: 3000, }, - sentryVitePlugin({ - silent: mode === 'development', - release: { - create: false, - inject: false, + plugins: [ + // BIG DISCLAIMER - Vite only processes files with the .jsx or .tsx extension with + // babel, and changing this configuration is... cumbersome and comes with a performance + // penalty. This manifests if you're using react-intl in .js/.mjs/.ts files etc., as + // they don't get transformed to inject the message ID. The solution is to rename the + // file extension to .jsx/.tsx + react({babel: {babelrc: true}}), + jsconfigPaths(), + eslint({ + build: true, + emitErrorAsWarning: mode === 'development', + }), + cjsTokens(), + ejsPlugin(), + // @formio/protected-eval requires js-interpeter (a forked version), which includes + // this['Interpreter'] = Interpreter. When this is bundled, it becomes a strict module + // and 'this' doesn't point to the window object, but is undefined, and causes the SDK + // to crash. + replace({ + preventAssignment: false, + include: ['**/node_modules/js-interpreter/interpreter.js'], + delimiters: ['', ''], + values: { + "this\['Interpreter'\]": "window['Interpreter']", + }, + }), + /** + * Plugin to ignore (S)CSS when bundling to UMD bundle target, since we use the ESM + * bundle to generate these. + * + * @todo Remove this when we drop the UMD bundle entirely (in 4.0?) + */ + { + name: 'ignore-styles-esm-bundle', + transform(code, id) { + if (!buildTargetDefined) return; + if (buildTarget === 'umd' && (id.endsWith('.css') || id.endsWith('scss'))) { + // skip processing + return {code: '', map: null}; + } + }, }, - sourcemaps: { - disable: true, + sentryVitePlugin({ + silent: mode === 'development', + release: { + create: false, + inject: false, + }, + sourcemaps: { + disable: true, + }, + bundleSizeOptimizations: { + excludeDebugStatements: true, + excludeTracing: true, + excludeReplayCanvas: true, + excludeReplayShadowDom: true, + excludeReplayIframe: true, + excludeReplayWorker: true, + }, + telemetry: false, + }), + // must be last! + codecovVitePlugin({ + enableBundleAnalysis: buildTarget !== 'esm' && process.env.CODECOV_TOKEN !== undefined, + bundleName: '@open-formulieren/sdk', + uploadToken: process.env.CODECOV_TOKEN, + }), + ], + resolve: { + alias: { + // ensure react-router imports don't end up with multiple copies/installations. See + // https://github.com/remix-run/react-router/issues/12785 for more context. + 'react-router/dom': path.resolve( + './node_modules/react-router/dist/development/dom-export.mjs' + ), + 'react-router': path.resolve('./node_modules/react-router/dist/development/index.mjs'), }, - bundleSizeOptimizations: { - excludeDebugStatements: true, - excludeTracing: true, - excludeReplayCanvas: true, - excludeReplayShadowDom: true, - excludeReplayIframe: true, - excludeReplayWorker: true, - }, - telemetry: false, - }), - // must be last! - codecovVitePlugin({ - enableBundleAnalysis: buildTarget !== 'esm' && process.env.CODECOV_TOKEN !== undefined, - bundleName: '@open-formulieren/sdk', - uploadToken: process.env.CODECOV_TOKEN, - }), - ], - resolve: { - alias: { - // ensure react-router imports don't end up with multiple copies/installations. See - // https://github.com/remix-run/react-router/issues/12785 for more context. - 'react-router/dom': path.resolve( - './node_modules/react-router/dist/development/dom-export.mjs' - ), - 'react-router': path.resolve('./node_modules/react-router/dist/development/index.mjs'), - }, - }, - build: { - target: 'modules', // the default - assetsInlineLimit: 8 * 1024, // 8 KiB - cssCodeSplit: false, - sourcemap: buildTarget !== 'esm', - outDir: 'dist', - // we write the .mjs file to the same directory - emptyOutDir: buildTarget !== 'esm-bundle', - rollupOptions: { - input: 'src/sdk.jsx', - // do not externalize anything in UMD build - bundle everything - external: buildTarget === 'esm' ? packageRegexes : undefined, - output: getOutput(buildTarget), - preserveEntrySignatures: 'strict', }, - }, - css: { - preprocessorOptions: { - scss: { - additionalData: `$fa-font-path: '@fortawesome/fontawesome-free/webfonts/';`, - charset: false, + build: { + target: 'modules', // the default + assetsInlineLimit: 8 * 1024, // 8 KiB + cssCodeSplit: false, + sourcemap: buildTarget !== 'esm', + outDir: buildDist, + // we write the .mjs file to the same directory + emptyOutDir: buildTarget !== 'esm-bundle', + rollupOptions: { + input: 'src/sdk.jsx', + // do not externalize anything in UMD build - bundle everything + external: buildTarget === 'esm' ? packageRegexes : undefined, + output: getOutput(buildTarget, buildDist), + preserveEntrySignatures: 'strict', }, }, - }, - test: { - environment: 'jsdom', - environmentOptions: { - jsdom: { - url: 'http://localhost', + css: { + preprocessorOptions: { + scss: { + additionalData: `$fa-font-path: '@fortawesome/fontawesome-free/webfonts/';`, + charset: false, + }, }, }, - globals: true, // for compatibility with jest - // See https://vitest.dev/guide/migration.html#fake-timers-defaults - fakeTimers: { - toFake: ['setTimeout', 'clearTimeout', 'Date'], - }, - setupFiles: ['./src/vitest.setup.mjs'], - coverage: { - provider: 'istanbul', - include: ['src/**/*.{js,jsx,ts,tsx}'], - exclude: [ - 'src/**/*.d.ts', - 'src/**/*.stories.{js,jsx,ts,tsx}', - 'src/api-mocks/*', - 'src/**/mocks.{js,jsx}', - 'src/story-utils/*', - ...coverageConfigDefaults.exclude, - ], - reporter: ['text', 'cobertura', 'html'], + test: { + environment: 'jsdom', + environmentOptions: { + jsdom: { + url: 'http://localhost', + }, + }, + globals: true, // for compatibility with jest + // See https://vitest.dev/guide/migration.html#fake-timers-defaults + fakeTimers: { + toFake: ['setTimeout', 'clearTimeout', 'Date'], + }, + setupFiles: ['./src/vitest.setup.mjs'], + coverage: { + provider: 'istanbul', + include: ['src/**/*.{js,jsx,ts,tsx}'], + exclude: [ + 'src/**/*.d.ts', + 'src/**/*.stories.{js,jsx,ts,tsx}', + 'src/api-mocks/*', + 'src/**/mocks.{js,jsx}', + 'src/story-utils/*', + ...coverageConfigDefaults.exclude, + ], + reporter: ['text', 'cobertura', 'html'], + }, }, - }, -})); + }; +});