Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Install composer dependencies
run: composer install
Expand All @@ -21,12 +21,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up node
uses: actions/setup-node@v3
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '16'
node-version: '22'
cache: 'yarn'

- name: Install npm dependencies
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v17.9.1
v22.22.0
137 changes: 137 additions & 0 deletions frontend/build-scripts/service-worker-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
const path = require("path");
const xxhash = require("xxhashjs");

function contentHash(str) {
const hasher = new xxhash.h32(0);
hasher.update(str);
return hasher.digest();
}

function injectServiceWorker(swFile, findUnhashedFileNamesFromBundle, placeholdersPerChunk) {
const swName = path.basename(swFile);
let version;
let logger;

return {
name: "chatrix:inject-service-worker",
apply: "build",
enforce: "post",
buildStart() {
this.emitFile({
type: "chunk",
fileName: swName,
id: swFile,
});
},
configResolved(config) {
version = JSON.parse(config.define.DEFINE_VERSION);
logger = config.logger;
},
generateBundle(_options, bundle) {
const otherUnhashedFiles = findUnhashedFileNamesFromBundle(bundle);
const unhashedFilenames = [swName].concat(otherUnhashedFiles);
const unhashedFileContentMap = unhashedFilenames.reduce((map, fileName) => {
const chunkOrAsset = bundle[fileName];
if (!chunkOrAsset) {
throw new Error("could not get content for uncached asset or chunk " + fileName);
}
map[fileName] = chunkOrAsset.source || chunkOrAsset.code;
return map;
}, {});
const assets = Object.values(bundle);
const hashedFileNames = assets.map((o) => o.fileName).filter((fileName) => !unhashedFileContentMap[fileName]);
const globalHash = getBuildHash(hashedFileNames, unhashedFileContentMap);
const placeholderValues = {
DEFINE_GLOBAL_HASH: `"${globalHash}"`,
...getCacheFileNamePlaceholderValues(swName, unhashedFilenames, assets)
};
replacePlaceholdersInChunks(assets, placeholdersPerChunk, placeholderValues);
logger.info(`\nBuilt ${version} (${globalHash})`);
}
};
}

function getBuildHash(hashedFileNames, unhashedFileContentMap) {
const unhashedHashes = Object.entries(unhashedFileContentMap).map(([fileName, content]) => {
return `${fileName}-${contentHash(Buffer.from(content))}`;
});
const globalHashAssets = hashedFileNames.concat(unhashedHashes);
globalHashAssets.sort();
return contentHash(globalHashAssets.join(",")).toString();
}

const NON_PRECACHED_JS = [
"hydrogen-legacy",
"olm_legacy.js",
"main.js"
];

function getBundleName(asset) {
return asset.name || asset.names?.[0] || asset.originalFileNames?.[0] || asset.fileName || "";
}

function isPreCached(asset) {
const name = getBundleName(asset);
const { fileName } = asset;

if (!name && fileName.includes("sync-worker")) {
if (fileName.endsWith(".js.map")) {
return false;
}

if (fileName.endsWith(".js")) {
return false;
}
}

return name.endsWith(".svg") ||
name.endsWith(".png") ||
name.endsWith(".css") ||
name.endsWith(".wasm") ||
name.endsWith(".html") ||
fileName.endsWith(".js") && !NON_PRECACHED_JS.includes(path.basename(name));
}

function getCacheFileNamePlaceholderValues(swName, unhashedFilenames, assets) {
const unhashedPreCachedAssets = [];
const hashedPreCachedAssets = [];
const hashedCachedOnRequestAssets = [];

for (const asset of assets) {
const { fileName } = asset;
if (fileName === swName) {
continue;
} else if (unhashedFilenames.includes(fileName)) {
unhashedPreCachedAssets.push(fileName);
} else if (isPreCached(asset)) {
hashedPreCachedAssets.push(fileName);
} else {
hashedCachedOnRequestAssets.push(fileName);
}
}

return {
DEFINE_UNHASHED_PRECACHED_ASSETS: JSON.stringify(unhashedPreCachedAssets),
DEFINE_HASHED_PRECACHED_ASSETS: JSON.stringify(hashedPreCachedAssets),
DEFINE_HASHED_CACHED_ON_REQUEST_ASSETS: JSON.stringify(hashedCachedOnRequestAssets)
};
}

function replacePlaceholdersInChunks(assets, placeholdersPerChunk, placeholderValues) {
for (const [name, placeholderMap] of Object.entries(placeholdersPerChunk)) {
const chunk = assets.find((asset) => asset.type === "chunk" && asset.name === name);
if (!chunk) {
throw new Error(`could not find chunk ${name} to replace placeholders`);
}
for (const [placeholderName, placeholderLiteral] of Object.entries(placeholderMap)) {
const replacedValue = placeholderValues[placeholderName];
const oldCode = chunk.code;
chunk.code = chunk.code.replaceAll(placeholderLiteral, replacedValue);
if (chunk.code === oldCode) {
throw new Error(`Could not replace ${placeholderName} in ${name}, looking for literal ${placeholderLiteral}:\n${chunk.code}`);
}
}
}
}

module.exports = { injectServiceWorker };
2 changes: 1 addition & 1 deletion frontend/vite-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default defineConfig(() => {
outDir: resolve(__dirname, "../build/"),
lib: {
entry: resolve(__dirname, `./app.ts`),
formats: ["iife"],
formats: ["iife" as const],
name: "Chatrix",
fileName: "app"
},
Expand Down
2 changes: 1 addition & 1 deletion frontend/vite-logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig(() => {
outDir: resolve(__dirname, "../build/"),
lib: {
entry: resolve(__dirname, `./logout.ts`),
formats: ["iife"],
formats: ["iife" as const],
name: "ChatrixLogout",
fileName: "logout"
},
Expand Down
25 changes: 24 additions & 1 deletion frontend/vite.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import react from '@vitejs/plugin-react';
import injectWebManifest from "hydrogen-web/scripts/build-plugins/manifest";
import { createPlaceholderValues, injectServiceWorker } from "hydrogen-web/scripts/build-plugins/service-worker";
import compileVariables from "hydrogen-web/scripts/postcss/css-compile-variables";
import urlProcessor from "hydrogen-web/scripts/postcss/css-url-processor";
import urlVariables from "hydrogen-web/scripts/postcss/css-url-to-variables";
Expand All @@ -10,6 +9,7 @@ import { defineConfig } from "vite";
import manifest from "../package.json";
import themeBuilder from "./build-scripts/build-themes";
import { derive } from "./build-scripts/color";
import { injectServiceWorker } from "./build-scripts/service-worker-plugin";
import { buildColorizedSVG as replacer } from "./build-scripts/svg-builder";

const compiledVariables = new Map();
Expand All @@ -21,6 +21,12 @@ export default defineConfig(({mode}) => {
base: "",
root: __dirname,
envDir: __dirname,
resolve: {
alias: {
"fake-indexeddb/lib/FDBFactory.js": "fake-indexeddb/lib/FDBFactory",
"fake-indexeddb/lib/FDBKeyRange.js": "fake-indexeddb/lib/FDBKeyRange",
},
},
define: {
DEFINE_VERSION: JSON.stringify(manifest.version),
...definePlaceholders,
Expand Down Expand Up @@ -92,3 +98,20 @@ function findUnhashedFileNamesFromBundle(bundle) {
}
return names;
}

function createPlaceholderValues(mode) {
return {
DEFINE_GLOBAL_HASH: definePlaceholderValue(mode, "DEFINE_GLOBAL_HASH", null),
DEFINE_UNHASHED_PRECACHED_ASSETS: definePlaceholderValue(mode, "UNHASHED_PRECACHED_ASSETS", []),
DEFINE_HASHED_PRECACHED_ASSETS: definePlaceholderValue(mode, "HASHED_PRECACHED_ASSETS", []),
DEFINE_HASHED_CACHED_ON_REQUEST_ASSETS: definePlaceholderValue(mode, "HASHED_CACHED_ON_REQUEST_ASSETS", []),
};
}

function definePlaceholderValue(mode, name, devValue) {
if (mode === "production") {
return JSON.stringify(`__CHATRIX_${name}__`);
}

return JSON.stringify(devValue);
}
46 changes: 39 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
"@types/wordpress__i18n": "^3.11.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-react": "^1.3.2",
"@wordpress/scripts": "^24.2.0",
"@vitejs/plugin-react": "^4.7.0",
"@wordpress/scripts": "^31.8.0",
"eslint": "^8.57.1",
"fake-indexeddb": "^4.0.2",
"postcss-css-variables": "^0.19.0",
"postcss-flexbugs-fixes": "^5.0.2",
"rollup-plugin-external-globals": "^0.7.1",
"typescript": "4.7.*",
"vite": "^2.9.18",
"vite-plugin-css-injected-by-js": "^2.1.1",
"rollup-plugin-external-globals": "^0.13.0",
"typescript": "4.7.4",
"vite": "^6.4.2",
"vite-plugin-css-injected-by-js": "^3.5.2",
"xxhashjs": "^0.2.2"
},
"dependencies": {
Expand All @@ -42,9 +42,41 @@
"node-html-parser": "^4.0.0"
},
"resolutions": {
"@babel/runtime": "7.29.7",
"@sideway/formula": "^3.0.1",
"@types/react": "^17.0.2",
"json5": "^2.2.*"
"base-x": "4.0.1",
"body-parser": "1.20.5",
"braces": "3.0.3",
"cookie": "0.7.2",
"cross-spawn": "7.0.6",
"dompurify": "3.4.0",
"eslint/js-yaml": "4.1.1",
"express": "4.22.2",
"flatted": "3.4.2",
"follow-redirects": "1.16.0",
"json5": "^2.2.*",
"@eslint/eslintrc/js-yaml": "4.1.1",
"@istanbuljs/load-nyc-config/js-yaml": "3.14.2",
"markdownlint-cli/js-yaml": "4.1.1",
"lodash": "4.18.1",
"eslint/minimatch": "3.1.5",
"@humanwhocodes/config-array/minimatch": "3.1.5",
"@eslint/eslintrc/minimatch": "3.1.5",
"npm-packlist/**/minimatch": "3.1.5",
"@wordpress/eslint-plugin/minimatch": "9.0.9",
"@wordpress/eslint-plugin/**/minimatch": "3.1.5",
"@typescript-eslint/typescript-estree/minimatch": "9.0.9",
"test-exclude/minimatch": "3.1.5",
"markdownlint-cli/minimatch": "3.1.5",
"node-forge": "1.4.0",
"on-headers": "1.1.0",
"qs": "6.15.2",
"send": "0.19.0",
"serialize-javascript": "7.0.5",
"serve-static": "1.16.2",
"uuid": "11.1.1",
"webpack-dev-server": "5.2.4"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"noEmit": true,
"jsx": "react-jsx",
"resolveJsonModule": true,
"skipLibCheck": true,
"target": "ES2020",
"module": "ES2020",
"strictNullChecks": true,
Expand Down
Loading