Skip to content

Commit ee182b0

Browse files
committed
Process changelog markdown during build process to avoid having to include marked in the build
~5% reduction in app bundle size
1 parent 0f71bf6 commit ee182b0

File tree

4 files changed

+63
-11
lines changed

4 files changed

+63
-11
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ A clone of [2048](https://play2048.co/) created using TypeScript, HTML, and CSS.
3535
- Confetti animation when player achieves 2048 (using [canvas-confetti](https://github.com/catdad/canvas-confetti) library)
3636
- Changelog Dialog
3737
- Shows the contents of [CHANGELOG.md](CHANGELOG.md) in a dialog box in-game
38-
- Uses [marked](https://github.com/markedjs/marked) to parse the changelog markdown file into HTML to be displayed in the dialog
38+
- Uses [marked](https://github.com/markedjs/marked) during build time to parse the changelog markdown file into HTML to be displayed in the dialog
3939

4040
## Development Setup
4141

plugins/file-transformer.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
4+
export default function fileTransformerPlugin({ input, transformer, output }) {
5+
if (!input || !transformer || !output) {
6+
throw new Error('fileTransformerPlugin requires "input", "transformer", and "output" options.');
7+
}
8+
9+
return {
10+
name: 'file-transformer',
11+
async buildStart() {
12+
// Do not perform emit file operation in watch mode (ie. `vite dev`)
13+
if (this.meta.watchMode) return;
14+
15+
// Read and process the file during the build start phase
16+
const filePath = path.resolve(input);
17+
let fileContent;
18+
19+
try {
20+
fileContent = fs.readFileSync(filePath, 'utf-8');
21+
} catch (err) {
22+
throw new Error(`Failed to read file: ${input} - ${err.message}`);
23+
}
24+
25+
// Transform the content using the provided transformer function
26+
const transformedContent = await transformer(fileContent);
27+
28+
// Emit the processed file as an asset
29+
this.emitFile({
30+
type: 'asset',
31+
fileName: output,
32+
source: transformedContent,
33+
});
34+
},
35+
configureServer(server) {
36+
server.middlewares.use(async (req, res, next) => {
37+
if (req.url === `/${output}`) {
38+
try {
39+
const content = fs.readFileSync(input, 'utf-8');
40+
const transformed = await transformer(content);
41+
res.setHeader('Content-Type', 'text/html');
42+
res.end(transformed);
43+
} catch (err) {
44+
next(err);
45+
}
46+
} else {
47+
next();
48+
}
49+
});
50+
},
51+
};
52+
}

src/index.ts

+3-10
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import posthog from "posthog-js";
3131
import { UndoManager } from "./manager/undo";
3232
import { AssetManager } from "./manager/asset";
3333
import { formatTilesetName } from "./util/format";
34-
import * as marked from "marked";
3534
import { FullscreenManager } from "./manager/fullscreen";
3635
import { ActionIconManager } from "./manager/action-icon";
3736
import { AppIconManager } from "./manager/app-icon";
@@ -79,14 +78,6 @@ const LANDSCAPE_CLASS_NAME = "landscape";
7978

8079
const CLASSIC_THEME_LABEL = "2048Clone";
8180

82-
let changelogText: string;
83-
// @ts-ignore TODO: Fix ts error saying that CHANGELOG.md cannot be found
84-
import("../CHANGELOG.md").then((res) => {
85-
fetch(res.default)
86-
.then((resp) => resp.text())
87-
.then((text) => (changelogText = text));
88-
});
89-
9081
let isAnimationEnabled = false;
9182

9283
let isPrompted = false;
@@ -1040,8 +1031,10 @@ document.addEventListener("DOMContentLoaded", async () => {
10401031
const changelogLink = document.querySelector("#changelog-link") as HTMLAnchorElement;
10411032
changelogLink.addEventListener("click", async (e) => {
10421033
e.preventDefault();
1034+
// Fetch changelog
1035+
// TODO: Cache it
1036+
const changelog = await fetch("CHANGELOG.html").then((res) => res.text());
10431037
const dialogElem = createDialogContentFromTemplate("#changelog-content");
1044-
const changelog = await marked.parse(changelogText);
10451038
const changelogElem = dialogElem.querySelector("#changelog-text") as HTMLElement;
10461039
changelogElem.innerHTML = changelog;
10471040
// Capitalize title

vite.config.ts

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { version } from "./package.json";
55
import { sentryVitePlugin } from "@sentry/vite-plugin";
66
import * as childProcess from "child_process";
77
import appIconLabel from './plugins/app-labels';
8+
import fileTransformerPlugin from "./plugins/file-transformer";
9+
import * as marked from "marked";
810

911
const commitHash = childProcess.execSync("git rev-parse --short HEAD").toString();
1012

@@ -82,6 +84,11 @@ export default defineConfig(({ mode }) => {
8284
],
8385
position: 'bottom',
8486
}),
87+
fileTransformerPlugin({
88+
input: 'CHANGELOG.md',
89+
transformer: (content) => marked.parse(content),
90+
output: 'CHANGELOG.html',
91+
}),
8592
// Must go after all other plugins
8693
sentryVitePlugin({
8794
org: "james-cote",

0 commit comments

Comments
 (0)