grunt-webfonts
Version:
SVG to webfont converter for Grunt
138 lines (120 loc) • 4.65 kB
JavaScript
/**
* grunt-webfont: fontforge engine
*
* @requires fontforge, ttfautohint 1.00+ (optional), eotlitetool.py
* @license
* Copyright Andrey Chalkin <L2jLiga> and Artem Sapegin (http://sapegin.me). All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/L2jLiga/grunt-webfonts/LICENSE
*/
;
const fs = require('node:fs');
const path = require('node:path');
const temp = require('temp');
const exec = require('node:child_process').exec;
const chalk = require('chalk');
const wf = require('../util/util');
module.exports = function fontForgeEngine(options, allDone) {
const logger = options.logger;
// Copy source files to temporary directory
const tempDir = temp.mkdirSync();
options.files.forEach((file) => {
fs.writeFileSync(path.join(tempDir, options.rename(file)), fs.readFileSync(file));
});
// Run Fontforge
const args = [
'fontforge',
'-script',
'"' + path.join(__dirname, 'fontforge/generate.py') + '"',
].join(' ');
const proc = exec(args, {maxBuffer: options.execMaxBuffer}, (err, out) => {
if (err instanceof Error && err.code === 127) {
return fontforgeNotFound();
} else if (err) {
if (err instanceof Error) {
return error(err.message);
}
// Skip some fontforge output such as copyrights. Show warnings only when no font files was created
// or in verbose mode.
const success = !!wf.generatedFontFiles(options);
const notError = /(Copyright|License |with many parts BSD |Executable based on sources from|Library based on sources from|Based on source from git)/;
const lines = err.split('\n');
const warn = [];
lines.forEach((line) => {
if (!line.match(notError) && !success) {
warn.push(line);
} else {
logger.verbose(chalk.grey('fontforge: ') + line);
}
});
if (warn.length) {
return error(warn.join('\n'));
}
}
// Trim fontforge result
const json = out.replace(/^[^{]+/, '').replace(/[^}]+$/, '');
// Parse json
let result;
try {
result = JSON.parse(json);
} catch (errorMessage) {
logger.verbose('Webfont did not receive a proper JSON result from Python script: ' + errorMessage);
return error(
'Something went wrong when running fontforge. Probably fontforge wasn’t installed correctly or one of your SVGs is too complicated for fontforge.\n\n' +
'1. Try to run Grunt in verbose mode: ' + chalk.bold('grunt --verbose webfont') + ' and see what fontforge says. Then search GitHub issues for the solution: ' + chalk.underline('https://github.com/sapegin/grunt-webfont/issues') + '.\n\n' +
'2. Try to use “node” engine instead of “fontforge”: ' + chalk.underline('https://github.com/sapegin/grunt-webfont#engine') + '\n\n' +
'3. To find “bad” icon try to remove SVGs one by one until error disappears. Then try to simplify this SVG in Sketch, Illustrator, etc.\n\n',
);
}
allDone({
fontName: path.basename(result.file),
});
});
// Send JSON with params
if (!proc) return;
proc.stdin.on('error', (err) => {
if (err.code === 'EPIPE') {
fontforgeNotFound();
}
});
proc.stderr.on('data', (data) => {
logger.verbose(data);
});
proc.stdout.on('data', (data) => {
logger.verbose(data);
});
proc.on('exit', (code) => {
if (code !== 0) {
logger.log( // cannot use error() because it will stop execution of callback of exec (which shows error message)
'fontforge process has unexpectedly closed.\n' +
'1. Try to run grunt in verbose mode to see fontforge output: ' + chalk.bold('grunt --verbose webfont') + '.\n' +
'2. If stderr maxBuffer exceeded try to increase ' + chalk.bold('execMaxBuffer') + ', see ' +
chalk.underline('https://github.com/sapegin/grunt-webfont#execMaxBuffer') + '. ',
);
}
return true;
});
const params = Object.assign({}, options, {
inputDir: tempDir,
});
proc.stdin.write(JSON.stringify(params));
proc.stdin.end();
/**
* Log error message
* @param {*} args
* @return {Boolean}
*/
function error(...args) {
logger.error.apply(null, ...args);
allDone(false);
return false;
}
/**
* Show error message when fontForge not found
* @return {void}
*/
function fontforgeNotFound() {
error('fontforge not found. Please install fontforge and all other requirements: ' + chalk.underline('https://github.com/sapegin/grunt-webfont#installation'));
}
};