zachleat / glyphhanger

Your web font utility belt. It can subset web fonts. It can find unicode-ranges for you automatically. It makes julienne fries.
https://www.zachleat.com/web/glyphhanger/
MIT License
748 stars 21 forks source link

Flag to specify name for generated font file #14

Open Paul-Hebert opened 2 years ago

Paul-Hebert commented 2 years ago

Hey, thanks for the awesome library! I found this really useful on a recent project where I needed to subset some fonts.

It would be nice to be able to specify a name for the output file via a --name flag similar to the --output flag.

My use case

I had a specific use case where this would have been helpful.

In my case I was subsetting fonts for a dynamically populated blog, so instead of crawling a page/site and creating a subset based on its contents, I made alphabet-based subsets. For example, I provide a Latin subset, as well as Latin Extended, Cyrillic, Greek, Vietnamese, etc. This works well with unicode-range since the browser just loads the subsets it needs. This is similar to how Google Fonts handles subsetting: https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght@8..144,100&display=swap

Since I was creating a number of different subsets, I wanted to give them each a different name. e.g. Inter-latin-ext.woff2 instead of Inter-subset.woff2.

I couldn't find a good way to do this, so instead I had to create the subset font, and then rename it. That ended up with a script looking like this:

const subsets = [/* subsets array */]

for (const subset of subsets) {
  // We want to wait for each subset to finish before starting the next one
  // (this is required for to make sure we rename the right file)
  await new Promise((resolve) => {
    const glyphhangerProcess = spawn(
      'glyphhanger',
      [
        `--whitelist=${subset.unicodeRange} `,
        `--subset=Inter.woff2`,
        '--output=subsets',
        '--formats=woff2',
      ],
      { stdio: 'inherit' }
    );

    glyphhangerProcess.on('close', () => {
      // I couldn't figure out a way to change the output file name in glyphhanger
      // Instead we manually change it after the file is generated
      const oldPath = path.join(
        __dirname,
        `subsets/Inter-subset.woff2`
      );
      const newPath = path.join(
        __dirname,
        `subsets/Inter-${subset.name}.woff2`
      );
      renameSync(oldPath, newPath);

      resolve();
    });
  });
}

This works fine, but it feels a little verbose, and could be quicker if we could run the subsetting tasks in tandem. I'd like to be able to do this:

const subsets = [/* subsets array */]

await Promise.all(subsets.map(async (subset) => { 
  return new Promise((resolve) => {
    const glyphhangerProcess = spawn(
      'glyphhanger',
      [
        `--whitelist=${subset.unicodeRange} `,
        `--subset=Inter.woff2`,
        '--output=subsets',
        // Set the name via a flag!
        `--name=Inter-${subset.name}`,
        '--formats=woff2',
      ],
      { stdio: 'inherit' }
    );

    glyphhangerProcess.on('close', () => {
      resolve();
    });
  });
}))

Let me know if I'm missing an option that would make this easier, or if you'd be open for a PR for this change. Thanks!