Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fe7a304
feat: optimize icons by generating solid components
aminya Jan 20, 2023
50b8c76
perf: parallelize the post build script
aminya Jan 19, 2023
8a09f93
fix: use aminya/esbuild-plugin-solid
aminya Jan 20, 2023
a79e498
fix: pass compact true to Babel to avoid deoptimization
aminya Jan 20, 2023
5ab179b
test: update the tests to test FiIconsCircle
aminya Jan 20, 2023
942383a
chore: use async fs-extra in the build script
aminya Jan 21, 2023
a24a0ff
feat: create separate icon JSX files to allow flexible build options
aminya Jan 21, 2023
1b3aff3
fix: export the individual icons in the package.json
aminya Jan 21, 2023
26143e7
fix: fix the absolute package path on windows
aminya Jan 21, 2023
c136dba
fix: enable SSR and Hydration for the node bundle
aminya Jan 21, 2023
2359827
fix: set the exports based on the environment
aminya Jan 21, 2023
1b30a8f
fix: parallelize optimization using workerpool
aminya Jan 21, 2023
371fad0
fix: fix the get-icon worker
aminya Jan 21, 2023
9c07f09
fix: fix the ssr config in the solid-plugin
aminya Jan 21, 2023
514f08a
fix: parallelize post build using workerpool
aminya Jan 21, 2023
9fc8248
fix: terminate the workerpools after being done
aminya Jan 21, 2023
00dadc5
fix: use the released esbuild-plugin-solid
aminya Jan 23, 2023
b5cd9a3
test: fix the icon name in the test
aminya Feb 1, 2023
5e0bab0
fix: update the dependencies
aminya Feb 1, 2023
6034b81
fix: avoid running out of memory when building
aminya Feb 1, 2023
a723db0
fix: keep the un-bundled entry ts file
aminya Feb 1, 2023
017fbd8
fix: remove unused types from the lib
aminya Feb 1, 2023
23d86d5
fix: use vite to create the bundles and externalize solid-js
aminya Feb 4, 2023
84797ce
fix: fix importing the individual files
aminya Feb 4, 2023
8d7feab
fix: keep the module type in the dist
aminya Feb 6, 2023
4299ead
fix: fix hydration for the SSR build
aminya Feb 18, 2023
0d716b3
fix: enable hydration for both server and web
aminya Feb 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Modern solution for use icons on SolidJS
<p>

<p align="center">
<a href="https://solid-icons.vercel.app/">Icons Explorer</a> | <a href="https://github.com/x64Bits/solid-icons-web">Example</a>
<a href="https://solid-icons.vercel.app/">Icons Explorer</a> | <a href="https://github.com/x64Bits/solid-icons-web">Example</a>
</p>

<h4 align="center">
Expand Down Expand Up @@ -52,7 +52,7 @@ npm install solid-icons --save
## Usage

```jsx
import { SiJavascript } from "solid-icons/si";
import { SiJavascript } from "solid-icons/si/SiJavascript";

<SiJavascript size={24} color="#2c4f7c" />;
```
Expand Down
29 changes: 17 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,37 @@
],
"devDependencies": {
"@rollup/plugin-typescript": "^11.0.0",
"@solidjs/testing-library": "^0.6.0",
"@types/fs-extra": "^11.0.1",
"@types/node": "^18.11.18",
"@types/svg-parser": "^2.0.3",
"@types/svgo": "2.6.4",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.2",
"@vitest/coverage-c8": "^0.27.1",
"@types/workerpool": "^6.1.1",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"@vitest/coverage-c8": "^0.28.4",
"arg": "^5.0.2",
"chalk": "^5.2.0",
"cheerio": "^1.0.0-rc.12",
"dotenv": "^16.0.3",
"eslint": "^8.32.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
"jsdom": "^21.0.0",
"fs-extra": "^11.1.0",
"jsdom": "^21.1.0",
"prettier": "2.8.3",
"rgb-hex": "^4.0.0",
"rollup": "^3.10.0",
"rollup": "^3.13.0",
"rollup-plugin-delete": "^2.0.0",
"rollup-preset-solid": "^2.0.1",
"solid-js": "1.6.9",
"solid-testing-library": "^0.5.0",
"solid-js": "1.6.10",
"svgo": "3.0.2",
"ts-node": "^10.9.1",
"tslib": "^2.4.1",
"typescript": "^4.9.4",
"vite-plugin-solid": "^2.5.0",
"vitest": "^0.27.1"
"tslib": "^2.5.0",
"typescript": "^4.9.5",
"vite": "^4.1.1",
"vite-plugin-solid": "2.5.0",
"vitest": "0.28.4",
"workerpool": "^6.3.1"
},
"engines": {
"node": ">= 16"
Expand Down
66 changes: 33 additions & 33 deletions src/build/file-types.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
import type { IconContent } from "./types";

function cjsTemplate(icon: IconContent): string {
return /* javascript */ `
module.exports.${icon.fileName} = function ${icon.fileName}(props) {
return IconTemplate({
a: ${JSON.stringify(icon.svgAttribs)},
c: '${icon.contents}'
}, props)
}`;
}

function moduleTemplate(icon: IconContent) {
return /* javascript */ `
export function ${icon.fileName} (props) {
return IconTemplate({
a: ${JSON.stringify(icon.svgAttribs)},
c: '${icon.contents}'
}, props)
}`;
export function ${icon.fileName}(props) {
const svgAttribs = ${JSON.stringify(icon.svgAttribs)};
const mergedProps = mergeProps(svgAttribs, props);

return (
<svg
fill="currentColor"
stroke-width="0"
style={{
...props.style,
overflow: "visible",
color: props.color || "currentColor",
}}
{...mergedProps}
height={props.size || "1em"}
width={props.size || "1em"}
xmlns="http://www.w3.org/2000/svg"
>
${icon.contents}
{props.title && <title>{props.title}</title>}
</svg>
);
}`;
}

function typesTemplate(icon: IconContent) {
return /* javascript */ `\nexport declare const ${icon.fileName}: IconTypes;`;
return /* typescript */ `\nexport declare function ${icon.fileName}(props: IconProps): JSX.Element`;
}

export const fileTypes = [
{
type: "cjs",
template: (iconContent: IconContent) => cjsTemplate(iconContent),
template: moduleTemplate,
// eslint-disable-next-line quotes, @typescript-eslint/quotes
header: /* javascript */ `var IconTemplate = require('../lib/index.cjs').IconTemplate;`,
fileName: "index.cjs",
header: /* javascript */ `import { mergeProps } from "../lib/index.js";
`,
extension: ".jsx",
},
{
type: "mjs",
template: (iconContent: IconContent) => moduleTemplate(iconContent),
// eslint-disable-next-line quotes, @typescript-eslint/quotes
header: /* javascript */ `import { IconTemplate } from "../lib/index.js";`,
fileName: "index.js",
},
{
type: "types",
template: (iconContent: IconContent) => typesTemplate(iconContent),
// eslint-disable-next-line quotes, @typescript-eslint/quotes
header: /* javascript */ `import type { IconTypes } from "../lib/index"\n`,
fileName: "index.d.ts",
template: typesTemplate,
header: /* typescirpt */ `import { type JSX } from "solid-js";
import { type IconProps } from "../lib/index";
`,
extension: ".d.ts",
},
];
11 changes: 7 additions & 4 deletions src/build/get-files.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import fs from "fs";
import fs from "fs-extra";
import path from "path";

import { ROOT_PATH } from "./constants";

export function getPackFiles(dirPath: string, files: string[] = []): string[] {
const paths = fs.readdirSync(dirPath);
export async function getPackFiles(
dirPath: string,
files: string[] = []
): Promise<string[]> {
const paths = await fs.readdir(dirPath);

for (let current = 0; current < paths.length; current++) {
const file = paths[current];

if (fs.statSync(`${dirPath}/${file}`).isDirectory()) {
files = getPackFiles(`${dirPath}/${file}`, files);
files = await getPackFiles(`${dirPath}/${file}`, files);
} else if (file.includes(".svg")) {
files.push(path.join(ROOT_PATH, dirPath, "/", file));
}
Expand Down
36 changes: 36 additions & 0 deletions src/build/get-icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import fs from "fs-extra";
import { load } from "cheerio";
import { worker } from "workerpool";

import { formatFileName } from "./utils/file-name";
import { IconContent, PackItem } from "./types";
import { optimizeContents } from "./optimize";

export const getIconContent = async (
path: string,
pack: PackItem
): Promise<IconContent> => {
const rawFile = await fs.readFile(path, "utf-8");
const optimizeFile = await optimizeContents(rawFile, pack.shortName);

const $ = load(optimizeFile.data, { xmlMode: true });
const mountedElement = $("svg");

const { children, attribs } = mountedElement[0];

return {
fileName: formatFileName(path, pack),
contents: children
.reduce(
(prev: string[], current) =>
current.type === "tag" ? [...prev, $.html(current)] : prev,
[]
)
.join(""),
svgAttribs: attribs,
};
};

worker({
getIconContent,
});
56 changes: 17 additions & 39 deletions src/build/get-icons.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,20 @@
import fs from "fs";
import { load } from "cheerio";

import { getPackFiles } from "./get-files";
import { formatFileName } from "./utils/file-name";
import { optimizeContents } from "./optimize/index";
import { IconContent, PackItem } from "./types";

export const getFileByPath = (path: string) => fs.readFileSync(path, "utf8");

const getIconContent = async (
path: string,
pack: PackItem
): Promise<IconContent> => {
const rawFile = getFileByPath(path);
const optimizeFile = await optimizeContents(rawFile, pack.shortName);

const $ = load(optimizeFile.data, { xmlMode: true });
const mountedElement = $("svg");

const { children, attribs } = mountedElement[0];

return {
fileName: formatFileName(path, pack),
contents: children
.reduce(
(prev: string[], current) =>
current.type === "tag" ? [...prev, $.html(current)] : prev,
[]
)
.join(""),
svgAttribs: attribs,
};
};

export function getIcons(pack: PackItem): Promise<IconContent[]> {
const filesPath = getPackFiles(pack.path);

return Promise.all(
filesPath.map(async (path) => await getIconContent(path, pack))
import type { IconContent, PackItem } from "./types";
import type { getIconContent } from "./get-icon";
import { getIconContentPool } from "./index";

export async function getIcons(pack: PackItem): Promise<IconContent[]> {
const filesPath = await getPackFiles(pack.path);

const iconContents = await Promise.all(
filesPath.map(async (path) => {
const worker = await getIconContentPool.proxy<{
getIconContent: typeof getIconContent;
}>();
const content = await await worker.getIconContent(path, pack);
return content;
})
);

return iconContents;
}
11 changes: 10 additions & 1 deletion src/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import arg from "arg";
import chalk from "chalk";
import { pool } from "workerpool";

import packages from "./packages.json" assert { type: "json" };
import { getIcons } from "./get-icons";
import { prepareDist, writeLibFiles } from "./lib-files";
import { writeWebFiles } from "./web-files";
import { supportedArgs } from "./constants";
import { log, supportedArgs } from "./constants";
import { PackAttachedIcons } from "./types";


function isolatePack(shortName: string, isolateBy: string): boolean {
return shortName === isolateBy;
}
Expand All @@ -23,6 +26,8 @@ function getArgs() {
};
}

export const getIconContentPool = pool("./src/build/get-icon.js");

async function main() {
const { isIsolate, buildWeb } = getArgs();

Expand All @@ -39,6 +44,10 @@ async function main() {
icons: await getIcons(pack),
}))
);
await getIconContentPool.terminate();
log(
chalk.dim("🗜️ Icons have been optimized and prepared") + chalk.green(" ✓")
);

writeLibFiles(attachedFiles);

Expand Down
Loading