Updated frontend apps to use new config

refs https://github.com/TryGhost/Team/issues/1719

- creates scripts injected for portal/search/comments using new config format
- adds `data-styles` to search/comments script for adding external styles URL
This commit is contained in:
Rishabh 2022-07-25 21:49:05 +05:30 committed by Rishabh Garg
parent a44460d226
commit eb75888b48
6 changed files with 115 additions and 25 deletions

View File

@ -1,11 +1,12 @@
const {SafeString} = require('../services/handlebars');
const {config, urlUtils, getFrontendKey, labs, settingsCache} = require('../services/proxy');
const {urlUtils, getFrontendKey, labs, settingsCache} = require('../services/proxy');
const {getFrontendAppConfig, getDataAttributes} = require('../utils/frontend-apps');
async function comments(options) {
// todo: For now check on the comment id to exclude normal pages (we probably have a better way to do this)
const commentId = this.comment_id;
if (!commentId) {
return;
}
@ -21,7 +22,7 @@ async function comments(options) {
if (commentsEnabled === 'off' || !hasAccess) {
return;
}
let colorScheme = 'auto';
if (options.hash.color_scheme === 'dark' || options.hash.color_scheme === 'light') {
colorScheme = options.hash.color_scheme;
@ -38,29 +39,27 @@ async function comments(options) {
}
const frontendKey = await getFrontendKey();
const {scriptUrl, stylesUrl, appVersion} = getFrontendAppConfig('comments');
const data = {
'ghost-comments': urlUtils.getSiteUrl(),
api: urlUtils.urlFor('api', {type: 'content'}, true),
admin: urlUtils.urlFor('admin', true),
key: frontendKey,
styles: stylesUrl,
'post-id': this.id,
'sentry-dsn': '', /* todo: insert sentry dsn key here */
'color-scheme': colorScheme,
'avatar-saturation': avatarSaturation,
'accent-color': accentColor,
'app-version': config.get('comments:version'),
'app-version': appVersion,
'comments-enabled': commentsEnabled
};
let dataAttributes = '';
Object.entries(data).forEach(([key, value]) => {
dataAttributes += `data-${key}="${value}" `;
});
const dataAttributes = getDataAttributes(data);
return new SafeString(`
<script defer src="${config.get('comments:url')}" ${dataAttributes} crossorigin="anonymous"></script>
<script defer src="${scriptUrl}" ${dataAttributes} crossorigin="anonymous"></script>
`);
}

View File

@ -13,6 +13,7 @@ const logging = require('@tryghost/logging');
const _ = require('lodash');
const debug = require('@tryghost/debug')('ghost_head');
const templateStyles = require('./tpl/styles');
const {getFrontendAppConfig, getDataAttributes} = require('../utils/frontend-apps');
const {get: getMetaData, getAssetUrl} = metaData;
@ -47,9 +48,20 @@ function getMembersHelper(data, frontendKey) {
if (!settingsCache.get('members_enabled')) {
return '';
}
const {scriptUrl} = getFrontendAppConfig('portal');
const colorString = _.has(data, 'site._preview') && data.site.accent_color ? ` data-accent-color="${data.site.accent_color}"` : '';
let membersHelper = `<script defer src="${config.get('portal:url')}" data-ghost="${urlUtils.getSiteUrl()}"${colorString} data-key="${frontendKey}" data-api="${urlUtils.urlFor('api', {type: 'content'}, true)}" crossorigin="anonymous"></script>`;
const colorString = (_.has(data, 'site._preview') && data.site.accent_color) ? data.site.accent_color : '';
const attributes = {
ghost: urlUtils.getSiteUrl(),
key: frontendKey,
api: urlUtils.urlFor('api', {type: 'content'}, true)
};
if (colorString) {
attributes['accent-color'] = colorString;
}
const dataAttributes = getDataAttributes(attributes);
let membersHelper = `<script defer src="${scriptUrl}" ${dataAttributes} crossorigin="anonymous"></script>`;
membersHelper += (`<style id="gh-members-styles">${templateStyles}</style>`);
if (settingsCache.get('paid_members_enabled')) {
membersHelper += '<script async src="https://js.stripe.com/v3/"></script>';
@ -59,8 +71,14 @@ function getMembersHelper(data, frontendKey) {
function getSearchHelper(frontendKey) {
const adminUrl = urlUtils.getAdminUrl() || urlUtils.getSiteUrl();
let helper = `<script defer src="${config.get('sodoSearch:url')}" data-sodo-search="${adminUrl}" data-version="${config.get('sodoSearch:version')}" data-key="${frontendKey}" crossorigin="anonymous"></script>`;
const {scriptUrl, stylesUrl} = getFrontendAppConfig('sodoSearch');
const attrs = {
key: frontendKey,
styles: stylesUrl,
'sodo-search': adminUrl
};
const dataAttrs = getDataAttributes(attrs);
let helper = `<script defer src="${scriptUrl}" ${dataAttrs} crossorigin="anonymous"></script>`;
return helper;
}

View File

@ -0,0 +1,33 @@
const {config} = require('../services/proxy');
function getFrontendAppConfig(app) {
const appVersion = config.get(`${app}:version`);
let scriptUrl = config.get(`${app}:url`);
let stylesUrl = config.get(`${app}:styles`);
if (scriptUrl.includes('{version}')) {
scriptUrl = scriptUrl.replace('{version}', appVersion);
}
if (stylesUrl?.includes('{version}')) {
stylesUrl = stylesUrl.replace('{version}', appVersion);
}
return {
scriptUrl,
stylesUrl,
appVersion
};
}
function getDataAttributes(data) {
let dataAttributes = '';
if (!data) {
return dataAttributes;
}
Object.entries(data).forEach(([key, value]) => {
dataAttributes += `data-${key}="${value}" `;
});
return dataAttributes.trim();
}
module.exports = {getFrontendAppConfig, getDataAttributes};

View File

@ -56,8 +56,8 @@ describe('{{comments}} helper', function () {
}
});
should.exist(rendered);
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/comments-ui');
rendered.string.should.containEql('data-ghost-comments="http://127.0.0.1:2369/" data-api="http://127.0.0.1:2369/ghost/api/content/" data-admin="http://127.0.0.1:2369/ghost/" data-key="xyz" data-post-id="post_id_123" data-sentry-dsn="" data-color-scheme="auto" data-avatar-saturation="50" data-accent-color="" data-app-version="test.version" data-comments-enabled="all"');
rendered.string.should.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/comments-ui');
rendered.string.should.containEql('data-ghost-comments="http://127.0.0.1:2369/" data-api="http://127.0.0.1:2369/ghost/api/content/" data-admin="http://127.0.0.1:2369/ghost/" data-key="xyz" data-styles="https://cdn.jsdelivr.net/npm/@tryghost/comments-ui@~test.version/umd/main.css" data-post-id="post_id_123" data-sentry-dsn="" data-color-scheme="auto" data-avatar-saturation="50" data-accent-color="" data-app-version="test.version" data-comments-enabled="all"');
});
it('returns a script tag for paid only commenting', async function () {
@ -75,8 +75,8 @@ describe('{{comments}} helper', function () {
}
});
should.exist(rendered);
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/comments-ui');
rendered.string.should.containEql('data-ghost-comments="http://127.0.0.1:2369/" data-api="http://127.0.0.1:2369/ghost/api/content/" data-admin="http://127.0.0.1:2369/ghost/" data-key="xyz" data-post-id="post_id_123" data-sentry-dsn="" data-color-scheme="auto" data-avatar-saturation="50" data-accent-color="" data-app-version="test.version" data-comments-enabled="paid"');
rendered.string.should.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/comments-ui');
rendered.string.should.containEql('data-ghost-comments="http://127.0.0.1:2369/" data-api="http://127.0.0.1:2369/ghost/api/content/" data-admin="http://127.0.0.1:2369/ghost/" data-key="xyz" data-styles="https://cdn.jsdelivr.net/npm/@tryghost/comments-ui@~test.version/umd/main.css" data-post-id="post_id_123" data-sentry-dsn="" data-color-scheme="auto" data-avatar-saturation="50" data-accent-color="" data-app-version="test.version" data-comments-enabled="paid"');
});
it('returns undefined when comments are disabled', async function () {
@ -113,4 +113,3 @@ describe('{{comments}} helper', function () {
should.not.exist(rendered);
});
});

View File

@ -1669,7 +1669,7 @@ describe('{{ghost_head}} helper', function () {
}
})).then(function (rendered) {
should.exist(rendered);
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/portal');
rendered.string.should.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/portal');
rendered.string.should.containEql('data-ghost="http://127.0.0.1:2369/" data-key="xyz" data-api="http://127.0.0.1:2369/ghost/api/content/"');
rendered.string.should.containEql('<style id="gh-members-styles">');
done();
@ -1688,7 +1688,7 @@ describe('{{ghost_head}} helper', function () {
}
})).then(function (rendered) {
should.exist(rendered);
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/portal');
rendered.string.should.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/portal');
rendered.string.should.containEql('data-ghost="http://127.0.0.1:2369/" data-key="xyz" data-api="http://127.0.0.1:2369/ghost/api/content/"');
rendered.string.should.containEql('<style id="gh-members-styles">');
rendered.string.should.containEql('<script async src="https://js.stripe.com');
@ -1708,7 +1708,7 @@ describe('{{ghost_head}} helper', function () {
}
})).then(function (rendered) {
should.exist(rendered);
rendered.string.should.not.containEql('<script defer src="https://unpkg.com/@tryghost/portal');
rendered.string.should.not.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/portal');
rendered.string.should.not.containEql('data-ghost="http://127.0.0.1:2369/" data-key="xyz" data-api="http://127.0.0.1:2369/ghost/api/content/"');
rendered.string.should.not.containEql('<style id="gh-members-styles">');
rendered.string.should.not.containEql('<script async src="https://js.stripe.com');
@ -1728,7 +1728,7 @@ describe('{{ghost_head}} helper', function () {
}
})).then(function (rendered) {
should.exist(rendered);
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/portal');
rendered.string.should.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/portal');
rendered.string.should.containEql('data-ghost="http://127.0.0.1:2369/" data-key="xyz" data-api="http://127.0.0.1:2369/ghost/api/content/"');
rendered.string.should.containEql('<style id="gh-members-styles">');
rendered.string.should.not.containEql('<script async src="https://js.stripe.com');
@ -1749,8 +1749,8 @@ describe('{{ghost_head}} helper', function () {
}
})).then(function (rendered) {
should.exist(rendered);
rendered.string.should.containEql('<script defer src="https://unpkg.com/@tryghost/sodo-search');
rendered.string.should.containEql('data-sodo-search="http://127.0.0.1:2369/" data-version="0.1.0" data-key="xyz"');
rendered.string.should.containEql('<script defer src="https://cdn.jsdelivr.net/npm/@tryghost/sodo-search');
rendered.string.should.containEql('data-key="xyz" data-styles="https://cdn.jsdelivr.net/npm/@tryghost/sodo-search@~1.0/umd/main.css" data-sodo-search="http://127.0.0.1:2369/"');
done();
}).catch(done);

View File

@ -0,0 +1,41 @@
const should = require('should');
const {getFrontendAppConfig, getDataAttributes} = require('../../../../core/frontend/utils/frontend-apps');
const configUtils = require('../../../utils/configUtils');
describe('Frontend apps:', function () {
describe('getFrontendAppConfig', function () {
before(function () {
configUtils.set({'portal:url': 'https://cdn.example.com/~{version}/portal.min.js'});
configUtils.set({'portal:version': '1.0'});
configUtils.set({'portal:styles': 'https://cdn.example.com/~{version}/main.css'});
});
after(function () {
configUtils.restore();
});
it('should return app urls and version from config', async function () {
const {stylesUrl, scriptUrl, appVersion} = getFrontendAppConfig('portal');
should.equal(appVersion, '1.0');
should.equal(stylesUrl, 'https://cdn.example.com/~1.0/main.css');
should.equal(scriptUrl, 'https://cdn.example.com/~1.0/portal.min.js');
});
});
describe('getDataAttributes', function () {
it('should generate data attributes string from object', async function () {
const dataAttributes = getDataAttributes({
admin: 'test',
'example-version': '1.0'
});
should.equal(dataAttributes, 'data-admin="test" data-example-version="1.0"');
});
it('should generate empty string for missing data object', async function () {
const dataAttributes = getDataAttributes();
should.equal(dataAttributes, '');
});
});
});