tabler-icons/packages/icons-webfont/.build/build-outline.mjs

136 lines
4.8 KiB
JavaScript

import outlineStroke from 'svg-outline-stroke'
import { asyncForEach, getAllIcons, getCompileOptions, getPackageDir, HOME_DIR } from '../../../.build/helpers.mjs'
import fs from 'fs'
import { resolve, basename } from 'path'
import crypto from 'crypto'
import { glob } from 'glob'
import { optimize } from 'svgo'
import { fixOutline } from './fix-outline.mjs'
const DIR = getPackageDir('icons-webfont')
const strokes = {
200: 1,
300: 1.5,
400: 2,
}
const buildOutline = async () => {
let filesList = {}
const icons = getAllIcons(true)
const compileOptions = getCompileOptions()
for (const strokeName in strokes) {
const stroke = strokes[strokeName]
await asyncForEach(Object.entries(icons), async ([type, icons]) => {
fs.mkdirSync(resolve(DIR, `icons-outlined/${strokeName}/${type}`), { recursive: true })
filesList[type] = []
await asyncForEach(icons, async function ({ name, content, unicode }) {
if (compileOptions.includeIcons.length === 0 || compileOptions.includeIcons.indexOf(name) >= 0) {
if (unicode) {
console.log(`Stroke ${strokeName} for:`, name, unicode)
let filename = `${name}.svg`
if (unicode) {
filename = `u${unicode.toUpperCase()}-${name}.svg`
}
filesList[type].push(filename)
content = content
.replace('width="24"', 'width="1000"')
.replace('height="24"', 'height="1000"')
content = content
.replace('stroke-width="2"', `stroke-width="${stroke}"`)
const cachedFilename = `u${unicode.toUpperCase()}-${name}.svg`;
if (unicode && fs.existsSync(resolve(DIR, `icons-outlined/${strokeName}/${type}/${cachedFilename}`))) {
// Get content
let cachedContent = fs.readFileSync(resolve(DIR, `icons-outlined/${strokeName}/${type}/${cachedFilename}`), 'utf-8')
// Get hash
let cachedHash = '';
cachedContent = cachedContent.replace(/<!--\!cache:([a-z0-9]+)-->/, function (m, hash) {
cachedHash = hash;
return '';
})
// Check hash
if (crypto.createHash('sha1').update(cachedContent).digest("hex") === cachedHash) {
console.log('Cached stroke for:', name, unicode)
return true;
}
}
await outlineStroke(content, {
optCurve: true,
steps: 4,
round: 0,
centerHorizontally: true,
fixedWidth: false,
color: 'black'
}).then(outlined => {
// Fix outline direction (using JS instead of fontforge)
const fixed = fixOutline(outlined)
// Optimize with svgo (in memory, no subprocess)
const optimized = optimize(fixed, { multipass: true }).data
// Prepare final content with hash
const finalContent = optimized.replace(/\n/g, ' ').trim()
const hashString = `<!--!cache:${crypto.createHash('sha1').update(finalContent).digest("hex")}-->`
// Save file (single write instead of 3 file operations)
fs.writeFileSync(
resolve(DIR, `icons-outlined/${strokeName}/${type}/${filename}`),
finalContent + hashString,
'utf-8'
)
}).catch(error => console.log(error))
}
}
})
})
// Remove old files
await asyncForEach(Object.entries(icons), async ([type, icons]) => {
const existedFiles = (await glob(resolve(DIR, `icons-outlined/${strokeName}/${type}/*.svg`))).map(file => basename(file))
existedFiles.forEach(file => {
if (filesList[type].indexOf(file) === -1) {
console.log('Remove:', file)
fs.unlinkSync(resolve(DIR, `icons-outlined/${strokeName}/${type}/${file}`))
}
})
})
// Copy icons from firs to all directory
await asyncForEach(Object.entries(icons), async ([type, icons]) => {
fs.mkdirSync(resolve(DIR, `icons-outlined/${strokeName}/all`), { recursive: true })
await asyncForEach(icons, async function ({ name, unicode }) {
const iconName = `u${unicode.toUpperCase()}-${name}`
if (fs.existsSync(resolve(DIR, `icons-outlined/${strokeName}/${type}/${iconName}.svg`))) {
// Copy file
console.log(`Copy ${iconName} to all directory`)
fs.copyFileSync(
resolve(DIR, `icons-outlined/${strokeName}/${type}/${iconName}.svg`),
resolve(DIR, `icons-outlined/${strokeName}/all/${iconName}${type !== 'outline' ? `-${type}` : ''}.svg`)
)
}
})
})
}
console.log('Done')
}
await buildOutline()