vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.96k stars 33.68k forks source link

VueSSRServerPlugin produces a slow-to-parse JSON for large projects #8241

Open nemtsov opened 6 years ago

nemtsov commented 6 years ago

What problem does this feature solve?

Makes for a better development experience with vue SSR.

I was looking into why it takes 500ms to render an single-component page from the server in our fairly large application and found an interesting issue. Webpack creates ~40 bundles for us. Altogether, these weigh ~20MB. The way VueSSRServerPlugin plugin works, as you know, is it combines all of these files into a single vue-ssr-server-bundle.json file. Reading that file in node is fast (5ms on average) for us, but after reading it we need to JSON.parse it before providing to createBundleRenderer and that takes ~400ms.

Initially I was thinking of using webpack's splitChunks, to reduce the file-size (our router dynamically imports top-level pages, so each chunk could benefit from not having to bring in common component) but VueSSRServerPlugin does not support that (and throws the "Server-side bundle should have one single entry file" error).

What does the proposed API look like?

I'm not exactly sure what to do here at this point as I just noticed this issue. I'm concerned that as the app grows, the json parse time will increase adding seconds to the load-time in development.

yyx990803 commented 6 years ago

400ms reload during dev seems acceptable for "a fairly large application"... unless you expect your app to be 3~4 times larger than it already is in the future?

nemtsov commented 6 years ago

Thanks for responding, @yyx990803. We're anticipating the app to grow by more pages. That is what's making me concerned that a single JSON file containing all of the code (without at least the ability to split out common chunks) will not scale for us. Also (and this is subjective, of course) 400ms is a noticeable penalty for every refresh of the app.

fogil commented 6 years ago

I would be willing to bet 95% of your ~20MB file is redundant code from external libraries. You should never be recompiling external libraries and bunching them into your bundle file.

Analyze the bundle file and make sure only your app's proprietary code is inside. This should only be page template, business logic, routing logic, state management logic. If you see the Vue library in there that should set off alarm bells.

Always externalize vendor libraries. On the server, on the client, everywhere.

Another rule of thumb is if npm run build takes longer than 10 seconds, something is wrong.

Once you axe out the redundant code you'll notice your real app is actually something along the lines of 500KBs tops, and JSON.parse will be back to bearable speed.

nemtsov commented 6 years ago

Thanks for your analysis and care for the ecosystem, @zeltice!

You're correct in that by externalizing our vendor libraries the size of the vue-ssr-server-bundle.json goes down. The amount of reduction we see with the use of webpack-node-externals isn't quite 95% unfortunately, but is a decent ~20%. This brings us down to ~16MB.

The next big chunk of that file is made up of source-maps, disabling which unsurprisingly gives us a ~50% reduction (to ~8MB of first party code). Of course, this also means that we can't debug, so disabling these isn't an option, but it's important to know that it isn't just code in there.

As I wrote, we're running a large website with ~30-and-growing top-level page components and many features across those pages. Although tolerable for now, I don't believe the single-json-file approach of theVueSSRServerPlugin scales well. That being said, 90% of the time is spent parsing the JSON file, and not reading it, so perhaps a low-hanging fruit is to optimize that, maybe by using an alternative serialization format, or maybe by allowing source-maps to be their own file.

fogil commented 6 years ago

In regards to source maps, you're likely working with two environments: dev & production

In dev: you should never have source maps enabled since your JS should not be minified anyway. Therefore, source map size should be 0 bytes.

In production: During the build stage, webpack creates a separate file for the source maps -- those are never part of your js bundle, unless there was a misconfiguration. Remember that the source maps are retrieved as separate files in separate HTTP requests in production. These source map URLs are hinted by specialized commented hints in your minified, packaged js and css files.

Regardless, the original problem is slow development experience -- so dev environment. Source map should not exist in dev.

nemtsov commented 6 years ago

Thanks again for your comment, @zeltice. Webpack combines our source files into a single bundle and uses the loaders to compile the source .vue templates and styles into JS. Thus, disabling source maps in development would mean that we would get post-combine-and-compile bundle-specific line & column numbers in stack traces instead of source-file-specific line numbers, making it very difficult to identify the source of errors.

fogil commented 6 years ago

I see. If you must have source maps in dev, try the cheaper but still effective source map solutions going for a balance of filesize and speed:

https://webpack.js.org/configuration/devtool/

My company does not use source maps in dev so my advice is only based on experience from 4 years ago where I used "cheap-eval-source-map"; which was good enough to identify the file and line number of the problem, yet fast enough to be ~1 second delay in updates on every code change.

mojodev commented 5 years ago

In production: During the build stage, webpack creates a separate file for the source maps -- those are never part of your js bundle, unless there was a misconfiguration. Remember that the source maps are retrieved as separate files in separate HTTP requests in production. These source map URLs are hinted by specialized commented hints in your minified, packaged js and css files.

Regardless, the original problem is slow development experience -- so dev environment. Source map should not exist in dev.

In my projet server bundle vue-ssr-server-bundle.json file size is 21.4 mb because of source map. i don't know why server bundle including source map. i am using this scaffolding. can you guys tell me where i am doing wrong ?

nemtsov commented 4 years ago

It has now been two years since I opened this issue. Whereas the vue-ssr-server-bundle.json was 20MB then and took 400ms to reload it is now 51MB in size and takes seconds to reload. The application is 3-4 times larger now (or rather we've converted the rest of it to use vue) @yyx990803 . If you have any suggestions we'd happily try them out, as we're finding it more and more difficult to tolerate the reload time. Thank you for your amazing work!