普通vue-cli初始專案轉為服務端渲染SSR
1、第一步沒啥好說的,利用vue-cli腳手架建立一個demo專案:
vue init webpack vue-ssr-demo
cd vue-ssr-demo
npm install
2、安裝SSR依賴的模組:
npm i -D vue-server-renderer
3、隨便加一個components/test.vue
<template>
<div>
Just a test page.
</div>
</template>
<script>
export default {
data () {
return {
}
}
}
</script>
4、src目錄下建立倆js檔案:
src ├── entry-client.js # 僅執行於瀏覽器 └── entry-server.js # 僅執行於伺服器
5、修改router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export function createRouter () {
return new Router({
mode: 'history', // 注意這裡也是為history模式
routes: [
{
path: '/',
name: 'Hello',
component: HelloWorld
}, {
path: '/test',
name: 'Test',
component: () => import('@/components/test') // 非同步元件
}
]
})
}
6、修改main.js里路由的引入:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import { createRouter } from './router'
export function createApp () {
// 建立 router 例項
const router = new createRouter()
const app = new Vue({
// 注入 router 到根 Vue 例項
router,
render: h => h(App)
})
// 返回 app 和 router
return { app, router }
}
7、在entry_client.js裡面寫上如下內容:
import { createApp } from './main';
const {app, store, router} = createApp();
router.onReady(() => {
// 新增路由鉤子函式,用於處理 asyncData.
// 在初始路由 resolve 後執行,
// 以便我們不會二次預取(double-fetch)已有的資料。
// 使用 `router.beforeResolve()`,以便確保所有非同步元件都 resolve。
router.beforeResolve((to, from, next) => {
const matched = router.getMatchedComponents(to)
const prevMatched = router.getMatchedComponents(from)
// 我們只關心非預渲染的元件
// 所以我們對比它們,找出兩個匹配列表的差異元件
let diffed = false
const activated = matched.filter((c, i) => {
return diffed || (diffed = (prevMatched[i] !== c))
})
if (!activated.length) {
return next()
}
// 這裡如果有載入指示器 (loading indicator),就觸發
Promise.all(activated.map(c => {
if (c.asyncData) {
return c.asyncData({ store, route: to })
}
})).then(() => {
// 停止載入指示器(loading indicator)
next()
}).catch(next)
})
app.$mount('#app')
})
8、在entry_server.js裡寫如下內容:
import { createApp } from './main'
export default context => {
// 因為有可能會是非同步路由鉤子函式或元件,所以我們將返回一個 Promise,
// 以便伺服器能夠等待所有的內容在渲染前,
// 就已經準備就緒。
return new Promise((resolve, reject) => {
const { app, router } = createApp()
// 設定伺服器端 router 的位置
router.push(context.url)
// 等到 router 將可能的非同步元件和鉤子函式解析完
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
// 匹配不到的路由,執行 reject 函式,並返回 404
if (!matchedComponents.length) {
// eslint-disable-next-line
return reject({ code: 404 })
}
// Promise 應該 resolve 應用程式例項,以便它可以渲染
resolve(app)
}, reject)
})
}
9、在build資料夾下新增一個webpack.server.conf.js,寫上:
const webpack = require('webpack')
const merge = require('webpack-merge')
const base = require('./webpack.base.conf.js')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
module.exports = merge(base, {
target: 'node',
devtool: '#source-map',
entry: './src/entry-server.js',
output: {
filename: 'server-bundle.js',
libraryTarget: 'commonjs2'
},
resolve: {
alias: {
'create-api': './create-api-server.js'
}
},
// https://webpack.js.org/configuration/externals/#externals
// https://github.com/liady/webpack-node-externals
externals: nodeExternals({
// do not externalize CSS files in case we need to import it from a dep
allowlist: /\.css$/
}),
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.VUE_ENV': '"server"'
}),
new VueSSRServerPlugin()
]
})
10、在webpack.prod.conf.js中加上:
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') // 開頭引入這個
....
new webpack.DefinePlugin({
'process.env': env,
'process.env.VUE_ENV': '"client"' // 這裡加一行process.env.VUE_ENV
}),
....
new VueSSRClientPlugin() // plugins陣列裡最後加一個這個
11、修改webpack.base.conf.js的entry:
entry: {
app: './src/entry-client.js' // 改為這個
},
12、配置package.json
增加打包伺服器端構建命令並修改原打包命令:
"build:client": "node build/build.js",
"build:server": "cross-env NODE_ENV=production webpack --config build/webpack.server.conf.js --progress --hide-modules",
"build": "rimraf dist && npm run build:client && npm run build:server"
13、根目錄新建一個index.template.html模板頁面(或者直接修改原index.html,只是這樣要區分生產環境和開發環境,否則run dev的時候就不ok):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title></title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
14、根目錄下新建一個server.js(沒安裝express的先npm install express):
const express = require('express');
const fs = require('fs');
const path = require('path');
const { createBundleRenderer } = require('vue-server-renderer');
const app = express();
const serverBundle = require('./dist/vue-ssr-server-bundle.json');
const clientManifest = require('./dist/vue-ssr-client-manifest.json');
const template = fs.readFileSync(path.resolve('./index.template.html'), 'utf-8'); // 這裡就看13步驟裡你是哪個檔案
const render = createBundleRenderer(serverBundle, {
runInNewContext: false, // 推薦
template, // (可選)頁面模板
clientManifest
});
app.use(express.static('./dist',{index:false}))
app.get('*', (req, res) => {
const context = { url: req.url }
render.renderToString(context, (err, html) => {
console.log(html)
// 處理異常……
res.end(html)
})
})
const port = 3003;
app.listen(port, function() {
console.log(`server started at localhost:${port}`);
});
15、準備就緒了兄弟們,因為是本地執行,偷偷把"build:server"裡的NODE_ENV先等於development,執行:
npm run build
之後可以看到生成了dist目錄:
16、然後,執行:
node server
成功啟動server started at localhost:3003
開啟localhost:3003,在控制檯NetWork裡看到如下,SSR服務端渲染成功。
相關文章
- Vue 服務端渲染(SSR)Vue服務端
- 實現SSR服務端渲染服務端
- 實現ssr服務端渲染demo服務端
- React + Koa 實現服務端渲染(SSR)React服務端
- React服務端渲染(專案搭建)React服務端
- docsify 4.0 釋出,支援服務端渲染(SSR)服務端
- nuxtjs+express+vue2+vuex搭建的服務端渲染(SSR)個人網站專案UXJSExpressVue服務端網站
- React + Koa 實現服務端渲染(SSR) Part IIReact服務端
- Vue SSR服務端渲染之資料快取Vue服務端快取
- React16.x中的服務端渲染(SSR)React服務端
- 對比分析--淺析SSR(服務端渲染)和SPA(客戶端渲染)服務端客戶端
- 仿掘金前臺 vue 服務端渲染(ssr)後臺 react (spa) 後臺服務是 koa 的一個專案Vue服務端React
- 深度理解React專案的服務端渲染改造React服務端
- 使用 Nuxt.js 快速搭建服務端渲染(SSR) 應用UXJS服務端
- Vue/React 元件 PHP 服務端渲染(SSR)可行性分析VueReact元件PHP服務端
- 服務端渲染到前端渲染,再到“服務端渲染”服務端前端
- 手把手教你搭建 Vue 服務端渲染專案Vue服務端
- Inertia.js SSR | 讓 Laravel x Vue 實現服務端渲染JSLaravelVue服務端
- Vue 服務端渲染(SSR)、Nuxt.js – 從入門到實踐Vue服務端UXJS
- Vue 服務端渲染(SSR)、Nuxt.js - 從入門到實踐Vue服務端UXJS
- Vue 服務端渲染(SSR)、Nuxt2 - 從入門到實踐Vue服務端UX
- Vue 服務端渲染 & 預渲染Vue服務端
- 服務端渲染和客戶端渲染服務端客戶端
- 基於vue現有專案的伺服器端渲染SSR改造Vue伺服器
- 深入學習Vue SSR服務端渲染 用Nuxt.js打造CNode社群Vue服務端UXJS
- react 服務端渲染React服務端
- nuxt.js實現服務端渲染ssr (一)(環境配置、 多環境開發、程式守護、服務端映象)UXJS服務端
- 如何理解服務端渲染?服務端
- 服務端渲染基礎服務端
- 【長文慎入】一文吃透 React SSR 服務端渲染和同構原理React服務端
- SSR後端渲染和CSR前端渲染的區別後端前端
- Angular6 服務端渲染Angular服務端
- Universal-webpack服務端渲染Web服務端
- node服務端渲染(完整demo)服務端
- Vue 服務端渲染技術Vue服務端
- vue:服務端渲染技術Vue服務端
- (精華2020年5月31日更新) react基礎篇 手寫ssr服務端渲染React服務端
- 我很懶,什麼都沒留下系列 之 教你上手React服務端渲染(React SSR)&& HMRReact服務端