From fb006b643da0c63381d6a7c270b4845535ff4967 Mon Sep 17 00:00:00 2001 From: Ahmed Yasin Koculu Date: Thu, 15 Oct 2026 10:04:52 +0200 Subject: [PATCH] Update ts-svg-icons to be tree-shake friendly. --- package.json | 2 +- packages/purestack/package.json | 2 +- packages/purestack/src/index.ts | 2 +- packages/ts-common/package.json | 2 +- packages/ts-components/package.json | 2 +- packages/ts-css/package.json | 2 +- packages/ts-html/package.json | 2 +- packages/ts-minidom/package.json | 2 +- packages/ts-page-scripts/package.json | 2 +- packages/ts-render/package.json | 2 +- packages/ts-ssg-vscode/package.json | 2 +- packages/ts-ssg/package.json | 2 +- packages/ts-ssg/src/build/svg-icons.test.ts | 85 +++ packages/ts-ssg/src/config/head.ts | 2 +- packages/ts-style/package.json | 2 +- packages/ts-svg-icons/package.json | 2 +- packages/ts-svg-icons/src/getSvgIcon.ts | 13 +- .../src/lucide.client.chunk-0.generated.ts | 696 +++++++++--------- .../src/lucide.client.chunk-1.generated.ts | 608 +++++++++++++-- packages/ts-svg-icons/src/lucide.generated.ts | 378 +++++++--- packages/ts-util-node/package.json | 2 +- packages/ts-util/package.json | 2 +- scripts/generate-icons.ts | 25 +- 23 files changed, 1275 insertions(+), 564 deletions(-) create mode 100644 packages/ts-ssg/src/build/svg-icons.test.ts diff --git a/package.json b/package.json index fca42b5f..b2bf01ab 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "purestack-repo", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.18.1", "type": "module", "sideEffects": false, diff --git a/packages/purestack/package.json b/packages/purestack/package.json index e8b57f31..78ccbf64 100644 --- a/packages/purestack/package.json +++ b/packages/purestack/package.json @@ -1,6 +1,6 @@ { "name": "purestack", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/purestack.mjs", "types": "./dist/purestack.d.mts", diff --git a/packages/purestack/src/index.ts b/packages/purestack/src/index.ts index 95b17239..8af10807 100644 --- a/packages/purestack/src/index.ts +++ b/packages/purestack/src/index.ts @@ -1,3 +1,3 @@ -export const version: string = '1.1.11' +export const version: string = '1.1.12' export * from '@purestack/ts-ssg' diff --git a/packages/ts-common/package.json b/packages/ts-common/package.json index 735f0a28..5ef74f17 100644 --- a/packages/ts-common/package.json +++ b/packages/ts-common/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-common", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-common.mjs", "types": "./dist/ts-common.d.mts", diff --git a/packages/ts-components/package.json b/packages/ts-components/package.json index 929b9d85..20d666fb 100644 --- a/packages/ts-components/package.json +++ b/packages/ts-components/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-components", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-components.mjs", "types": "./dist/ts-components.d.mts", diff --git a/packages/ts-css/package.json b/packages/ts-css/package.json index 3d175537..d6521296 100644 --- a/packages/ts-css/package.json +++ b/packages/ts-css/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-css", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-css.mjs", "types": "./dist/ts-css.d.mts", diff --git a/packages/ts-html/package.json b/packages/ts-html/package.json index e52f2738..e41209f2 100644 --- a/packages/ts-html/package.json +++ b/packages/ts-html/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-html", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-html.mjs", "types": "./dist/ts-html.d.mts", diff --git a/packages/ts-minidom/package.json b/packages/ts-minidom/package.json index ae454416..981ccc3b 100644 --- a/packages/ts-minidom/package.json +++ b/packages/ts-minidom/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-minidom", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-minidom.mjs", "types": "./dist/ts-minidom.d.mts", diff --git a/packages/ts-page-scripts/package.json b/packages/ts-page-scripts/package.json index 595583e0..107a8b2a 100644 --- a/packages/ts-page-scripts/package.json +++ b/packages/ts-page-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-page-scripts", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-page-scripts.mjs", "types": "./dist/ts-page-scripts.d.mts", diff --git a/packages/ts-render/package.json b/packages/ts-render/package.json index 6ad827e0..ee8d4351 100644 --- a/packages/ts-render/package.json +++ b/packages/ts-render/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-render", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-render.mjs", "types": "./dist/ts-render.d.mts", diff --git a/packages/ts-ssg-vscode/package.json b/packages/ts-ssg-vscode/package.json index d6649a40..0304eb4a 100644 --- a/packages/ts-ssg-vscode/package.json +++ b/packages/ts-ssg-vscode/package.json @@ -2,7 +2,7 @@ "name": "purestack-component-navigation", "displayName": "PureStack Component Tools", "description": "Component navigation, prop IntelliSense, lit-html syntax highlighting, and template formatting for Markdown, Regor MDX, and TypeScript templates.", - "version": "1.1.11", + "version": "1.1.12", "private": true, "publisher": "purestack", "license": "MIT", diff --git a/packages/ts-ssg/package.json b/packages/ts-ssg/package.json index c21dd3e4..9fd7bb58 100644 --- a/packages/ts-ssg/package.json +++ b/packages/ts-ssg/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-ssg", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-ssg.mjs", "types": "./dist/ts-ssg.d.mts", diff --git a/packages/ts-ssg/src/build/svg-icons.test.ts b/packages/ts-ssg/src/build/svg-icons.test.ts new file mode 100644 index 00000000..c425c58f --- /dev/null +++ b/packages/ts-ssg/src/build/svg-icons.test.ts @@ -0,0 +1,85 @@ +import { fileURLToPath } from 'node:url' +import { build } from 'esbuild' +import { describe, expect, it } from 'vitest' +import { + getSvgIcon, + iconoir_cube, + lucide_chevron_down, + phosphor_acorn, + tabler_world, +} from '../../../ts-svg-icons/src/index' + +describe('SVG icon exports', () => { + it('resolves server lookup names to the direct export for each provider', () => { + expect(getSvgIcon('iconoir:cube')).toBe(iconoir_cube) + expect(getSvgIcon('lucide:chevron-down')).toBe(lucide_chevron_down) + expect(getSvgIcon('phosphor:acorn')).toBe(phosphor_acorn) + expect(getSvgIcon('tabler:world')).toBe(tabler_world) + }) + + it('passes inline SVG through unchanged', () => { + expect(getSvgIcon(tabler_world)).toBe(tabler_world) + }) + + it('reports unknown icon names', () => { + expect(() => getSvgIcon('missing:icon')).toThrow( + 'Unknown icon: missing:icon', + ) + }) + + it('tree-shakes named imports after the package exports are bundled together', async () => { + // Reproduce a package build followed by a browser build. The catalog lookup + // remains exported in the first stage, but must disappear in the second. + const published = await build({ + entryPoints: [ + fileURLToPath( + new URL('../../../ts-svg-icons/src/index.ts', import.meta.url), + ), + ], + bundle: true, + format: 'esm', + platform: 'node', + treeShaking: true, + write: false, + }) + const browser = await build({ + stdin: { + contents: `import { iconoir_cube, lucide_chevron_down, phosphor_acorn, tabler_world } from 'published-icons'; +export const icons = [iconoir_cube, lucide_chevron_down, phosphor_acorn, tabler_world];`, + }, + bundle: true, + format: 'esm', + platform: 'browser', + treeShaking: true, + write: false, + plugins: [ + { + name: 'published-icon-package', + setup(builder) { + builder.onResolve({ filter: /^published-icons$/ }, () => ({ + path: 'published-icons', + namespace: 'icon-package', + })) + builder.onLoad({ filter: /.*/, namespace: 'icon-package' }, () => ({ + contents: published.outputFiles[0].text, + loader: 'js', + })) + }, + }, + ], + }) + const output = browser.outputFiles[0] + expect(output.contents.byteLength).toBeLessThan(20_000) + expect(output.text).not.toContain('SVG_ICONS') + expect(output.text).not.toContain('iconoir_accessibility') + const result = await import( + /* @vite-ignore */ `data:text/javascript;base64,${Buffer.from(output.contents).toString('base64')}` + ) + expect(result.icons).toEqual([ + iconoir_cube, + lucide_chevron_down, + phosphor_acorn, + tabler_world, + ]) + }) +}) diff --git a/packages/ts-ssg/src/config/head.ts b/packages/ts-ssg/src/config/head.ts index a9acd10d..4729953a 100644 --- a/packages/ts-ssg/src/config/head.ts +++ b/packages/ts-ssg/src/config/head.ts @@ -25,7 +25,7 @@ export function getHead(config?: BasicHeadConfig) { const head = createHead(getHeadConfig(merge(DEFAULTS, config))).push( h('meta').attr({ name: 'generator', - content: 'PureStack v1.1.11', + content: 'PureStack v1.1.12', }), h('meta').attr({ name: 'color-scheme', diff --git a/packages/ts-style/package.json b/packages/ts-style/package.json index 18db8f77..51e823ae 100644 --- a/packages/ts-style/package.json +++ b/packages/ts-style/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-style", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-style.mjs", "types": "./dist/ts-style.d.mts", diff --git a/packages/ts-svg-icons/package.json b/packages/ts-svg-icons/package.json index 1528904c..681989a6 100644 --- a/packages/ts-svg-icons/package.json +++ b/packages/ts-svg-icons/package.json @@ -1,6 +1,6 @@ { "name": "@purestack/ts-svg-icons", - "version": "1.1.11", + "version": "1.1.12", "packageManager": "yarn@4.9.2", "module": "./dist/ts-svg-icons.mjs", "types": "./dist/ts-svg-icons.d.mts", diff --git a/packages/ts-svg-icons/src/getSvgIcon.ts b/packages/ts-svg-icons/src/getSvgIcon.ts index 81af71a6..4a08455a 100644 --- a/packages/ts-svg-icons/src/getSvgIcon.ts +++ b/packages/ts-svg-icons/src/getSvgIcon.ts @@ -12,13 +12,6 @@ export type AvailableIconNames = | TablerIconName | (string & {}) -const SVG_ICONS: Record = { - ...ICONOIR_ICONS, - ...LUCIDE_ICONS, - ...PHOSPHOR_ICONS, - ...TABLER_ICONS, -} - /** * Returns an SVG string for a generated icon name or passes through raw SVG input. * @@ -32,7 +25,11 @@ const SVG_ICONS: Record = { */ export function getSvgIcon(name: AvailableIconNames): string { if (name?.includes('