Skip to content

Commit 8db148f

Browse files
authored
Merge pull request #763 from quoid/perf/preprocess-markdown
perf: preprocess markdown transform at build time
2 parents 4329566 + 831f67d commit 8db148f

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

scripts/build-safari-15.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import { build } from "vite";
1818
import { svelte } from "@sveltejs/vite-plugin-svelte";
19+
import pluginMarkedDivest from "./vite-plugin-marked-divest.js";
1920
import * as Utils from "./utils.js";
2021

2122
/** @type {import("vite").InlineConfig} */
@@ -36,7 +37,7 @@ const sharedConfig = {
3637
*/
3738
build({
3839
...Utils.baseConfig,
39-
plugins: [svelte()],
40+
plugins: [svelte(), pluginMarkedDivest()],
4041
build: {
4142
...sharedConfig.build,
4243
outDir: `${Utils.APP_SHARED_RESOURCES}/dist/`,

scripts/build-safari-16.4.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import { build } from "vite";
1717
import { svelte } from "@sveltejs/vite-plugin-svelte";
18+
import pluginMarkedDivest from "./vite-plugin-marked-divest.js";
1819
import * as Utils from "./utils.js";
1920

2021
/** @type {import("vite").InlineConfig} */
@@ -35,7 +36,7 @@ const sharedConfig = {
3536
*/
3637
build({
3738
...Utils.baseConfig,
38-
plugins: [svelte()],
39+
plugins: [svelte(), pluginMarkedDivest()],
3940
build: {
4041
...sharedConfig.build,
4142
outDir: `${Utils.APP_SHARED_RESOURCES}/dist/`,

scripts/vite-plugin-marked-divest.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { fileURLToPath } from "node:url";
2+
import { readFile } from "node:fs/promises";
3+
import { marked } from "marked";
4+
5+
/**
6+
* Exclude files that do not need to be processed
7+
* @param {string} id
8+
* @returns {boolean}
9+
*/
10+
function isExclude(id) {
11+
const res = [/\/src\/app\/_locales\/[A-Za-z0-9_]+\/messages\.js/];
12+
for (const re of res) {
13+
if (re.test(id)) return false;
14+
}
15+
return true;
16+
}
17+
18+
/**
19+
* Preprocess `marked` calls and `.md?raw` transformations at build time
20+
* to avoid including `marked` modules and runtime transformations
21+
* @returns {import('vite').Plugin}
22+
*/
23+
function preprocessMarked() {
24+
return {
25+
name: "preprocess-marked",
26+
resolveId: {
27+
order: "pre",
28+
handler(source, importer) {
29+
if (isExclude(importer)) return;
30+
if (source.endsWith(".md?raw")) {
31+
const importerUrl = new URL(importer, import.meta.url);
32+
const sourceUrl = new URL(source, importerUrl);
33+
return fileURLToPath(sourceUrl) + "?marked";
34+
}
35+
},
36+
},
37+
load: {
38+
order: "pre",
39+
async handler(id) {
40+
if (!id.endsWith(".md?marked")) return;
41+
const url = new URL(id, import.meta.url);
42+
const text = await readFile(fileURLToPath(url), "utf8");
43+
const html = await marked.parse(text);
44+
return `export default ${JSON.stringify(html)}`;
45+
},
46+
},
47+
transform(code, id) {
48+
if (isExclude(id)) return;
49+
if (!code.includes("marked.parse")) return;
50+
const node = this.parse(code);
51+
if (node.sourceType !== "module") return;
52+
for (const module of node.body) {
53+
if (module.type !== "ImportDeclaration") continue;
54+
if (!module.source.value.toString().endsWith(".md?raw")) continue;
55+
const specifier = module.specifiers.find(
56+
(specifier) => specifier.type === "ImportDefaultSpecifier",
57+
);
58+
const varName = specifier.local.name;
59+
code = code.replace(`await marked.parse(${varName})`, varName);
60+
// console.debug(`optimizing 'await marked.parse(${varName})'`, id); // DEBUG
61+
}
62+
return { code };
63+
},
64+
};
65+
}
66+
67+
/**
68+
* Turn off `Marked` module side effects for better tree-shaking
69+
* @returns {import('vite').Plugin}
70+
*/
71+
function disableMarkedSideEffects() {
72+
return {
73+
name: "disable-marked-side-effects",
74+
transform(code, id) {
75+
if (id.includes("/node_modules/marked")) {
76+
return { code, moduleSideEffects: false };
77+
}
78+
},
79+
};
80+
}
81+
82+
/**
83+
* @returns {import('vite').Plugin[]}
84+
*/
85+
function markedDivest() {
86+
return [disableMarkedSideEffects(), preprocessMarked()];
87+
}
88+
89+
export default markedDivest;

src/app/i18n.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ function getLangFrom(messages, messageName, substitutions = undefined) {
1414
console.warn(`i18n - "${messageName}" not found`, messages);
1515
return "";
1616
}
17-
/** @type {string} message */
1817
let text = messages[messageName].message;
1918
// handle substitutions
2019
if (typeof substitutions === "string") {

0 commit comments

Comments
 (0)