From 3572fa9657b8f44873caf341d126fb563e69b09e Mon Sep 17 00:00:00 2001 From: Lukas Spirig Date: Tue, 7 May 2024 11:41:30 +0200 Subject: [PATCH] feat: add root entry point with global component registration (#2641) This feature allows using `import '@sbb-esta/lyne-components'`, which will import all components and add them to `globalThis`, but will not provide an export. This is useful for SSR or for providing examples/reproductions and wanting to load all components. --- src/components/vite.config.ts | 8 ++++- tools/vite/generate-root-entry-point.ts | 47 +++++++++++++++++++++++++ tools/vite/index.ts | 1 + 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tools/vite/generate-root-entry-point.ts diff --git a/src/components/vite.config.ts b/src/components/vite.config.ts index fed7f32e60..9bf5a7038a 100644 --- a/src/components/vite.config.ts +++ b/src/components/vite.config.ts @@ -13,6 +13,7 @@ import { packageJsonTemplate, typography, verifyEntryPoints, + generateRootEntryPoint, } from '../../tools/vite/index.js'; import rootConfig from '../../vite.config.js'; @@ -39,9 +40,14 @@ export default defineConfig((config) => ...(isProdBuild(config) ? [ customElementsManifest(), + generateRootEntryPoint(), packageJsonTemplate({ exports: { - '.': { sass: './_index.scss' }, + '.': { + types: './index.d.ts', + sass: './_index.scss', + default: './index.js', + }, ...buildStyleExports([ 'a11y.css', 'animation.css', diff --git a/tools/vite/generate-root-entry-point.ts b/tools/vite/generate-root-entry-point.ts new file mode 100644 index 0000000000..6d35ca49e0 --- /dev/null +++ b/tools/vite/generate-root-entry-point.ts @@ -0,0 +1,47 @@ +import type { LibraryOptions, PluginOption, ResolvedConfig } from 'vite'; + +export function generateRootEntryPoint(): PluginOption { + let viteConfig: ResolvedConfig; + return { + name: 'package-json-templating', + configResolved(config) { + viteConfig = config; + }, + async generateBundle() { + if (viteConfig.command !== 'build') { + return; + } + const entry = (viteConfig.build.lib as LibraryOptions).entry as Record; + const classNameMap: Record = { + SbbOptgroupElement: 'SbbOptGroupElement', + }; + const toElementName = (key: string): string => { + const className = `sbb-${key.split('/').reverse()[0]}-element`.replace(/(^\w|-\w)/g, (m) => + m.replace(/-/, '').toUpperCase(), + ); + return classNameMap[className] ?? className; + }; + const keys = Object.keys(entry) + .filter( + (e, _, a) => + a.every((iv) => !iv.startsWith(e + '/')) && + !e.startsWith('core/') && + !e.endsWith('/common'), + ) + .sort() + .map((e) => ({ path: `./${e}.js`, symbol: toElementName(e) })) + .filter((v, i, a) => a.findIndex((iv) => iv.symbol === v.symbol) === i); + const imports = keys.map((e) => `import { ${e.symbol} } from "${e.path}";\n`).join(''); + this.emitFile({ + type: 'asset', + fileName: 'index.js', + source: `${imports}\n${keys.map((e) => `globalThis.${e.symbol} = ${e.symbol};\n`).join('')}\nexport {}\n`, + }); + this.emitFile({ + type: 'asset', + fileName: 'index.d.ts', + source: `${imports}\ndeclare global {\n${keys.map((e) => ` var ${e.symbol}: ${e.symbol};\n`).join('')}}\n\nexport {}\n`, + }); + }, + }; +} diff --git a/tools/vite/index.ts b/tools/vite/index.ts index 80d7a31801..2a0a808b44 100644 --- a/tools/vite/index.ts +++ b/tools/vite/index.ts @@ -4,6 +4,7 @@ export * from './copy-sass.js'; export * from './custom-elements-manifest.js'; export * from './dts.js'; export * from './generate-react-wrappers.js'; +export * from './generate-root-entry-point.js'; export * from './package-json-template.js'; export * from './resolve-entry-points.js'; export * from './typography.js';