Skip to content

Commit

Permalink
Merge pull request #796 from open-formulieren/fix/vite-build-dir-base…
Browse files Browse the repository at this point in the history
…d-on-build-version

Define the assets directory for a build using the SDK_VERSION env variable
  • Loading branch information
robinmolen authored Feb 20, 2025
2 parents 5e94e35 + e4b3a57 commit ba5fd41
Showing 1 changed file with 187 additions and 173 deletions.
360 changes: 187 additions & 173 deletions vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -35,204 +35,218 @@ 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
* the primary distribution mechanism is in a Docker image.
*
* @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'],
},
},
},
}));
};
});

0 comments on commit ba5fd41

Please sign in to comment.