mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #4926 from overleaf/jpa-webpack-dynamic-entrypoint-chunks
[web] get the list of js/css entrypoint chunks from webpack manifest GitOrigin-RevId: 42a8d3606e461e8d9eebcc754e3207d5be1746ab
This commit is contained in:
parent
e687230f8a
commit
a1c74f27d9
8 changed files with 147 additions and 95 deletions
|
@ -6,9 +6,7 @@ const Url = require('url')
|
|||
const Path = require('path')
|
||||
const moment = require('moment')
|
||||
const pug = require('pug-runtime')
|
||||
|
||||
const IS_DEV_ENV = ['development', 'test'].includes(process.env.NODE_ENV)
|
||||
|
||||
const request = require('request')
|
||||
const Features = require('./Features')
|
||||
const SessionManager = require('../Features/Authentication/SessionManager')
|
||||
const PackageVersions = require('./PackageVersions')
|
||||
|
@ -16,17 +14,63 @@ const Modules = require('./Modules')
|
|||
const SafeHTMLSubstitute = require('../Features/Helpers/SafeHTMLSubstitution')
|
||||
|
||||
let webpackManifest
|
||||
if (!IS_DEV_ENV) {
|
||||
// Only load webpack manifest file in production. In dev, the web and webpack
|
||||
// containers can't coordinate, so there no guarantee that the manifest file
|
||||
// exists when the web server boots. We therefore ignore the manifest file in
|
||||
// dev reload
|
||||
webpackManifest = require(`../../../public/manifest.json`)
|
||||
switch (process.env.NODE_ENV) {
|
||||
case 'production':
|
||||
// Only load webpack manifest file in production.
|
||||
webpackManifest = require(`../../../public/manifest.json`)
|
||||
break
|
||||
case 'development':
|
||||
// In dev, fetch the manifest from the webpack container.
|
||||
loadManifestFromWebpackDevServer()
|
||||
setInterval(loadManifestFromWebpackDevServer, 10 * 1000)
|
||||
break
|
||||
default:
|
||||
// In ci, all entries are undefined.
|
||||
webpackManifest = {}
|
||||
}
|
||||
function loadManifestFromWebpackDevServer(done = function () {}) {
|
||||
request(
|
||||
{
|
||||
uri: `${Settings.apis.webpack.url}/manifest.json`,
|
||||
headers: { Host: 'localhost' },
|
||||
json: true,
|
||||
},
|
||||
(err, res, body) => {
|
||||
if (!err && res.statusCode !== 200) {
|
||||
err = new Error(`webpack responded with statusCode: ${res.statusCode}`)
|
||||
}
|
||||
if (err) {
|
||||
logger.err({ err }, 'cannot fetch webpack manifest')
|
||||
return done(err)
|
||||
}
|
||||
webpackManifest = body
|
||||
done()
|
||||
}
|
||||
)
|
||||
}
|
||||
const IN_CI = process.env.NODE_ENV === 'test'
|
||||
function getWebpackAssets(entrypoint, section) {
|
||||
if (IN_CI) {
|
||||
// Emit an empty list of entries in CI.
|
||||
return []
|
||||
}
|
||||
return webpackManifest.entrypoints[entrypoint].assets[section] || []
|
||||
}
|
||||
|
||||
const I18N_HTML_INJECTIONS = new Set()
|
||||
|
||||
module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// In the dev-env, delay requests until we fetched the manifest once.
|
||||
webRouter.use(function (req, res, next) {
|
||||
if (!webpackManifest) {
|
||||
loadManifestFromWebpackDevServer(next)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
webRouter.use(function (req, res, next) {
|
||||
res.locals.session = req.session
|
||||
next()
|
||||
|
@ -81,43 +125,25 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
|||
res.locals.buildBaseAssetPath = function () {
|
||||
// Return the base asset path (including the CDN url) so that webpack can
|
||||
// use this to dynamically fetch scripts (e.g. PDFjs worker)
|
||||
return Url.resolve(staticFilesBase, '/')
|
||||
return staticFilesBase + '/'
|
||||
}
|
||||
|
||||
res.locals.buildJsPath = function (jsFile) {
|
||||
let path
|
||||
if (IS_DEV_ENV) {
|
||||
// In dev: resolve path within JS asset directory
|
||||
// We are *not* guaranteed to have a manifest file when the server
|
||||
// starts up
|
||||
path = Path.join('/js', jsFile)
|
||||
} else {
|
||||
// In production: resolve path from webpack manifest file
|
||||
// We are guaranteed to have a manifest file since webpack compiles in
|
||||
// the build
|
||||
path = `/${webpackManifest[jsFile]}`
|
||||
}
|
||||
|
||||
return Url.resolve(staticFilesBase, path)
|
||||
return staticFilesBase + webpackManifest[jsFile]
|
||||
}
|
||||
|
||||
// Temporary hack while jQuery/Angular dependencies are *not* bundled,
|
||||
// instead copied into output directory
|
||||
res.locals.buildCopiedJsAssetPath = function (jsFile) {
|
||||
let path
|
||||
if (IS_DEV_ENV) {
|
||||
// In dev: resolve path to root directory
|
||||
// We are *not* guaranteed to have a manifest file when the server
|
||||
// starts up
|
||||
path = Path.join('/', jsFile)
|
||||
} else {
|
||||
// In production: resolve path from webpack manifest file
|
||||
// We are guaranteed to have a manifest file since webpack compiles in
|
||||
// the build
|
||||
path = `/${webpackManifest[jsFile]}`
|
||||
}
|
||||
return staticFilesBase + (webpackManifest[jsFile] || '/' + jsFile)
|
||||
}
|
||||
|
||||
return Url.resolve(staticFilesBase, path)
|
||||
res.locals.entrypointScripts = function (entrypoint) {
|
||||
const chunks = getWebpackAssets(entrypoint, 'js')
|
||||
return chunks.map(chunk => staticFilesBase + chunk)
|
||||
}
|
||||
|
||||
res.locals.entrypointStyles = function (entrypoint) {
|
||||
const chunks = getWebpackAssets(entrypoint, 'css')
|
||||
return chunks.map(chunk => staticFilesBase + chunk)
|
||||
}
|
||||
|
||||
res.locals.mathJaxPath = `/js/libs/mathjax/MathJax.js?${querystring.stringify(
|
||||
|
@ -150,20 +176,7 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
|||
}
|
||||
|
||||
res.locals.buildStylesheetPath = function (cssFileName) {
|
||||
let path
|
||||
if (IS_DEV_ENV) {
|
||||
// In dev: resolve path within CSS asset directory
|
||||
// We are *not* guaranteed to have a manifest file when the server
|
||||
// starts up
|
||||
path = Path.join('/stylesheets/', cssFileName)
|
||||
} else {
|
||||
// In production: resolve path from webpack manifest file
|
||||
// We are guaranteed to have a manifest file since webpack compiles in
|
||||
// the build
|
||||
path = `/${webpackManifest[cssFileName]}`
|
||||
}
|
||||
|
||||
return Url.resolve(staticFilesBase, path)
|
||||
return staticFilesBase + webpackManifest[cssFileName]
|
||||
}
|
||||
|
||||
res.locals.buildCssPath = function (themeModifier = '') {
|
||||
|
@ -172,7 +185,7 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
|||
|
||||
res.locals.buildImgPath = function (imgFile) {
|
||||
const path = Path.join('/img/', imgFile)
|
||||
return Url.resolve(staticFilesBase, path)
|
||||
return staticFilesBase + path
|
||||
}
|
||||
|
||||
next()
|
||||
|
|
|
@ -15,7 +15,9 @@ html(
|
|||
|
||||
//- Stylesheet
|
||||
link(rel='stylesheet', href=buildCssPath(getCssThemeModifier(userSettings, brandVariation)), id="main-stylesheet")
|
||||
link(rel='stylesheet', href=buildStylesheetPath("libraries.css"))
|
||||
block css
|
||||
each file in entrypointStyles('main')
|
||||
link(rel='stylesheet', href=file)
|
||||
|
||||
block _headLinks
|
||||
|
||||
|
@ -122,8 +124,8 @@ html(
|
|||
!= moduleIncludes("contactModal", locals)
|
||||
|
||||
block foot-scripts
|
||||
script(type="text/javascript", nonce=scriptNonce, src=buildJsPath('libraries.js'))
|
||||
script(type="text/javascript", nonce=scriptNonce, src=buildJsPath('main.js'))
|
||||
each file in entrypointScripts("main")
|
||||
script(type="text/javascript", nonce=scriptNonce, src=file)
|
||||
script(type="text/javascript", nonce=scriptNonce).
|
||||
//- Look for bundle
|
||||
var cdnBlocked = typeof Frontend === 'undefined'
|
||||
|
|
|
@ -12,7 +12,8 @@ html(lang="en")
|
|||
|
||||
link(rel="icon", href="/favicon.ico")
|
||||
|
||||
if buildCssPath
|
||||
link(rel="stylesheet", href=buildCssPath())
|
||||
if entrypointStyles
|
||||
each file in entrypointStyles('main')
|
||||
link(rel='stylesheet', href=file)
|
||||
|
||||
block body
|
||||
|
|
|
@ -6,8 +6,9 @@ block vars
|
|||
- var suppressSkipToContent = true
|
||||
- metadata.robotsNoindexNofollow = true
|
||||
|
||||
block _headLinks
|
||||
link(rel='stylesheet', href=buildStylesheetPath("ide.css"))
|
||||
block css
|
||||
each file in entrypointStyles('ide')
|
||||
link(rel='stylesheet', href=file)
|
||||
|
||||
block content
|
||||
.editor(ng-controller="IdeController").full-size
|
||||
|
@ -200,5 +201,5 @@ block append meta
|
|||
block foot-scripts
|
||||
script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js')
|
||||
script(type="text/javascript", nonce=scriptNonce, src=mathJaxPath)
|
||||
script(type="text/javascript", nonce=scriptNonce, src=buildJsPath('libraries.js'))
|
||||
script(type="text/javascript", nonce=scriptNonce, src=buildJsPath('ide.js'))
|
||||
each file in entrypointScripts("ide")
|
||||
script(type="text/javascript", nonce=scriptNonce, src=file)
|
||||
|
|
|
@ -212,6 +212,9 @@ module.exports = {
|
|||
notifications: {
|
||||
url: `http://${process.env.NOTIFICATIONS_HOST || 'localhost'}:3042`,
|
||||
},
|
||||
webpack: {
|
||||
url: `http://${process.env.WEBPACK_HOST || 'localhost'}:3808`,
|
||||
},
|
||||
|
||||
// For legacy reasons, we need to populate the below objects.
|
||||
v1: {},
|
||||
|
|
82
services/web/package-lock.json
generated
82
services/web/package-lock.json
generated
|
@ -25173,6 +25173,15 @@
|
|||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lockfile": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz",
|
||||
"integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
|
@ -25218,6 +25227,12 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||
},
|
||||
"lodash.has": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
|
||||
"integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
|
@ -37737,6 +37752,48 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"webpack-assets-manifest": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/webpack-assets-manifest/-/webpack-assets-manifest-4.0.6.tgz",
|
||||
"integrity": "sha512-9MsBOINUoGcj3D7XHQOOuQri7VEDArkhn5gqnpCqPungLj8Vy3utlVZ6vddAVU5feYroj+DEncktbaZhnBxdeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.0",
|
||||
"deepmerge": "^4.0",
|
||||
"lockfile": "^1.0",
|
||||
"lodash.get": "^4.0",
|
||||
"lodash.has": "^4.0",
|
||||
"mkdirp": "^1.0",
|
||||
"schema-utils": "^3.0",
|
||||
"tapable": "^1.0",
|
||||
"webpack-sources": "^1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"dev": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-cli": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz",
|
||||
|
@ -38315,31 +38372,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"webpack-manifest-plugin": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz",
|
||||
"integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs-extra": "^7.0.0",
|
||||
"lodash": ">=3.5 <5",
|
||||
"object.entries": "^1.1.0",
|
||||
"tapable": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
|
||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-merge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
|
||||
|
|
|
@ -256,9 +256,9 @@
|
|||
"to-string-loader": "^1.1.6",
|
||||
"val-loader": "^1.1.1",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-assets-manifest": "^4.0.6",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-manifest-plugin": "^2.2.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ const fs = require('fs')
|
|||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const CopyPlugin = require('copy-webpack-plugin')
|
||||
const ManifestPlugin = require('webpack-manifest-plugin')
|
||||
const WebpackAssetsManifest = require('webpack-assets-manifest')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
|
||||
const PackageVersions = require('./app/src/infrastructure/PackageVersions')
|
||||
|
@ -42,6 +42,8 @@ module.exports = {
|
|||
output: {
|
||||
path: path.join(__dirname, '/public'),
|
||||
|
||||
publicPath: '/',
|
||||
|
||||
// By default write into js directory
|
||||
filename: 'js/[name].js',
|
||||
|
||||
|
@ -250,11 +252,9 @@ module.exports = {
|
|||
plugins: [
|
||||
// Generate a manifest.json file which is used by the backend to map the
|
||||
// base filenames to the generated output filenames
|
||||
new ManifestPlugin({
|
||||
// Always write the manifest file to disk (even if in dev mode, where
|
||||
// files are held in memory). This is needed because the server will read
|
||||
// this file (from disk) when building the script's url
|
||||
writeToFileEmit: true,
|
||||
new WebpackAssetsManifest({
|
||||
entrypoints: true,
|
||||
publicPath: true,
|
||||
}),
|
||||
|
||||
// Prevent moment from loading (very large) locale files that aren't used
|
||||
|
|
Loading…
Reference in a new issue