From 4bde5f9f3ff04ce7f96e5de4a0da55c22b24948e Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Fri, 20 Dec 2024 23:05:32 +0100 Subject: [PATCH] :hammer: [#724] Support outputting UMD build of Open Forms SDK --- package.json | 1 + src/formio/components/Number.js | 2 +- src/formio/validators/plugins.js | 2 +- src/sdk.jsx | 6 +++ vite.config.mts | 78 +++++++++++++++++++++++++------- 5 files changed, 71 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 53c27769e..8b8a0b642 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "start": "npm run build:design-tokens && node scripts/start.js", "build": "node scripts/build.js && npm run build:esm", "build:esm": "rimraf dist/esm && NODE_ENV=production babel --no-babelrc --config-file ./.babelrc.esm-build --ignore 'src/**/*.spec.js','src/**/fixtures/**','src/setupTests.js','src/reportWebVitals.js' src --out-dir dist/esm", + "build:vite": "BUILD_TARGET=umd vite build && BUILD_TARGET=esm vite build", "test": "TZ=Europe/Amsterdam vitest", "test:storybook": "test-storybook --coverage", "clean": "rimraf dist/*", diff --git a/src/formio/components/Number.js b/src/formio/components/Number.js index 2c56b0638..abd697899 100644 --- a/src/formio/components/Number.js +++ b/src/formio/components/Number.js @@ -1,5 +1,5 @@ import {maskInput} from '@formio/vanilla-text-mask'; -import {set} from 'lodash'; +import set from 'lodash/set'; import {Formio} from 'react-formio'; import {setErrorAttributes} from '../utils'; diff --git a/src/formio/validators/plugins.js b/src/formio/validators/plugins.js index 966bb7118..979326b8b 100644 --- a/src/formio/validators/plugins.js +++ b/src/formio/validators/plugins.js @@ -1,4 +1,4 @@ -import {isEmpty} from 'lodash'; +import isEmpty from 'lodash/isEmpty'; import {post} from '../../api'; diff --git a/src/sdk.jsx b/src/sdk.jsx index c4503c95d..6433cc9a7 100644 --- a/src/sdk.jsx +++ b/src/sdk.jsx @@ -1,5 +1,6 @@ import ProtectedEval from '@formio/protected-eval'; import 'flatpickr'; +import lodash from 'lodash'; import {fixIconUrls as fixLeafletIconUrls} from 'map'; import React from 'react'; import {createRoot} from 'react-dom/client'; @@ -23,6 +24,11 @@ import OpenFormsModule from './formio/module'; import OFLibrary from './formio/templates'; import './styles.scss'; +// lodash must be bundled for Formio templates to work properly... +if (typeof window !== 'undefined') { + window._ = lodash; +} + // use protected eval to not rely on unsafe-eval (CSP) Formio.use(ProtectedEval); diff --git a/vite.config.mts b/vite.config.mts index c9fdf5400..c13eae22f 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,6 +1,7 @@ /// // https://vitejs.dev/config/ import react from '@vitejs/plugin-react'; +import type {OutputOptions} from 'rollup'; import {defineConfig} from 'vite'; import jsconfigPaths from 'vite-jsconfig-paths'; import {coverageConfigDefaults} from 'vitest/config'; @@ -8,6 +9,62 @@ import {coverageConfigDefaults} from 'vitest/config'; import {cjsTokens, ejsPlugin} from './build/plugins.mjs'; import {packageRegexes} from './build/utils.mjs'; +// type definition for our custom envvars +declare global { + namespace NodeJS { + interface ProcessEnv { + BUILD_TARGET: 'umd' | 'esm'; + } + } +} + +const buildTarget = process.env.BUILD_TARGET || 'umd'; + +/** + * Rollup output options for ESM build, which is what we package in the NPM package + * under the 'esm' subdirectory. + * + * The ESM package is experimental. Known issues: + * @fixme + * + * - the react-intl translations are not distributed yet (also broken in CRA/babel build!) + */ +const esmOutput = { + dir: 'dist-vite/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; + +/** + * Rollup output options for UMD bundle, included in the NPM package but + * the primary distribution mechanism is in a Docker image. + * + * @todo - optimize with bundle splitting/chunk management. + */ +const umdOutput = { + dir: 'dist-vite', + 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; + export default defineConfig({ base: './', publicDir: false, @@ -24,26 +81,15 @@ export default defineConfig({ ], build: { target: 'modules', // the default - outDir: 'dist-vite', assetsInlineLimit: 8 * 1024, // 8 KiB cssCodeSplit: false, + sourcemap: buildTarget !== 'esm', + outDir: 'dist-vite/umd', rollupOptions: { input: 'src/sdk.jsx', - external: packageRegexes, - output: { - dir: 'dist-vite/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]'; - }, - sourcemap: false, - }, + // do not externalize anything in UMD build - bundle everything + external: buildTarget === 'esm' ? packageRegexes : undefined, + output: buildTarget === 'esm' ? esmOutput : umdOutput, preserveEntrySignatures: 'strict', }, },