Hello. This actually is a story behind one of our nuxt based production applications, some workarounds was used to make ssr bundle smaller and much much more faster. All of them are implemented in nuxt-helpers/optimize.js and tested against nuxt 0.9.9.
About one week ago just after first deployment, i just figured out that SSR is really slow (~8req/sec with 1 worker) so the first thing i have checked was big ssr bundle size (~800kb), thanks to super useful nuxt extend function, i have enabled BundleAnalyzerPlugin for server side like this :
extend (config, {isServer}) {
if (isServer) config.plugins.push(new BundleAnalyzerPlugin({}));
}
The result was shucking

sass and css files where bundled
They are really useless for server-side and just make things much slower. unfortunately without some hacks it is not possible to remove them from bundle. so i have used ignore-loader plugin to bypass vue loader :
['scss', 'css'].forEach(function (ext) {
config.module.rules[0].query.loaders[ext] = 'ignore-loader';
});
vendors are not externalized
We are just externalizing direct dependencies in package.json (like vue documentation example) but if we have indirect dependencies like nuxt-helpers they will be loaded into SSR bundle and have to parsed/loaded on each request! Simple workaround was adding nuxt.js vendors to externals too : config.externals = _.uniq(config.externals.concat(nuxt.build.vendor));
unnecessary babel presets
If you look in bundle analyzer result again, you will see big core-js and regenerator runtimes packaged with bundle. As a first attempt i just tried to externalize them like other vendors, but unfortunately this won't work and will throw run-time errors as they should be required by default. Worst than it babel is compiling many lines of code into older js syntax which makes code slower, many of them (including async/await are now enabled in modern & stable node.js releases and are much much much faster than babel compiled code. I have used this workaround to reduce amount of presets and just compiling a modern SSR bundle :) It would be great if nuxt.js just has a built-in option to enable this optimization.
The result

Bundle size is now about 9x smaller (under 100kb), it is much faster because no vendors are included and are cached and much much faster because of using modern native async/awaits. I can't exactly remind but SSR was handling ~150requests/sec with 4 workers using optimizated version. 😎
Extra 1
I was also tried new vue ssr bundle format with no luck (mentioned problems just exists and code splitting didn't helped a lot)
Extra 2
Also during last hack i have found a bug in nuxt extend function! base.config.js is applying defaults to bable options on original object. so if some one changes anything shared in extend for server, it will be applied to client options too! Although no one should do this it can be easily fixed and prevented by extending on a new object like this : defaults({}, this.options,...
Hi @pi0 thank you for your implication with nuxt.js. I will take a deeper look at it and come back to your later.
Actually, I am implementing Vue 2.2 which will let us add the CSS used by the rendered components directly in the <head> so the CSS might be needed in the server bundle.
@pi0 what was your "workaround" to compile against modern node and native async/await feature?
your link is not-found now (oh i see https://github.com/fandogh/nuxt-helpers/commits/master).
The 0.10 release it out ✋
@pi0 do you mind checking again an give me a feedback now? 😃
@Atinux Congratulations for this release :) I'm going to experiment new features and upgrade things :) Will come back soon.
@Atinux As first attempt i started migration of static BootstrapVue docs. Generated html files are so HUGE (~176kb each) including entire Bootstrap css.
I then tried moving imports from css in nuxt.config to layout files (with import directive) but still same behavior... Is it expected or there should be only used selectors on header? And if so what is your suggestion? :(
UPDATE: example generated html
UPDATE 2 Current docs indicates that:
In production, all CSS will be minified and extracted in a file named styles.css and added in the
of the page.
We should change this alert message? Keeping this option working as was before and generating special css chunk for only and if css part exists would be great. Without that custom global themes should pass another external build steps on each release. I can prepare a PR or Proposal if you agree. (At least giving users an option to choose either behavior)
UPDATE 3 Some related interesting stuff:
Also going to have a SSR benchmark on a production project soon.
@pi0 for the html files, only one needs to be loaded by the browser, and gzipped, the size is 26.9KB.
What about using your CDN to include the bootstrap CSS instead?
nuxt.config.js
module.exports = {
head: {
link: [
{ type: 'text/css', rel: 'stylesheet', href: '//unpkg.com/bootstrap@next/dist/css/bootstrap.min.css' },
{ type: 'text/css', rel: 'stylesheet', href: '//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css' },
}
}
I need to remove the warning for the moment, actually I was thinking of letting the option for the user but extracting the CSS does not help to improves the performances and getting closer to PWA.
@Atinux I Agree :)) It was my bad resisting on new technology just because older one WORKS :)) Closing this PR to keep Issues clean. Will provide a fresh report next week when I've researched enough about available solutions :)
Thanks for your hard work on awesome Nuxt ;)
Thanks to you for helping us to make Nuxt.js better :)
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Hi @pi0 thank you for your implication with nuxt.js. I will take a deeper look at it and come back to your later.
Actually, I am implementing Vue 2.2 which will let us add the CSS used by the rendered components directly in the
<head>so the CSS might be needed in the server bundle.