Skip to content
Snippets Groups Projects

Task update2024

Merged Johannes Kreiner requested to merge task_update2024 into master
Compare and Show latest version
18 files
+ 130
143
Compare changes
  • Side-by-side
  • Inline
Files
18
const path = require('path');
const mustache = require('mustache');
const fs = require('fs');
const parseXmlStringSync = require('xml2js-parser').parseStringSync;
const globby = require('globby');
const _ = require('underscore');
const svgToMiniDataURI = require('mini-svg-data-uri');
const imagemin = require('imagemin');
const imageminSvgo = require('imagemin-svgo');
module.exports = class InlineSvg {
import path from 'node:path';
import mustache from 'mustache';
import fs from 'node:fs';
import pkg from 'xml2js-parser';
const { parseStringSync } = pkg;
import * as globby from 'globby';
import _ from 'underscore';
import svgToMiniDataURI from 'mini-svg-data-uri';
import imagemin from 'imagemin';
import imageminSvgo from 'imagemin-svgo';
import { Buffer } from 'node:buffer';
export class InlineSvg {
/**
* Kick things off
*
* @param {String} _svgFilePath The path to the folder containing the SVGs
* @param {Object} _options Configuration object
* @returns {Promise}
*/
constructor(_svgFilePath, _options) {
let defaultOptions = {
template: __dirname + '/template.mustache',
template: './template.mustache',
context: {},
interceptor: null
interceptor: null,
};
this._files = {};
this._svgs = [];
this._options = _.extend(defaultOptions, _options);
return this._process(_svgFilePath);
this._svgFilePath = _svgFilePath;
}
static async create(_svgFilePath, _options) {
const instance = new InlineSvg(_svgFilePath, _options);
return instance._process(_svgFilePath);
}
/**
* Process all SVG files
*
* @param {String} _svgFilePath The path to the folder containing the SVGs
* @param {string} _svgFilePath The path to the folder containing the SVGs
*/
async _process(_svgFilePath) {
return new Promise(async (_resolve, _reject) => {
try {
let svgs = await this._readFiles(_svgFilePath);
let templateContent = await imagemin.buffer(this._getTemplateContent(), {
plugins: [
imageminSvgo()
]
});
svgs.forEach(svg => this._processSvg(svg, _svgFilePath));
let template = mustache.render(
templateContent.toString(),
_.extend(
{},
this._options.context,
{
svgs: this._svgs
}
)
);
_resolve(template);
} catch (e) {
console.log(e);
}
});
try {
let svgs = await this._readFiles(_svgFilePath);
let templateContent = this._getTemplateContent();
// Convert string to Buffer before passing to imagemin
let optimizedTemplateBuffer = await imagemin.buffer(Buffer.from(templateContent), {
plugins: [imageminSvgo()],
});
svgs.forEach((svg) => this._processSvg(svg, _svgFilePath));
let template = mustache.render(
Buffer.from(optimizedTemplateBuffer).toString('utf8'),
_.extend({}, this._options.context, {
svgs: this._svgs,
}),
);
return template;
} catch (error) {
console.error('Template processing error:', error);
throw error;
}
}
/**
@@ -72,48 +74,63 @@ module.exports = class InlineSvg {
* @param {String} _svgFilePath Original File Path from the fetched SVG
*/
_processSvg(_data, _svgFilePath) {
const xmlString = parseXmlStringSync(_data.content.toString(), {
attrNameProcessors: [name => name.toLowerCase()]
const xmlString = parseStringSync(_data.content.toString(), {
attrNameProcessors: [(name) => name.toLowerCase()],
});
const svgDimensions = this._getSvgDimensions(xmlString);
const _svgFilePathAdjusted = _svgFilePath.replace('**', '');
const svgData = {
name: _data.fileName.replace(_svgFilePathAdjusted, '').replace(/\//g, '-').replace('.svg', '').replace('fontawesome-', ''),
name: _data.fileName
.replace(_svgFilePathAdjusted, '')
.replaceAll('/', '-')
.replace('.svg', '')
.replace('fontawesome-', ''),
// add fill="white" to allow later color changes based on this value
inline: svgToMiniDataURI(_data.content.indexOf('fill=') === -1 ? _data.content.replace('<svg', '<svg fill="white"') : _data.content),
width: parseInt(svgDimensions.width) + 'px',
height: parseInt(svgDimensions.height) + 'px',
dimensions: svgDimensions
inline: svgToMiniDataURI(
_data.content.includes('fill=')
? _data.content
: _data.content.replace('<svg', '<svg fill="white"'),
),
width: Number.parseInt(svgDimensions.width) + 'px',
height: Number.parseInt(svgDimensions.height) + 'px',
dimensions: svgDimensions,
};
// store this svg data
this._svgs.push(
_.isFunction(this._options.interceptor)
? _.extend({}, svgData, this._options.interceptor(svgData) || svgData)
: svgData
: svgData,
);
}
/**
* Extracts the dimensions from the SVG source
*
* @param {String} xmlString The SVG source
* @param {Object} xmlString The parsed SVG XML object
* @returns {Object}
*/
_getSvgDimensions(xmlString) {
const hasWidthHeightAttr = xmlString.svg.$['width'] && xmlString.svg.$['width'];
const hasWidthHeightAttribute = xmlString.svg.$['width'] && xmlString.svg.$['height'];
let width;
let height;
if (hasWidthHeightAttr) {
width = parseInt(xmlString.svg.$['width']);
height = parseInt(xmlString.svg.$['height']);
if (hasWidthHeightAttribute) {
width = Number.parseInt(xmlString.svg.$['width']);
height = Number.parseInt(xmlString.svg.$['height']);
} else {
width = parseInt(xmlString.svg.$['viewbox'].toString().replace(/^\d+\s\d+\s(\d+\.?[\d])\s(\d+\.?[\d])/, "$1"));
height = parseInt(xmlString.svg.$['viewbox'].toString().replace(/^\d+\s\d+\s(\d+\.?[\d])\s(\d+\.?[\d])/, "$2"));
width = Number.parseInt(
xmlString.svg.$['viewbox']
.toString()
.replace(/^\d+\s\d+\s(\d+\.?[\d])\s(\d+\.?[\d])/, '$1'),
);
height = Number.parseInt(
xmlString.svg.$['viewbox']
.toString()
.replace(/^\d+\s\d+\s(\d+\.?[\d])\s(\d+\.?[\d])/, '$2'),
);
}
return {
width,
height
height,
};
}
@@ -124,18 +141,16 @@ module.exports = class InlineSvg {
* @returns {Promise}
*/
async _readFiles(_path) {
return new Promise(async (resolve, reject) => {
let files = await globby(path.join(_path, '*.svg'));
let svgs = [];
await files.forEach(async _file => {
let content = fs.readFileSync(_file, 'utf-8');
svgs.push({
fileName: _file,
content: content
});
const files = await globby.globby(path.join(_path, '*.svg'));
const svgs = [];
files.forEach((_file) => {
const content = fs.readFileSync(_file, 'utf8');
svgs.push({
fileName: _file,
content: content,
});
resolve(svgs);
})
});
return svgs;
}
/**
@@ -144,6 +159,6 @@ module.exports = class InlineSvg {
* @returns {String}
*/
_getTemplateContent() {
return fs.readFileSync(this._options.template);
return fs.readFileSync(this._options.template, 'utf8');
}
};
}
Loading