Ghost/core/bridge.js
Naz 979474a8cc Refactored bootstrap module into RouterManager class
refs https://linear.app/tryghost/issue/CORE-104/decouple-frontend-routing-events-from-urlserver-events

- The "bootstrap" didn't give enough credit to everything this module was doing - it's responsible for managing correct initialization and reinitialization of the frontend Routes as well as passing router creation information back to the frontend's URL service
- The refactor is done in two steps - the "bootstrap.js" will be renamed in the follow-up commit to have a clean history of how the file evolved
2021-10-19 07:29:09 +13:00

99 lines
3.6 KiB
JavaScript

/**
* The Bridge
*
* The bridge is responsible for handing communication from the server to the frontend.
* Data should only be flowing server -> frontend.
* As the architecture improves, the number of cross requires here should go down
* Eventually, the aim is to make this a component that is initialized on boot and is either handed to or actively creates the frontend, if the frontend is desired.
*
* This file is a great place for all the cross-component event handling in lieu of refactoring
* NOTE: You may require anything from shared, the frontend or server here - it is the one place (other than boot) that is allowed :)
*/
const debug = require('@tryghost/debug')('bridge');
const errors = require('@tryghost/errors');
const config = require('./shared/config');
const logging = require('@tryghost/logging');
const tpl = require('@tryghost/tpl');
const themeEngine = require('./frontend/services/theme-engine');
const frontendRouting = require('./frontend/services/routing').bootstrap;
const settingsCache = require('./shared/settings-cache');
// Listen to settings.lang.edited, similar to the member service and models/base/listeners
const events = require('./server/lib/common/events');
const messages = {
activateFailed: 'Unable to activate the theme "{theme}".'
};
class Bridge {
constructor() {
/**
* When locale changes, we reload theme translations
* @deprecated: the term "lang" was deprecated in favor of "locale" publicly in 4.0
*/
events.on('settings.lang.edited', (model) => {
debug('Active theme init18n');
this.getActiveTheme().initI18n({locale: model.get('value')});
});
// NOTE: eventually this event should somehow be listened on and handled by the URL Service
// for now this eliminates the need for the frontend routing to listen to
// server events
events.on('settings.timezone.edited', (model) => {
frontendRouting.handleTimezoneEdit(model);
});
}
getActiveTheme() {
return themeEngine.getActive();
}
activateTheme(loadedTheme, checkedTheme) {
let settings = {
locale: settingsCache.get('lang')
};
// no need to check the score, activation should be used in combination with validate.check
// Use the two theme objects to set the current active theme
try {
let previousGhostAPI;
if (this.getActiveTheme()) {
previousGhostAPI = this.getActiveTheme().engine('ghost-api');
}
themeEngine.setActive(settings, loadedTheme, checkedTheme);
const currentGhostAPI = this.getActiveTheme().engine('ghost-api');
if (previousGhostAPI !== undefined && (previousGhostAPI !== currentGhostAPI)) {
events.emit('services.themes.api.changed');
this.reloadFrontend();
}
} catch (err) {
logging.error(new errors.InternalServerError({
message: tpl(messages.activateFailed, {theme: loadedTheme.name}),
err: err
}));
}
}
getFrontendApiVersion() {
if (this.getActiveTheme()) {
return this.getActiveTheme().engine('ghost-api');
} else {
return config.get('api:versions:default');
}
}
reloadFrontend() {
const apiVersion = this.getFrontendApiVersion();
debug('reload frontend', apiVersion);
const siteApp = require('./server/web/site/app');
siteApp.reload({apiVersion});
}
}
const bridge = new Bridge();
module.exports = bridge;