etherpad-lite/src/node/hooks/express/static.js
2022-05-06 02:54:34 -04:00

182 lines
5.5 KiB
JavaScript

'use strict';
const minify = require('../../utils/Minify');
const plugins = require('../../../static/js/pluginfw/plugin_defs');
const settings = require('../../utils/Settings');
const CachingMiddleware = require('../../utils/caching_middleware');
const Yajsml = require('etherpad-yajsml');
const tar = (() => {
const associations = {
'pad.js': [
'pad.js',
'pad_utils.js',
'$js-cookie/dist/js.cookie.js',
'security.js',
'$security.js',
'vendors/browser.js',
'pad_cookie.js',
'pad_editor.js',
'pad_editbar.js',
'vendors/nice-select.js',
'pad_modals.js',
'pad_automatic_reconnect.js',
'ace.js',
'collab_client.js',
'cssmanager.js',
'pad_userlist.js',
'pad_impexp.js',
'pad_savedrevs.js',
'pad_connectionstatus.js',
'ChatMessage.js',
'chat.js',
'vendors/gritter.js',
'$js-cookie/dist/js.cookie.js',
'$tinycon/tinycon.js',
'vendors/farbtastic.js',
'skin_variants.js',
'socketio.js',
'colorutils.js',
],
'timeslider.js': [
'timeslider.js',
'colorutils.js',
'draggable.js',
'pad_utils.js',
'$js-cookie/dist/js.cookie.js',
'vendors/browser.js',
'pad_cookie.js',
'pad_editor.js',
'pad_editbar.js',
'vendors/nice-select.js',
'pad_modals.js',
'pad_automatic_reconnect.js',
'pad_savedrevs.js',
'pad_impexp.js',
'AttributePool.js',
'Changeset.js',
'domline.js',
'linestylefilter.js',
'cssmanager.js',
'broadcast.js',
'broadcast_slider.js',
'broadcast_revisions.js',
'socketio.js',
'AttributeManager.js',
'AttributeMap.js',
'attributes.js',
'ChangesetUtils.js',
],
'ace2_inner.js': [
'ace2_inner.js',
'vendors/browser.js',
'AttributePool.js',
'Changeset.js',
'ChangesetUtils.js',
'skiplist.js',
'colorutils.js',
'undomodule.js',
'$unorm/lib/unorm.js',
'contentcollector.js',
'changesettracker.js',
'linestylefilter.js',
'domline.js',
'AttributeManager.js',
'AttributeMap.js',
'attributes.js',
'scroll.js',
'caretPosition.js',
'pad_utils.js',
'$js-cookie/dist/js.cookie.js',
'security.js',
'$security.js',
],
'ace2_common.js': [
'ace2_common.js',
'vendors/browser.js',
'vendors/jquery.js',
'rjquery.js',
'$async.js',
'underscore.js',
'$underscore.js',
'$underscore/underscore.js',
'security.js',
'$security.js',
'pluginfw/client_plugins.js',
'pluginfw/plugin_defs.js',
'pluginfw/shared.js',
'pluginfw/hooks.js',
],
};
const prefixLocalLibraryPath = (path) => {
if (path.charAt(0) === '$') {
return path.slice(1);
} else {
return `ep_etherpad-lite/static/js/${path}`;
}
};
const tar = {};
for (const [key, relativeFiles] of Object.entries(associations)) {
const files = relativeFiles.map(prefixLocalLibraryPath);
tar[prefixLocalLibraryPath(key)] = files
.concat(files.map((p) => p.replace(/\.js$/, '')))
.concat(files.map((p) => `${p.replace(/\.js$/, '')}/index.js`));
}
return tar;
})();
exports.expressPreSession = async (hookName, {app}) => {
// Cache both minified and static.
const assetCache = new CachingMiddleware();
app.all(/\/javascripts\/(.*)/, assetCache.handle.bind(assetCache));
// Minify will serve static files compressed (minify enabled). It also has
// file-specific hacks for ace/require-kernel/etc.
app.all('/static/:filename(*)', minify.minify);
// Setup middleware that will package JavaScript files served by minify for
// CommonJS loader on the client-side.
// Hostname "invalid.invalid" is a dummy value to allow parsing as a URI.
const jsServer = new (Yajsml.Server)({
rootPath: 'javascripts/src/',
rootURI: 'http://invalid.invalid/static/js/',
libraryPath: 'javascripts/lib/',
libraryURI: 'http://invalid.invalid/static/plugins/',
requestURIs: minify.requestURIs, // Loop-back is causing problems, this is a workaround.
});
const StaticAssociator = Yajsml.associators.StaticAssociator;
const associations = Yajsml.associators.associationsForSimpleMapping(tar);
const associator = new StaticAssociator(associations);
jsServer.setAssociator(associator);
app.use(jsServer.handle.bind(jsServer));
// serve plugin definitions
// not very static, but served here so that client can do
// require("pluginfw/static/js/plugin-definitions.js");
app.get('/pluginfw/plugin-definitions.json', (req, res, next) => {
// No need to tell clients about server-side hooks.
const stripServerSideHooks = (parts) => parts.reduce((parts, part) => {
if (part.client_hooks != null) {
if (part.hooks) part = {...part, hooks: undefined};
parts.push(part);
}
return parts;
}, []);
const clientParts = stripServerSideHooks(plugins.parts);
const clientPlugins = {};
for (const name of new Set(clientParts.map((part) => part.plugin))) {
const plugin = plugins.plugins[name];
clientPlugins[name] = {
...plugin,
parts: stripServerSideHooks(plugin.parts),
};
delete clientPlugins[name].package;
}
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
res.write(JSON.stringify({plugins: clientPlugins, parts: clientParts}));
res.end();
});
};