Added asset manifest generation

This commit is contained in:
squidfunk 2021-02-21 17:35:11 +01:00
parent 029e5d80d0
commit eb819535f6
4 changed files with 74 additions and 19 deletions

View File

@ -36,7 +36,7 @@ input {
color: var(--md-typeset-color); color: var(--md-typeset-color);
font-feature-settings: "kern", "liga"; font-feature-settings: "kern", "liga";
font-family: font-family:
var(--md-text-font-family,) var(--md-text-font-family, _),
-apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif; -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
} }
@ -47,7 +47,7 @@ kbd {
color: var(--md-typeset-color); color: var(--md-typeset-color);
font-feature-settings: "kern"; font-feature-settings: "kern";
font-family: font-family:
var(--md-code-font-family,) var(--md-code-font-family, _),
SFMono-Regular, Consolas, Menlo, monospace; SFMono-Regular, Consolas, Menlo, monospace;
} }

View File

@ -120,8 +120,8 @@
/> />
<style> <style>
:root { :root {
--md-text-font-family: "{{ font.text }}",; --md-text-font-family: "{{ font.text }}";
--md-code-font-family: "{{ font.code }}",; --md-code-font-family: "{{ font.code }}";
} }
</style> </style>
{% endif %} {% endif %}

View File

@ -24,17 +24,21 @@ import { createHash } from "crypto"
import * as fs from "fs/promises" import * as fs from "fs/promises"
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, defer, from, merge, of } from "rxjs" import { EMPTY, concat, defer, from, merge, of } from "rxjs"
import { import {
concatMap, concatMap,
map, map,
mergeMap,
switchMap, switchMap,
takeWhile toArray
} from "rxjs/operators" } from "rxjs/operators"
import { extendDefaultPlugins, optimize } from "svgo" import {
extendDefaultPlugins,
optimize
} from "svgo"
import { copyAll } from "./copy" import { copy, copyAll } from "./copy"
import { base, resolve } from "./resolve" import { base, cachebust, resolve } from "./resolve"
import { import {
transformScript, transformScript,
transformStyle transformStyle
@ -176,24 +180,53 @@ const javascripts$ = resolve("**/{bundle,search}.ts", { cwd: "src" })
) )
/* Add content hashes to assets and replace occurrences */ /* Add content hashes to assets and replace occurrences */
const manifest$ = defer(() => resolve(`${base}/**/*.{css,js}`) const manifest$ = defer(() => process.argv.includes("--optimize")
? resolve("**/*.{css,js}", { cwd: base })
: EMPTY
)
.pipe( .pipe(
takeWhile(() => process.argv.includes("--optimize")), concatMap(file => from(fs.readFile(`${base}/${file}`, "utf8"))
concatMap(asset => from(fs.readFile(asset, "utf8"))
.pipe( .pipe(
map(data => createHash("sha256").update(data).digest("hex")), map(data => createHash("sha256").update(data).digest("hex")),
switchMap(hash => of(`${asset}`, `${asset}.map`) switchMap(hash => of(`${file}`, `${file}.map`)
.pipe( .pipe(
switchMap(file => fs.rename( concatMap(part => cachebust(part, hash, { cwd: base }))
file,
file.replace(/\b(?=\.)/, `.${hash.slice(0, 8)}.min`)
))
) )
) )
) )
) ),
toArray(),
map(tuples => new Map(tuples)),
mergeMap(manifest => concat(
// TODO: split this into two. manifest + cachebust!
...["base.html", "overrides/main.html"]
.map(file => copy({
src: `${base}/${file}`,
out: `${base}/${file}`,
transform: async data => [...manifest.entries()]
.reduce((content, [key, value]) => content
.replace(
new RegExp(`('|")${key}\\1`, "g"),
`$1${value}$1`
),
data
)
})),
// TODO: interate this into the actual compilation...
...[...manifest.keys()]
.filter(file => !file.endsWith(".map"))
.map(file => copy({
src: `${base}/${manifest.get(file)!}`,
out: `${base}/${manifest.get(file)!}`,
transform: async data => data.replace(
path.basename(file),
path.basename(manifest.get(file)!),
)
}))
))
) )
)
/* Copy Lunr.js search stemmers and segmenter */ /* Copy Lunr.js search stemmers and segmenter */
const stemmers$ = ["min/*.js", "tinyseg.js"] const stemmers$ = ["min/*.js", "tinyseg.js"]

View File

@ -81,3 +81,25 @@ export function mkdir(
mapTo(directory) mapTo(directory)
) )
} }
/**
* Cachebust a file using a content hash
*
* @param file - File
* @param hash - Content hash
* @param options - Options
*
* @returns Cachebusting tuple observable
*/
export function cachebust(
file: string, hash: string, options: ResolveOptions
): Observable<[string, string]> {
const name = file.replace(/\b(?=\.)/, `.${hash.slice(0, 8)}.min`)
return from(fs.rename(
`${options.cwd}/${file}`,
`${options.cwd}/${name}`
))
.pipe(
mapTo([file, name])
)
}