Added back SVG optimization

This commit is contained in:
squidfunk 2021-02-21 14:34:17 +01:00
parent 45cfb1024e
commit 4d462c1667
7 changed files with 157 additions and 40 deletions

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2016-2021 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
import "~/integrations/search/worker/main"

View File

@ -355,7 +355,7 @@
"base": base_url, "base": base_url,
"features": features, "features": features,
"translations": {}, "translations": {},
"search": "assets/javascripts/worker/search.js" | url, "search": "assets/javascripts/workers/search.js" | url,
} -%} } -%}
<!-- Translations --> <!-- Translations -->

View File

@ -34,11 +34,12 @@ import { mkdir, resolve } from "../resolve"
/** /**
* Copy transform function * Copy transform function
* *
* @param content - Content * @param data - File data
* @param name - File name
* *
* @returns Transformed content * @returns Transformed file data
*/ */
type CopyTransformFn = (content: string) => Promise<string> type CopyTransformFn = (data: string, name: string) => Promise<string>
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@ -71,8 +72,8 @@ export function copy(
? from(fs.copyFile(src, out)) ? from(fs.copyFile(src, out))
: from(fs.readFile(src, "utf8")) : from(fs.readFile(src, "utf8"))
.pipe( .pipe(
switchMap(content => transform(content)), switchMap(data => transform(data, src)),
switchMap(content => fs.writeFile(out, content)) switchMap(data => fs.writeFile(out, data))
) )
), ),
mapTo(out) mapTo(out)

View File

@ -22,8 +22,9 @@
import { minify as minhtml } from "html-minifier" import { minify as minhtml } from "html-minifier"
import * as path from "path" import * as path from "path"
import { concat, merge } from "rxjs" import { concat, defer, merge } from "rxjs"
import { concatMap } from "rxjs/operators" import { concatMap, tap } from "rxjs/operators"
import { extendDefaultPlugins, optimize } from "svgo"
import { copyAll } from "./copy" import { copyAll } from "./copy"
import { base, resolve } from "./resolve" import { base, resolve } from "./resolve"
@ -48,6 +49,26 @@ function ext(file: string, extension: string): string {
return file.replace(path.extname(file), extension) return file.replace(path.extname(file), extension)
} }
/**
* Optimize SVG data
*
* This function will just pass-through non-SVG data, which makes the pipeline
* much simpler, as we can reuse it for the license texts.
*
* @param data - SVG data
*
* @returns Minified SVG data
*/
function minsvg(data: string): string {
const result = optimize(data, {
plugins: extendDefaultPlugins([
{ name: "removeDimensions", active: true },
{ name: "removeViewBox", active: false }
])
})
return result.data || data
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Program * Program
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
@ -59,28 +80,30 @@ const dependencies$ = concat(
...["*.svg", "../LICENSE"] ...["*.svg", "../LICENSE"]
.map(pattern => copyAll(pattern, { .map(pattern => copyAll(pattern, {
src: "node_modules/@mdi/svg/svg", src: "node_modules/@mdi/svg/svg",
out: `${base}/.icons/material` out: `${base}/.icons/material`,
...process.argv.includes("--optimize") && {
transform: async data => minsvg(data)
}
})), })),
/* Copy GitHub octicons */ /* Copy GitHub octicons */
...["*.svg", "../../LICENSE"] ...["*.svg", "../../LICENSE"]
.map(pattern => copyAll(pattern, { .map(pattern => copyAll(pattern, {
src: "node_modules/@primer/octicons/build/svg", src: "node_modules/@primer/octicons/build/svg",
out: `${base}/.icons/octicons` out: `${base}/.icons/octicons`,
...process.argv.includes("--optimize") && {
transform: async data => minsvg(data)
}
})), })),
/* Copy FontAwesome icons */ /* Copy FontAwesome icons */
...["**/*.svg", "../LICENSE.txt"] ...["**/*.svg", "../LICENSE.txt"]
.map(pattern => copyAll(pattern, { .map(pattern => copyAll(pattern, {
src: "node_modules/@fortawesome/fontawesome-free/svgs", src: "node_modules/@fortawesome/fontawesome-free/svgs",
out: `${base}/.icons/fontawesome` out: `${base}/.icons/fontawesome`,
})), ...process.argv.includes("--optimize") && {
transform: async data => minsvg(data)
/* Copy Lunr.js search stemmers and segmenter */ }
...["min/*.js", "tinyseg.js"]
.map(pattern => copyAll(pattern, {
src: "node_modules/lunr-languages",
out: `${base}/assets/javascripts/lunr`
})) }))
) )
@ -98,7 +121,7 @@ const assets$ = concat(
copyAll("**/*.html", { copyAll("**/*.html", {
src: "src", src: "src",
out: base, out: base,
transform: async content => { transform: async data => {
const metadata = require("../package.json") const metadata = require("../package.json")
const banner = const banner =
"{#-\n" + "{#-\n" +
@ -106,7 +129,7 @@ const assets$ = concat(
"-#}\n" "-#}\n"
/* Normalize line feeds and minify HTML */ /* Normalize line feeds and minify HTML */
const html = content.replace(/\r\n/gm, "\n") const html = data.replace(/\r\n/gm, "\n")
return banner + minhtml(html, { return banner + minhtml(html, {
collapseBooleanAttributes: true, collapseBooleanAttributes: true,
includeAutoGeneratedTags: false, includeAutoGeneratedTags: false,
@ -136,36 +159,38 @@ const stylesheets$ = resolve("**/[!_]*.scss", { cwd: "src" })
})) }))
) )
/* Transform scripts with ESBuild */ /* Transform stylesheets with SASS and PostCSS */
const javascripts$ = merge( const javascripts$ = resolve("**/{bundle,search}.ts", { cwd: "src" })
.pipe(
/* Transform application */ concatMap(file => transformScript({
transformScript({ src: `src/${file}`,
src: "src/assets/javascripts/index.ts", out: ext(`${base}/${file}`, ".js")
out: `${base}/assets/javascripts/bundle.js` }))
}),
/* Transform application overrides */
transformScript({
src: "src/overrides/assets/javascripts/index.ts",
out: `${base}/overrides/assets/javascripts/bundle.js`
}),
/* Transform search worker */
transformScript({
src: "src/assets/javascripts/integrations/search/worker/main/index.ts",
out: `${base}/assets/javascripts/worker/search.js`
})
) )
/* Compile everything */ /* Add content hashes to files and replace occurrences */
const manifest$ = defer(() => resolve("**/*.{css,js}", {cwd: base })
.pipe(tap(console.log)))
/* Copy Lunr.js search stemmers and segmenter */
const stemmers$ = ["min/*.js", "tinyseg.js"]
.map(pattern => copyAll(pattern, {
src: "node_modules/lunr-languages",
out: `${base}/assets/javascripts/lunr`
}))
/* ------------------------------------------------------------------------- */
/* Put everything together */
concat( concat(
dependencies$, dependencies$,
merge( merge(
assets$, assets$,
stylesheets$, stylesheets$,
javascripts$ javascripts$
) ),
manifest$,
stemmers$
) )
.subscribe() .subscribe()
// .subscribe(console.log) // .subscribe(console.log)

68
typings/svgo/index.d.ts vendored Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016-2021 Martin Donath <martin.donath@squidfunk.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* ----------------------------------------------------------------------------
* Types
* ------------------------------------------------------------------------- */
declare module "svgo" {
/**
* Plugin
*/
interface Plugin {
name: string
active: boolean
}
/**
* Optimization configuration
*/
interface OptimizeConfig {
plugins: Plugin[]
}
/**
* Optimization result
*/
interface OptimizeResult {
data: string
}
/**
* Optimize SVG
*
* @param data - SVG data
*
* @returns Optimization result
*/
function optimize(data: string, config: OptimizeConfig): OptimizeResult
/**
* Extend the list of default plugins
*
* @param plugins - Plugins
*
* @returns Plugins
*/
function extendDefaultPlugins(plugins: Plugin[]): Plugin[]
}