mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 12:07:43 +01:00
Improve types export for lucide-react (#1424)
* Add types plugin * Add js doc comment * Only enable dynamic imports for CJS and ESM builds * Add documentation * Adjust docs * Add test for dynamic import * Adjust note * Adjustment in docs
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@ packages/**/src/icons/*.js
|
||||
packages/**/src/icons/*.ts
|
||||
packages/**/src/icons/*.tsx
|
||||
packages/**/src/aliases.ts
|
||||
packages/**/src/dynamicIconImports.ts
|
||||
packages/**/LICENSE
|
||||
categories.json
|
||||
tags.json
|
||||
|
||||
@@ -67,6 +67,8 @@ It is possible to create one generic icon component to load icons. It's not reco
|
||||
|
||||
::: danger
|
||||
Example below importing all ES Modules, caution using this example. All icons will be imported. When using bundlers like: `Webpack`, `Rollup` or `Vite` the application build size will grow strongly and harming the performance the application.
|
||||
|
||||
This is not the case for the latest NextJS, because it uses server side rendering. The icons will be streamed to the client when needed. For NextJS with Dynamic Imports, see [dynamic imports](#nextjs-example) section for more information.
|
||||
:::
|
||||
|
||||
### Icon Component Example
|
||||
@@ -94,3 +96,59 @@ const App = () => {
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
#### With Dynamic Imports
|
||||
|
||||
> :warning: This is experimental and only works with bundlers that support dynamic imports.
|
||||
|
||||
Lucide react exports a dynamic import map `dynamicIconImports`. Useful for applications that want to show icons dynamically by icon name. For example when using a content management system with where icon names are stored in a database.
|
||||
|
||||
When using client side rendering, it will fetch the icon component when it's needed. This will reduce the initial bundle size.
|
||||
|
||||
The keys of the dynamic import map are the lucide original icon names (kebab case).
|
||||
|
||||
Example with React suspense:
|
||||
|
||||
```tsx
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
const fallback = <div style={{ background: '#ddd', width: 24, height: 24 }}/>
|
||||
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={fallback}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default Icon
|
||||
```
|
||||
|
||||
##### NextJS Example
|
||||
|
||||
In NextJS [the dynamic function](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#nextdynamic) can be used to load the icon component dynamically.
|
||||
|
||||
```tsx
|
||||
import dynamic from 'next/dynamic'
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
interface IconProps extends LucideProps {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = dynamic(dynamicIconImports[name])
|
||||
|
||||
return <LucideIcon {...props} />;
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
@@ -60,7 +60,7 @@ It is possible to create a generic icon component to load icons.
|
||||
> :warning: The example below is importing all ES modules. This is **not** recommended when you using a bundler since your application build size will grow substantially.
|
||||
|
||||
```js
|
||||
import * as icons from 'lucide-react';
|
||||
import { icons } from 'lucide-react';
|
||||
|
||||
const Icon = ({ name, color, size }) => {
|
||||
const LucideIcon = icons[name];
|
||||
@@ -70,3 +70,59 @@ const Icon = ({ name, color, size }) => {
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
#### With Dynamic Imports
|
||||
|
||||
> :warning: This is experimental and only works with bundlers that support dynamic imports.
|
||||
|
||||
Lucide react exports a dynamic import map `dynamicIconImports`. Useful for applications that want to show icons dynamically by icon name. For example when using a content management system with where icon names are stored in a database.
|
||||
|
||||
When using client side rendering, it will fetch the icon component when it's needed. This will reduce the initial bundle size.
|
||||
|
||||
The keys of the dynamic import map are the lucide original icon names.
|
||||
|
||||
Example with React suspense:
|
||||
|
||||
```tsx
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
const fallback = <div style={{ background: '#ddd', width: 24, height: 24 }}/>
|
||||
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={fallback}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default Icon
|
||||
```
|
||||
|
||||
##### NextJS Example
|
||||
|
||||
In NextJS [the dynamic function](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#nextdynamic) can be used to load the icon component dynamically.
|
||||
|
||||
```tsx
|
||||
import dynamic from 'next/dynamic'
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
interface IconProps extends LucideProps {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = dynamic(dynamicIconImports[name])
|
||||
|
||||
return <LucideIcon {...props} />;
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm typecheck && pnpm build:bundles && pnpm build:types",
|
||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm typecheck && pnpm build:bundles",
|
||||
"copy:license": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts",
|
||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts",
|
||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --withDynamicImports --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts",
|
||||
"build:types": "node ./scripts/buildTypes.mjs",
|
||||
"build:bundles": "rollup -c ./rollup.config.mjs",
|
||||
"typecheck": "tsc",
|
||||
@@ -44,6 +44,7 @@
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"rollup": "^3.5.1",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
"typescript": "^4.8.4",
|
||||
"vite": "^4.3.9",
|
||||
"vitest": "^0.32.2"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import plugins, { replace } from '@lucide/rollup-plugins';
|
||||
import pkg from './package.json' assert { type: 'json' };
|
||||
import dts from "rollup-plugin-dts";
|
||||
|
||||
const packageName = 'LucideReact';
|
||||
const outputFileName = 'lucide-react';
|
||||
@@ -21,19 +22,21 @@ const bundles = [
|
||||
format: 'cjs',
|
||||
inputs,
|
||||
outputDir,
|
||||
aliasesSupport: true
|
||||
aliasesSupport: true,
|
||||
withDynamicImports: true,
|
||||
},
|
||||
{
|
||||
format: 'esm',
|
||||
inputs,
|
||||
outputDir,
|
||||
preserveModules: true,
|
||||
aliasesSupport: true
|
||||
aliasesSupport: true,
|
||||
withDynamicImports: true,
|
||||
},
|
||||
];
|
||||
|
||||
const configs = bundles
|
||||
.map(({ inputs, outputDir, format, minify, preserveModules, aliasesSupport }) =>
|
||||
.map(({ inputs, outputDir, format, minify, preserveModules, aliasesSupport, withDynamicImports }) =>
|
||||
inputs.map(input => ({
|
||||
input,
|
||||
plugins: [
|
||||
@@ -47,6 +50,15 @@ const configs = bundles
|
||||
}),
|
||||
] : []
|
||||
),
|
||||
...(
|
||||
!withDynamicImports ? [
|
||||
replace({
|
||||
"export { default as dynamicIconImports } from './dynamicIconImports';": '',
|
||||
delimiters: ['', ''],
|
||||
preventAssignment: false,
|
||||
}),
|
||||
] : []
|
||||
),
|
||||
...plugins(pkg, minify)
|
||||
],
|
||||
external: ['react', 'prop-types'],
|
||||
@@ -71,4 +83,13 @@ const configs = bundles
|
||||
)
|
||||
.flat();
|
||||
|
||||
export default configs;
|
||||
export default [
|
||||
{
|
||||
input: inputs[0],
|
||||
output: [{
|
||||
file: `dist/${outputFileName}.d.ts`, format: "es"
|
||||
}],
|
||||
plugins: [dts()],
|
||||
},
|
||||
...configs
|
||||
];
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import path from 'path';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { getAliases } from '@lucide/build-icons';
|
||||
import {
|
||||
readSvgDirectory,
|
||||
resetFile,
|
||||
toPascalCase,
|
||||
writeFile,
|
||||
getCurrentDirPath,
|
||||
} from '../../../scripts/helpers.mjs';
|
||||
|
||||
const currentDir = getCurrentDirPath(import.meta.url);
|
||||
const srcDirectory = path.join(currentDir, '../dist');
|
||||
|
||||
const writeDeclarationFile = (typesFile, directory, content) => {
|
||||
resetFile(typesFile, directory);
|
||||
writeFile(content, typesFile, directory);
|
||||
};
|
||||
|
||||
const ICONS_DIR = path.resolve(currentDir, '../../../icons');
|
||||
const TYPES_FILE = 'lucide-react.d.ts';
|
||||
|
||||
let declarationFileContent = `\
|
||||
/// <reference types="react" />
|
||||
import { SVGAttributes, FC, SVGProps, ReactSVG } from 'react'
|
||||
|
||||
declare module 'lucide-react'
|
||||
|
||||
// Create interface extending SVGProps
|
||||
export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = (props: LucideProps) => JSX.Element;
|
||||
|
||||
export type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]
|
||||
|
||||
export declare const createLucideIcon: (iconName: string, iconNode: IconNode) => LucideIcon;
|
||||
|
||||
export type Icon = FC<LucideProps>;
|
||||
|
||||
// Generated icon
|
||||
`;
|
||||
|
||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
||||
|
||||
svgFiles.forEach((svgFile) => {
|
||||
const iconName = path.basename(svgFile, '.svg');
|
||||
const componentName = toPascalCase(iconName);
|
||||
|
||||
declarationFileContent += `export declare const ${componentName}: LucideIcon;\n`;
|
||||
});
|
||||
|
||||
const aliases = await getAliases(ICONS_DIR);
|
||||
|
||||
declarationFileContent += `\n
|
||||
|
||||
// Generated icon aliases
|
||||
`;
|
||||
|
||||
let aliasesCount = 0;
|
||||
|
||||
svgFiles.forEach((svgFile) => {
|
||||
const iconName = path.basename(svgFile, '.svg');
|
||||
const componentName = toPascalCase(iconName);
|
||||
const iconAliases = aliases[iconName]?.aliases;
|
||||
|
||||
declarationFileContent += `// ${componentName} aliases\n`;
|
||||
declarationFileContent += `export declare const ${componentName}Icon: LucideIcon;\n`;
|
||||
declarationFileContent += `export declare const Lucide${componentName}: LucideIcon;\n`;
|
||||
aliasesCount += 1;
|
||||
if (iconAliases != null && Array.isArray(iconAliases)) {
|
||||
iconAliases.forEach((alias) => {
|
||||
const componentNameAlias = toPascalCase(alias);
|
||||
declarationFileContent += `export declare const ${componentNameAlias}: LucideIcon;\n`;
|
||||
|
||||
aliasesCount += 1;
|
||||
});
|
||||
}
|
||||
|
||||
declarationFileContent += '\n';
|
||||
});
|
||||
|
||||
writeDeclarationFile(TYPES_FILE, srcDirectory, declarationFileContent);
|
||||
console.log(
|
||||
`Generated ${TYPES_FILE} file with`,
|
||||
svgFiles.length,
|
||||
'icons and with',
|
||||
aliasesCount,
|
||||
'aliases',
|
||||
);
|
||||
@@ -1,7 +1,33 @@
|
||||
export default ({ componentName, children }) => `
|
||||
export default ({ componentName, iconName, children, getSvg }) => {
|
||||
const svgContents = getSvg();
|
||||
|
||||
const svgBase64 = Buffer.from(
|
||||
svgContents
|
||||
.replace('\n', '')
|
||||
.replace(
|
||||
'stroke="currentColor"',
|
||||
'stroke="#000" style="background-color: #fff; border-radius: 2px"',
|
||||
),
|
||||
).toString('base64');
|
||||
|
||||
// declarationFileContent += `\
|
||||
|
||||
return `
|
||||
import createLucideIcon from '../createLucideIcon';
|
||||
|
||||
/**
|
||||
* @component @name ${componentName}
|
||||
* @description Lucide SVG icon component, renders SVG Element with children.
|
||||
*
|
||||
* @preview  - https://lucide.dev/icons/${iconName}
|
||||
* @see https://lucide.dev/guide/packages/lucide-react - Documentation
|
||||
*
|
||||
* @param {Object} props - Lucide icons props and any valid SVG attribute
|
||||
* @returns {JSX.Element} JSX Element
|
||||
*
|
||||
*/
|
||||
const ${componentName} = createLucideIcon('${componentName}', ${JSON.stringify(children)});
|
||||
|
||||
export default ${componentName};
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { forwardRef, createElement, ReactSVG, SVGProps } from 'react';
|
||||
import { forwardRef, createElement, ReactSVG, SVGProps, ForwardRefExoticComponent, RefAttributes } from 'react';
|
||||
import defaultAttributes from './defaultAttributes';
|
||||
|
||||
export type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]
|
||||
@@ -9,6 +9,8 @@ export interface LucideProps extends SVGAttributes {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = ForwardRefExoticComponent<LucideProps & RefAttributes<SVGSVGElement>>
|
||||
/**
|
||||
* Converts string to KebabCase
|
||||
* Copied from scripts/helper. If anyone knows how to properly import it here
|
||||
@@ -19,7 +21,7 @@ export interface LucideProps extends SVGAttributes {
|
||||
*/
|
||||
export const toKebabCase = (string: string) => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode) => {
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => {
|
||||
const Component = forwardRef<SVGSVGElement, LucideProps>(
|
||||
({ color = 'currentColor', size = 24, strokeWidth = 2, absoluteStrokeWidth, children, ...rest }, ref) =>
|
||||
createElement(
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
export * from './icons';
|
||||
export * as icons from './icons';
|
||||
export * from './aliases';
|
||||
export { default as createLucideIcon } from './createLucideIcon';
|
||||
export { default as dynamicIconImports } from './dynamicIconImports';
|
||||
export {
|
||||
default as createLucideIcon,
|
||||
type IconNode,
|
||||
type LucideProps,
|
||||
type LucideIcon,
|
||||
} from './createLucideIcon';
|
||||
|
||||
@@ -5,3 +5,5 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render icons dynamically by using the dynamicIconImports module 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-smile\\" aria-label=\\"smile\\"><circle cx=\\"12\\" cy=\\"12\\" r=\\"10\\"></circle><path d=\\"M8 14s1.5 2 4 2 4-2 4-2\\"></path><line x1=\\"9\\" x2=\\"9.01\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"15\\" x2=\\"15.01\\" y1=\\"9\\" y2=\\"9\\"></line></svg>"`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render, cleanup } from '@testing-library/react'
|
||||
import { Pen, Edit2, Grid } from '../src/lucide-react';
|
||||
import { render, cleanup, waitFor } from '@testing-library/react'
|
||||
import { Pen, Edit2, Grid, dynamicIconImports, LucideProps } from '../src/lucide-react';
|
||||
import { Suspense, lazy } from 'react';
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
it('should render an component', () => {
|
||||
@@ -73,4 +74,37 @@ describe('Using lucide icon components', () => {
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render icons dynamically by using the dynamicIconImports module', async () => {
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
const { container, getByLabelText } = render(
|
||||
<Icon
|
||||
aria-label="smile"
|
||||
name="smile"
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>,
|
||||
);
|
||||
|
||||
await waitFor(() => getByLabelText('smile'))
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -384,6 +384,9 @@ importers:
|
||||
rollup:
|
||||
specifier: ^3.5.1
|
||||
version: 3.23.0
|
||||
rollup-plugin-dts:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0(rollup@3.23.0)(typescript@4.9.5)
|
||||
typescript:
|
||||
specifier: ^4.8.4
|
||||
version: 4.9.5
|
||||
@@ -1828,10 +1831,6 @@ packages:
|
||||
resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
/@babel/helper-validator-identifier@7.19.1:
|
||||
resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
/@babel/helper-validator-identifier@7.22.5:
|
||||
resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -4872,7 +4871,7 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.21.5
|
||||
'@babel/helper-validator-identifier': 7.19.1
|
||||
'@babel/helper-validator-identifier': 7.22.5
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
/@babel/types@7.22.5:
|
||||
|
||||
30
tools/build-icons/building/generateDynamicImports.mjs
Normal file
30
tools/build-icons/building/generateDynamicImports.mjs
Normal file
@@ -0,0 +1,30 @@
|
||||
import path from 'path';
|
||||
import { resetFile, appendFile } from '../../../scripts/helpers.mjs';
|
||||
|
||||
export default function generateDynamicImports({
|
||||
iconNodes,
|
||||
outputDirectory,
|
||||
fileExtension,
|
||||
showLog = true,
|
||||
}) {
|
||||
const fileName = path.basename(`dynamicIconImports${fileExtension}`);
|
||||
const icons = Object.keys(iconNodes);
|
||||
|
||||
// Reset file
|
||||
resetFile(fileName, outputDirectory);
|
||||
|
||||
let importString = `const dynamicIconImports = {\n`;
|
||||
|
||||
// Generate Import for Icon VNodes
|
||||
icons.forEach((iconName) => {
|
||||
importString += ` '${iconName}': () => import('./icons/${iconName}'),\n`;
|
||||
});
|
||||
|
||||
importString += '};\nexport default dynamicIconImports;\n';
|
||||
|
||||
appendFile(importString, fileName, outputDirectory);
|
||||
|
||||
if (showLog) {
|
||||
console.log(`Successfully generated ${fileName} file`);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import prettier from 'prettier';
|
||||
import { toPascalCase } from '../../../scripts/helpers.mjs';
|
||||
import { readSvg, toPascalCase } from '../../../scripts/helpers.mjs';
|
||||
|
||||
export default ({
|
||||
iconNodes,
|
||||
@@ -10,6 +10,7 @@ export default ({
|
||||
showLog = true,
|
||||
iconFileExtension = '.js',
|
||||
pretty = true,
|
||||
iconsDir,
|
||||
}) => {
|
||||
const icons = Object.keys(iconNodes);
|
||||
const iconsDistDirectory = path.join(outputDirectory, `icons`);
|
||||
@@ -25,7 +26,9 @@ export default ({
|
||||
let { children } = iconNodes[iconName];
|
||||
children = children.map(({ name, attributes }) => [name, attributes]);
|
||||
|
||||
const elementTemplate = template({ componentName, iconName, children });
|
||||
const getSvg = () => readSvg(`${iconName}.svg`, iconsDir);
|
||||
|
||||
const elementTemplate = template({ componentName, iconName, children, getSvg });
|
||||
const output = pretty
|
||||
? prettier.format(elementTemplate, {
|
||||
singleQuote: true,
|
||||
|
||||
@@ -10,6 +10,7 @@ import generateExportsFile from './building/generateExportsFile.mjs';
|
||||
import { readSvgDirectory, getCurrentDirPath } from '../../scripts/helpers.mjs';
|
||||
import generateAliasesFile from './building/generateAliasesFile.mjs';
|
||||
import getAliases from './utils/getAliases.mjs';
|
||||
import generateDynamicImports from './building/generateDynamicImports.mjs';
|
||||
|
||||
const cliArguments = getArgumentOptions(process.argv.slice(2));
|
||||
|
||||
@@ -30,6 +31,7 @@ const {
|
||||
importImportFileExtension = '',
|
||||
exportFileName = 'index.js',
|
||||
withAliases = false,
|
||||
withDynamicImports = false,
|
||||
aliasesFileExtension = '.js',
|
||||
aliasImportFileExtension = '',
|
||||
pretty = true,
|
||||
@@ -54,6 +56,7 @@ async function buildIcons() {
|
||||
showLog: !silent,
|
||||
iconFileExtension,
|
||||
pretty: JSON.parse(pretty),
|
||||
iconsDir: ICONS_DIR,
|
||||
});
|
||||
|
||||
if (withAliases) {
|
||||
@@ -69,6 +72,15 @@ async function buildIcons() {
|
||||
});
|
||||
}
|
||||
|
||||
if (withDynamicImports) {
|
||||
generateDynamicImports({
|
||||
iconNodes: icons,
|
||||
outputDirectory: OUTPUT_DIR,
|
||||
fileExtension: aliasesFileExtension,
|
||||
showLog: !silent,
|
||||
});
|
||||
}
|
||||
|
||||
// Generates entry files for the compiler filled with icons exports
|
||||
generateExportsFile(
|
||||
path.join(OUTPUT_DIR, 'icons', exportFileName),
|
||||
|
||||
Reference in New Issue
Block a user