Skip to content

Commit

Permalink
Make webpack config less hacky
Browse files Browse the repository at this point in the history
  • Loading branch information
rosslh committed Jan 19, 2025
1 parent 8089d74 commit 1cc10df
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 93 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Mandelbrot.site is built using modern web technologies to deliver a high-perform

For performance optimization, it employs [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) via the [threads.js](https://github.com/andywer/threads.js) library. This setup prevents intensive computations from blocking the main browser thread by creating a pool of workers that handle the generation of Mandelbrot set tiles in parallel. A key optimization technique used is "rectangle checking," which saves computation time for areas entirely within the set by checking only the perimeter of a tile.

The application leverages [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) to prioritize a local-first experience, ensuring that users can explore the Mandelbrot set and or with minimal network dependencies.
It is a [Progressive Web App](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) (PWA), leveraging [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) to prioritize a local-first experience. This ensures that users can explore the Mandelbrot set with minimal network dependencies.

This robust architecture ensures that Mandelbrot.site provides a seamless and responsive experience for users exploring the intricate details of the Mandelbrot set through an online interface.

Expand Down
2 changes: 1 addition & 1 deletion client/css/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ body {
sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
}

html {
html.fractal-root {
height: 100%;
width: 100%;

Expand Down
40 changes: 23 additions & 17 deletions client/html/blog-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,38 @@
<head>
<meta charset="utf-8" />
<!-- HTML Meta Tags -->
<title>{{title}} | Mandelbrot Set Explorer</title>
<meta name="description" content="{{description}}" />
<link rel="canonical" href="https://mandelbrot.site/{{slug}}" />
<title><%= title %> | Mandelbrot Set Explorer</title>
<meta name="description" content="<%= description %>" />
<link rel="canonical" href="https://mandelbrot.site/<%= slug %>" />

<!-- Google / Search Engine Tags -->
<meta itemprop="name" content="{{title}} | Mandelbrot Set Explorer" />
<meta itemprop="description" content="{{description}}" />
<meta itemprop="name" content="<%= title %> | Mandelbrot Set Explorer" />
<meta itemprop="description" content="<%= description %>" />
<meta
itemprop="image"
content="https://mandelbrot.site/static/site-image.png"
/>

<!-- Facebook Meta Tags -->
<meta property="og:url" content="https://mandelbrot.site/{{slug}}" />
<meta property="og:url" content="https://mandelbrot.site/<%= slug %>" />
<meta property="og:type" content="website" />
<meta property="og:title" content="{{title}} | Mandelbrot Set Explorer" />
<meta property="og:description" content="{{description}}" />
<meta
property="og:title"
content="<%= title %> | Mandelbrot Set Explorer"
/>
<meta property="og:description" content="<%= description %>" />
<meta
property="og:image"
content="https://mandelbrot.site/static/site-image.png"
/>

<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{title}} | Mandelbrot Set Explorer" />
<meta name="twitter:description" content="{{description}}" />
<meta
name="twitter:title"
content="<%= title %> | Mandelbrot Set Explorer"
/>
<meta name="twitter:description" content="<%= description %>" />
<meta
name="twitter:image"
content="https://mandelbrot.site/static/site-image.png"
Expand Down Expand Up @@ -72,39 +78,39 @@ <h2 class="site-name">Mandelbrot.site</h2>
<li>
<a
href="/how-mandelbrot-site-was-built"
class="{{howMandelbrotSiteWasBuiltClass}}"
class="<%= howMandelbrotSiteWasBuiltClass %>"
>
How Mandelbrot.site Was Built
</a>
</li>
<li>
<a
href="/what-is-mandelbrot-set"
class="{{whatIsMandelbrotSetClass}}"
class="<%= whatIsMandelbrotSetClass %>"
>
What Is the Mandelbrot Set?
</a>
</li>
<li>
<a
href="/history-of-mandelbrot-set"
class="{{historyOfMandelbrotSetClass}}"
class="<%= historyOfMandelbrotSetClass %>"
>
History of the Mandelbrot Set
</a>
</li>
<li>
<a
href="/who-was-benoit-mandelbrot"
class="{{whoWasBenoitMandelbrotClass}}"
class="<%= whoWasBenoitMandelbrotClass %>"
>
Who Was Benoit Mandelbrot?
</a>
</li>
<li>
<a
href="/why-mandelbrot-set-important"
class="{{whyMandelbrotSetImportantClass}}"
class="<%= whyMandelbrotSetImportantClass %>"
>
Why the Mandelbrot Set Is Important
</a>
Expand All @@ -128,8 +134,8 @@ <h2 class="site-name">Mandelbrot.site</h2>
</nav>
<main>
<div class="blog-content">
<h1>{{title}}</h1>
{{content}}
<h1><%= title %></h1>
<%= content %>
<div class="bottom-spacer"></div>
</div>
</main>
Expand Down
2 changes: 1 addition & 1 deletion client/html/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en">
<html lang="en" class="fractal-root">
<head>
<meta charset="utf-8" />
<!-- HTML Meta Tags -->
Expand Down
49 changes: 23 additions & 26 deletions client/js/index.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
import "./static";
import MandelbrotMap from "./MandelbrotMap";

if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
window.addEventListener("load", () => {
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/service-worker.js")
.then(() => {
console.log("Service worker registered.");
})
.catch((err: unknown) => {
console.error("Service worker registration failed:", err);
});
});
}
}

window.addEventListener("load", () => {
new MandelbrotMap({
htmlId: "leaflet",
initialConfig: {
iterations: 200,
exponent: 2,
colorScheme: "turbo",
lightenAmount: 0,
saturateAmount: 0,
shiftHueAmount: 0,
colorSpace: 2,
reverseColors: false,
highDpiTiles: false,
smoothColoring: true,
if (document.getElementById("leaflet")) {
new MandelbrotMap({
htmlId: "leaflet",
initialConfig: {
iterations: 200,
exponent: 2,
colorScheme: "turbo",
lightenAmount: 0,
saturateAmount: 0,
shiftHueAmount: 0,
colorSpace: 2,
reverseColors: false,
highDpiTiles: false,
smoothColoring: true,

re: -0.5,
im: 0,
zoom: 3,
},
});
re: -0.5,
im: 0,
zoom: 3,
},
});
}
});
28 changes: 14 additions & 14 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"@wasm-tool/wasm-pack-plugin": "^1.7.0",
"css-loader": "^6.9.1",
"css-loader": "^7.1.2",
"dotenv-webpack": "^8.1.0",
"eslint": "^8.56.0",
"file-loader": "^6.2.0",
Expand All @@ -34,8 +34,8 @@
"marked": "^12.0.2",
"mini-css-extract-plugin": "^2.7.7",
"prettier": "3.3.3",
"sass": "^1.70.0",
"sass-loader": "^14.1.0",
"sass": "^1.83.4",
"sass-loader": "^16.0.4",
"ts-loader": "^9.5.1",
"typescript": "^5.3.3",
"webpack": "^5.90.1",
Expand Down
66 changes: 36 additions & 30 deletions client/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const dist = path.resolve(__dirname, "dist");
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
const { marked } = require("marked");
const frontMatter = require("front-matter");
const fs = require("fs");
const template = require("lodash/template");
const camelCase = require("lodash/camelCase");
const fromPairs = require("lodash/fromPairs");
const Dotenv = require("dotenv-webpack");
const WorkboxPlugin = require("workbox-webpack-plugin");

if (!fs.existsSync("./dist")) {
fs.mkdirSync("./dist");
}
const dist = path.resolve(__dirname, "dist");

function getBlogPostPlugins() {
const blogDir = "./blog";
const blogPostPlugins = [];

const privacyPolicySrc = path.join(__dirname, "html", "privacy-policy.html");
const privacyPolicyDest = path.join(__dirname, "dist", "privacy-policy.html");
fs.copyFileSync(privacyPolicySrc, privacyPolicyDest);
for (const file of fs.readdirSync(blogDir)) {
if (!file.endsWith(".md")) continue;

const blogDir = "./blog";
for (const file of fs.readdirSync(blogDir)) {
if (file.endsWith(".md")) {
const md = fs.readFileSync(path.join(blogDir, file), "utf8");
const metadata = frontMatter(md).attributes;
const html = marked(md.replace(/^---$.*^---$/ms, ""));
const { attributes, body } = frontMatter(md);
const html = marked(body);
const htmlFile = file.replace(".md", ".html");
const blogTemplate = fs.readFileSync("./html/blog-template.html", "utf8");

const slug = htmlFile.replace(/\.html$/, "");
const slugCamel = camelCase(slug);

Expand All @@ -40,24 +34,36 @@ for (const file of fs.readdirSync(blogDir)) {
"whoWasBenoitMandelbrotClass",
"whyMandelbrotSetImportantClass",
].map((c) => {
return [c, slugCamel === c.split("Class")[0] ? "active" : ""];
const checkSlug = c.split("Class")[0];
return [c, slugCamel === checkSlug ? "active" : ""];
}),
);

const result = template(blogTemplate, {
interpolate: /{{([\s\S]+?)}}/g,
})({
title: metadata.title,
description: metadata.excerpt,
content: html,
slug,
...linkClasses,
});

fs.writeFileSync(path.join("./dist", htmlFile), result);
blogPostPlugins.push(
new HtmlWebpackPlugin({
filename: htmlFile,
template: "./html/blog-template.html",
templateParameters: {
title: attributes.title,
description: attributes.excerpt,
content: html,
slug,
...linkClasses,
},
}),
);
}

return blogPostPlugins;
}

const privacyPolicyPlugin = new HtmlWebpackPlugin({
filename: "privacy-policy.html",
template: path.join(__dirname, "html", "privacy-policy.html"),
});

const blogPostPlugins = getBlogPostPlugins();

const oneWeekInSeconds = 60 * 60 * 24 * 7;

const workbox = new WorkboxPlugin.GenerateSW({
Expand All @@ -81,13 +87,13 @@ const workbox = new WorkboxPlugin.GenerateSW({
const appConfig = {
entry: "./js/index.ts",
plugins: [
new Dotenv({
systemvars: true,
}),
new Dotenv({ systemvars: true }),
new HtmlWebpackPlugin({
template: "html/index.html",
root: path.resolve(__dirname, "."),
}),
...blogPostPlugins,
privacyPolicyPlugin,
new MiniCssExtractPlugin(),
workbox,
],
Expand Down

0 comments on commit 1cc10df

Please sign in to comment.