Ghost/core/bridge.js
Hannah Wolfe d1e5ccae14
💡 Pinned frontend API version to canary
- Ghost themes are allowed to define the API version they want to use, but this concept has never really worked correctly
- We have a theory that it doesn't ever do quite what people want, and so always loading latest would not really break anything - this commit tests that theory
- We're pinning to canary, as we're aiming to get rid of the concept of versions altogether
- I could have done return config.get('api:versions:default');, but this actually returns v4 (although the same as canary, conceptually different)
  and it also seemed like an unnecessary level of indirection. This change should be easy to understand and to revert if we are wrong
2022-02-17 17:55:55 +00:00

109 lines
3.9 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 logging = require('@tryghost/logging');
const tpl = require('@tryghost/tpl');
const themeEngine = require('./frontend/services/theme-engine');
const cardAssetService = require('./frontend/services/card-assets');
const routerManager = require('./frontend/services/routing').routerManager;
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 {
init() {
/**
* 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) => {
routerManager.handleTimezoneEdit(model);
});
}
getActiveTheme() {
return themeEngine.getActive();
}
async 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');
await this.reloadFrontend();
}
const cardAssetConfig = this.getCardAssetConfig();
debug('reload card assets config', cardAssetConfig);
await cardAssetService.load(cardAssetConfig);
} catch (err) {
logging.error(new errors.InternalServerError({
message: tpl(messages.activateFailed, {theme: loadedTheme.name}),
err: err
}));
}
}
getFrontendApiVersion() {
// @NOTE: we've pinned the frontend to canary in a step towards removing API versions
return 'canary';
}
getCardAssetConfig() {
if (this.getActiveTheme()) {
return this.getActiveTheme().config('card_assets');
} else {
return true;
}
}
async reloadFrontend() {
const apiVersion = this.getFrontendApiVersion();
debug('reload frontend', apiVersion);
const siteApp = require('./frontend/web/site');
await siteApp.reload({apiVersion});
}
}
const bridge = new Bridge();
module.exports = bridge;