Server-side rendering is a technique where a portion of the app’s client-side code (determined by the route) is run on the server in order to produce the HTML (and CSS if it is created dynamically) for that particular “page” of the app and then those assets are sent to the client instead of a bare-bones HTML page with script and link tags. This provides much better SEO, and the page is already rendered before the scripts are run, so users perceive better performance and can begin reading your content right away. Meanwhile, your script is run and either takes control of the rendered page elements and adds interactivity to it, or potentially it overwrites the existing elements.
Server-side rendering isn’t simple. There are some parts of your code that can’t or don’t make sense to run on the server. There are some bits that should run on the server, but not on the client. At first, with simple applications, much of this may be simple enough to do from scratch, but as you get into larger and more complex applications, you’ll likely run into more and more hurdles to get over.
Thankfully, most of the real work has been done for us. For developers using React, Next.js can handle the server-side rendering aspects for you. This is extremely helpful and makes server-side rendering relatively simple to get started with. It works far better if you start writing the application with Next.js rather than retrofitting an existing application due to conventions and APIs that wouldn’t normally be used in an app without server-side rendering.
What About Vue?
This article is about doing server-side rendering with Vue.js, so let’s actually jump into that. First of all, the Vue core team has come up with a Vue.js server-side rendering guide that tells you pretty much everything you need to know. It tells you patterns to avoid (including ways to work around those patterns if they do exist), how to handle the routing and code splitting those routes, letting webpack bundle the backend portions you need, and lots more.
If you’d like to learn a lot about how server-side rendering is handled, this is a great read, but I know a lot of you will likely want to jump into getting it set up quickly and don’t want to create your own solution for handling the rendering. For us, there is Nuxt.js.
Nuxt In Line
Nuxt.js is Next.js for Vue. It says right in their introduction:
The 25th of October 2016, the team behind zeit.co, announced Next.js, a framework for server-rendered React applications. A few hours after the announcement, the idea of creating server-rendered Vue.js applications the same way as Next.js was obvious: Nuxt.js was born.
As you might guess, Nuxt takes a lot of concepts straight from Next, but so does the server-side rendering guide by the Vue team. The biggest difference is that Nuxt actually implements the concepts rather than simply giving you the information you need to implement them yourself. Let’s take a look at some of the basics of what Nuxt does for you.
The very first thing you’ll find from Nuxt is that it has its own vue-cli template to set up the entire project in a jiffy. Instead of using one of the included template names when you init (e.g. vue init webpack <project-name>), you would use the shortcut to point to the Github repo of their own template:
> vue init nuxt-community/starter-template <project-name>
Once you’ve done that, your project will be scaffolded out with all of the default configuration and basic setup a Nuxt project should need. If you’d like to integrate Nuxt into your existing application there will be a lot more work to do, and I won’t be going over that here. It may not even be possible to give full instructions since much of it will have to do with how your current project is set up. Even if you have an existing project, it may be wise to use this scaffold to get used to how Nuxt is set up so it’ll be easier to migrate your app.
File and Folder Structure
Nuxt, like Next, tries to use a bit of the old Ruby on Rails concept of “convention over configuration”. So, instead of configuring your router or writing the code needed for you to bootstrap your application and handle routing, Nuxt handles much of that for you and specifies a certain folder structure so it can make assumptions about what your files do.
Inside the root of the app is several folders:
- layouts: contains the components that specify the outer shell/layout for a page.
- pages: contains the components that are for specific routes/pages. There are also subfolder/file name conventions that can be used to create static and dynamic routes without the need to configure the router. Pages can specify which layout they use.
- components: contains the Vue components that aren’t used to specify a layout or page.
- plugins: contains the Vue plugins you wish to use. You’ll need to specify in the Nuxt configuration which ones you’re using.
- middleware: contains custom functions that can be run before rendering either a page or a layout.
- store: contains the definitions of your Vuex stores.
- assets: contains uncompiled source code that will be compiled/bundled. It’s pretty much any scripts or files you want webpack to deal with that don’t belong in any of the above folders.
- static: contains static files that will be copied verbatim to the server and be available at the root of the app URL.
- nuxt.config.js: The configuration file for Nuxt. It may have some “convention over configuration” tendencies, but there’s still plenty to configure.
That default structure is pretty simple to grok and get started with. If you have a sufficiently large application, you may have created a folder structure somewhat similar to this to more easily distinguish between components used for pages and those that can be used anywhere in the app.
Server-Specific and Client-Specific API
As mentioned before, there is some code that doesn’t make sense to run on the server but needs to be run on the client and vice versa. Nuxt recognizes this. They give you an API that allows you to add code specifically to be used on the server. This is done through component life-cycle hooks with parameters that allow you to get the data you need, such as the store and route information. It also doesn’t run certain life-cycle hooks on components when being rendered on the server.
This doesn’t mean that you’re entirely clear of the possibility of running client-side-only code on the server, but if you learn the API, it can help you find places to put the code where it won’t cause any issues.
If you’re looking to make your Vue applications pre-rendered on the server for any of a number of reasons, then you’re in pretty good hands. Nuxt handles a lot of the hassle of setting up a server-side rendered application while having some useful conventions and some extensibility to allow you to expand its base capabilities to fit your unique needs.