
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
Table of Contents generated with DocToc
This is a startert project that helps you build your own awesome icon library for any kind of framework or even for vanilla JS or TypeScript. Each SVG icons is processed, optimized and build for static code analysers to enable tree shaking.
svg-icons folder.npm run serve.Once you placed the icons inside the svg-icons folder you can deliver them to production. npm run build converts all the icons to JavaScript and generates the correct TypeScript declaration files into a dist folder.
Once published to npm, your icon library is ready to be consumed. There are various ways to consume the icon library.
To consum the icon library in ES6 you can import icons from your library, create an SVG element and add the icon data to it.
// Import the icon from the icon library
import {myIconSmilingFace} from 'my-icon-lib';
// Query the element that you want to append the icon to
const conatiner = document.getElementById('.container');
// Create a new svg element and apply the icon data to it
function buildSVGElement(icon) {
const div = document.createElement('DIV');
div.innerHTML = icon.data;
return (
div.querySelector('svg') ||
this.document.createElementNS('http://www.w3.org/2000/svg', 'path')
);
}
// Append the icon to the container
container.appendChild(buildSVGElement(icon);
The TypeScript usage is very similar to the JavaScript usage. The only difference is that you have additional type safety.
// Import the icon from the icon library
import {myIconSmilingFace, MyIcon} from 'my-icon-lib';
// Query the element that you want to append the icon to
const conatiner = document.getElementById('.container');
// Create a new svg element and apply the icon data to it
function buildSVGElement(icon: MyIcon): SVGElement {
const div = document.createElement('DIV');
div.innerHTML = icon.data;
return (
div.querySelector('svg') ||
this.document.createElementNS('http://www.w3.org/2000/svg', 'path')
);
}
// Append the icon to the container
container.appendChild(buildSVGElement(icon));
The usage in frameworks can be a bit more sophisticated than the usage in plain JavaScript or TypeScript. In frameworks we often work with additional concepts like components and more sophisticated builds.
In Angular we want to provide a reusable component for the icons. A reusable component that accepts a name as an Input property and displays the desired icon. Furthermore, we want to guarantee that tree shaking is supported. If the icon library contains 300 icons but only one of them is used, only one should end up in the resulting bundle. Furthermore it should also support code splitting and lazy loading in a way that the icon only ends up in the chunk it is used.
To achieve these things we implement a IconRegistry.
import {Injectable} from '@angular/core';
import {MyIcon} from './my-icon-lib';
@Injectable({
providedIn: 'root'
})
export class MyIconsRegistry {
private registry = new Map<string, string>();
public registerIcons(icons: MyIcon[]): void {
icons.forEach((icon: MyIcon) => this.registry.set(icon.name, icon.data));
}
public getIcon(iconName: string): string | undefined {
if (!this.registry.has(iconName)) {
console.warn(
`We could not find the Icon with the name ${iconName}, did you add it to the Icon registry?`
);
}
return this.registry.get(iconName);
}
}
The icon registry holds all the icons in a Map. Next we build the my-icon.component.ts that will use the registry to display an icon.
import {
ChangeDetectionStrategy, Component, ElementRef, HostBinding, Inject, Input, Optional, ViewEncapsulation
} from '@angular/core';
import {MyIconsRegistry} from './my-icons-registry.service';
import {DOCUMENT} from '@angular/common';
@Component({
selector: 'my-icon',
template: `
<ng-content></ng-content>
`,
styles: [':host::ng-deep svg{width: 50px; height: 50px}'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyIconComponent {
private svgIcon: SVGElement;
@Input()
set name(iconName: string) {
if (this.svgIcon) {
this.element.nativeElement.removeChild(this.svgIcon);
}
const svgData = this.myIconsRegistry.getIcon(iconName);
this.svgIcon = this.svgElementFromString(svgData);
this.element.nativeElement.appendChild(this.svgIcon);
}
constructor(private element: ElementRef, private myIconsRegistry: MyIconsRegistry,
@Optional() @Inject(DOCUMENT) private document: any) {
}
private svgElementFromString(svgContent: string): SVGElement {
const div = this.document.createElement('DIV');
div.innerHTML = svgContent;
return div.querySelector('svg') || this.document.createElementNS('http://www.w3.org/2000/svg', 'path');
}
}
At this point we are ready to consum the my-icon component. We first register the desired icon in the lazy loaded module and then consume it in a component.
import { NgModule, Component } from '@angular/core';
import {myIconSmilingFace} from 'my-icon-lib';
import {MyIconsRegistry} from './my-icons-registry';
import {MyIconModule} from './my-icon.module.ts';
@Component({
selector: 'my-feature',
template: `<my-icon name="smiling_face"></my-icon>`
})
export class MyFeatureComponent {}
@NgModule({
declarations: [MyFeatureComponent],
imports: [MyIconModule]
})
export class MyFeatureModule {
constructor(private myIconsRegistry: MyIconsRegistry) {
myIconsRegistry.registerIcons([myIconSmilingFace]);
}
}
If you want to find out more about why we need a registry and how it helps tree shaking I recommend you to check out this blogpost.
Maybe you have a special setup or you are only interested in TypeScript files and don't want to compile the icons to JavaScript. In such cases you can always adjust the svg-to-ts config in your project. To prevent the JavaScript compilation for example you can simply disable it by setting the compileSources flag to false. For more information check out the svg-to-ts docs.
FAQs
Starter project to build an SVG icon library
We found that tt-icons demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.