Skip to content

Commit 5dc6499

Browse files
Use Babel to transpile icons into separate chunks and source maps - No bundling required (#280)
* Added missing type definitions * Updated the icon templates to default export the icons * Updated babel.config.json * Transpile the generated icons to ESM and CJS * Removed Rollup and dependendencies * Auto generate type definitions * Updated pre build script * Generated type definitions in the root folder * Updated exports for all CJS paths
1 parent 1e1cca7 commit 5dc6499

18 files changed

+302
-1086
lines changed

.github/pull_request_template.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
**Checklist**
66

77
- [ ] I have made corresponding changes to the documentation.
8-
- [ ] I have updated the types definition of modified exports.
98
- [ ] I have verified the functionality in some of the neeto web-apps.
109
- [ ] I have added the necessary label (patch/minor/major - If package publish
1110
is required).

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,6 @@ lerna-debug.log
9494
.DS_Store
9595
Thumbs.db
9696
preview/
97+
98+
# Generated type definitions
99+
*.d.ts

app-icons.d.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

babel.config.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
{
2-
"presets": ["@babel/preset-env", "@babel/preset-react"]
3-
}
2+
"sourceMaps": true,
3+
"presets": [
4+
["@babel/preset-env", { "modules": false }],
5+
"@babel/preset-react"
6+
]
7+
}
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ const commonProps = {
2121
},
2222
}
2323

24-
const componentGenerationConfig = [
24+
const ICON_TYPE ="type IconProps = {\r\n\tsize?: string | number;\r\n\tstrokeWidth?: string | number;\r\n\tcolor?: string;\r\n} & React.SVGProps<SVGSVGElement>;\r\n"
25+
const TYPEFACE_ICON_TYPE = "type IconProps = { width?: string | number, height?: string | number } & React.SVGProps<SVGSVGElement>;\r\n";
26+
const OTHER_ICON_TYPE = "type IconProps = { size?: string | number } & React.SVGProps<SVGSVGElement>;\r\n";
27+
28+
export const ENCODING_STANDARD = "utf-8";
29+
30+
export const COMPONENT_GENERATION_CONFIG = [
2531
{
2632
options: {
2733
icon: true,
@@ -44,6 +50,7 @@ const componentGenerationConfig = [
4450
}},
4551
destination: "./generate/icons",
4652
source: "./source/icons/**.svg",
53+
iconType: ICON_TYPE,
4754
},
4855
{
4956
options: {
@@ -55,6 +62,7 @@ const componentGenerationConfig = [
5562
},
5663
destination: "./generate/logos",
5764
source: "./source/logos/**.svg",
65+
iconType: OTHER_ICON_TYPE,
5866
},
5967
{
6068
options: {
@@ -66,6 +74,7 @@ const componentGenerationConfig = [
6674
},
6775
destination: "./generate/app-icons",
6876
source: "./source/appIcons/**.svg",
77+
iconType: OTHER_ICON_TYPE,
6978
},
7079
{
7180
options: {
@@ -77,6 +86,7 @@ const componentGenerationConfig = [
7786
},
7887
destination: "./generate/typeface-logos",
7988
source: "./source/typefaceLogos/**.svg",
89+
iconType: TYPEFACE_ICON_TYPE,
8090
},
8191
{
8292
options: {
@@ -87,7 +97,6 @@ const componentGenerationConfig = [
8797
},
8898
destination: "./generate/misc",
8999
source: "./source/misc/**.svg",
100+
iconType: OTHER_ICON_TYPE,
90101
},
91102
];
92-
93-
export default componentGenerationConfig;

build/index.mjs

Lines changed: 108 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,83 +4,124 @@ import uppercamelcase from "uppercamelcase";
44
import path from "path";
55
import mkdirp from "mkdirp";
66
import { transform } from "@svgr/core";
7-
import * as cheerio from "cheerio"
7+
import * as cheerio from "cheerio";
8+
import {
9+
COMPONENT_GENERATION_CONFIG,
10+
ENCODING_STANDARD,
11+
} from "./constants.mjs";
812

9-
export const generateComponents = (config = {}) => {
10-
return {
11-
name: "generate-components",
12-
buildStart: async () => {
13-
await config.forEach(({
14-
options = {},
15-
source = "./source/icons/**.svg",
16-
additionalTransformations = (string) => string,
17-
destination = "./generate/icons",
18-
}) => {
19-
try {
20-
const encodingStandard = "utf-8"
21-
const indexFilePath = path.join(destination, "index.js");
22-
const directory = path.parse(indexFilePath).dir;
13+
const generateComponents = () => {
14+
// delete the dist and generate folders
15+
try {
16+
fs.rmSync("dist", { recursive: true, force: true });
17+
fs.rmSync("generate", { recursive: true, force: true });
18+
} catch (err) {
19+
if (err.code !== "ENOENT") console.log(err);
20+
}
2321

24-
// make the directory
25-
mkdirp.sync(directory);
22+
COMPONENT_GENERATION_CONFIG.forEach(
23+
({
24+
options = {},
25+
source = "./source/icons/**.svg",
26+
additionalTransformations = (string) => string,
27+
destination = "./generate/icons",
28+
iconType,
29+
}) => {
30+
try {
31+
const indexFilePath = path.join(destination, "index.js");
32+
const typeFilePath = `${destination.split("/").at(-1)}.d.ts`;
33+
const directory = path.parse(indexFilePath).dir;
2634

27-
// make the index file
28-
fs.writeFileSync(indexFilePath, "", encodingStandard);
35+
// make the directory
36+
mkdirp.sync(directory);
2937

30-
// make the icon folder
31-
mkdirp.sync(destination);
38+
// make the index file
39+
fs.writeFileSync(indexFilePath, "", ENCODING_STANDARD);
3240

33-
// read the icon source
34-
glob(source, (err, icons) => {
35-
if (err) {
36-
throw err;
37-
}
41+
// make the type file
42+
fs.writeFileSync(
43+
typeFilePath,
44+
`import React from "react";\n\n${iconType}\r\n`,
45+
ENCODING_STANDARD
46+
);
3847

39-
if (icons.length === 0) {
40-
throw Error(
41-
"Unable to find any icons. Make sure you use a glob format. [path/**.svg]",
42-
);
43-
}
48+
// make the icon folder
49+
mkdirp.sync(destination);
4450

45-
icons.forEach((iconPath) => {
46-
const svg = cheerio.load(fs.readFileSync(iconPath, encodingStandard), { xmlMode: true });
47-
const iconName = path.basename(iconPath, path.extname(iconPath));
48-
const componentName = uppercamelcase(iconName);
49-
const importStatement = `export * from "./${componentName}";\r\n`
50-
const iconDestination = path.join(
51-
destination,
52-
componentName + ".js", );
51+
// read the icon source
52+
glob(source, (err, icons) => {
53+
if (err) {
54+
throw err;
55+
}
5356

54-
// perform some santization and specific transformations besides
55-
// the ones provided to us by svgr
56-
svg("*").each((_, el) => {
57-
const element = svg(el)
58-
Object.keys(el.attribs).forEach((attribute) => {
59-
additionalTransformations(attribute, svg(el));
60-
})
61-
if (el.name === "svg") {
62-
element.removeAttr("class")
63-
.removeAttr("xmlns")
64-
}
65-
});
57+
if (icons.length === 0) {
58+
throw Error(
59+
"Unable to find any icons. Make sure you use a glob format. [path/**.svg]"
60+
);
61+
}
6662

67-
// generate component code
68-
const reactComponent = transform.sync(
69-
svg("svg").toString(),
70-
options,
71-
{ componentName, filePath: iconDestination },
72-
);
63+
const components = [];
64+
icons.forEach((iconPath) => {
65+
const svg = cheerio.load(
66+
fs.readFileSync(iconPath, ENCODING_STANDARD),
67+
{ xmlMode: true }
68+
);
69+
const iconName = path.basename(iconPath, path.extname(iconPath));
70+
const componentName = uppercamelcase(iconName);
71+
const importStatement = `import ${componentName} from "./${componentName}";\r\n`;
72+
const typeDefinition = `export const ${componentName}: React.FC<IconProps>;\r\n`;
73+
const iconDestination = path.join(
74+
destination,
75+
componentName + ".js"
76+
);
77+
components.push(componentName);
7378

74-
// write component to file
75-
fs.writeFileSync(iconDestination, reactComponent, encodingStandard);
76-
// append component import statement to the index file
77-
fs.appendFileSync( indexFilePath, importStatement, encodingStandard );
79+
// perform some santization and specific transformations besides
80+
// the ones provided to us by svgr
81+
svg("*").each((_, el) => {
82+
const element = svg(el);
83+
Object.keys(el.attribs).forEach((attribute) => {
84+
additionalTransformations(attribute, svg(el));
85+
});
86+
if (el.name === "svg") {
87+
element.removeAttr("class").removeAttr("xmlns");
88+
}
7889
});
90+
91+
// generate component code
92+
const reactComponent = transform.sync(
93+
svg("svg").toString(),
94+
options,
95+
{ componentName, filePath: iconDestination }
96+
);
97+
98+
// write component to file
99+
fs.writeFileSync(
100+
iconDestination,
101+
reactComponent,
102+
ENCODING_STANDARD
103+
);
104+
// append component import statement to the index file
105+
fs.appendFileSync(
106+
indexFilePath,
107+
importStatement,
108+
ENCODING_STANDARD
109+
);
110+
// append type definition
111+
fs.appendFileSync(typeFilePath, typeDefinition, ENCODING_STANDARD);
79112
});
80-
} catch (err) {
81-
console.log(err);
82-
}
83-
});
84-
},
85-
};
113+
114+
const exportStatement = `export { \r\n\t${components.join(
115+
",\r\n\t"
116+
)}\r\n};`;
117+
// append export statement to the index file
118+
fs.appendFileSync(indexFilePath, exportStatement, ENCODING_STANDARD);
119+
});
120+
} catch (err) {
121+
console.log(err);
122+
}
123+
}
124+
);
86125
};
126+
127+
generateComponents();
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
const appIconTemplate = ({ componentName, jsx }, { tpl }) => tpl`
22
import React from 'react';
33
4-
export const ${componentName} = ({size=36, ...props}) => {
4+
const ${componentName} = ({size=36, ...props}) => {
55
return ${jsx};
66
}
7+
8+
export default ${componentName};
79
`;
810

911
export default appIconTemplate;

build/templates/icon-template.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
const iconTemplate = ({ componentName, jsx }, { tpl }) => tpl`
22
import React from 'react';
33
4-
export const ${componentName} = ({ size=24, color="currentColor", strokeWidth=1.5, ...props }) => {
4+
const ${componentName} = ({ size=24, color="currentColor", strokeWidth=1.5, ...props }) => {
55
return ${jsx};
66
}
7+
8+
export default ${componentName};
79
`;
810

911
export default iconTemplate;

build/templates/logo-template.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
const logoTemplate = ({ componentName, jsx }, { tpl }) => tpl`
22
import React from 'react';
33
4-
export const ${componentName} = ({size=36, ...props}) => {
4+
const ${componentName} = ({size=36, ...props}) => {
55
return ${jsx};
66
}
7+
8+
export default ${componentName};
79
`;
810

911
export default logoTemplate;

build/templates/misc-template.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
const miscTemplate = ( { componentName, jsx }, { tpl }, ) => tpl`
22
import React from "react";
33
4-
export const ${componentName} = ({size=24, ...props}) => {
4+
const ${componentName} = ({size=24, ...props}) => {
55
return ${jsx};
66
}
7+
8+
export default ${componentName};
79
`;
810

911
export default miscTemplate;

0 commit comments

Comments
 (0)