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