feat: Replace build.py with JSX-based webpack-native book index generation
Port the Python HTML-generation script to a React component (src/BookIndex.jsx) rendered at build time via renderToStaticMarkup, removing the need to run build.py separately before webpack. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,35 @@
|
||||
require("@babel/register")({ presets: ["@babel/preset-react"] });
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const React = require("react");
|
||||
const { renderToStaticMarkup } = require("react-dom/server");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const BookIndex = require("./src/BookIndex.jsx").default;
|
||||
|
||||
function readPages(dir) {
|
||||
const pageNums = fs
|
||||
.readdirSync(dir)
|
||||
.map(f => { const m = f.match(/^(\d+)\.html$/); return m ? parseInt(m[1], 10) : null; })
|
||||
.filter(n => n !== null)
|
||||
.sort((a, b) => a - b);
|
||||
|
||||
return pageNums.map(n => {
|
||||
let content = fs.readFileSync(path.join(dir, `${n}.html`), "utf8");
|
||||
content = content.replace(/[ \t]*<link[^>]+>\n?/g, "").trim();
|
||||
return { n, content };
|
||||
});
|
||||
}
|
||||
|
||||
function bookTemplateContent(title, logoText, dir) {
|
||||
const pages = readPages(dir);
|
||||
return () =>
|
||||
"<!DOCTYPE html>" +
|
||||
renderToStaticMarkup(React.createElement(BookIndex, { title, logoText, pages }));
|
||||
}
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const isProd = argv.mode === "production";
|
||||
@@ -17,7 +44,6 @@ module.exports = (env, argv) => {
|
||||
filename: isProd ? "[name].[contenthash].js" : "[name].js",
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
clean: true,
|
||||
// Disable IIFE wrapping so onclick= handlers can reach global functions
|
||||
iife: false,
|
||||
},
|
||||
module: {
|
||||
@@ -42,13 +68,21 @@ module.exports = (env, argv) => {
|
||||
scriptLoading: "blocking",
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./books/core/index.html",
|
||||
templateContent: bookTemplateContent(
|
||||
"Fabula Ultima - Core Rulebook",
|
||||
"Core Rules",
|
||||
"./books/core"
|
||||
),
|
||||
filename: "books/core/index.html",
|
||||
chunks: ["book"],
|
||||
scriptLoading: "blocking",
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./books/natural-fantasy-atlas/index.html",
|
||||
templateContent: bookTemplateContent(
|
||||
"Fabula Ultima - Natural Fantasy Atlas",
|
||||
"Natural Fantasy Atlas",
|
||||
"./books/natural-fantasy-atlas"
|
||||
),
|
||||
filename: "books/natural-fantasy-atlas/index.html",
|
||||
chunks: ["book"],
|
||||
scriptLoading: "blocking",
|
||||
@@ -91,7 +125,6 @@ module.exports = (env, argv) => {
|
||||
devServer: {
|
||||
static: [
|
||||
{ directory: path.resolve(__dirname, "dist") },
|
||||
// Serve raw html/ pages at /book in dev so they don't need to be copied
|
||||
{ directory: path.resolve(__dirname, "books"), publicPath: "/books" },
|
||||
{ directory: path.resolve(__dirname, "css"), publicPath: "/css" },
|
||||
],
|
||||
@@ -99,7 +132,6 @@ module.exports = (env, argv) => {
|
||||
open: true,
|
||||
historyApiFallback: {
|
||||
rewrites: [
|
||||
// /book (no trailing slash) → /book/index.html
|
||||
{ from: /^\/book$/, to: "/book/index.html" },
|
||||
],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user