don't require server restart on client changes,

by watching the asset files and reloading if changed
This commit is contained in:
HF 2023-12-13 11:11:25 +01:00
parent 058290aa16
commit 8d41c6533d
8 changed files with 112 additions and 41 deletions

View File

@ -4,6 +4,7 @@
*
*/
import assetWatcher from './core/fsWatcher';
import canvases from './core/canvases';
import ttag from './core/ttag';
@ -58,16 +59,21 @@ function getCanvases(t) {
return localizedCanvases;
}
const lCanvases = {};
(() => {
function translateCanvases() {
const parsedCanvases = {};
const langs = Object.keys(ttag);
langs.forEach((lang) => {
lCanvases[lang] = getCanvases(ttag[lang].t);
parsedCanvases[lang] = getCanvases(ttag[lang].t);
});
})();
export function getLocalizedCanvases(lang = 'en') {
return lCanvases[lang] || lCanvases.en;
return parsedCanvases;
}
export default lCanvases;
let lCanvases = translateCanvases();
// reload on asset change
assetWatcher.onChange(() => {
lCanvases = translateCanvases();
});
export default function getLocalizedCanvases(lang = 'en') {
return lCanvases[lang] || lCanvases.en;
}

View File

@ -1,7 +1,13 @@
/*
* Provide css and js asset files for client
*/
import fs from 'fs';
import path from 'path';
const ASSET_DIR = '/assets';
import assetWatcher from './fsWatcher';
import { ASSET_DIR } from './config';
const assetDir = path.join(__dirname, 'public', ASSET_DIR);
/*
* {
@ -78,8 +84,11 @@ function checkAssets() {
return parsedAssets;
}
// eslint-disable-next-line prefer-const
assets = checkAssets();
// reload on asset change
assetWatcher.onChange(() => {
assets = checkAssets();
});
export function getLangsOfJsAsset(name) {
const nameAssets = assets.js[name];

View File

@ -10,6 +10,8 @@ if (process.env.BROWSER) {
);
}
export const ASSET_DIR = '/assets';
export const PORT = process.env.PORT || 8080;
export const HOST = process.env.HOST || 'localhost';

55
src/core/fsWatcher.js Normal file
View File

@ -0,0 +1,55 @@
/*
* Watch for filesystem changes
*/
import fs from 'fs';
import path from 'path';
import logger from './logger';
import { ASSET_DIR } from './config';
class FsWatcher {
#path;
#timeout = null;
#listeners = [];
filetypes;
delay;
constructor(watchPath, { delay = 5000, filetypes = [] }) {
if (!watchPath) {
throw new Error('Must define a path to watch');
}
this.#path = watchPath;
this.delay = delay;
this.filetypes = filetypes;
this.initialize();
}
initialize() {
const watchPath = this.#path;
fs.watch(watchPath, (eventType, filename) => {
if (filename && this.filetypes.length) {
const ext = filename.split('.').pop();
if (!this.filetypes.includes(ext)) {
return;
}
}
if (this.#timeout) {
clearTimeout(this.#timeout);
}
this.#timeout = setTimeout(() => {
logger.info('ASSET CHANGE, detected change in asset files');
this.#listeners.forEach((cb) => cb(eventType, filename));
}, this.delay);
});
}
onChange(cb) {
this.#listeners.push(cb);
}
}
const assetWatcher = new FsWatcher(
path.join(__dirname, 'public', ASSET_DIR),
{ filetypes: ['js', 'css'] },
);
export default assetWatcher;

View File

@ -4,7 +4,7 @@
* various api endpoints.
*
*/
import { getLocalizedCanvases } from '../canvasesDesc';
import getLocalizedCanvases from '../canvasesDesc';
import { USE_MAILER } from './config';
import chatProvider from './ChatProvider';

View File

@ -4,6 +4,7 @@
import { TTag } from 'ttag';
import cookie from 'cookie';
import assetWatcher from './fsWatcher';
import { getLangsOfJsAsset } from './assets';
// eslint-disable-next-line max-len
@ -13,13 +14,18 @@ const ttags = {};
export const availableLangs = [];
(() => {
function loadTtags() {
const langs = localeImports.keys();
const jsLangs = getLangsOfJsAsset('client');
availableLangs.length = 0;
if (jsLangs.includes('en')) {
ttags.en = new TTag();
if (!ttags.en) {
ttags.en = new TTag();
}
availableLangs.push(['en', 'gb']);
} else if (ttags.en) {
delete ttags.en;
}
for (let i = 0; i < langs.length; i += 1) {
@ -37,14 +43,24 @@ export const availableLangs = [];
[lang, flag] = lang.split('-');
}
if (jsLangs.includes(lang)) {
const ttag = new TTag();
ttag.addLocale(lang, localeImports(file).default);
ttag.useLocale(lang);
ttags[lang] = ttag;
if (!ttags[lang]) {
const ttag = new TTag();
ttag.addLocale(lang, localeImports(file).default);
ttag.useLocale(lang);
ttags[lang] = ttag;
}
availableLangs.push([lang, flag]);
} else if (ttags[lang]) {
delete ttags[lang];
}
}
})();
}
loadTtags();
// reload on asset change
assetWatcher.onChange(() => {
loadTtags();
});
export function getTTag(lang) {
return ttags[lang] || ttags.en || Object.values(ttags)[0];

View File

@ -12,17 +12,6 @@ import socketEvents from '../socket/socketEvents';
import { BACKUP_URL } from '../core/config';
import { getHostFromRequest } from '../utils/ip';
/*
* values that we pass to client scripts
*/
const ssv = {
availableStyles: getCssAssets(),
langs,
};
if (BACKUP_URL) {
ssv.backupurl = BACKUP_URL;
}
const bodyScript = '(function(){const sr=(e)=>{if(e.shadowRoot)e.remove();else if(e.children){for(let i=0;i<e.children.length;i+=1)sr(e.children[i]);}};const a=new MutationObserver(e=>e.forEach(e=>e.addedNodes.forEach((l)=>{if(l.querySelectorAll)l.querySelectorAll("option").forEach((o)=>{if(o.value==="random")window.location="https://discord.io/pixeltraaa";});sr(l);})));a.observe(document.body,{childList:!0});})()';
const bodyScriptHash = createHash('sha256').update(bodyScript).digest('base64');
@ -38,7 +27,9 @@ function generateMainPage(req) {
const shard = (host.startsWith(`${socketEvents.thisShard}.`))
? null : socketEvents.getLowestActiveShard();
const ssvR = JSON.stringify({
...ssv,
availableStyles: getCssAssets(),
langs,
backupurl: BACKUP_URL,
shard,
lang,
});

View File

@ -12,16 +12,6 @@ import { getJsAssets, getCssAssets } from '../core/assets';
import { BACKUP_URL } from '../core/config';
import { getHostFromRequest } from '../utils/ip';
/*
* values that we pass to client scripts
*/
const ssv = {
availableStyles: getCssAssets(),
langs,
};
if (BACKUP_URL) {
ssv.backupurl = BACKUP_URL;
}
/*
* generates string with html of win page
@ -34,7 +24,9 @@ function generatePopUpPage(req) {
const shard = (host.startsWith(`${socketEvents.thisShard}.`))
? null : socketEvents.getLowestActiveShard();
const ssvR = JSON.stringify({
...ssv,
availableStyles: getCssAssets(),
langs,
backupurl: BACKUP_URL,
shard,
lang,
});