The Impact of Server-Side Rendering Vue.js Applications

The Impact of Server-Side Rendering Vue.js Applications

Performance of different rendering methods in Vue
Barbara Odozi β€’ 2023 October 30 β€’ Read time 10 min read
Learn how rendering Vue.js applications on the server-side can positively affect the performance of your application.
  • twitter
  • facebook

Vue.js is a JavaScript framework, often dubbed as the progressive JavaScript framework, used in building interactive web interfaces. It's known for its simplicity and flexibility.

Server-side rendering, abbreviated as SSR, is a technique used for displaying web pages of an application from the server side instead of the client-side (browser), which is beneficial for performance and SEO purposes.

In this article, we'll explore the impact of server-side rendering on the performance of Vue.js applications, some of its benefits and trade-offs, as well as tips for implementing SSR in your application. In order to make sense of this enlightening journey, let us take a moment to understand the traditional rendering of Vue.js and the fundamentals of server-side rendering.


Understanding Server-Side Rendering

SSR isn't a new concept; it has always been a staple of web development since the early days of the internet but became popular in recent years due to the rise of JavaScript frameworks like Vue and React.

The earliest web pages were primarily static, with servers generating HTML documents and delivering them to clients. As web technologies advanced, the paradigm shifted to dynamic, client-side rendering through JavaScript. This evolution introduced new challenges, particularly concerning performance and search engine optimization.

You can find the source of this tutorial on GitHub.

What is SSR?

In SSR, web pages are rendered on the server rather than the client. When a user requests a page, the server generates the HTML content dynamically and sends a fully rendered page to the client's browser. This approach offers several benefits, such as:

  • Faster Load Times: SSR reduces the time it takes for a web page to load initially because users receive pre-rendered HTML from the server, making it easier to access content more quickly, enhancing the overall experience.
  • Improved SEO: Search engines can easily crawl and index content prior to delivery, which is beneficial for search engine optimization. With faster load times, SSR helps efficiently load web pages with slow internet connections.

SSR vs CSR

To understand SSR completely, it's important to contrast it with its counterpart: client-side rendering (CSR). With CSR, the web browser downloads a minimal HTML page and renders the content dynamically using JavaScript. Although it has its merits, such as dynamic content loading and interactivity, it loads slower compared to SSR due to the time taken for JavaScript execution and data fetching.

SSR seamlessly blends the responsiveness of client-side rendering with the speed and SEO-friendliness of server-side rendering, creating an exceptional user experience and establishing itself as an invaluable tool in modern web development.

difference between SSR and CSR explained
Difference between SSR and CSR

Vue.js integrates SSR capabilities, allowing developers to achieve speed improvements and optimal SEO, which is important for businesses today. Large-scale Vue.js applications leverage SSR for optimal performance and user satisfaction to deliver exceptional user experiences.

Having explored the history, benefits, and real-world applications of server-side rendering, we're equipped to grasp its transformative potential. Moving forward, we'll examine Vue.js's default rendering approach, SSR implementation in Vue.js applications, and SSR's significant impact on performance and SEO. At the end of this article, we'll also take a look at some best practices.


How Vue.js Handles Rendering by Default

Vue.js's default rendering approach is client-side rendering. The entire application is loaded into the client's browser as a bundle of JavaScript files. When you access a Vue.js application, the browser downloads this bundle and executes it locally.

When you first visit a Vue.js application, the server sends a minimal HTML file along with the bundled JavaScript and CSS files to the client's browser. The HTML file typically contains a root element where Vue.js will be mounted, such as:

Copied to clipboard!
<div id="app"></div>
Root element of a Vue app

Upon loading, the JavaScript bundle executes in the user's browser while Vue.js takes control of the designated root element and initializes the application, creating a virtual DOM representation of the app's components and data.

When you interact with the application, Vue.js dynamically updates the Virtual DOM in response to your actions or data changes. These changes trigger the browser to re-render the affected parts of the UI, ensuring a responsive and interactive user experience.

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScriptinfo Remove ads

Implementing SSR in Vue.js

In this section, we'll go through a step-by-step guide on setting up SSR in a Vue.js application.

This tutorial assumes you have Node.js and NPM or Yarn installed for package management, as well as some basic knowledge of Vue.js.

On that note, we'll begin by bootstrapping a new Vue.js project (you can use an existing one if you wish) and installing the necessary dependencies for SSR. Run the following commands inside your terminal one by one:

Copied to clipboard!
npm init -y             # Initialize a new project
npm install create-vite # Install Vite for Vue 3
npm install express     # Install Express
Follow the installation steps

Once everything has been installed, create the following files. Here’s what your directory should look like:

Copied to clipboard!
β”œβ”€ src
β”‚  β”œβ”€ main.js
β”‚  β”œβ”€ entry-client.js
β”‚  β”œβ”€ entry-server.js
β”œβ”€ index.html
β”œβ”€ server.js
Project structure
  • index.html: The entry file for our Vue.js project.
  • server.js: This is the main application server.
  • src: All project-related files, such as components, will be in this folder.
  • main.js: This will store the function to initialize our app.
  • entry-client.js: This mounts the app to a DOM element and will be used during hydration.
  • entry-server.js: This uses the framework’s SSR API to render the app, which will be utilized in server.js.

Adding client-side code

The main.js will hold our app logic, which will be utilized for both client and server-side rendering. In Vue 3, the createSSRApp function simplifies server-side rendering, allowing us to render Vue applications on the server:

Copied to clipboard! Playground
import { createSSRApp } from 'vue'
import App from './App.vue'

export const createApp = () => {
    const app = createSSRApp(App)
    
    return {
        app
    }
}
main.js
Create the entry point for the app

Use createSSRApp to render the Vue App on the server and send it to the user to do the hydration process. Next, we add entry-client.js to initiate our app on the client-side:

Copied to clipboard! Playground
import { createApp } from './main.js'

// Initiate the Vue App for a client-side application
const { app } = createApp()
app.mount('#app')
entry-client.js
Initialize the client-side of the app

Then, update the App.vue to display a counter inside the button which increments with every click. We'll use this component to test rendering.

Copied to clipboard!
<template>
    <div>
        <button @click="handleIncrement">{{ count }}</button>
    </div>
</template>

<script setup lang="ts">
    import { ref } from 'vue'

    const count = ref(1)
    const handleIncrement = () => {
	count.value += 1
    }
</script>
App.vue
Update App.vue

Adding server-side code

The next step is to handle the server-side code. In entry-server.js, we'll use createSSRApp to initialize our app, then render the app to HTML using renderToString, which can be sent to the client.

Copied to clipboard! Playground
import { renderToString } from 'vue/server-renderer'
import { createApp } from './main'

export const render = async () => {
    const { app } = createApp()
    const html = await renderToString(app)

    return {
        html
    }
}
entry-server.js
Initialize the server-side of the app

To initiate the Vue App for a server-side application, we use renderToString to render the app to HTML. Then, we need to combine the client and server. To do this, we'll use Express.js, which we installed earlier. Add the following code in the server.js file:

Copied to clipboard! Playground
import express from 'express'
import { fileURLToPath } from 'url'
import path from 'path'
import { createServer } from 'vite'
import { promises as fs } from 'fs'

async function initServer() {
    const app = express()

    const vite = await createServer({
        server: { middlewareMode: true },
	appType: 'custom'
    })

    app.use(vite.middlewares)

    app.use('*', async (req, res) => {
        try {
	    const __filename = fileURLToPath(import.meta.url)
	    const __dirname = path.dirname(__filename)

	    let template = await fs.readFile(
	        path.resolve(__dirname, 'index.html'),
		'utf-8'
	    )

	    template = await vite.transformIndexHtml(req.originalUrl, template)

	    const { render } = await vite.ssrLoadModule('/src/entry-server.js')
	    const { html: appHtml } = await render()
	    const html = template.replace('<!--main-app-->', appHtml)

	    res.set({ 'Content-Type': 'text/html' }).end(html)
	} catch (error) {
	    console.error(error)
	    res.status(500).end('Internal Server Error')
	}
    })

    return app
}

initServer().then((app) =>
    app.listen(3000, () => {
        console.log('Server is running on http://localhost:3000')
    })
)
server.js
Implement Express in server.js

Here's a breakdown of what we've done:

  • Lines 19-20: Get the current module's directory using import.meta.url.
  • Lines 22-25: Read the index.html file.
  • Line 27: Apply Vite HTML transforms and injects the Vite HMR (Hot Module Replacement) client and processes HTML modifications from Vite plugins.
  • Line 29: Load the server-side entry point using ssrLoadModule, which transforms ESM source code for Node.js without bundling, providing efficient invalidation similar to HMR.
  • Line 30: Render the app HTML using the render function from entry-server.js. The function utilizes the framework's SSR (Server-Side Rendering) APIs to generate the initial HTML representation of the app.
  • Line 31: Inject the HTML content rendered by the application into the template.
  • Line 33: Send the final rendered HTML content back as the response.

Next up is to update our index.html by adding the placeholder and updating the script src attribute to /src/entry-client.js like so:

Copied to clipboard! Playground
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
	<link rel="icon" href="/favicon.ico" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>Vite App</title>
    </head>
    <body>
        <div id="app"><!--main-app--></div>

	<script type="module" src="/src/entry-client.js"></script>
    </body>
</html>
index.html
Update index.html
  • Line 10: Add <!--main-app--> it will be replaced by our App.
  • Line 12: Update the src to entry-client.ts.

Finally, update the dev script in package.json to node server.js:

Copied to clipboard!
"scripts": {
    "dev": "node server.js",
    "build": "vite build",
    "preview": "vite preview"
}
package.json
Update package.json with the new script

Impact on Performance

Performance is a critical aspect of any web application, directly influencing user experience and engagement. In traditional client-side rendering, several challenges can impact performance, especially during the initial page load. Let's compare these challenges with the improvements introduced by SSR:

PerformanceCSR ApproachSSR Approach
Slow initial load timesRequires downloading and executing JS on clientPre-renders HTML on server, reducing load times
SEO limitationsSearch engines struggle with JavaScript contentProvides fully-rendered HTML to search engines
Delayed interactivityWaits for JS execution for interactive elementsFaster initial rendering leads to quicker interactivity
Bandwidth consumptionHeavier JS bundles increase bandwidth usageReduces the need for large initial JS downloads
Mobile performanceSlower performance on devices with limited resourcesImproves performance, especially on mobile devices

SSR Best Practices

You can significantly enhance the performance and search engine optimization of your Vue.js applications when implemented correctly, and there are best practices to follow to avoid pitfalls.

Some things to consider when using SSR in Vue.js:

  • Design components to be SSR-friendly. Make sure to avoid relying on browser-specific APIs or global objects, as they may not be available during server-side rendering.
  • Utilize asyncData and fetch options in Vue components to handle asynchronous data fetching. They work both on the server and client.
  • Use Vue's reactivity system and computed properties for dynamic content updates because using direct DOM manipulation in components can lead to inconsistencies.
  • Consider using caching strategies like memoization or server-side caching mechanisms to prevent redundant requests during rendering.
  • Use tools like Google PageSpeed Insights to monitor performance and continue to optimize based on performance metrics and user experience feedback.

Conclusion

In summary, server-side rendering in Vue.js is a game-changer for web development. It tackles the limitations of traditional client-side rendering by offering faster loading, improved SEO, and a better user experience. SSR optimizes Vue.js applications, creating seamless interfaces, especially on mobile devices, and ensures visibility on search engines.

For Vue.js developers, delving into SSR is crucial. By implementing it in your projects, you enhance user experiences and contribute to a faster, more accessible web ecosystem. It's worth mentioning that tools like Nuxt.js simplify SSR implementation with built-in functionalities, making the process even more straightforward. Embrace SSR, enhance your skills, and shape a user-centric web landscape.

  • twitter
  • facebook
Did you find this page helpful?
πŸ“š More Webtips
Mentoring

Rocket Launch Your Career

Speed up your learning progress with our mentorship program. Join as a mentee to unlock the full potential of Webtips and get a personalized learning experience by experts to master the following frontend technologies:

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.