vue ssr同構

前面記錄了下next 如何作服務端渲染,最近看了看vue官方得ssr說明,而後不基於next,本身來作一個vue得ssr服務端渲染.

官方文檔:https://ssr.vuejs.org/css

官方文檔的解釋:Vue.js 是構建客戶端應用程序的框架。默認狀況下,能夠在瀏覽器中輸出 Vue組件,進行生成 DOM 和操做 DOM。然而,也能夠將同一個組件渲染爲服務器端的 HTML 字符串,將它們直接發送到瀏覽器,最後將這些靜態標記"激活"爲客戶端上徹底可交互的應用程序。html

服務器渲染的 Vue.js 應用程序也能夠被認爲是"同構"或"通用",由於應用程序的大部分代碼均可以在服務器和客戶端上運行。vue

仍是老樣子,咱們在用ssr服務端渲染以前須要先問本身是否真的須要它.node

技術層面:webpack

  • 更快的首屏渲染速度
  • 更好的 SEO

業務層面:web

  • 不適合管理系統
  • 適合門戶資訊類網站,例如企業官網、知乎、簡書等
  • 適合移動網站

vue的ssr 主要分爲兩種express

  1. Nuxt.js 開發框架npm

    1. NUXT提供了平滑的開箱即用的體驗,它創建在同等的Vue技術棧之上,但抽象出不少模板,並提供了一些額外的功能,例如靜態站點生成。經過 Nuxt.js 能夠快速的使用 Vue SSR 構建同構應用。
  2. 基於 Vue SSR 官方文檔提供的解決方案json

    1. 官方方案具備更直接的控制應用程序的結構,更深刻底層,更加靈活,同時在使用官方方案的過程當中,也會對Vue SSR有更加深刻的瞭解。
    2. 該方式須要你熟悉 Vue.js 自己,而且具備 Node.js 和 webpack 的至關不錯的應用經驗。

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,開發階段熱加載,路由定位,數據預取等都沒有,下面就咱們來進一步實現它。

首先咱們來看一張圖,來看它的構建流程:
image.png

首先來看,咱們確定是須要使用webpack來打包咱們的vue程序的,由於:

  • 一般 Vue 應用程序是由 webpack 和vue-loader構建,而且許多 webpack 特定功能不能直接在Node.js 中運行(例如經過file-loader導入文件,經過css-loader導入 CSS)。
  • 儘管 Node.js 最新版本可以徹底支持 ES2015 特性,咱們仍是須要轉譯客戶端代碼以適應老版瀏覽器。這也會涉及到構建步驟。

因此是這樣,首先咱們把全部的源代碼例如(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...

一個基本的項目應該是這樣:
image.png

  • setup-dev-server: 開發模式下,用來監視打包構建,從新生成renderer渲染器
  • webpack.base.config 公共的webpack配置
  • webpack.client.config 客戶端webpack配置
  • webpack.server.config 服務端webpack配置
  • pages,router,store 是vue 相關文件
  • index.template.html 模板html文件
  • app.js咱們應用程序的「通用 entry」,在純客戶端應用程序中,咱們將在此文件中建立根 Vue 實例,並直接掛載到 DOM。可是,對於服務器端渲染(SSR),責任轉移到純客戶端 entry 文件。
  • entry-server.js 服務器 entry 使用 default export 導出函數,並在每次渲染中重複調用此函數。此時,除了建立和返回應用程序實例以外,它不會作太多事情 - 可是稍後咱們將在此執行服務器端路由匹配 (server-sideroute matching) 和數據預取邏輯 (data pre-fetching logic)。
  • entry-client.js 客戶端 entry 只需建立應用程序,而且將其掛載到 DOM 中
  • server.js 咱們node服務的啓動文件

而後下面就是一步一步來實如今這些功能.
準備工做安裝依賴:
生產:

說明
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() //錯誤提示插件
  ]
}
相關文章
相關標籤/搜索