Files
overleaf-cep/services/web/app/src/infrastructure/Views.js
Jakob Ackermann f0a3c15559 Merge pull request #19220 from overleaf/jpa-precompile-pug
[web] precompile pug templates in CI

GitOrigin-RevId: 6ec2b85a357fa3d5c35d8e7eb1a2e81ac5f3b447
2024-07-04 08:04:51 +00:00

131 lines
3.4 KiB
JavaScript

const logger = require('@overleaf/logger')
const pug = require('pug')
const globby = require('globby')
const Settings = require('@overleaf/settings')
const fs = require('fs')
const Path = require('path')
// Generate list of view names from app/views
function buildViewList() {
return globby
.sync('app/views/**/*.pug', {
onlyFiles: true,
concurrency: 1,
ignore: [
// Ignore includes
'**/_*.pug',
'**/_*/**',
// Ignore shared layout files
'app/views/layout*',
'app/views/layout/*',
],
})
.concat(
globby.sync('modules/*/app/views/**/*.pug', {
onlyFiles: true,
concurrency: 1,
// Ignore includes
ignore: ['**/_*.pug', '**/_*/**'],
})
)
.concat(Object.values(Settings.viewIncludes).flat())
.map(x => Path.resolve(x))
}
const PUG_COMPILE_ARGUMENTS = {
doctype: 'html',
cache: true,
compileDebug: Settings.debugPugTemplates,
inlineRuntimeFunctions: false,
module: true,
}
function precompileViewsAndCacheToDisk() {
const startTime = Date.now()
let success = 0
let precompiled = 0
for (const filename of buildViewList()) {
const precompiledFilename = filename.replace(/\.pug$/, '.js')
try {
const src = pug.compileFileClient(filename, PUG_COMPILE_ARGUMENTS)
try {
if (fs.readFileSync(precompiledFilename, 'utf-8') === src) {
precompiled++
continue
}
} catch {}
fs.writeFileSync(precompiledFilename, src, {
encoding: 'utf-8',
mode: 0o644,
})
success++
} catch (err) {
logger.err({ err, filename }, 'failed to precompile pug template')
throw err
}
}
logger.info(
{ timeTaken: Date.now() - startTime, success, precompiled },
'compiled pug templates'
)
}
module.exports = {
compileViewIncludes(app) {
const viewIncludes = {}
for (const [view, paths] of Object.entries(Settings.viewIncludes)) {
viewIncludes[view] = []
for (const filePath of paths) {
viewIncludes[view].push(
pug.compileFile(filePath, {
...PUG_COMPILE_ARGUMENTS,
cache: app.enabled('view cache'),
})
)
}
}
return viewIncludes
},
precompileViews(app) {
const startTime = Date.now()
let success = 0
let precompiled = 0
let failures = 0
for (const filename of buildViewList()) {
const precompiledFilename = filename.replace(/\.pug$/, '.js')
if (fs.existsSync(precompiledFilename)) {
logger.debug({ filename }, 'loading precompiled pug template')
try {
pug.cache[filename] = require(precompiledFilename)
precompiled++
continue
} catch (err) {
logger.error(
{ filename, err },
'error loading precompiled pug template'
)
failures++
}
}
try {
logger.warn({ filename }, 'compiling pug template at boot time')
pug.compileFile(filename, PUG_COMPILE_ARGUMENTS)
success++
} catch (err) {
logger.error({ filename, err }, 'error compiling pug template')
failures++
}
}
logger.debug(
{ timeTaken: Date.now() - startTime, failures, success, precompiled },
'compiled pug templates'
)
},
}
if (require.main === module) {
precompileViewsAndCacheToDisk()
process.exit(0)
}