From 6e2854a2f7e6fa8de04981e03f1da879a5878ed7 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 22 Apr 2026 09:14:50 -0400 Subject: [PATCH 1/2] feat(types): add core-free-icons subpath type shim @hugeicons/core-free-icons advertises subpath exports via "./*" but only ships a barrel index.d.ts, so subpath imports resolve at runtime but TS can't find types under node16/nodenext/bundler resolution (see #3). Ships an opt-in shim as @hugeicons/react/core-free-icons that declares the wildcard module with IconSvgElement. Consumers reference it once: /// Removable when core-free-icons emits per-icon .d.ts files. --- README.md | 2 ++ rollup.config.mjs | 19 +++++++++++++++++-- src/core-free-icons.d.ts | 4 ++++ src/index.ts | 4 +++- 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 src/core-free-icons.d.ts diff --git a/README.md b/README.md index de82052..a0b670e 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ import { NotificationIcon } from '@hugeicons/core-free-icons'; - **Tree-shaking**: The package is fully tree-shakeable, ensuring only the icons you use are included in your final bundle - **Optimized SVGs**: All icons are optimized for size and performance - **Code Splitting**: Icons can be easily code-split when using dynamic imports +- **Subpath imports**: `import SearchIcon from "@hugeicons/core-free-icons/SearchIcon"` loads one icon instead of the full barrel ## Troubleshooting @@ -153,6 +154,7 @@ import { NotificationIcon } from '@hugeicons/core-free-icons'; 3. **Bundle size concerns?** - Use named imports instead of importing the entire icon set + - Use subpath imports (`import Icon from "@hugeicons/core-free-icons/Icon"`) to cut dev-bundle size - Add code splitting for different sections of your app - Verify your bundler is configured to tree shake ESM builds diff --git a/rollup.config.mjs b/rollup.config.mjs index 6f0af62..5b3a501 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -4,7 +4,7 @@ import terser from '@rollup/plugin-terser'; import dts from 'rollup-plugin-dts'; import nodeResolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; -import { writeFileSync, mkdirSync } from 'fs'; +import { copyFileSync, readFileSync, writeFileSync, mkdirSync } from 'fs'; // Plugin to generate package.json with "type": "module" for ESM build const generateEsmPackageJson = () => ({ @@ -16,6 +16,21 @@ const generateEsmPackageJson = () => ({ } }); +// Plugin to copy ambient .d.ts files and reference them from the entry +const copyAmbientTypes = () => ({ + name: 'copy-ambient-types', + writeBundle(options) { + if (options.dir && options.dir.includes('types')) { + copyFileSync('src/core-free-icons.d.ts', `${options.dir}/core-free-icons.d.ts`); + const indexPath = `${options.dir}/index.d.ts`; + const content = readFileSync(indexPath, 'utf8'); + if (!content.startsWith('/// /^react($|\/)/.test(id); const globals = { @@ -105,6 +120,6 @@ export default defineConfig([ preserveModulesRoot: 'src' }, external, - plugins: [dts()] + plugins: [dts(), copyAmbientTypes()] } ]); diff --git a/src/core-free-icons.d.ts b/src/core-free-icons.d.ts new file mode 100644 index 0000000..42cb235 --- /dev/null +++ b/src/core-free-icons.d.ts @@ -0,0 +1,4 @@ +declare module '@hugeicons/core-free-icons/*' { + const icon: import('./HugeiconsIcon').IconSvgElement; + export default icon; +} diff --git a/src/index.ts b/src/index.ts index ca1d866..b3b1a18 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,4 @@ +/// + export { default as HugeiconsIcon } from './HugeiconsIcon'; -export type { HugeiconsIconProps, HugeiconsProps, IconSvgElement } from './HugeiconsIcon'; \ No newline at end of file +export type { HugeiconsIconProps, HugeiconsProps, IconSvgElement } from './HugeiconsIcon'; From 7237e6c48de2ba9ef937de01d9c89d8daa49dfa7 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 5 May 2026 11:47:17 -0400 Subject: [PATCH 2/2] fix(types): match core-free-icons IconSvgObject union shape The previous shape pulled IconSvgElement (readonly only) from @hugeicons/react. Switch to the IconSvgObject union (mutable | readonly) that core-free-icons itself uses for its barrel exports, so subpath and barrel imports type identically. HugeiconsIcon still accepts the value either way (mutable arrays are assignable to readonly), so this is consistent only, no behavior change. --- src/core-free-icons.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core-free-icons.d.ts b/src/core-free-icons.d.ts index 42cb235..d24ce11 100644 --- a/src/core-free-icons.d.ts +++ b/src/core-free-icons.d.ts @@ -1,4 +1,6 @@ declare module '@hugeicons/core-free-icons/*' { - const icon: import('./HugeiconsIcon').IconSvgElement; + const icon: + | [string, { [key: string]: string | number }][] + | readonly (readonly [string, { readonly [key: string]: string | number }])[]; export default icon; }