-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Ssr webpack #937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ssr webpack #937
Conversation
@skirtles-code @danielroe would you mind checking this draft? It's very raw so far, any suggestions/improvements are much appreciated! 🙇🏻♀️ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great! I've made a few comments for your consideration.
There is also some legacy ES5 syntax in getting started that was untouched by this PR - it may be worth just making sure everything is consistent across the examples.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't tried running the code examples myself yet but I've had a read through and made some suggestions.
I feel that Vue CLI could do more to facilitate this. Relying on a big chunk of webpack configuration in the SSR docs doesn't seem very maintainable. But we are where we are for now...
I should really spend some time learning webpack properly. I can muddle my way through but I don't really have the knowledge required to make good suggestions at the moment.
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
Co-authored-by: Daniel Roe <[email protected]>
@CyberAP I would be really happy if you could take a look too 🙏🏻 I believe your input on SSR is super valuable |
const webpack = require('webpack') | ||
|
||
module.exports = { | ||
chainWebpack: webpackConfig => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking whether it is a good idea or not to have 3 configs here?
One for common rules likes aliases, one for client only and one for server only. Both of them deriving from the base config (using webpackMerge
).
The reasoning behind this is that using chainWebpack
for re-configuration is hardly maintainable. It does get very complex extremely fast so noone wants to touch this config because noone understands what happens here. I have the same setup on my project and it overwrites a ton of rules exactly like shown here: replacements\deletions inside if
statements which depend on environment. I think a static webpack config is way more readable because you can understand what it does at the first glance just by the structure of that config (given you have an experience with webpack). This programmatic config is hard to read because you have to parse it line by line working as an interpreter. It is also unclear what the base vue-cli config looks like, so all the delete
calls look like magic to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the point but I have a few questions regarding it:
- should we move away from Vue CLI in this case? I am not sure how it's done correctly in the CLI environment as I usually always went with
configureWebpack
/chainWebpack
in the `vue.config.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a follow-up to refactor to CLI agnostic build with a base, server and client configs: #969
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is probably not feasible with current vue-cli API, so it should be a part of vue-cli agnostic build in that case.
src/guide/ssr/universal.md
Outdated
|
||
Most [custom directives](/guide/custom-directive.html#custom-directives) directly manipulate the DOM, which will cause errors during SSR. There are two ways to work around this: | ||
|
||
1. Prefer using components as the abstraction mechanism and work at the Virtual-DOM level (e.g. using [render functions](/guide/render-function.html#the-dom-tree)) instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the idea here is to replace directives with components as much as possible, but that exact wording is a bit unclear to me unfortunately. It is also unclear how render functions could help me in that case (an example would be much welcomed I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rephrased a bit and removed a second point (see below)
@@ -64,6 +64,8 @@ yarn add express | |||
``` | |||
|
|||
```js | |||
// server.js |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since most of the people who want to migrate from CSR to SSR would be having some kind of main.js
entry file maybe it would make sense to show this migration path as a step-by-step guide how we extract our current code from main.js
and split it into three different files: app.js
, entry-client.js
and entry-server.js
. The current approach is also very good, but I think it's more focused on writing an SSR app from scracth. Maybe there should be a separate guide for migrating from CSR to SSR? What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, it would be a great improvement! Created a follow-up: #970
|
||
const isServer = typeof window === 'undefined' | ||
|
||
const history = isServer ? createMemoryHistory() : createWebHistory() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a slightly better approach here would be to pass the history
instance on an entry-level, so we have better code-splitting here and won't have to check for isServer
flag.
src/guide/ssr/hydration.md
Outdated
|
||
In development mode, Vue will assert the client-side generated virtual DOM tree matches the DOM structure rendered from the server. If there is a mismatch, it will bail hydration, discard existing DOM and render from scratch. There will be a warning in the browser console but your site will still work. | ||
|
||
However, in production mode, this assertion is disabled for maximum performance, which means that **it is crucial you ensure your client- and server-side DOM trees match**. Otherwise your HTML will remain static and non-reactive. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this one, does it really fail completely on hydration mismatch? I am not able to test this right now, but I remember that hydration algorithm in Vue 3 was significantly improved so the app doesn't crash completely in case of a mismatch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'd need to check this too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@CyberAP I still can see a warning in the console for this but in prod mode, it's the same as in dev: app just renders from scratch without crashing 👍🏻 I'll unify both paragraphs removing a distinction for modes
@@ -0,0 +1,121 @@ | |||
# Routing and Code-Splitting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an SSR app developer I am also curious how Critical CSS should be implemeneted correctly with this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree! However, this guide is not full and there are a few missing parts here. Here is an issue with 'what's currently missing': #971
Co-authored-by: Stanislav Lashmanov <[email protected]>
I am also curious whether something about vue-meta integration has changed. In Vue 2 it was important for meta config to be defined only on route config or on a page-level component (a component that can be retrieved from the route config). Vue 3 also has an improved rendering mechanism which allows for a much flexible data fetching. Previously you had to declare your data fetching hooks on a page-level component which significantly limited component composition and data flow. In Vue 3 we have async setup and Suspense that remove that limitation. I think that might also be important to cover. And I think in general it is important to cover a topic of data fetching and data transfer from server to client. Where to store that data (the most common solution here is to use Vuex), how to transfer that data (from naive JSON.stringify approach to more complex ones that support complex object types), how to hydrate that data so the hook that fetched the data on server doesn't trigger on client (usually done by checking hydration state in created hook via vnode.elm presence). Lastly, there's a renderToStream method in vue server-render package. It produces a lower time to first byte and can increase lighthouse metrics. But it also imposes some restrictions on how you should write your code: no synchronous Teleports (can not replace the markup that has already been sent) or async meta configs (or at least we should wait for the meta to resolve before sending any data, since head tag goes first). |
@CyberAP thank you so much for the great comments! I addressed 'smaller' ones and created follow-ups for the bigger refactorings 👍🏻 Please feel free to add more points here or to follow-up issues, your input is much appreciated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more suggestions from me.
│ ├── MyUser.vue | ||
│ └── MyTable.vue | ||
├── App.vue | ||
├── app.js # universal entry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering whether we should rename app.js
to main.js
? The Vite SSR example calls it main.js
and it would help to avoid any confusion between this file and the app.js
files created by the build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would argue here that with SSR we lose the idea of a single entry point file which was main.js
for CSR and switch to a more generic app.js
. Then we can launch our app in different environments if it's written in a universal style.
Co-authored-by: skirtle <[email protected]>
Co-authored-by: skirtle <[email protected]>
Co-authored-by: skirtle <[email protected]>
Co-authored-by: skirtle <[email protected]>
Co-authored-by: skirtle <[email protected]>
@skirtles-code I've addressed your comments, could you please check again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last couple of small changes from me and then I think we're good to merge.
Co-authored-by: skirtle <[email protected]>
Co-authored-by: skirtle <[email protected]>
Thanks to everyone who was reviewing this monster! 🙌🏻 I am merging this one and then we'll iterate to shape it through the follow up issues |
Excuse me, How to use asyncData in SSR? |
I tried to use suspense, but is an experimental feature and its API will likely change. |
Description of Problem
This is a draft for SSR documentation with a build step
Deployed demo here: https://deploy-preview-937--vue-docs-next-preview.netlify.app/guide/ssr/introduction.html
Close #533
Close #726