阿里云主机折上折
  • 微信号
Current Site:Index > Server-side rendering supports this.

Server-side rendering supports this.

Author:Chuan Chen 阅读数:26519人阅读 分类: Vue.js

Basic Concepts of Server-Side Rendering

Server-Side Rendering (SSR) refers to rendering Vue components into HTML strings on the server side and sending them directly to the browser. This approach differs from traditional Client-Side Rendering (CSR), where the DOM is dynamically generated in the browser via JavaScript.

// Client-Side Rendering Example
new Vue({
  el: '#app',
  render: h => h(App)
})

The main advantages of SSR include:

  • Better SEO: Search engines can directly crawl the rendered HTML content
  • Faster initial page load: The browser doesn't need to wait for all JavaScript to download and execute
  • Better compatibility with low-end devices: Reduces client-side computational burden

Implementation Principles of Vue SSR

Vue's SSR implementation is based on two key components: the vue-server-renderer package and a Node.js server. The core process is as follows:

  1. Create a Vue instance factory function
  2. Use createRenderer to create a renderer
  3. Render the Vue instance into HTML during server request handling
// Basic SSR Implementation Example
const Vue = require('vue')
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
  const app = new Vue({
    data: () => ({ url: req.url }),
    template: `<div>Visited URL: {{ url }}</div>`
  })

  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Server Error')
      return
    }
    res.end(`
      <!DOCTYPE html>
      <html>
        <head><title>SSR Example</title></head>
        <body>${html}</body>
      </html>
    `)
  })
})

SSR Support in the Nuxt.js Framework

Nuxt.js is a popular framework that provides out-of-the-box SSR support for Vue applications. It simplifies SSR configuration and offers a convention-over-configuration development experience.

Typical Nuxt.js project structure:

├── pages/         // Auto-generated routes
├── components/    // Vue components
├── store/         // Vuex store
├── nuxt.config.js // Configuration file

Configuration example:

// nuxt.config.js
export default {
  ssr: true, // Enable SSR
  target: 'server', // Server-side rendering target
  head: {
    title: 'My Nuxt App',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' }
    ]
  }
}

Client-Side Hydration

Client-side hydration is a key concept in SSR, referring to the process of "taking over" the server-rendered static HTML in the browser and turning it into a dynamic Vue application.

// Client entry file
import Vue from 'vue'
import App from './App.vue'

new Vue({
  el: '#app', // Must match the mount point in the server HTML
  render: h => h(App)
})

Important considerations for hydration:

  • Vue versions on the client and server must match
  • Initial state must be consistent
  • Avoid using client-only APIs in component lifecycles

Data Prefetching Strategies

Common data fetching patterns in SSR applications:

  1. Component-Level Data Prefetching:
// Page component
export default {
  async asyncData({ params }) {
    const { data } = await axios.get(`/api/user/${params.id}`)
    return { user: data }
  }
}
  1. Vuex Store Prefetching:
// Store action
export const actions = {
  async fetchUser({ commit }, userId) {
    const { data } = await axios.get(`/api/user/${userId}`)
    commit('SET_USER', data)
  }
}
  1. Server-Side Data Injection:
// Server-side
const store = createStore()
await store.dispatch('fetchUser', userId)
const context = { url: req.url, state: store.state }

Performance Optimization Techniques

  1. Component Caching:
const LRU = require('lru-cache')
const renderer = createRenderer({
  cache: LRU({
    max: 10000,
    maxAge: 1000 * 60 * 15 // 15-minute cache
  })
})
  1. Code Splitting:
// Dynamic component import
const Foo = () => import('./Foo.vue')

// Route-level code splitting
const router = new VueRouter({
  routes: [
    { path: '/foo', component: () => import('./Foo.vue') }
  ]
})
  1. Streaming Rendering:
// Use renderToStream instead of renderToString
const stream = renderer.renderToStream(app)
stream.pipe(res, { end: false })
stream.on('end', () => res.end('</body></html>'))

Common Issues and Solutions

Issue 1: window/document is undefined

// Solution: Use in mounted hook or check runtime environment
export default {
  mounted() {
    if (process.client) {
      window.addEventListener('resize', this.handleResize)
    }
  }
}

Issue 2: Memory Leaks

// Ensure creating new Vue instance per request
export default context => {
  return new Vue({
    data: () => ({ count: 0 }),
    template: `<div>{{ count }}</div>`
  })
}

Issue 3: Async Component Loading

// Use Vue's async components with webpack magic comments
const AsyncComponent = () => ({
  component: import(/* webpackChunkName: "async" */ './AsyncComponent.vue'),
  loading: LoadingComponent,
  error: ErrorComponent,
  delay: 200,
  timeout: 3000
})

Deployment and Monitoring

  1. PM2 Deployment Configuration:
{
  "apps": [{
    "name": "my-ssr-app",
    "script": "server/index.js",
    "instances": "max",
    "exec_mode": "cluster",
    "env": {
      "NODE_ENV": "production"
    }
  }]
}
  1. Performance Monitoring:
// Use Performance API to monitor key metrics
const perfObserver = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('[Perf]', entry.name, entry.duration)
  }
})
perfObserver.observe({ entryTypes: ['measure'] })
  1. Error Tracking:
// Global error handling
Vue.config.errorHandler = (err, vm, info) => {
  logErrorToService(err, {
    component: vm.$options.name,
    lifecycleHook: info
  })
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:Pinia插件开发

下一篇:持久化存储方案

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.