From ed6a8dca76d33d0b43f865bf9f006fd4a93bb2ba Mon Sep 17 00:00:00 2001 From: Daniel Lockyer Date: Thu, 21 Oct 2021 10:27:56 +0200 Subject: [PATCH] Inlined package requires to save boot time and memory no issue - following on from https://github.com/TryGhost/Ghost/commit/f4fb0fcbaa6dd98b2da5ac85e5d1451340f302ba, this commit moves around some package requires in Ghost - these are often niche packages that do something in a subsystem of Ghost, and are not necessarily be needed to boot the application - these packages use non-negligible CPU and memory when they are required, so it makes sense to lazy-require them - the concern here is that we obscure the code too much by moving random requires further into code, but the changes are small and the improvements big - this commit bring the boot time since 4.19.0 down ~31% and initial memory usage down by a total of ~12% --- core/server/lib/mobiledoc.js | 2 +- core/server/models/user.js | 3 ++- core/server/services/bulk-email/mailgun.js | 2 +- .../services/mega/post-email-serializer.js | 2 +- core/server/update-check.js | 6 +++--- core/server/web/oauth/app.js | 6 ++++-- core/server/web/well-known.js | 20 +++++++++---------- core/shared/html-to-plaintext.js | 4 ++-- core/shared/labs.js | 2 +- 9 files changed, 25 insertions(+), 22 deletions(-) diff --git a/core/server/lib/mobiledoc.js b/core/server/lib/mobiledoc.js index a401355501..8cc474b680 100644 --- a/core/server/lib/mobiledoc.js +++ b/core/server/lib/mobiledoc.js @@ -3,7 +3,6 @@ const errors = require('@tryghost/errors'); const logging = require('@tryghost/logging'); const config = require('../../shared/config'); const storage = require('../adapters/storage'); -const imageTransform = require('@tryghost/image-transform'); let cardFactory; let cards; @@ -34,6 +33,7 @@ module.exports = { siteUrl: config.get('url'), imageOptimization: config.get('imageOptimization'), canTransformImage(storagePath) { + const imageTransform = require('@tryghost/image-transform'); const {ext} = path.parse(storagePath); // NOTE: the "saveRaw" check is smelly diff --git a/core/server/models/user.js b/core/server/models/user.js index e3dee324b0..c9be0e09e3 100644 --- a/core/server/models/user.js +++ b/core/server/models/user.js @@ -8,7 +8,6 @@ const limitService = require('../services/limits'); const tpl = require('@tryghost/tpl'); const errors = require('@tryghost/errors'); const security = require('@tryghost/security'); -const {gravatar} = require('../lib/image'); const {pipeline} = require('@tryghost/promise'); const validatePassword = require('../lib/validate-password'); const permissions = require('../services/permissions'); @@ -191,6 +190,8 @@ User = ghostBookshelf.Model.extend({ // If the user's email is set & has changed & we are not importing if (self.hasChanged('email') && self.get('email') && !options.importing) { tasks.gravatar = (function lookUpGravatar() { + const {gravatar} = require('../lib/image'); + return gravatar.lookup({ email: self.get('email') }).then(function (response) { diff --git a/core/server/services/bulk-email/mailgun.js b/core/server/services/bulk-email/mailgun.js index 80b306559c..a8ba29614b 100644 --- a/core/server/services/bulk-email/mailgun.js +++ b/core/server/services/bulk-email/mailgun.js @@ -1,6 +1,5 @@ const _ = require('lodash'); const {URL} = require('url'); -const mailgun = require('mailgun-js'); const logging = require('@tryghost/logging'); const configService = require('../../../shared/config'); const settingsCache = require('../../../shared/settings-cache'); @@ -8,6 +7,7 @@ const settingsCache = require('../../../shared/settings-cache'); const BATCH_SIZE = 1000; function createMailgun(config) { + const mailgun = require('mailgun-js'); const baseUrl = new URL(config.baseUrl); return mailgun({ diff --git a/core/server/services/mega/post-email-serializer.js b/core/server/services/mega/post-email-serializer.js index d9300382b4..b65a26af63 100644 --- a/core/server/services/mega/post-email-serializer.js +++ b/core/server/services/mega/post-email-serializer.js @@ -1,5 +1,4 @@ const _ = require('lodash'); -const juice = require('juice'); const template = require('./template'); const settingsCache = require('../../../shared/settings-cache'); const urlUtils = require('../../../shared/url-utils'); @@ -20,6 +19,7 @@ const ALLOWED_REPLACEMENTS = ['first_name']; const formatHtmlForEmail = function formatHtmlForEmail(html) { const juiceOptions = {inlinePseudoElements: true}; + const juice = require('juice'); let juicedHtml = juice(html, juiceOptions); // convert juiced HTML to a DOM-like interface for further manipulation diff --git a/core/server/update-check.js b/core/server/update-check.js index a218d40a76..d4903fc2c7 100644 --- a/core/server/update-check.js +++ b/core/server/update-check.js @@ -1,7 +1,6 @@ const _ = require('lodash'); const api = require('./api'); -const GhostMailer = require('./services/mail').GhostMailer; const config = require('../shared/config'); const urlUtils = require('./../shared/url-utils'); const jobsService = require('./services/jobs'); @@ -10,8 +9,6 @@ const request = require('@tryghost/request'); const ghostVersion = require('@tryghost/version'); const UpdateCheckService = require('@tryghost/update-check-service'); -const ghostMailer = new GhostMailer(); - /** * Initializes and triggers update check * @@ -25,6 +22,9 @@ module.exports = async () => { return; } + const {GhostMailer} = require('./services/mail'); + const ghostMailer = new GhostMailer(); + const updateChecker = new UpdateCheckService({ api: { settings: { diff --git a/core/server/web/oauth/app.js b/core/server/web/oauth/app.js index 68a37cd083..7f1fa72310 100644 --- a/core/server/web/oauth/app.js +++ b/core/server/web/oauth/app.js @@ -1,7 +1,5 @@ const debug = require('@tryghost/debug')('web:oauth:app'); const {URL} = require('url'); -const passport = require('passport'); -const GoogleStrategy = require('passport-google-oauth20').Strategy; const express = require('../../../shared/express'); const urlUtils = require('../../../shared/url-utils'); const shared = require('../shared'); @@ -36,6 +34,10 @@ module.exports = function setupOAuthApp() { */ function googleOAuthMiddleware(clientId, secret) { return (req, res, next) => { + // Lazy-required to save boot time + const passport = require('passport'); + const GoogleStrategy = require('passport-google-oauth20').Strategy; + const adminURL = urlUtils.urlFor('admin', true); //Create the callback url to be sent to Google diff --git a/core/server/web/well-known.js b/core/server/web/well-known.js index fa47c7b337..a0b2149880 100644 --- a/core/server/web/well-known.js +++ b/core/server/web/well-known.js @@ -1,19 +1,19 @@ const express = require('../../shared/express'); const settings = require('../../shared/settings-cache'); -const jose = require('node-jose'); - -const dangerousPrivateKey = settings.get('ghost_private_key'); -const keyStore = jose.JWK.createKeyStore(); -const keyStoreReady = keyStore.add(dangerousPrivateKey, 'pem'); - -const getSafePublicJWKS = async () => { - await keyStoreReady; - return keyStore.toJSON(); -}; module.exports = function setupWellKnownApp() { const wellKnownApp = express('well-known'); + const jose = require('node-jose'); + const dangerousPrivateKey = settings.get('ghost_private_key'); + const keyStore = jose.JWK.createKeyStore(); + const keyStoreReady = keyStore.add(dangerousPrivateKey, 'pem'); + + const getSafePublicJWKS = async () => { + await keyStoreReady; + return keyStore.toJSON(); + }; + wellKnownApp.get('/jwks.json', async (req, res) => { const jwks = await getSafePublicJWKS(); res.json(jwks); diff --git a/core/shared/html-to-plaintext.js b/core/shared/html-to-plaintext.js index 8413918ceb..a5b6dc6f8e 100644 --- a/core/shared/html-to-plaintext.js +++ b/core/shared/html-to-plaintext.js @@ -1,6 +1,6 @@ -const htmlToText = require('html-to-text'); - module.exports = function htmlToPlaintext(html) { + const htmlToText = require('html-to-text'); + return htmlToText.fromString(html, { wordwrap: 80, ignoreImage: true, diff --git a/core/shared/labs.js b/core/shared/labs.js index 61e13a0f1d..abfb93d8cb 100644 --- a/core/shared/labs.js +++ b/core/shared/labs.js @@ -1,6 +1,5 @@ const _ = require('lodash'); const Promise = require('bluebird'); -const SafeString = require('express-hbs').SafeString; const errors = require('@tryghost/errors'); const logging = require('@tryghost/logging'); const tpl = require('@tryghost/tpl'); @@ -87,6 +86,7 @@ module.exports.enabledHelper = function enabledHelper(options, callback) { logging.error(new errors.DisabledFeatureError(errDetails)); + const {SafeString} = require('express-hbs'); errString = new SafeString(``); if (options.async) {