feat(metrics): improved optimizers (#680)

This commit is contained in:
Simon Lecoq
2021-11-26 05:15:36 +01:00
committed by GitHub
parent 91ed522dce
commit 490d3cf2e4
3 changed files with 80 additions and 32 deletions

View File

@@ -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 */