Skip to content

Commit

Permalink
Add missing files
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbmatter committed Jan 31, 2025
1 parent 732b4ba commit 7199203
Show file tree
Hide file tree
Showing 15 changed files with 3,583 additions and 9 deletions.
17 changes: 8 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
*.pyc
*.sublime-project
*.sublime-workspace
node_modules
test_case.html
npm-debug.log
build
local.log
stats-*.html
.idea/
foo
.vscode
/node_modules
/npm-debug.log
/build
/local.log
/stats-*.html
/.idea/
/foo
/.vscode
35 changes: 35 additions & 0 deletions tools/build/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import fs from "node:fs/promises";
import { buildCss } from "./buildCss.ts";
import { buildJs } from "./buildJs.ts";
import { buildSw } from "./buildSw.ts";
import { copyFiles } from "./copyFiles.ts";
import { generateJsonSchema } from "./generateJsonSchema.ts";
import { getSport } from "../lib/getSport.ts";
import { minifyIndexHtml } from "./minifyIndexHtml.ts";
import { reset } from "./reset.ts";

export const build = async () => {
const sport = getSport();

console.log(`Building ${sport}...`);

await reset();
await copyFiles();

const jsonSchema = generateJsonSchema(sport);
await fs.mkdir("build/files", { recursive: true });
await fs.writeFile(
"build/files/league-schema.json",
JSON.stringify(jsonSchema, null, 2),
);

console.log("Bundling JavaScript files...");
await buildJs();

console.log("Processing CSS/HTML files...");
await buildCss();
await minifyIndexHtml();

console.log("Generating sw.js...");
await buildSw();
};
104 changes: 104 additions & 0 deletions tools/build/buildCss.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Buffer } from "node:buffer";
import fs from "node:fs";
import browserslist from "browserslist";
import * as lightningCSS from "lightningcss";
import { PurgeCSS } from "purgecss";
import * as sass from "sass";
import { fileHash } from "./fileHash.ts";
import { replace } from "./replace.ts";

export const buildCss = async (watch: boolean = false) => {
const filenames = ["light", "dark"];
const rawCSS = filenames.map((filename) => {
const sassFilePath = `public/css/${filename}.scss`;
const sassResult = sass.renderSync({
file: sassFilePath,
});
return sassResult.css.toString();
});

const purgeCSSResults = watch
? []
: await new PurgeCSS().purge({
content: ["build/gen/*.js"],
css: rawCSS.map((raw) => ({ raw })),
safelist: {
standard: [/^qc-cmp2-persistent-link$/],
greedy: [
// react-bootstrap stuff
/^modal/,
/^navbar/,
/^popover/,
/^tooltip/,
/^bs-tooltip/,

// For align="end" in react-bootstrap
/^dropdown-menu-end$/,

// flag-icons
/^fi$/,
/^fi-/,

/^dark-select/,
/^bar-graph/,
/^watch-active/,
/^dashboard-top-link-other/,
],
},
});

for (let i = 0; i < filenames.length; i++) {
const filename = filenames[i];

let output;
if (!watch) {
// https://zengm.com/blog/2022/07/investigating-a-tricky-performance-bug/
const DANGER_CSS = ".input-group.has-validation";
if (!rawCSS[i].includes(DANGER_CSS)) {
throw new Error(
`rawCSS no longer contains ${DANGER_CSS} - same problem might exist with another name?`,
);
}

const purgeCSSResult = purgeCSSResults[i].css;

const { code } = lightningCSS.transform({
filename: `${filename}.css`,
code: Buffer.from(purgeCSSResult),
minify: true,
sourceMap: false,
targets: lightningCSS.browserslistToTargets(
browserslist("Chrome >= 75, Firefox >= 78, Safari >= 12.1"),
),
});

output = code.toString();

if (output.includes(DANGER_CSS)) {
throw new Error(`CSS output contains ${DANGER_CSS}`);
}
} else {
output = rawCSS[i];
}

let outFilename;
if (watch) {
outFilename = `build/gen/${filename}.css`;
} else {
const hash = fileHash(output);
outFilename = `build/gen/${filename}-${hash}.css`;

replace({
paths: ["build/index.html"],
replaces: [
{
searchValue: `CSS_HASH_${filename.toUpperCase()}`,
replaceValue: hash,
},
],
});
}

fs.writeFileSync(outFilename, output);
}
};
85 changes: 85 additions & 0 deletions tools/build/buildJs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import fs from "node:fs";
import { Worker } from "node:worker_threads";
import { fileHash } from "./fileHash.ts";
import { generateVersionNumber } from "./generateVersionNumber.ts";
import { replace } from "./replace.ts";
import { setTimestamps } from "./setTimestamps.ts";

const versionNumber = generateVersionNumber();
console.log(versionNumber);

export const buildJs = async () => {
const promises = [];
for (const name of ["ui", "worker"]) {
for (const legacy of [false, true]) {
promises.push(
new Promise<void>((resolve) => {
const worker = new Worker(
new URL("buildJsWorker.ts", import.meta.url),
{
workerData: {
legacy,
name,
rev: versionNumber,
},
},
);

worker.on("message", () => {
resolve();
});
}),
);
}
}
await Promise.all(promises);

// Hack because otherwise I'm somehow left with no newline before the souce map URL, which confuses Bugsnag
const replacePaths = fs
.readdirSync("build/gen")
.filter((filename) => filename.endsWith(".js"))
.map((filename) => `build/gen/${filename}`);
replace({
paths: replacePaths,
replaces: [
{
searchValue: ";//# sourceMappingURL",
replaceValue: ";\n//# sourceMappingURL",
},
],
});

setTimestamps(versionNumber);

const jsonFiles = [
"names",
"names-female",
"real-player-data",
"real-player-stats",
];
const replaces = [];
for (const filename of jsonFiles) {
const filePath = `build/gen/${filename}.json`;
if (fs.existsSync(filePath)) {
const string = fs.readFileSync(filePath, "utf8");
const compressed = JSON.stringify(JSON.parse(string));

const hash = fileHash(compressed);
const newFilename = filePath.replace(".json", `-${hash}.json`);
fs.rmSync(filePath);
fs.writeFileSync(newFilename, compressed);

replaces.push({
searchValue: `/gen/${filename}.json`,
replaceValue: `/gen/${filename}-${hash}.json`,
});
}
}
replace({
paths: [
`build/gen/worker-legacy-${versionNumber}.js`,
`build/gen/worker-${versionNumber}.js`,
],
replaces,
});
};
59 changes: 59 additions & 0 deletions tools/build/buildJsWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { rollup, type ModuleFormat } from "rollup";
import rollupConfig from "../lib/rollupConfig.ts";
import { parentPort, workerData } from "node:worker_threads";

const LODASH_BLACKLIST = [
/^lodash$/,
/^lodash-es/,

// lodash/debounce and lodash/memoize are used by visx
/^lodash\/(?!debounce|memoize)/,
];

const BLACKLIST = {
ui: [...LODASH_BLACKLIST, /\/worker/],
worker: [...LODASH_BLACKLIST, /\/ui/, /^react/],
};

const buildFile = async (
name: "ui" | "worker",
legacy: boolean,
rev: string,
) => {
const bundle = await rollup({
...rollupConfig("production", {
blacklistOptions: BLACKLIST[name],
statsFilename: `stats-${name}${legacy ? "-legacy" : ""}.html`,
legacy,
}),
input: {
[name]: `src/${name}/index.${name === "ui" ? "tsx" : "ts"}`,
},
preserveEntrySignatures: false,
});

let format: ModuleFormat;
if (legacy) {
// ES modules don't work in workers in all the browsers currently supported
// Chrome 80, Firefox 114, Safari 15.5/16.4
format = name === "ui" ? "es" : "iife";
} else {
format = "es";
}

await bundle.write({
compact: true,
format,
indent: false,
sourcemap: true,
entryFileNames: `[name]-${legacy ? "legacy-" : ""}${rev}.js`,
chunkFileNames: `chunk-${legacy ? "legacy-" : ""}[hash].js`,
dir: "build/gen",
});

parentPort!.postMessage("done");
};

const { legacy, name, rev } = workerData;

await buildFile(name, legacy, rev);
Loading

0 comments on commit 7199203

Please sign in to comment.