From d19fb4f21553e01a83a7709d5c2aeb3c47817275 Mon Sep 17 00:00:00 2001 From: Philip Waritschlager Date: Mon, 23 Mar 2020 13:25:42 +0100 Subject: [PATCH 1/5] Always remove extract-css-loader on server ... even when `cricitcalCSS` is disabled. This fixes the `document is not defined` bug in production mode Fixes #186 --- lib/webpack.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/webpack.js b/lib/webpack.js index 2e4993d..40ecd24 100644 --- a/lib/webpack.js +++ b/lib/webpack.js @@ -24,7 +24,7 @@ exports.chainWebpack = (webpackConfig) => { webpackConfig.plugins.delete('friendly-errors') const isExtracting = webpackConfig.plugins.has('extract-css') - if (isExtracting && config.criticalCSS) { + if (isExtracting) { // Remove extract const langs = ['css', 'postcss', 'scss', 'sass', 'less', 'stylus'] const types = ['vue-modules', 'vue', 'normal-modules', 'normal'] @@ -32,8 +32,9 @@ exports.chainWebpack = (webpackConfig) => { for (const type of types) { const rule = webpackConfig.module.rule(lang).oneOf(type) rule.uses.delete('extract-css-loader') - // Critical CSS - rule.use('css-context').loader(CssContextLoader).before('css-loader') + if (config.criticalCSS) { + rule.use('css-context').loader(CssContextLoader).before('css-loader') + } } } webpackConfig.plugins.delete('extract-css') From 7c8724d81f07b6e28220a4b8d431eb33b3c20938 Mon Sep 17 00:00:00 2001 From: phil294 Date: Fri, 29 May 2020 11:16:03 +0200 Subject: [PATCH 2/5] refactor(webpack): Remove some unnecessary nesting --- lib/webpack.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/webpack.js b/lib/webpack.js index 40ecd24..8ec2a4f 100644 --- a/lib/webpack.js +++ b/lib/webpack.js @@ -90,20 +90,16 @@ exports.chainWebpack = (webpackConfig) => { webpackConfig.node.clear() - if (!isClient) { - webpackConfig.module.rule('vue').use('cache-loader').tap(options => { - // Change cache directory for server-side - options.cacheIdentifier += '-server' - options.cacheDirectory += '-server' - return options - }) - } + webpackConfig.module.rule('vue').use('cache-loader').tap(options => { + // Change cache directory for server-side + options.cacheIdentifier += '-server' + options.cacheDirectory += '-server' + return options + }) webpackConfig.module.rule('vue').use('vue-loader').tap(options => { - if (!isClient) { - options.cacheIdentifier += '-server' - options.cacheDirectory += '-server' - } + options.cacheIdentifier += '-server' + options.cacheDirectory += '-server' options.optimizeSSR = !isClient return options }) From a01e8fde74a9b4f9f89c8140fb91df3de5d21a9a Mon Sep 17 00:00:00 2001 From: phil294 Date: Sat, 30 May 2020 17:22:58 +0200 Subject: [PATCH 3/5] Make `compile` a seperate async function So it can be called multiple times, even asynchronously --- index.js | 81 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/index.js b/index.js index a916eab..2ef0960 100644 --- a/index.js +++ b/index.js @@ -21,50 +21,61 @@ module.exports = (api, options) => { api.registerCommand('ssr:build', { description: 'build for production (SSR)', }, async (args) => { - const webpack = require('webpack') const rimraf = require('rimraf') - const formatStats = require('@vue/cli-service/lib/commands/build/formatStats') - - const options = service.projectOptions - rimraf.sync(api.resolve(config.distPath)) const { getWebpackConfigs } = require('./lib/webpack') const [clientConfig, serverConfig] = getWebpackConfigs(service) - const compiler = webpack([clientConfig, serverConfig]) - const onCompilationComplete = (err, stats) => { - if (err) { - // eslint-disable-next-line - console.error(err.stack || err) - if (err.details) { - // eslint-disable-next-line - console.error(err.details) + const compile = ({ webpackConfigs, watch, service }) => { + Object.keys(require.cache) + .filter(key => key.includes('@vue/cli-plugin-babel')) + .forEach(key => delete require.cache[key]) + + const webpack = require('webpack') + const formatStats = require('@vue/cli-service/lib/commands/build/formatStats') + + const options = service.projectOptions + + const compiler = webpack(webpackConfigs) + return new Promise((resolve) => { + const onCompilationComplete = (err, stats) => { + if (err) { + // eslint-disable-next-line + console.error(err.stack || err) + if (err.details) { + // eslint-disable-next-line + console.error(err.details) + } + return resolve() + } + + if (stats.hasErrors()) { + stats.toJson().errors.forEach(err => console.error(err)) + process.exitCode = 1 + } + + if (stats.hasWarnings()) { + stats.toJson().warnings.forEach(warn => console.warn(warn)) + } + + try { + // eslint-disable-next-line + console.log(formatStats(stats, options.outputDir, api)); + } catch (e) { + } + resolve() } - return - } - - if (stats.hasErrors()) { - stats.toJson().errors.forEach(err => console.error(err)) - process.exitCode = 1 - } - - if (stats.hasWarnings()) { - stats.toJson().warnings.forEach(warn => console.warn(warn)) - } - - try { - // eslint-disable-next-line - console.log(formatStats(stats, options.outputDir, api)); - } catch (e) { - } - } - if (args.watch) { - compiler.watch({}, onCompilationComplete) - } else { - compiler.run(onCompilationComplete) + if (watch) { + compiler.watch({}, onCompilationComplete) + } else { + compiler.run(onCompilationComplete) + } + }) } + + await compile({ webpackConfigs: [clientConfig, serverConfig], watch: args.watch, service }) }) api.registerCommand('ssr:serve', { From a59c3a21dea8a789dbb95ff443b305149288d366 Mon Sep 17 00:00:00 2001 From: phil294 Date: Sat, 30 May 2020 17:30:35 +0200 Subject: [PATCH 4/5] Build in modern mode Always build in modern mode (even in dev mode), config option for this is still missing. There are now three webpack configs, two client (modern/legacy) ones and one for the server. --- index.js | 9 +++++++-- lib/app.js | 5 +++++ lib/dev-server.js | 14 +++++++------- lib/webpack.js | 37 ++++++++++++++++++++++++++++++++++--- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 2ef0960..51782b8 100644 --- a/index.js +++ b/index.js @@ -25,7 +25,7 @@ module.exports = (api, options) => { rimraf.sync(api.resolve(config.distPath)) const { getWebpackConfigs } = require('./lib/webpack') - const [clientConfig, serverConfig] = getWebpackConfigs(service) + const [clientConfigLegacy, clientConfigModern, serverConfig] = getWebpackConfigs(service) const compile = ({ webpackConfigs, watch, service }) => { Object.keys(require.cache) @@ -75,7 +75,12 @@ module.exports = (api, options) => { }) } - await compile({ webpackConfigs: [clientConfig, serverConfig], watch: args.watch, service }) + process.env.VUE_CLI_MODERN_MODE = true + await compile({ webpackConfigs: [clientConfigLegacy, serverConfig], watch: args.watch, service }) + process.env.VUE_CLI_MODERN_BUILD = true + // Modern build depends on files from legacy build, that's why these + // compilations cannot run parallely + await compile({ webpackConfigs: [clientConfigModern], watch: args.watch, service }) }) api.registerCommand('ssr:serve', { diff --git a/lib/app.js b/lib/app.js index d19e816..59c1f39 100644 --- a/lib/app.js +++ b/lib/app.js @@ -123,6 +123,11 @@ module.exports = (app, options) => { renderer.renderToString(context, (err, renderedHtml) => { let html = renderedHtml + // Unfortunately, both vue template renderer *and* + // vue-cli ModernModePlugin inject script tags into the html, so + // the former ones are now being removed again + html = html.replace(/