feat(metrics): improved optimizers (#680)
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
//Imports
|
||||
import ejs from "ejs"
|
||||
import SVGO from "svgo"
|
||||
import util from "util"
|
||||
import xmlformat from "xml-formatter"
|
||||
import * as utils from "./utils.mjs"
|
||||
|
||||
//Setup
|
||||
@@ -174,32 +172,12 @@ export default async function metrics({login, q}, {graphql, rest, plugins, conf,
|
||||
if (q["config.gemoji"])
|
||||
rendered = await imports.svg.gemojis(rendered, {rest})
|
||||
//Optimize rendering
|
||||
if (!q.raw)
|
||||
rendered = xmlformat(rendered, {lineSeparator:"\n", collapseContent:true})
|
||||
if ((conf.settings?.optimize) && (!q.raw)) {
|
||||
console.debug(`metrics/compute/${login} > optimize`)
|
||||
if (experimental.has("--optimize")) {
|
||||
const {error, data:optimized} = await SVGO.optimize(rendered, {
|
||||
multipass:true,
|
||||
plugins:SVGO.extendDefaultPlugins([
|
||||
//Additional cleanup
|
||||
{name:"cleanupListOfValues"},
|
||||
{name:"removeRasterImages"},
|
||||
{name:"removeScriptElement"},
|
||||
//Force CSS style consistency
|
||||
{name:"inlineStyles", active:false},
|
||||
{name:"removeViewBox", active:false},
|
||||
]),
|
||||
})
|
||||
if (error)
|
||||
throw new Error(`Could not optimize SVG: \n${error}`)
|
||||
rendered = optimized
|
||||
console.debug(`metrics/compute/${login} > optimize > success`)
|
||||
}
|
||||
else
|
||||
console.debug(`metrics/compute/${login} > optimize > this feature is currently disabled due to display issues (use --optimize flag in experimental features to force enable it)`)
|
||||
|
||||
}
|
||||
if ((conf.settings?.optimize === true) || (conf.settings?.optimize?.includes?.("css")))
|
||||
rendered = await imports.svg.optimize.css(rendered)
|
||||
if ((conf.settings?.optimize === true) || (conf.settings?.optimize?.includes?.("xml")))
|
||||
rendered = await imports.svg.optimize.xml(rendered, q)
|
||||
if ((conf.settings?.optimize === true) || (conf.settings?.optimize?.includes?.("svg")))
|
||||
rendered = await imports.svg.optimize.svg(rendered, q, experimental)
|
||||
//Verify svg
|
||||
if (verify) {
|
||||
console.debug(`metrics/compute/${login} > verify SVG`)
|
||||
|
||||
@@ -26,6 +26,11 @@ import emoji from "emoji-name-map"
|
||||
import minimatch from "minimatch"
|
||||
import crypto from "crypto"
|
||||
import linguist from "linguist-js"
|
||||
import purgecss from "purgecss"
|
||||
import csso from "csso"
|
||||
import SVGO from "svgo"
|
||||
import xmlformat from "xml-formatter"
|
||||
|
||||
prism_lang()
|
||||
|
||||
//Exports
|
||||
@@ -155,7 +160,7 @@ export function htmlunescape(string, u = {"&":true, "<":true, ">":true, '"':true
|
||||
|
||||
/**Chartist */
|
||||
export async function chartist() {
|
||||
const css = `<style>${await fs.readFile(paths.join(__module(import.meta.url), "../../../node_modules", "node-chartist/dist/main.css")).catch(_ => "")}</style>`
|
||||
const css = `<style data-optimizable="true">${await fs.readFile(paths.join(__module(import.meta.url), "../../../node_modules", "node-chartist/dist/main.css")).catch(_ => "")}</style>`
|
||||
return (await nodechartist(...arguments))
|
||||
.replace(/class="ct-chart-line">/, `class="ct-chart-line">${css}`)
|
||||
}
|
||||
@@ -510,6 +515,64 @@ export const svg = {
|
||||
rendered = rendered.replace(new RegExp(emoji, "g"), gemoji)
|
||||
return rendered
|
||||
},
|
||||
/**Optimizers */
|
||||
optimize:{
|
||||
/**CSS optimizer */
|
||||
async css(rendered) {
|
||||
//Extract styles
|
||||
console.debug("metrics/svg/optimize/css > optimizing")
|
||||
const regex = /<style data-optimizable="true">(?<style>[\s\S]*?)<\/style>/
|
||||
const cleaned = "<!-- (optimized css) -->"
|
||||
const css = []
|
||||
while (regex.test(rendered)) {
|
||||
const style = htmlunescape(rendered.match(regex)?.groups?.style ?? "")
|
||||
rendered = rendered.replace(regex, cleaned)
|
||||
css.push({raw:style})
|
||||
}
|
||||
const content = [{raw:rendered, extension:"html"}]
|
||||
|
||||
//Purge CSS
|
||||
const purged = await new purgecss.PurgeCSS().purge({content, css})
|
||||
const optimized = `<style>${csso.minify(purged.map(({css}) => css).join("\n")).css}</style>`
|
||||
return rendered.replace(cleaned, optimized)
|
||||
},
|
||||
/**XML optimizer */
|
||||
async xml(rendered, {raw = false} = {}) {
|
||||
console.debug("metrics/svg/optimize/xml > optimizing")
|
||||
if (raw) {
|
||||
console.debug("metrics/svg/optimize/xml > skipped as raw option is enabled")
|
||||
return rendered
|
||||
}
|
||||
return xmlformat(rendered, {lineSeparator:"\n", collapseContent:true})
|
||||
},
|
||||
/**SVG optimizer */
|
||||
async svg(rendered, {raw = false} = {}, experimental = new Set()) {
|
||||
console.debug("metrics/svg/optimize/svg > optimizing")
|
||||
if (raw) {
|
||||
console.debug("metrics/svg/optimize/svg > skipped as raw option is enabled")
|
||||
return rendered
|
||||
}
|
||||
if (!experimental.has("--optimize")) {
|
||||
console.debug("metrics/svg/optimize/svg > this feature require experimental feature flag --optimize-svg")
|
||||
return rendered
|
||||
}
|
||||
const {error, data:optimized} = await SVGO.optimize(rendered, {
|
||||
multipass:true,
|
||||
plugins:SVGO.extendDefaultPlugins([
|
||||
//Additional cleanup
|
||||
{name:"cleanupListOfValues"},
|
||||
{name:"removeRasterImages"},
|
||||
{name:"removeScriptElement"},
|
||||
//Force CSS style consistency
|
||||
{name:"inlineStyles", active:false},
|
||||
{name:"removeViewBox", active:false},
|
||||
]),
|
||||
})
|
||||
if (error)
|
||||
throw new Error(`Could not optimize SVG: \n${error}`)
|
||||
return optimized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**Wait */
|
||||
|
||||
@@ -106,8 +106,14 @@ inputs:
|
||||
# Some templates may not support this option
|
||||
optimize:
|
||||
description: SVG optimization
|
||||
type: boolean
|
||||
default: yes
|
||||
type: array
|
||||
default: css, xml
|
||||
format:
|
||||
- comma-separated
|
||||
values:
|
||||
- css # Purge and minify CSS styles
|
||||
- xml # Pretty-print XML
|
||||
- svg # Optimize SVG with SVGO (experimental, require --optimize-svg flag)
|
||||
|
||||
# Setup additional templates from remote repositories
|
||||
setup_community_templates:
|
||||
@@ -280,13 +286,14 @@ inputs:
|
||||
default: no
|
||||
|
||||
# Experimental features
|
||||
# Note that no backward compatibility are guaranteed for these features
|
||||
experimental_features:
|
||||
description: Experimental features
|
||||
type: array
|
||||
format: space-separated
|
||||
default: ""
|
||||
values:
|
||||
- --optimize
|
||||
- --optimize-svg
|
||||
|
||||
# Use mocked data to bypass external APIs
|
||||
use_mocked_data:
|
||||
|
||||
Reference in New Issue
Block a user