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() //错误提示插件
  ]
}
相关文章
相关标签/搜索