diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09b4a8bc7..e6ad36935 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,9 @@ importers: cookie-parser: specifier: ^1.4.6 version: 1.4.6 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 cross-spawn: specifier: ^7.0.3 version: 7.0.3 @@ -2085,6 +2088,11 @@ packages: typescript: optional: true + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -6144,6 +6152,10 @@ snapshots: optionalDependencies: typescript: 5.5.3 + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.3 + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 diff --git a/src/node/hooks/express/specialpages.ts b/src/node/hooks/express/specialpages.ts index 4053dbabd..384da2cda 100644 --- a/src/node/hooks/express/specialpages.ts +++ b/src/node/hooks/express/specialpages.ts @@ -1,13 +1,13 @@ 'use strict'; -const path = require('path'); +import path from 'node:path'; const eejs = require('../../eejs') -const fs = require('fs'); +import fs from 'node:fs'; const fsp = fs.promises; const toolbar = require('../../utils/toolbar'); const hooks = require('../../../static/js/pluginfw/hooks'); const settings = require('../../utils/Settings'); -const util = require('util'); +import util from 'node:util'; const webaccess = require('./webaccess'); const plugins = require('../../../static/js/pluginfw/plugin_defs'); import {hash, createHash} from 'node:crypto' @@ -83,91 +83,110 @@ exports.expressCreateServer = async (hookName: string, args: any, cb: Function) res.send(eejs.require('ep_etherpad-lite/templates/index.html', {req})); }); - await fsp.writeFile( - path.join(settings.root, 'var/js/padbootstrap.js'), - eejs.require('ep_etherpad-lite/templates/padBootstrap.js', { + + const padString = eejs.require('ep_etherpad-lite/templates/padBootstrap.js', { pluginModules: (() => { const pluginModules = new Set(); for (const part of plugins.parts) { for (const [, hookFnName] of Object.entries(part.client_hooks || {})) { + // @ts-ignore pluginModules.add(hookFnName.split(':')[0]); } } return [...pluginModules]; })(), settings, - })); + }) - await fsp.writeFile( - path.join(settings.root, 'var/js/timesliderBootstrap.js'), - eejs.require('ep_etherpad-lite/templates/timeSliderBootstrap.js', { + + const timeSliderString = eejs.require('ep_etherpad-lite/templates/timeSliderBootstrap.js', { pluginModules: (() => { const pluginModules = new Set(); for (const part of plugins.parts) { for (const [, hookFnName] of Object.entries(part.client_hooks || {})) { + // @ts-ignore pluginModules.add(hookFnName.split(':')[0]); } } return [...pluginModules]; })(), settings, - })); + }) + - const hash = createHash('sha256').update(fs.readFileSync(path.join(settings.root, 'var/js/padbootstrap.js'))).digest('hex'); - const hashTimeSlider = createHash('sha256').update(fs.readFileSync(path.join(settings.root, 'var/js/timesliderBootstrap.js'))).digest('hex'); - const fileName = `padbootstrap-${hash.substring(0,16)}.min.js` - const fileNameTimeSlider = `timeSliderBootstrap-${hashTimeSlider.substring(0,16)}.min.js` const outdir = path.join(settings.root, 'var','js') - - - buildSync({ - entryPoints: path.join(outdir, 'padbootstrap.js'), // Entry file(s) + const padWriteResult = buildSync({ + stdin: { + contents: padString, + resolveDir: path.join(settings.root, 'var','js'), + loader: 'js' + }, // Entry file(s) bundle: true, // Bundle the files together - minify: false, // Minify the output + minify: process.env.NODE_ENV === "production", // Minify the output + sourcemap: true, // Generate source maps + sourceRoot: settings.root+"/src/static/js/", + + target: ['es2020'], // Target ECMAScript version + metafile: true, + + write: false, // Do not write to file system, + }) + + const outputPadJS = padWriteResult.outputFiles[0].text + + const timeSliderWrite = buildSync({ + //entryPoints: [path.join(outdir, "timesliderBootstrap.js")], // Entry file(s), + stdin: { + contents: timeSliderString, + resolveDir: path.join(settings.root, 'var','js'), + loader: 'js' + }, + bundle: true, // Bundle the files together + minify: process.env.NODE_ENV === "production", // Minify the output sourcemap: true, // Generate source maps sourceRoot: settings.root+"/src/static/js/", target: ['es2020'], // Target ECMAScript version metafile: true, - write: true, // Do not write to file system, - outfile: path.join(outdir,fileName), // Output file + write: false, // Do not write to file system, }) - buildSync({ - entryPoints: [settings.root + "/var/js/timesliderBootstrap.js"], // Entry file(s) - bundle: true, // Bundle the files together - minify: false, // Minify the output - sourcemap: true, // Generate source maps - sourceRoot: settings.root+"/src/static/js/", - target: ['es2020'], // Target ECMAScript version - metafile: true, + const outputTimeslider = timeSliderWrite.outputFiles[0].text - write: true, // Do not write to file system, - outfile: path.join(outdir,fileNameTimeSlider), // Output file + const hash = createHash('sha256').update(outputPadJS).digest('hex').substring(0,8); + const hashTimeSlider = createHash('sha256').update(outputTimeslider).digest('hex').substring(0,8); + + const fileNamePad = `padbootstrap-${hash}.min.js` + const fileNameTimeSlider = `timeSliderBootstrap-${hashTimeSlider}.min.js` + const pathNamePad = path.join(outdir, fileNamePad) + const pathNameTimeSlider = path.join(outdir, fileNameTimeSlider) + + if (!fs.existsSync(pathNamePad)) { + fs.writeFileSync(pathNamePad, outputPadJS); + } + + if (!fs.existsSync(pathNameTimeSlider)) { + fs.writeFileSync(pathNameTimeSlider,outputTimeslider) + } + + args.app.get("/"+fileNamePad, (req: any, res: any) => { + res.sendFile(pathNamePad) }) - - args.app.get(`/${fileName}`, (req: any, res: any) => { - res.sendFile(settings.root+`/var/js/${fileName}`) + args.app.get("/"+fileNamePad+".map", (req: any, res: any) => { + res.sendFile(pathNamePad+".map") }) - args.app.get(`/${fileName}.map`, (req: any, res: any) => { - res.sendFile(settings.root+`/var/js/${fileName}.map`) + args.app.get("/"+fileNameTimeSlider, (req: any, res: any) => { + res.sendFile(pathNameTimeSlider) }) - args.app.get(`/${fileNameTimeSlider}`, (req: any, res: any) => { - res.sendFile(settings.root+`/var/js/${fileNameTimeSlider}`) + args.app.get("/"+fileNameTimeSlider+".map", (req: any, res: any) => { + res.sendFile(pathNameTimeSlider+".map") }) - args.app.get(`/${fileNameTimeSlider}.map`, (req: any, res: any) => { - res.sendFile(settings.root+`/var/js/${fileNameTimeSlider}.map`) - }) - - - - // serve pad.html under /p args.app.get('/p/:pad', (req: any, res: any, next: Function) => { @@ -185,7 +204,7 @@ exports.expressCreateServer = async (hookName: string, args: any, cb: Function) req, toolbar, isReadOnly, - entrypoint: "/"+fileName + entrypoint: "/"+fileNamePad })); }); diff --git a/src/package.json b/src/package.json index ab49c1ae7..ad5c95a69 100644 --- a/src/package.json +++ b/src/package.json @@ -75,7 +75,8 @@ "ueberdb2": "^4.2.82", "underscore": "1.13.6", "unorm": "1.6.0", - "wtfnode": "^0.9.3" + "wtfnode": "^0.9.3", + "cross-env": "^7.0.3" }, "bin": { "etherpad-healthcheck": "../bin/etherpad-healthcheck", @@ -124,8 +125,8 @@ "test": "mocha --import=tsx --timeout 120000 --recursive tests/backend/specs/**.ts ../node_modules/ep_*/static/tests/backend/specs/**", "test-utils": "mocha --import=tsx --timeout 5000 --recursive tests/backend/specs/*utils.ts", "test-container": "mocha --import=tsx --timeout 5000 tests/container/specs/api", - "dev": "node --require tsx/cjs node/server.ts", - "prod": "node --require tsx/cjs node/server.ts", + "dev": "cross-env NODE_ENV=development node --require tsx/cjs node/server.ts", + "prod": "cross-env NODE_ENV=production node --require tsx/cjs node/server.ts", "ts-check": "tsc --noEmit", "ts-check:watch": "tsc --noEmit --watch", "test-ui": "npx playwright test tests/frontend-new/specs",