Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: misc #68

Merged
merged 3 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/src/middlewares/docLatestRewrite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Next } from "$dep/frugal/mod.ts";
import { getToc, latest } from "../pages/doc/toc.ts";

export async function docLatestRewrite(context: Context, next: Next<Context>) {
const matches = context.request.url.match(/\/doc@latest(:\/(.*))?$/);
const matches = context.request.url.match(/\/doc@latest(?:\/(.*))?$/);
if (matches) {
const toc = await getToc(context.resolve);
const redirectUrl = context.request.url.replace("/doc@latest", `/doc@${latest(toc)}`);
Expand Down
48 changes: 38 additions & 10 deletions src/plugin/googleFonts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
return {
name: "frugal:googleFonts",
setup(build) {
build.onResolve({ filter: /^\/\/fonts.googleapis.com\//, namespace: "https" }, async (args) => {
const name = (await xxhash.create()).update(args.path).digest("hex").toString();
build.onResolve({
filter: /^\/\/fonts.googleapis.com\//,
namespace: "https",
}, async (args) => {
const name = (await xxhash.create()).update(args.path).digest("hex")
.toString();
return {
path: `/googlefonts-${name}.css`,
namespace: "virtual",
Expand All @@ -25,7 +29,10 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
});

if (type === "external") {
build.onLoad({ filter: /^\/googlefonts-.*\.css$/, namespace: "virtual" }, async (args) => {
build.onLoad({
filter: /^\/googlefonts-.*\.css$/,
namespace: "virtual",
}, async (args) => {
const url = args.pluginData.url;
if (!url) {
return;
Expand All @@ -43,7 +50,10 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
return { contents: css, loader: "css" };
});

build.onResolve({ filter: /^\/\/fonts.gstatic.com\//, namespace: "https" }, () => {
build.onResolve({
filter: /^\/\/fonts.gstatic.com\//,
namespace: "https",
}, () => {
return { external: true };
});
}
Expand All @@ -53,7 +63,10 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
return { external: true };
});

build.onLoad({ filter: /^\/googlefonts-.*\.css$/, namespace: "virtual" }, async (args) => {
build.onLoad({
filter: /^\/googlefonts-.*\.css$/,
namespace: "virtual",
}, async (args) => {
const url = args.pluginData.url;
if (!url) {
return;
Expand All @@ -73,7 +86,8 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
for (const url of urls) {
const matched = url.match(/src\s*:\s*url\((.*?)\)/);
if (matched) {
const name = (await xxhash.create()).update(matched[1]).digest("hex")
const name = (await xxhash.create()).update(matched[1])
.digest("hex")
.toString();
const ext = path.extname(matched[1]);

Expand All @@ -82,7 +96,10 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {

try {
await fs.ensureDir(path.dirname(path.fromFileUrl(fontUrl)));
const file = await Deno.open(fontUrl, { createNew: true, write: true });
const file = await Deno.open(fontUrl, {
createNew: true,
write: true,
});
try {
log(`Loading font ${++index} of ${urls.length}`, {
scope: "frugal:googleFonts",
Expand All @@ -91,7 +108,9 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
const response = await fetch(matched[1]);
const readableStream = response.body?.getReader();
if (readableStream) {
const reader = streams.readerFromStreamReader(readableStream);
const reader = streams.readerFromStreamReader(
readableStream,
);

await streams.copy(reader, file);
}
Expand All @@ -104,9 +123,18 @@ export function googleFonts({ type = "local" }: Config = {}): Plugin {
}
}

const fontDest = new URL(`fonts/${name}${ext}`, frugal.config.publicdir);
const fontDest = new URL(
`fonts/${name}${ext}`,
frugal.config.publicdir,
);
await fs.ensureDir(path.dirname(path.fromFileUrl(fontDest)));
await fs.copy(fontUrl, fontDest);
try {
await fs.copy(fontUrl, fontDest);
} catch (error) {
if (!(error instanceof Deno.errors.AlreadyExists)) {
throw error;
}
}
css = css.replace(matched[1], `/fonts/${name}${ext}`);
}
}
Expand Down
45 changes: 37 additions & 8 deletions src/plugin/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ export function svg(
build.onLoad({ filter }, async (args) => {
const url = frugal.url(args);

const { meta: { spritesheet, id, viewBox } } = await svgBuilder.symbol(path.fromFileUrl(url));
const { meta: { spritesheet, id, viewBox } } = await svgBuilder
.symbol(path.fromFileUrl(url));

return {
contents: JSON.stringify({ href: `/${outdir}${spritesheet}#${id}`, viewBox }),
contents: JSON.stringify({
href: `/${outdir}${spritesheet}#${id}`,
viewBox,
}),
loader: "json",
};
});
Expand All @@ -58,8 +62,7 @@ export function svg(

for (const [name, symbols] of Object.entries(spritesheets)) {
const svg = svgBuilder.spritesheet(symbols, frugal.config);
const hash = (await xxhash.create()).update(svg).digest("hex").toString();
const svgPath = path.join("svg", `${name}-${hash}.svg`);
const svgPath = path.join("svg", `${name}`);
const svgUrl = new URL(svgPath, frugal.config.publicdir);
const assetPath = `/${svgPath}`;

Expand All @@ -76,7 +79,12 @@ export function svg(
};
}

type MetaSymbol = { id: string; viewBox: string; spritesheet: string; path: string };
type MetaSymbol = {
id: string;
viewBox: string;
spritesheet: string;
path: string;
};

type SvgSymbol = {
attributes: Record<string, string>;
Expand All @@ -91,12 +99,27 @@ type Symbol = {
};

class SvgBuilder {
#spritesheetName: Map<string, string>;
#symbolCache: Map<string, Symbol>;
#spritesheetCache: Map<string, string>;

constructor() {
this.#symbolCache = new Map();
this.#spritesheetCache = new Map();
this.#spritesheetName = new Map();
}

async #getSpritesheetName(svgPath: string) {
const baseName = path.basename(path.dirname(svgPath));

const name = this.#spritesheetName.get(baseName);
if (name != undefined) {
return name;
}

const hash = (await xxhash.create()).update(baseName).update(String(Date.now()))
.digest("hex").toString();
return `${name}-${hash}.svg`;
}

async symbol(svgPath: string) {
Expand All @@ -109,7 +132,10 @@ class SvgBuilder {
return cached;
}

log(`generating svg symbol from "${svgPath}"`, { level: "debug", scope: "frugal:svg" });
log(`generating svg symbol from "${svgPath}"`, {
level: "debug",
scope: "frugal:svg",
});

const doc = new dom.DOMParser().parseFromString(svgString, "text/html")!;
const svg = doc.querySelector("svg")!;
Expand All @@ -118,7 +144,7 @@ class SvgBuilder {
const height = svg.getAttribute("height");

const id = `${path.basename(svgPath, path.extname(svgPath))}-${svgHash}`;
const spritesheet = path.basename(path.dirname(svgPath));
const spritesheet = await this.#getSpritesheetName(svgPath);

const metaSymbol: MetaSymbol = {
id,
Expand Down Expand Up @@ -167,7 +193,10 @@ class SvgBuilder {
return cached;
}

log(`generating spritesheet "${symbols[0].meta.spritesheet}"`, { level: "debug", scope: "frugal:svg" });
log(`generating spritesheet "${symbols[0].meta.spritesheet}"`, {
level: "debug",
scope: "frugal:svg",
});

const seenId: Record<string, Set<string>> = {};
const svgContent = [];
Expand Down