De-gulpify: css, fonts, images
This commit is contained in:
parent
dccb5f716c
commit
3bab0a1715
58
lib/hash.ts
58
lib/hash.ts
|
@ -1,7 +1,7 @@
|
|||
import { Transform } from "node:stream";
|
||||
import { createHash } from "node:crypto";
|
||||
import File from "vinyl";
|
||||
import { PRODUCTION } from "./environment.js";
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
function fileHash(buffer: Buffer) {
|
||||
const hash = createHash("sha256");
|
||||
|
@ -9,28 +9,44 @@ function fileHash(buffer: Buffer) {
|
|||
return hash.digest("hex");
|
||||
}
|
||||
|
||||
const hashPath =
|
||||
(mappings: Map<string, string>) =>
|
||||
(file: File): File => {
|
||||
const hash = PRODUCTION ? fileHash(file.contents as Buffer) : "00000000";
|
||||
const newName = [
|
||||
file.basename.substring(0, file.basename.length - file.extname.length),
|
||||
hash.substring(0, 8),
|
||||
file.extname.substring(1),
|
||||
].join(".");
|
||||
|
||||
mappings.set(file.basename, newName);
|
||||
file.basename = newName;
|
||||
|
||||
return file;
|
||||
};
|
||||
|
||||
export default function (manifestName: string) {
|
||||
const mappings: { [path: string]: string } = {};
|
||||
return (observable: Observable<File>): Observable<File> =>
|
||||
new Observable((subscriber) => {
|
||||
const mappings = new Map<string, string>();
|
||||
const hash = hashPath(mappings);
|
||||
|
||||
return new Transform({
|
||||
objectMode: true,
|
||||
transform(chunk: File, _, callback) {
|
||||
const hash = PRODUCTION ? fileHash(chunk.contents as Buffer) : "00000000";
|
||||
const newName = `${chunk.basename.substring(0, chunk.basename.length - chunk.extname.length)}.${hash.substring(0, 8)}${chunk.extname}`;
|
||||
observable.subscribe({
|
||||
next(file) {
|
||||
subscriber.next(hash(file));
|
||||
},
|
||||
error(e) {
|
||||
subscriber.error(e);
|
||||
},
|
||||
complete() {
|
||||
const mappingFile = new File({
|
||||
path: manifestName,
|
||||
contents: Buffer.from(JSON.stringify(Object.fromEntries(mappings))),
|
||||
});
|
||||
|
||||
mappings[chunk.basename] = newName;
|
||||
chunk.basename = newName;
|
||||
|
||||
callback(null, chunk);
|
||||
},
|
||||
final(callback) {
|
||||
const mappingFile = new File({
|
||||
path: manifestName,
|
||||
contents: Buffer.from(JSON.stringify(mappings)),
|
||||
subscriber.next(mappingFile);
|
||||
subscriber.complete();
|
||||
},
|
||||
});
|
||||
this.push(mappingFile);
|
||||
|
||||
callback(null);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,27 @@
|
|||
import { src, dest } from "gulp";
|
||||
import postcss from "gulp-postcss";
|
||||
import hashPath from "../hash.js";
|
||||
import postcss, { Result } from "postcss";
|
||||
import config from "../../postcss.config.js";
|
||||
import { src, then, synchronise, dest } from "../rx-utils.js";
|
||||
import { map, lastValueFrom } from "rxjs";
|
||||
import hashPaths from "../hash.js";
|
||||
|
||||
export const css = () =>
|
||||
src("src/index.css").pipe(postcss()).pipe(hashPath("css.manifest")).pipe(dest("dist/_assets/"));
|
||||
lastValueFrom(
|
||||
src("src/index.css").pipe(
|
||||
then(
|
||||
(file) =>
|
||||
new Promise((resolve) =>
|
||||
postcss(config.plugins)
|
||||
.process(file.contents, { from: file.path })
|
||||
.then((result: Result) => {
|
||||
file.contents = Buffer.from(result.css);
|
||||
file.path = "index.css";
|
||||
|
||||
resolve(file);
|
||||
}),
|
||||
),
|
||||
),
|
||||
synchronise(),
|
||||
hashPaths("css.manifest"),
|
||||
map(dest("dist/_assets")),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,43 +1,42 @@
|
|||
import { Transform } from "node:stream";
|
||||
import File from "vinyl";
|
||||
import tmp from "tmp";
|
||||
import { execFile } from "node:child_process";
|
||||
import { readFileSync, unlinkSync } from "node:fs";
|
||||
import { src, dest } from "gulp";
|
||||
import hashPaths from "../hash.js";
|
||||
import { src, then, synchronise, dest } from "../rx-utils.js";
|
||||
import { map } from "rxjs";
|
||||
|
||||
const FONT_PRESETS = {
|
||||
mono: { ranges: ["20-7F", "2205", "2E22-2E25", "2713", "2717"] },
|
||||
text: { ranges: ["20-7F", "A0-FF", "2000-206F", "20AC"] },
|
||||
};
|
||||
|
||||
function compileFont() {
|
||||
return new Transform({
|
||||
objectMode: true,
|
||||
async transform(chunk: File, _, callback) {
|
||||
const [, variant, weight] = /([A-Z][a-z]+)-(\w+)\.ttf$/.exec(chunk.basename);
|
||||
const tmpOutput = tmp.fileSync({ discardDescriptor: true });
|
||||
const unicodes = FONT_PRESETS[variant.toLowerCase()].ranges;
|
||||
function compileFont(font: File): Promise<File> {
|
||||
const [, variant, weight] = /([A-Z][a-z]+)-(\w+)\.ttf$/.exec(font.basename);
|
||||
const tmpOutput = tmp.fileSync({ discardDescriptor: true });
|
||||
const unicodes = FONT_PRESETS[variant.toLowerCase()].ranges;
|
||||
|
||||
execFile("pyftsubset", [
|
||||
chunk.path,
|
||||
`--unicodes=${unicodes.join(",")}`,
|
||||
`--output-file=${tmpOutput.name}`,
|
||||
"--flavor=woff2",
|
||||
]).once("exit", () => {
|
||||
chunk.path = `iosevka-adaedra-${variant.toLowerCase()}-${weight.toLowerCase()}.woff2`;
|
||||
chunk.contents = readFileSync(tmpOutput.name);
|
||||
chunk.base = null;
|
||||
return new Promise((resolve) => {
|
||||
execFile("pyftsubset", [
|
||||
font.path,
|
||||
`--unicodes=${unicodes.join(",")}`,
|
||||
`--output-file=${tmpOutput.name}`,
|
||||
"--flavor=woff2",
|
||||
]).once("exit", () => {
|
||||
font.path = `iosevka-adaedra-${variant.toLowerCase()}-${weight.toLowerCase()}.woff2`;
|
||||
font.contents = readFileSync(tmpOutput.name);
|
||||
font.base = null;
|
||||
|
||||
unlinkSync(tmpOutput.name);
|
||||
callback(null, chunk);
|
||||
});
|
||||
},
|
||||
unlinkSync(tmpOutput.name);
|
||||
resolve(font);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const fonts = () =>
|
||||
src("vendor/*.ttf")
|
||||
.pipe(compileFont())
|
||||
.pipe(hashPaths("fonts.manifest"))
|
||||
.pipe(dest("dist/_assets"));
|
||||
src("vendor/*.ttf").pipe(
|
||||
then(compileFont),
|
||||
synchronise(),
|
||||
hashPaths("fonts.manifest"),
|
||||
map(dest("dist/_assets")),
|
||||
);
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
import { src, dest } from "gulp";
|
||||
import hashPaths from "../hash.js";
|
||||
import { src, then, synchronise, dest } from "../rx-utils.js";
|
||||
import { map } from "rxjs";
|
||||
|
||||
export const images = () =>
|
||||
src("src/*.avif", { encoding: false })
|
||||
.pipe(hashPaths("images.manifest"))
|
||||
.pipe(dest("dist/_assets/"));
|
||||
src("src/*.avif").pipe(
|
||||
then(async (file) => {
|
||||
file.path = file.path.substring(4);
|
||||
return file;
|
||||
}),
|
||||
synchronise(),
|
||||
hashPaths("images.manifest"),
|
||||
map(dest("dist/_assets")),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue
Block a user