官方文檔:https://ssr.vuejs.org/css
官方文檔的解釋:Vue.js 是構建客戶端應用程序的框架。默認狀況下,能夠在瀏覽器中輸出 Vue組件,進行生成 DOM 和操做 DOM。然而,也能夠將同一個組件渲染爲服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最後將這些靜態標記"激活"爲客戶端上徹底可交互的應用程序。html
服務器渲染的 Vue.js 應用程序也能夠被認爲是"同構"或"通用",由於應用程序的大部分代碼均可以在服務器和客戶端上運行。vue
仍是老樣子,咱們在用ssr服務端渲染以前須要先問本身是否真的須要它.node
技術層面:webpack
業務層面:web
vue的ssr 主要分爲兩種express
Nuxt.js 開發框架npm
基於 Vue SSR 官方文檔提供的解決方案json
next的文檔寫的很棒了,基本跟着它的文檔作就能夠了,這裏主要是參考vue ssr的文檔,來實現一下.
首先來個最簡單的,把一個vue的實例轉換成模板字符串,而後從服務器返回到客戶端.segmentfault
npm install vue vue-server-renderer --save
const Vue = require('vue'); const server = require('express')(); //建立服務 //選擇模板 const template = require('fs').readFileSync('./index.template.html', 'utf-8'); //建立渲染器 const renderer = require('vue-server-renderer').createRenderer({ template, }); //模板使用的數據上下文 const context = { title: 'vue ssr', metas: ` <meta name="keyword" content="vue,ssr"> <meta name="description" content="vue srr demo"> `, }; //匹配全部地址,返回html界面 server.get('*', (req, res) => { const app = new Vue({ //建立vue實例,每次請求都是一個新的實例,防止實例共享,數據錯亂 data: { url: req.url }, template: `<div>訪問的 URL 是: {{ url }}</div>`, }); //把vue實例和上下文數據和模板結合返回字符串給客戶端瀏覽器 renderer .renderToString(app, context, (err, html) => { console.log(html); if (err) { res.status(500).end('Internal Server Error') return; } res.end(html); }); }) //監聽端口 server.listen(8080);
模板注意點:注意 <!--vue-ssr-outlet-->
註釋 -- 這裏將是應用程序 HTML 標記注入的地方。
這是官網的例子:https://ssr.vuejs.org/zh/guide/
這會是一個最簡單的demo,開發階段熱加載,路由定位,數據預取等都沒有,下面就咱們來進一步實現它。
首先咱們來看一張圖,來看它的構建流程:
首先來看,咱們確定是須要使用webpack來打包咱們的vue程序的,由於:
因此是這樣,首先咱們把全部的源代碼例如(store,router,components),經過公共entry app.js和服務端的入口和客戶端入口進行webpack打包,對應客戶端應用程序和服務端應用程序打出來:服務器須要的bundle 也就是serve bundle,用於服務器渲染ssr, 而打出來的客戶端bundle 也就是client bundle, 這個js會寫入到html模板中,用於客戶端激活,接管服務端發送的靜態html,使其變爲由vue管理的動態dom.
因爲服務器已經渲染好了 HTML,咱們顯然無需將其丟棄再從新建立全部的 DOM 元素。相反,咱們須要"激活"這些靜態的 HTML,而後使他們成爲動態的(可以響應後續的數據變化)。
若是你檢查服務器渲染的輸出結果,你會注意到應用程序的根元素上添加了一個特殊的屬性:
<div id="app" data-server-rendered="true">
data-server-rendered
特殊屬性,讓客戶端 Vue 知道這部分 HTML 是由 Vue 在服務端渲染的,而且應該以激活模式進行掛載。注意,這裏並無添加 id="app"
,而是添加 data-server-rendered
屬性:你須要自行添加 ID 或其餘可以選取到應用程序根元素的選擇器,不然應用程序將沒法正常激活。
在開發模式下,Vue 將推斷客戶端生成的虛擬 DOM 樹 (virtual DOM tree),是否與從服務器渲染的 DOM 結構 (DOM structure) 匹配。若是沒法匹配,它將退出混合模式,丟棄現有的 DOM 並從頭開始渲染。在生產模式下,此檢測會被跳過,以免性能損耗。
客戶端渲染注意事項:https://ssr.vuejs.org/zh/guid...
一個基本的項目應該是這樣:
而後下面就是一步一步來實如今這些功能.
準備工做安裝依賴:
生產:
包 | 說明 |
---|---|
vue | Vue.js 核心庫 |
vue-server-renderer | Vue 服務端渲染工具 |
express | 基於 Node 的 Web 服務框架 |
cross-env | 經過 npm scripts 設置跨平臺環境變量 |
開發:
包 | 說明 |
---|---|
webpack | webpack 核心包 |
webpack-cli | webpack 的命令行工具 |
webpack-merge | webpack 配置信息合併工具 |
webpack-node-externals | 排除 webpack 中的 Node 模塊 |
rimraf | 基於 Node 封裝的一個跨平臺rm-rf工具 |
friendly-errors-webpack-plugin | 友好的 webpack 錯誤提示 |
@babel/core , @babel/plugin-transform-runtime, @babel/preset-env, babel-loader | Babel 相關工具 |
vue-loader,vue-template-compiler | 處理 .vue 資源 |
file-loader | 處理字體資源 |
css-loader | 處理 CSS 資源 |
url-loader | 處理圖片資源 |
而後一步一步來,首先是咱們的 webpack配置,先是公共的webpack.base.config.js
/** * 公共配置 */ const VueLoaderPlugin = require('vue-loader/lib/plugin') const path = require('path') const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')//友好的webpack錯誤提示 const resolve = file => path.resolve(__dirname, file) const isProd = process.env.NODE_ENV === 'production' //判斷是生產仍是開發環境 module.exports = { mode: isProd ? 'production' : 'development', output: { path: resolve('../dist/'), publicPath: '/dist/', //設置客戶端請求資源時的路徑,從dist打包輸出目錄讀取 filename: '[name].[chunkhash].js' //設置chunkhash }, resolve: { alias: { // 路徑別名,@ 指向 src '@': resolve('../src/') }, // 能夠省略的擴展名 // 當省略擴展名的時候,按照從前日後的順序依次解析 extensions: ['.js', '.vue', '.json'] }, devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map', module: { rules: [ // 處理圖片資源 { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, }, }, ], }, // 處理字體資源 { test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ 'file-loader', ], }, // 處理 .vue 資源 { test: /\.vue$/, loader: 'vue-loader' }, // 處理 CSS 資源 // 它會應用到普通的 `.css` 文件 // 以及 `.vue` 文件中的 `<style>` 塊 { test: /\.css$/, use: [ 'vue-style-loader', 'css-loader' ] }, // CSS 預處理器,參考:https://vue-loader.vuejs.org/zh/guide/pre-processors.html // 例如處理 Less 資源 // { // test: /\.less$/, // use: [ // 'vue-style-loader', // 'css-loader', // 'less-loader' // ] // }, ] }, plugins: [ new VueLoaderPlugin(), new FriendlyErrorsWebpackPlugin() //錯誤提示插件 ] }