omacranger / fontawesome-subset Goto Github PK
View Code? Open in Web Editor NEWCreates subsets of FontAwesome fonts for optimized use on the web.
License: GNU General Public License v3.0
Creates subsets of FontAwesome fonts for optimized use on the web.
License: GNU General Public License v3.0
Hello,
I found this project to make a font-awesome subset (nice project btw) and want to use it to amek a font-awesome pro subset. When I install this project as dependency it automatically downloads font-awesome free as well, while I don't need it.
Could font-awesome free moved from the dependencies to the optional dependencies?
Regards.
Hello,
I use the pro version with FontAwesome Kits, but I want to switch to self hosting fonts to improve performance. Subsetter software is easy to use but don't provide feature to add custom icon.
Any plan to add feature for support custom icons with fontawesome-subset ?
Cédric
I'm using your library (THANK YOU!) and made a script so that in dev we could use the regular fontawesome without having to worry about which icons are or aren't in the subset, and when we build the script discovers all the icons in use and auto-generates a subset.
I think with some improvements could be valuable to anyone who uses this project. Namely, the fact that grep
isn't available on all systems should be accounted for.
Since you can't do conditional imports in SCSS, in dev mode we generate a file that just includes the fontawesome lib as normal.
In prod the generated SCSS file references the subsetted font files.
package.json
scriptsWe use Webpack Encore so something like this worked for us
"scripts": {
"dev": "npm run fa-subset && encore dev",
"build": "npm run fa-subset && encore production --progress",
"fa-subset": "node scripts/fa-subset/index.mjs"
}
// $env is set in webpack.config.js via sass-loader's `additionalOptions` config property
@if not variable-exists(env) or $env == "development" {
// Use regular fontawesome-pro in dev for doubleplusgood DX
$fa-font-path: "~@fortawesome/fontawesome-pro/webfonts";
} @else {
// Use auto-generated subset in production for doubleplusgood UX
$fa-font-path: "/build/fontawesome/webfonts";
}
// Use self-hosted, subsetted fontawesome
@import "/build/fontawesome/fontawesome.scss";
@import "~@fortawesome/fontawesome-pro/scss/regular";
@import "~@fortawesome/fontawesome-pro/scss/solid";
@import "~@fortawesome/fontawesome-pro/scss/light";
@import "~@fortawesome/fontawesome-pro/scss/duotone";
@import "~@fortawesome/fontawesome-pro/scss/brands";
Hi, I'm trying to use this package but encountering Error: Could not convert the given font.
.
Here is how to replicate it. First create these file on the same directory:
package.json
{
"devDependencies": {
"@fortawesome/fontawesome-free": "5.14.0",
"fontawesome-subset": "^3.0.0"
}
}
extract_font.js
const {fontawesomeSubset} = require("fontawesome-subset");
fontawesomeSubset([
'envelope-o',
'github',
'linkedin',
'facebook'
], 'output');
Now run:
❯ npm i
added 111 packages, and audited 112 packages in 29s
5 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Then:
❯ node extract_font.js
/Users/linus/myself/lamhoangtung.github.io/node_modules/fontawesome-subset/dist/index.js:115
(0, fs_1.writeFileSync)(`${outputFile}.woff2`, ttf2woff2(ttf));
^
Error: Could not convert the given font.
at fontawesomeSubset (/Users/linus/myself/lamhoangtung.github.io/node_modules/fontawesome-subset/dist/index.js:115:56)
at Object.<anonymous> (/Users/linus/myself/lamhoangtung.github.io/extract_font.js:3:1)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
Here you can see the Error: Could not convert the given font.
.
Also the output
folder will be created with some of these files, but certainly not what we need.
❯ tree output
output
├── fa-solid-900.eot
├── fa-solid-900.svg
├── fa-solid-900.ttf
└── fa-solid-900.woff
0 directories, 4 files
Btw, my node version are v16.13.1
.
Are there anything that I'm doing wrong here ? How can I overcome this problem ? Thanks for checking by !
Hi,
We are currently using fontawesome-subset in our project, where the package manager is Yarn version 1. I am trying to migrate to Yarn modern version and to enable the Plug'n'Play mode, which basically removes the node_modules
folder and uses the .yarn
folder instead. Now when I try to run the script to generate the subset, I get the following error message:
Unable to find either the Free or Pro FontAwesome files in node_modules folder. Double-check that you have your preferred fontawesome package as a dependency in
package.json
and rerun the installation.
I understand the script is checking for existence of Font-Awesome in node_modules
if (!(existsSync("node_modules/@fortawesome/fontawesome-free") || existsSync("node_modules/@fortawesome/fontawesome-pro"))) {
This should be done differently for Yarn Modern version, although I am not completely sure what would be the best way. Could you possibly look into this?
Many thanks for your help!
Hi,
I see WOFF, EOT, SVG are not produced in version 4, but were in version 3.
May I ask what was behind that decision ? is it just about modern browser support ?
TTF and WOFF2 are great, but I need to add WOFF for some (unfortunate) IE11 legacy support for a project.
I've added the targetFormat - is that enough ? or do I have to do something else ?
Are you planning to make the targetFormats configurable via arguments in the function - this would be great :)
diff --git a/node_modules/fontawesome-subset/dist/index.js b/node_modules/fontawesome-subset/dist/index.js
index e80b450..84a37aa 100644
--- a/node_modules/fontawesome-subset/dist/index.js
+++ b/node_modules/fontawesome-subset/dist/index.js
@@ -14,6 +14,7 @@ const subset_font_1 = __importDefault(require("subset-font"));
const yaml_1 = __importDefault(require("yaml"));
const utils_1 = require("./utils");
const OUTPUT_FORMATS = [
+ { targetFormat: "woff", fileExt: "woff" },
{ targetFormat: "woff2", fileExt: "woff2" },
{ targetFormat: "sfnt", fileExt: "ttf" },
];
Hi,
Could you please provide an example for "Run via your favorite task manager" ?
I'm new to this and I'm not even sure if you mean Webpack or Grunt or something else.
An example you're using would be welcome.
Thanks!
hoping that this will save time to the one after me, here's my code for generating the all.css files only with the necessary stuff like font-awsome subsetter app does :)
//sets is the same as the object you pass to fontawesomeSubset
const all_icons = Object.values(sets).flat(1);
const vars = fs.readFileSync('node_modules/@fortawesome/fontawesome-pro/scss/_variables.scss', 'utf8').split('\n')
.filter(l => l.startsWith('$fa-var-'))
.map(l => l.match(/\$fa-var-([^:]+): \\([^:]+);/).slice(1, 3)); //[ico, code]
const css = [];
css.push(`/*!
* Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license (Commercial License)
*/
.fa, .fab, .fad, .fal, .far, .fas {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
line-height: 1
}
.fa-lg {
font-size: 1.33333em;
line-height: .75em;
vertical-align: -.0667em
}
.fa-xs {
font-size: .75em
}
.fa-sm {
font-size: .875em
}
.fa-1x {
font-size: 1em
}
.fa-2x {
font-size: 2em
}
.fa-3x {
font-size: 3em
}
.fa-4x {
font-size: 4em
}
.fa-5x {
font-size: 5em
}
.fa-6x {
font-size: 6em
}
.fa-7x {
font-size: 7em
}
.fa-8x {
font-size: 8em
}
.fa-9x {
font-size: 9em
}
.fa-10x {
font-size: 10em
}
.fa-fw {
text-align: center;
width: 1.25em
}
.fa-ul {
list-style-type: none;
margin-left: 2.5em;
padding-left: 0
}
.fa-ul > li {
position: relative
}
.fa-li {
left: -2em;
position: absolute;
text-align: center;
width: 2em;
line-height: inherit
}
.fa-border {
border: .08em solid #eee;
border-radius: .1em;
padding: .2em .25em .15em
}
.fa-pull-left {
float: left
}
.fa-pull-right {
float: right
}
.fa.fa-pull-left, .fab.fa-pull-left, .fal.fa-pull-left, .far.fa-pull-left, .fas.fa-pull-left {
margin-right: .3em
}
.fa.fa-pull-right, .fab.fa-pull-right, .fal.fa-pull-right, .far.fa-pull-right, .fas.fa-pull-right {
margin-left: .3em
}
.fa-spin {
-webkit-animation: fa-spin 2s linear infinite;
animation: fa-spin 2s linear infinite
}
.fa-pulse {
-webkit-animation: fa-spin 1s steps(8) infinite;
animation: fa-spin 1s steps(8) infinite
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg)
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn)
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg)
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn)
}
}
.fa-rotate-90 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
-webkit-transform: rotate(90deg);
transform: rotate(90deg)
}
.fa-rotate-180 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
-webkit-transform: rotate(180deg);
transform: rotate(180deg)
}
.fa-rotate-270 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
-webkit-transform: rotate(270deg);
transform: rotate(270deg)
}
.fa-flip-horizontal {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
-webkit-transform: scaleX(-1);
transform: scaleX(-1)
}
.fa-flip-vertical {
-webkit-transform: scaleY(-1);
transform: scaleY(-1)
}
.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical, .fa-flip-vertical {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"
}
.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {
-webkit-transform: scale(-1);
transform: scale(-1)
}
:root .fa-flip-both, :root .fa-flip-horizontal, :root .fa-flip-vertical, :root .fa-rotate-90, :root .fa-rotate-180, :root .fa-rotate-270 {
-webkit-filter: none;
filter: none
}
.fa-stack {
display: inline-block;
height: 2em;
line-height: 2em;
position: relative;
vertical-align: middle;
width: 2.5em
}
.fa-stack-1x, .fa-stack-2x {
left: 0;
position: absolute;
text-align: center;
width: 100%
}
.fa-stack-1x {
line-height: inherit
}
.fa-stack-2x {
font-size: 2em
}
.fa-inverse {
color: #fff
}
`);
css.push(...vars.filter(([ico]) => all_icons.includes(ico)).map(([ico, code]) => `.fa-${ico}:before{content:"\\${code}"}`));
css.push(`.sr-only {
border: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px
}
.sr-only-focusable:active, .sr-only-focusable:focus {
clip: auto;
height: auto;
margin: 0;
overflow: visible;
position: static;
width: auto
}
@font-face {
font-family: "Font Awesome 5 Brands";
font-style: normal;
font-weight: 400;
font-display: block;
src: url(../webfonts/fa-brands-400.eot);
src: url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"), url(../webfonts/fa-brands-400.woff2) format("woff2"), url(../webfonts/fa-brands-400.woff) format("woff"), url(../webfonts/fa-brands-400.ttf) format("truetype"), url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")
}
.fab {
font-family: "Font Awesome 5 Brands";
font-weight: 400
}
@font-face {
font-family: "Font Awesome 5 Duotone";
font-style: normal;
font-weight: 900;
font-display: block;
src: url(../webfonts/fa-duotone-900.eot);
src: url(../webfonts/fa-duotone-900.eot?#iefix) format("embedded-opentype"), url(../webfonts/fa-duotone-900.woff2) format("woff2"), url(../webfonts/fa-duotone-900.woff) format("woff"), url(../webfonts/fa-duotone-900.ttf) format("truetype"), url(../webfonts/fa-duotone-900.svg#fontawesome) format("svg")
}
.fad {
position: relative;
font-family: "Font Awesome 5 Duotone";
font-weight: 900
}
.fad:before {
position: absolute;
color: var(--fa-primary-color, inherit);
opacity: 1;
opacity: var(--fa-primary-opacity, 1)
}
.fad:after {
color: var(--fa-secondary-color, inherit)
}
.fa-swap-opacity .fad:before, .fad.fa-swap-opacity:before, .fad:after {
opacity: .4;
opacity: var(--fa-secondary-opacity, .4)
}
.fa-swap-opacity .fad:after, .fad.fa-swap-opacity:after {
opacity: 1;
opacity: var(--fa-primary-opacity, 1)
}
.fad.fa-inverse {
color: #fff
}
.fad.fa-stack-1x, .fad.fa-stack-2x {
position: absolute
}
.fad.fa-fw:before, .fad.fa-stack-1x:before, .fad.fa-stack-2x:before {
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%)
}
`);
css.push(...vars.filter(([ico]) => sets.duotone.includes(ico)).map(([ico, code]) => `.fad.fa-${ico}:after{content:"\\10${code}"}`));
css.push(`@font-face {
font-family: "Font Awesome 5 Pro";
font-style: normal;
font-weight: 300;
font-display: block;
src: url(../webfonts/fa-light-300.eot);
src: url(../webfonts/fa-light-300.eot?#iefix) format("embedded-opentype"), url(../webfonts/fa-light-300.woff2) format("woff2"), url(../webfonts/fa-light-300.woff) format("woff"), url(../webfonts/fa-light-300.ttf) format("truetype"), url(../webfonts/fa-light-300.svg#fontawesome) format("svg")
}
.fal {
font-weight: 300
}
@font-face {
font-family: "Font Awesome 5 Pro";
font-style: normal;
font-weight: 400;
font-display: block;
src: url(../webfonts/fa-regular-400.eot);
src: url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"), url(../webfonts/fa-regular-400.woff2) format("woff2"), url(../webfonts/fa-regular-400.woff) format("woff"), url(../webfonts/fa-regular-400.ttf) format("truetype"), url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")
}
.fal, .far {
font-family: "Font Awesome 5 Pro"
}
.far {
font-weight: 400
}
@font-face {
font-family: "Font Awesome 5 Pro";
font-style: normal;
font-weight: 900;
font-display: block;
src: url(../webfonts/fa-solid-900.eot);
src: url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"), url(../webfonts/fa-solid-900.woff2) format("woff2"), url(../webfonts/fa-solid-900.woff) format("woff"), url(../webfonts/fa-solid-900.ttf) format("truetype"), url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")
}
.fa, .fas {
font-family: "Font Awesome 5 Pro";
font-weight: 900
}
`);
const cssStr = css.map(c => c.replaceAll("\n\n", "\n")).join("\n");
Using Font Awesome 5 Free: how do I generate a set of the following icons:
fas fa-at
, fab fa-twitter
, far fa-circle
These are all part of Free, but use different prefixes (fas, fab, far).
This does not seem to work:
const fontawesomeSubset = require('fontawesome-subset');
fontawesomeSubset({
regular: ['circle'],
solid: ['at'],
brand: ['twitter']
},
'output',
{
package: 'free'
}
);
How can I accomplish this?
It appears version 6 no longer ships with the webfont svgs - just sprite sheets. Is that fatal for this project?
I just got started using your awesome tool and simply tried to get
import { fontawesomeSubset } from "fontawesome-subset";
fontawesomeSubset(
["check", "square", "caret-up"],
"sass/webfonts"
)
working. I installed FontAwesome Pro follolwing the instructions and got the feedback
Unable to find either the Free or Pro FontAwesome files in node_modules folder. Double-check that you have your preferred fontawesome package as a dependency in `package.json` and rerun the installation.
This is a bit confusing because it seems that if options are omitted the fallback is free
and the FontAwesome Free installation is not found while the Pro installation is present and correct. Adding
{ package: "pro" }
Afaik the feedback could be improved by pointing out that using pro requires the package
property set. My proposal:
Unable to find either the Free or Pro FontAwesome files in node_modules folder. Double-check that you have your preferred fontawesome package as a dependency in `package.json` and rerun the installation. You need to specify `package: "pro"` in `fontawesomeSubset` arguments in case you're using FontAwesome Pro.
Or maybe that's not how it's supposed to work and there's a bug in the auto-detection of free/pro or you want to implement such a detection right away.
experienced with 4.3.0
Some duotone icons fail subsetting. For example:
fontawesomeSubset({
duotone: ['sort']
},
'sass/webfonts',
{
package: 'pro'
});
Results in:
/node_modules/svg2ttf/lib/svg.js:18
if (pathElem.hasAttribute('d')) {
^
TypeError: Cannot read properties of undefined (reading 'hasAttribute')
at getGlyph (/node_modules/svg2ttf/lib/svg.js:18:18)
at /node_modules/svg2ttf/lib/svg.js:160:17
at /node_modules/lodash/lodash.js:4943:15
at Function.forEach (/node_modules/lodash/lodash.js:9410:14)
at Object.load (/node_modules/svg2ttf/lib/svg.js:159:5)
at svg2ttf (/node_modules/svg2ttf/index.js:22:21)
at fontawesomeSubset (node_modules/fontawesome-subset/dist/index.js:101:48)
Looking at Line 99 in index.js
const svgContentsNew = svgFile.replace(new RegExp(`(<glyph glyph-name="(${glyphsToRemove.join("|")})".*?\\/>)`, "gms"), "").replace(/>\s+</gms, "><");
svgContentsNew for this svg outputs 2 glyphs, "sort-primary" and "sort-secondary". I believe svg2ttf fails on some duotone icons because one of the glyphs have no "d" attribute. Here's a sample of the output:
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" ><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><metadata>
Created by FontForge 20201107 at Wed Aug 4 12:24:16 2021
By Robert Madole
Copyright (c) Font Awesome
</metadata><!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><defs><font id="FontAwesome5Duotone-Solid"><font-face
font-family="Font Awesome 5 Duotone Solid"/><missing-glyph /><glyph glyph-name="sort-primary" unicode=""/><glyph glyph-name="sort-secondary" unicode="􏃜" d="..." /></font></defs></svg>
Edit: Removed some icon specific stuff, I shouldn't have pasted the full icon output here due to license restrictions.
Could you add a way to make the src directories or files instead of manually adding your icon names?
On a big project this is quite difficult to maintain currently
How can I add doutone on webfonts generation ?
**Using Gulp. I'm possibly doing something wrong.
From my Gulpfile**
const fontawesomeSubset = require('fontawesome-subset');
function fa() { fontawesomeSubset(['home'], './web/dist/webfonts/fasubset'); }
My commands
c:\ gulp fa
I get the following error:
c:\ node_modules\fontawesome-subset\dist\index.js:84
var svgContentsNew = svgFile.replace(new RegExp("(<glyph glyph-name="(" + glyphsToRemove.join("|") + ")".*?\/>)", "gms"), "").replace(/>\s+</gms, "><");
^
SyntaxError: Invalid regular expression flags
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:607:28)
at Object.Module._extensions..js (module.js:654:10)
at Module.load (module.js:556:32)
at tryModuleLoad (module.js:499:12)
at Function.Module._load (module.js:491:3)
at Module.require (module.js:587:17)
at require (internal/module.js:11:18)
at Object. (c:\gulpfile.js:12:29)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.