jaywcjlove / svgtofont

Read a set of SVG icons and ouput a TTF/EOT/WOFF/WOFF2/SVG font.
https://jaywcjlove.github.io/svgtofont
MIT License
515 stars 81 forks source link

CSS generation is overwritten on several instances #202

Open Diono opened 1 year ago

Diono commented 1 year ago

I created a node script (ts-node) to play the generations of several distinct font-icons.

svgtofont.ts :

import fs from 'fs';
import path from 'path';
import svgtofont from 'svgtofont';
import type { CSSOptions } from 'svgtofont/lib/utils';

import svgoConfig from '../conf/svgo.config';

const iconsFolder = path.join(__dirname, '../www/src/icons');

const camalize = (str: string) =>
  str.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase());

const cssOptions = (fileName: string): CSSOptions => ({
  cssPath: '../../fonticon/',
  fileName: `_${camalize(fileName)}`,
  fontSize: '1rem',
  output: 'www/src/scss/fonticon'
});

fs.readdir(iconsFolder, (err, files) => {
  files.forEach(async fileName => {
    if (fileName) {
      await svgtofont({
        css: cssOptions(fileName),
        dist: path.join(__dirname, '../www/src/fonticon'), // output path
        fontName: fileName,
        log: true,
        src: path.join(__dirname, `../www/src/icons/${fileName}`), // svg path
        svgoOptions: svgoConfig
      });

      console.log(`font icon "${fileName}" is generated!`);
    }
  });
});

My fonts are well created as well as the CSS files, if I have only one directory everything is fine.

Now, if I add a second directory, all CSS files get the code of the last generated batch.

The CSS file of the first font retrieves my files but declares the CSS classes of the 2nd batch.

The first generated CSS file: ❎ www/src/scss/fonticon/_adminFonticon.scss:

@font-face {font-family: "admin-fonticon";
  src: url('../../fonticon/admin-fonticon.eot?t=1683226649160'); /* IE9*/
  src: url('../../fonticon/admin-fonticon.eot?t=1683226649160#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url("../../fonticon/admin-fonticon.woff2?t=1683226649160") format("woff2"),
  url("../../fonticon/admin-fonticon.woff?t=1683226649160") format("woff"),
  url('../../fonticon/admin-fonticon.ttf?t=1683226649160') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
  url('../../fonticon/admin-fonticon.svg?t=1683226649160#admin-fonticon') format('svg'); /* iOS 4.1- */
}

[class^="admin-fonticon-"], [class*=" admin-fonticon-"] {
  font-family: 'admin-fonticon' !important;
  font-size: 1rem;
  font-style:normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.admin-fonticon-discord:before { content: "\ea01"; }
.admin-fonticon-facebook:before { content: "\ea02"; }
.admin-fonticon-frame:before { content: "\ea03"; }
.admin-fonticon-giphy:before { content: "\ea04"; }
.admin-fonticon-instagram:before { content: "\ea05"; }
.admin-fonticon-linkedin:before { content: "\ea06"; }
.admin-fonticon-menu:before { content: "\ea07"; }
.admin-fonticon-patreon:before { content: "\ea08"; }
.admin-fonticon-soundcloud:before { content: "\ea09"; }
.admin-fonticon-tiktok:before { content: "\ea0a"; }
.admin-fonticon-tipeee:before { content: "\ea0b"; }
.admin-fonticon-twitch:before { content: "\ea0c"; }
.admin-fonticon-twitter:before { content: "\ea0d"; }
.admin-fonticon-utip:before { content: "\ea0e"; }
.admin-fonticon-youtube:before { content: "\ea0f"; }

$admin-fonticon-discord: "\ea01";
$admin-fonticon-facebook: "\ea02";
$admin-fonticon-frame: "\ea03";
$admin-fonticon-giphy: "\ea04";
$admin-fonticon-instagram: "\ea05";
$admin-fonticon-linkedin: "\ea06";
$admin-fonticon-menu: "\ea07";
$admin-fonticon-patreon: "\ea08";
$admin-fonticon-soundcloud: "\ea09";
$admin-fonticon-tiktok: "\ea0a";
$admin-fonticon-tipeee: "\ea0b";
$admin-fonticon-twitch: "\ea0c";
$admin-fonticon-twitter: "\ea0d";
$admin-fonticon-utip: "\ea0e";
$admin-fonticon-youtube: "\ea0f";

✅ INSTEAD OF

@font-face {font-family: "admin-fonticon";
  src: url('../../fonticon/admin-fonticon.eot?t=1683226887843'); /* IE9*/
  src: url('../../fonticon/admin-fonticon.eot?t=1683226887843#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url("../../fonticon/admin-fonticon.woff2?t=1683226887843") format("woff2"),
  url("../../fonticon/admin-fonticon.woff?t=1683226887843") format("woff"),
  url('../../fonticon/admin-fonticon.ttf?t=1683226887843') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
  url('../../fonticon/admin-fonticon.svg?t=1683226887843#admin-fonticon') format('svg'); /* iOS 4.1- */
}

[class^="admin-fonticon-"], [class*=" admin-fonticon-"] {
  font-family: 'admin-fonticon' !important;
  font-size: 1rem;
  font-style:normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.admin-fonticon-add:before { content: "\ea01"; }
.admin-fonticon-cancel:before { content: "\ea02"; }
.admin-fonticon-check:before { content: "\ea03"; }
.admin-fonticon-close:before { content: "\ea04"; }
.admin-fonticon-composite:before { content: "\ea05"; }
.admin-fonticon-edit:before { content: "\ea06"; }
.admin-fonticon-embed:before { content: "\ea07"; }
.admin-fonticon-lock:before { content: "\ea08"; }
.admin-fonticon-logout:before { content: "\ea09"; }
.admin-fonticon-paragraph:before { content: "\ea0a"; }
.admin-fonticon-picture:before { content: "\ea0b"; }
.admin-fonticon-slideshow:before { content: "\ea0c"; }
.admin-fonticon-sound:before { content: "\ea0d"; }
.admin-fonticon-submit:before { content: "\ea0e"; }
.admin-fonticon-trash:before { content: "\ea0f"; }
.admin-fonticon-unlock:before { content: "\ea10"; }
.admin-fonticon-upload-image:before { content: "\ea11"; }
.admin-fonticon-video:before { content: "\ea12"; }

$admin-fonticon-add: "\ea01";
$admin-fonticon-cancel: "\ea02";
$admin-fonticon-check: "\ea03";
$admin-fonticon-close: "\ea04";
$admin-fonticon-composite: "\ea05";
$admin-fonticon-edit: "\ea06";
$admin-fonticon-embed: "\ea07";
$admin-fonticon-lock: "\ea08";
$admin-fonticon-logout: "\ea09";
$admin-fonticon-paragraph: "\ea0a";
$admin-fonticon-picture: "\ea0b";
$admin-fonticon-slideshow: "\ea0c";
$admin-fonticon-sound: "\ea0d";
$admin-fonticon-submit: "\ea0e";
$admin-fonticon-trash: "\ea0f";
$admin-fonticon-unlock: "\ea10";
$admin-fonticon-upload-image: "\ea11";
$admin-fonticon-video: "\ea12";

and the second generated CSS file ✅ www/src/scss/fonticon/_fonticon.scss:

@font-face {font-family: "fonticon";
  src: url('../../fonticon/fonticon.eot?t=1683226649161'); /* IE9*/
  src: url('../../fonticon/fonticon.eot?t=1683226649161#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url("../../fonticon/fonticon.woff2?t=1683226649161") format("woff2"),
  url("../../fonticon/fonticon.woff?t=1683226649161") format("woff"),
  url('../../fonticon/fonticon.ttf?t=1683226649161') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
  url('../../fonticon/fonticon.svg?t=1683226649161#fonticon') format('svg'); /* iOS 4.1- */
}

[class^="fonticon-"], [class*=" fonticon-"] {
  font-family: 'fonticon' !important;
  font-size: 1rem;
  font-style:normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.fonticon-discord:before { content: "\ea01"; }
.fonticon-facebook:before { content: "\ea02"; }
.fonticon-frame:before { content: "\ea03"; }
.fonticon-giphy:before { content: "\ea04"; }
.fonticon-instagram:before { content: "\ea05"; }
.fonticon-linkedin:before { content: "\ea06"; }
.fonticon-menu:before { content: "\ea07"; }
.fonticon-patreon:before { content: "\ea08"; }
.fonticon-soundcloud:before { content: "\ea09"; }
.fonticon-tiktok:before { content: "\ea0a"; }
.fonticon-tipeee:before { content: "\ea0b"; }
.fonticon-twitch:before { content: "\ea0c"; }
.fonticon-twitter:before { content: "\ea0d"; }
.fonticon-utip:before { content: "\ea0e"; }
.fonticon-youtube:before { content: "\ea0f"; }

$fonticon-discord: "\ea01";
$fonticon-facebook: "\ea02";
$fonticon-frame: "\ea03";
$fonticon-giphy: "\ea04";
$fonticon-instagram: "\ea05";
$fonticon-linkedin: "\ea06";
$fonticon-menu: "\ea07";
$fonticon-patreon: "\ea08";
$fonticon-soundcloud: "\ea09";
$fonticon-tiktok: "\ea0a";
$fonticon-tipeee: "\ea0b";
$fonticon-twitch: "\ea0c";
$fonticon-twitter: "\ea0d";
$fonticon-utip: "\ea0e";
$fonticon-youtube: "\ea0f";
Diono commented 1 year ago

It seems that the problem comes from the forEach() which does not take into account the synchronous state of my function. It plays the 2 instances in parallel.

This shouldn't normally be a problem, but it seems that the list of icons to use in the CSS is not sandboxed.

If I change my code to a for(cons ... of ...) loop, I can play the 2 instances one after another. This temporarily solves my problem but slows down the process:


import fs from 'fs';
import path from 'path';
import svgtofont from 'svgtofont';
import type { CSSOptions } from 'svgtofont/lib/utils';

import svgoConfig from '../conf/svgo.config';

const iconsFolder = path.join(__dirname, '../www/src/icons');
const camalize = (str: string) =>
  str.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase());
const cssOptions = (fileName: string): CSSOptions => ({
  cssPath: '../../fonticon/',
  fileName: `_${camalize(fileName)}`,
  fontSize: '1rem',
  output: 'www/src/scss/fonticon'
});

const buildFont = async (fileName: string) => {
  if (fileName) {
    await svgtofont({
      css: cssOptions(fileName),
      dist: path.join(__dirname, '../www/src/fonticon'), // output path
      fontName: fileName,
      log: true,
      src: path.join(__dirname, `../www/src/icons/${fileName}`), // svg path
      svgoOptions: svgoConfig
    });

    console.log(`font icon "${fileName}" is generated!`);
  }
};

fs.readdir(iconsFolder, async (err, files) => {
  for (const file of files) {
    if (file) {
      await buildFont(file);
    }
  }
});