Skip to content

Commit

Permalink
Merge pull request #760 from open-formulieren/chore/npm-package-to-vite
Browse files Browse the repository at this point in the history
Configure Vite to build the SDK
  • Loading branch information
sergei-maertens authored Dec 30, 2024
2 parents e473e32 + d179ef5 commit 0e16b0a
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

# production
/storybook-static
/build
/dist
/dist-vite
/lib
/esm
*.tgz
Expand Down
35 changes: 35 additions & 0 deletions build/plugins.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import lodashTemplate from 'lodash/template';

// inspired on https://dev.to/koistya/using-ejs-with-vite-48id and
// https://github.com/difelice/ejs-loader/blob/master/index.js
export const ejsPlugin = () => ({
name: 'compile-ejs',
async transform(src: string, id: string) {
const options = {
variable: 'ctx',
evaluate: /\{%([\s\S]+?)%\}/g,
interpolate: /\{\{([\s\S]+?)\}\}/g,
escape: /\{\{\{([\s\S]+?)\}\}\}/g,
};
if (id.endsWith('.ejs')) {
// @ts-ignore
const code = lodashTemplate(src, options);
return {code: `export default ${code}`, map: null};
}
},
});

export const cjsTokens = () => ({
name: 'process-cjs-tokens',
async transform(src, id) {
if (
id.endsWith('/design-tokens/dist/tokens.js') ||
id.endsWith('node_modules/@utrecht/design-tokens/dist/tokens.cjs')
) {
return {
code: src.replace('module.exports = ', 'export default '),
map: null,
};
}
},
});
15 changes: 15 additions & 0 deletions build/utils.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {dependencies, peerDependencies} from '../package.json';

const externalPackages = [
...Object.keys(dependencies || {}),
...Object.keys(peerDependencies || {}),
'formiojs',
'lodash',
'@formio/vanilla-text-mask',
'@babel/runtime',
'@utrecht/component-library-react',
];

// Creating regexes of the packages to make sure subpaths of the
// packages are also treated as external
export const packageRegexes = externalPackages.map(packageName => new RegExp(`^${packageName}(/.*)?`));
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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/*",
Expand Down
2 changes: 1 addition & 1 deletion src/formio/components/Number.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
2 changes: 1 addition & 1 deletion src/formio/validators/plugins.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {isEmpty} from 'lodash';
import isEmpty from 'lodash/isEmpty';

import {post} from '../../api';

Expand Down
6 changes: 6 additions & 0 deletions src/sdk.jsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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);

Expand Down
97 changes: 68 additions & 29 deletions vite.config.mts
Original file line number Diff line number Diff line change
@@ -1,44 +1,69 @@
/// <reference types="vitest/config" />
// https://vitejs.dev/config/
import react from '@vitejs/plugin-react';
import lodashTemplate from 'lodash/template';
import type {OutputOptions} from 'rollup';
import {defineConfig} from 'vite';
import jsconfigPaths from 'vite-jsconfig-paths';
import {coverageConfigDefaults} from 'vitest/config';

// inspired on https://dev.to/koistya/using-ejs-with-vite-48id and
// https://github.com/difelice/ejs-loader/blob/master/index.js
const ejsPlugin = () => ({
name: 'compile-ejs',
async transform(src: string, id: string) {
const options = {
variable: 'ctx',
evaluate: /\{%([\s\S]+?)%\}/g,
interpolate: /\{\{([\s\S]+?)\}\}/g,
escape: /\{\{\{([\s\S]+?)\}\}\}/g,
};
if (id.endsWith('.ejs')) {
// @ts-ignore
const code = lodashTemplate(src, options);
return {code: `export default ${code}`, map: null};
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;

const cjsTokens = () => ({
name: 'process-cjs-tokens',
async transform(src, id) {
if (
id.endsWith('/design-tokens/dist/tokens.js') ||
id.endsWith('node_modules/@utrecht/design-tokens/dist/tokens.cjs')
) {
return {
code: src.replace('module.exports = ', 'export default '),
map: null,
};
/**
* 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: './',
Expand All @@ -54,6 +79,20 @@ export default defineConfig({
cjsTokens(),
ejsPlugin(),
],
build: {
target: 'modules', // the default
assetsInlineLimit: 8 * 1024, // 8 KiB
cssCodeSplit: false,
sourcemap: buildTarget !== 'esm',
outDir: 'dist-vite/umd',
rollupOptions: {
input: 'src/sdk.jsx',
// do not externalize anything in UMD build - bundle everything
external: buildTarget === 'esm' ? packageRegexes : undefined,
output: buildTarget === 'esm' ? esmOutput : umdOutput,
preserveEntrySignatures: 'strict',
},
},
css: {
preprocessorOptions: {
scss: {
Expand Down

0 comments on commit 0e16b0a

Please sign in to comment.