当我开始使用Vue收集有关SSR(服务器端渲染)的信息时,我必须从不同的文章以及官方文档中获取相关信息,以便全面了解这个主题。

以下是我在这些来源中发现的一些问题:

  • 很多关于你应该拥有的信息的假设,比如Webpack配置,连接Vue Router等的正确方法。
  • 缺乏一些重要的信息,并留下一些读者填写的空白。
  • 在给出的例子中,大多数不遵循官方文件提供的标准和最佳实践。

本文的目的是提供您可能需要的所有信息,以便使Vue Router与SSR一起工作,为避免任何可能会让您稍后头疼的差距做出额外的努力。我也尝试尊重所有Vue团队的建议。

途径

在进入实际实施之前,您需要了解一些主要概念:

  • SSR涉及在服务器上为请求的路由创建应用程序的完全加载版本。一旦该页面在客户端呈现,客户端代码将获得所有权。
  • 你需要为你的应用程序需要两个入口构建点,一个用于服务器,一个用于客户端。

考虑到这一点,我们将在这篇文章中完成:

  1. 安装所需的依赖关系
  2. Webpack配置
  3. NPM构建脚本
  4. 文件夹结构
  5. 应用配置
  6. 设置Vue路由器
  7. 客户入口点
  8. 服务器入口点
  9. 服务器配置

让我们希望这个例子给这个主题带来一些清晰!

依赖

我们来看看我们将要安装的依赖关系:

1.我们将使用一个已经具有VueJS应用程序的基本Webpack配置的模板。我们还需要安装vue-cli:

#install vue-clinpm install -g vue-cli#create project using webpack-simplevue init webpack-simple vue-ssr

现在我们需要安装webpack-simple模板的所有依赖关系。在此之前,我们没有做任何与SSR有关的事情。我们只是建立一个通用的VueJS环境。

#go to project foldercd vue-cli#install dependenciesnpm install 

2.所以现在我们有一个VueJS项目开始添加SSR配置。在我们做之前,我们需要添加三个与SSR相关的依赖关系。

#install vue-server-render, vue-router, express and webpack-mergenpm install vue-server-renderer vue-router express webpack-merge --save
  • vue-server-render:SSR的Vue库。
  • vue-router:SPA的Vue图书馆。
  • express:我们需要运行一个NodeJS服务器。
  • webpack-merge:我们将使用它来合并webpack配置。

Webpack配置

我们将需要两个Webpack配置,一个构建客户端入口文件和一个构建服务器入口文件。

我们先来看看Webpack客户端配置,这也将成为我们的服务器入口配置的基本Webpack配置。我们只是要使用我们安装的模板附带的一个,除了我们正在改变条目entry-client.js。

var path = require('path')var webpack = require('webpack')module.exports = {entry: './src/entry-client.js',output: {path: path.resolve(__dirname, './dist'),publicPath: '/dist/',filename: 'build.js'},module: {rules: [{test: /\.css$/,use: ['vue-style-loader','css-loader'],},{test: /\.scss$/,use: ['vue-style-loader','css-loader','sass-loader'],},{test: /\.sass$/,use: ['vue-style-loader','css-loader','sass-loader?indentedSyntax'],},{test: /\.vue$/,loader: 'vue-loader',options: {loaders: {// Since sass-loader (weirdly) has SCSS as its default parse mode, we map// the "scss" and "sass" values for the lang attribute to the right configs here.// other preprocessors should work out of the box, no loader config like this necessary.'scss': ['vue-style-loader','css-loader','sass-loader'],'sass': ['vue-style-loader','css-loader','sass-loader?indentedSyntax']}// other vue-loader options go here}},{test: /\.js$/,loader: 'babel-loader',exclude: /node_modules/},{test: /\.(png|jpg|gif|svg)$/,loader: 'file-loader',options: {name: '[name].[ext]?[hash]'}}]},resolve: {alias: {'vue$': 'vue/dist/vue.esm.js'},extensions: ['*', '.js', '.vue', '.json']},devServer: {historyApiFallback: true,noInfo: true,overlay: true},performance: {hints: false},devtool: '#eval-source-map'}if (process.env.NODE_ENV === 'production') {module.exports.devtool = '#source-map'// http://vue-loader.vuejs.org/en/workflow/production.htmlmodule.exports.plugins = (module.exports.plugins || []).concat([new webpack.DefinePlugin({'process.env': {NODE_ENV: '"production"'}}),new webpack.optimize.UglifyJsPlugin({sourceMap: true,compress: {warnings: false}}),new webpack.LoaderOptionsPlugin({minimize: true})])}

现在添加服务器webpack配置:

var path = require('path')var webpack = require('webpack')var merge = require('webpack-merge')var baseWebpackConfig = require('./webpack.config')var webpackConfig = merge(baseWebpackConfig, {target: 'node',entry: {app: './src/entry-server.js'},devtool: false,output: {path: path.resolve(__dirname, './dist'),filename: 'server.bundle.js',libraryTarget: 'commonjs2'},externals: Object.keys(require('./package.json').dependencies),plugins: [new webpack.DefinePlugin({'process.env': 'production'}),new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}})]})module.exports = webpackConfig

这里除了两件事之外没有什么奇怪的地方:条目是entry-server.js输出,我们commonjs用作图书馆的目标。

这就是Webpack的配置。现在让我们看看在package.json中构建应用程序的脚本。

package.json构建脚本

您可以根据自己的需要进行更改,但是需要执行以下三个步骤来启动应用程序:

  1. 您需要构建客户端条目
  2. 你需要建立服务器入口
  3. 你需要启动服务器
"scripts": {"start": "npm run build && npm run start-server","build": "npm run build-client && npm run build-server","build-client": "cross-env NODE_ENV=production webpack --progress --hide-modules","build-server": "cross-env NODE_ENV=production webpack --config webpack.server.config.js --progress --hide-modules","start-server": "node server.js"}

在配置中,我们正在使用start将要运行刚刚提到的三个步骤的脚本。但是,如果需要,我们还设置了脚本来分别运行它们。

文件夹结构

  • dist文件夹在构建时由webpack创建。
  • node_modules文件夹…你知道这是什么。
  • src包含我们的Vue应用程序。在里面,您将找到服务器和客户端入口点,Vue main.js文件,App组件,其他组件的文件夹(我们有家和关于组件),包含路由器配置的路由器文件夹,最后是资产夹。
  • .babelrc,.gitignore,packages.json …你可能知道它们是什么。
  • index.html是我们的应用程序的主要HTML。
  • server.js是服务器配置和启动文件。
  • 最后,这两个webpack配置文件。

索引HTML

这是我们的主要HTML文件。

<!doctype html><html lang="en"><head><!-- use triple mustache for non-HTML-escaped interpolation -->{{{ meta }}}<!-- use double mustache for HTML-escaped interpolation --><title>{{ title }}</title></head><body><!--vue-ssr-outlet--><script src="dist/build.js"></script></body></html>

有几件事要讨论:

  • 我已经添加了一些插值到模板来从服务器填充数据。这是Vue SSR的一个特性,我将在稍后展示。
  • 我们加载build.js这是从Webpack生成的客户端包。

App.vue组件

这个组件是我们的应用程序的根本组成部分,它有几个职责:

  1. 具有Vue路由器链接的菜单的配置。
  2. 设置要呈现的路由组件的容器。
  3. app使用将要用于装载应用程序的客户端部分的id设置元素。
<template><div id="app">Hello World!<p><router-link to="/">Go To Home</router-link><router-link to="/about">Go To About</router-link></p><router-view></router-view></div></template><script>export default {};</script>

路由器文件配置

由于我们的应用程序将在服务器上启动,因此我们需要为每个服务器请求提供一个新的路由器实例。在路由器文件夹里面,我们要用我们的路由器配置文件。

// router.jsimport Vue from 'vue';import Router from 'vue-router';import Home from '../components/Home.vue';import About from '../components/About.vue';Vue.use(Router);export function createRouter () {return new Router({mode: 'history',routes: [{ path: '/', component: Home },{ path: '/about', component: About }]});}

我们来看一下代码:

  • 我们导入所有我们需要的依赖关系。
  • 我们告诉Vue使用Vue路由器。
  • 我们导出一个提供路由器配置的新实例的函数。
  • 我们在历史模式下实例化路由器,并声明我们要处理的两条路由。

主要Vue文件配置

出于同样的原因,我们需要提供一个新的路由器实例,我们需要提供一个新的应用实例。该文件负责启动路由器和根应用程序组件。服务器入口点和客户端入口点都将使用此文件。

// main.jsimport Vue from 'vue'import App from './App.vue'import { createRouter } from './router/router.js'// export a factory function for creating fresh app, router and store// instancesexport function createApp() {// create router instanceconst router = createRouter();const app = new Vue({router,// the root instance simply renders the App component.render: h => h(App)});return { app, router };}

我们来看一下代码:

  • 我们导入所有需要的依赖关系。
  • 我们导出一个提供应用程序和路由器的新实例的函数。
  • 我们使用之前在router.js文件中看到的方法实例化路由器。
  • 我们用路由器和一个渲染函数创建一个新的应用程序实例,传递根应用程序组件。
  • 我们返回这两个实例。

客户端入口点

这段代码非常简单。这是Webpack客户端构建配置的入口文件。

//client-entry.jsimport { createApp } from './main.js';const { app } = createApp()// this assumes App.vue template root element has `id="app"`app.$mount('#app')

我们来看一下代码:

  • 我们导入所有需要的依赖关系。
  • 我们从main.js文件创建应用程序,并保持app实例。
  • 我们app在id设置为app的节点中进行装载。在本例中,包含该id的节点是App.vue组件模板的根元素。

服务器入口点

这个文件是webpack服务器构建的入口点。构建的结果是我们稍后在配置服务器时要实现的目标。

//server-entry.jsimport { createApp } from './main.js';export default context => {// since there could potentially be asynchronous route hooks or components,// we will be returning a Promise so that the server can wait until// everything is ready before rendering.return new Promise((resolve, reject) => {const { app, router } = createApp();// set server-side router's locationrouter.push(context.url);// wait until router has resolved possible async components and hooksrouter.onReady(() => {const matchedComponents = router.getMatchedComponents();// no matched routes, reject with 404if (!matchedComponents.length) {return reject({ code: 404 });}// the Promise should resolve to the app instance so it can be renderedresolve(app);}, reject);});}

我们来看一下代码:

  • 我们导入所有需要的依赖关系。
  • 我们导出一个接收上下文为param的函数。
  • 函数返回一个承诺。
  • 我们从main.js创建应用程序功能实例化应用程序和路由器。
  • 我们从上下文获取当前URL(这将由服务器提供),以便将正确的URL推送到路由器。
  • 一旦路由器准备就绪,我们检查路由是否与上下文URL匹配。如果是这样,我们解决承诺,并返回应用程序实例。否则,我们拒绝承诺。

配置和启动服务器

我们几乎准备好了一切。唯一缺少的是express服务器的配置和启动。

//server.jsconst express = require('express');const server = express();const fs = require('fs');const path = require('path');//obtain bundleconst bundle =require('./dist/server.bundle.js');//get renderer from vue server rendererconst renderer = require('vue-server-renderer').createRenderer({//set templatetemplate: fs.readFileSync('./index.html', 'utf-8')});server.use('/dist', express.static(path.join(__dirname, './dist')));//start serverserver.get('*', (req, res) => { bundle.default({ url: req.url }).then((app) => {//context to use as data source//in the template for interpolationconst context = {title: 'Vue JS - Server Render',meta: `<meta description="vuejs server side render">`};renderer.renderToString(app, context, function (err, html) { if (err) {if (err.code === 404) {res.status(404).end('Page not found')} else {res.status(500).end('Internal Server Error')}} else {res.end(html)}});}, (err) => {console.log(err);});});server.listen(8080);

哇!而你以为这是太多了。让我们深入代码,看看发生了什么。

  • 我们正在导入express来创建服务器。我们也在导入一些NodeJS功能。
  • 我们导入作为Webpack服务器构建结果的服务器包。
  • 我们导入vue-server-renderer库并创建渲染器,提供index.html模板的位置。
  • 我们配置express路径。
  • 我们启动服务器。
  • 这个bundle是serve-entry.js使用Webpack 构建的结果,所以我们可以使用接收上下文的默认函数作为URL的参数。由于这是一个承诺,我们设置了成功和错误回调。

成功回调做了一堆东西,所以让我们来看看:

  • 我们用要插入的数据创建一个常量index.html(我们在之前看到了index.html中的插值)。
  • 我们把渲染器的字符串函数作为接收应用程序的渲染器的字符串函数(由已解析的promise返回),我们刚刚创建的上下文(用于索引中的插值…这是可选的)以及回调函数(如果一切正常的话)好。
  • 呈现字符串回调函数检查是否有任何错误,如果不是,它只是发送生成的HTML作为响应。

最后,我们开始听8080端口。

现在,如果你运行这个脚本start并localhost:8080在浏览器中打开,你将会看到一个和vue-router一起工作的SSR。

就是这样,女士们,先生们!

结论

我不认为我需要说的是使事情有效的配置很多,但一旦完成,您不会触及很多事情。只要确定SSR是你所需要的。

未经允许不得转载:爱前端网 » Vue.js服务器端渲染与Vue路由器:分步指南

Vue.js服务器端渲染与Vue路由器:分步指南相关推荐

  1. Vue.js 服务器端渲染指南

    默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM.然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器. 简单理解是将组件或页面通过服务器生 ...

  2. Vue.js学习系列七——Vue服务器渲染Nuxt学习

    我又回来啦~这次我们来学习Vue的服务器渲染SSR. 关于SSR的文章网上很多,一开始看得我云里雾里.然后去Vue.js 服务器渲染指南和nuxt官网看了看,发现文章大多都是搬运官网的内容,真正讲的清 ...

  3. vue使用html渲染组件,Vue.js在渲染组件之前填充数据

    我是Vue.js的新手,我试图创建一个没有成功的简单组件,它包含一个selectList,我试图填充它的选项数据来模拟Ajax请求,这是我的代码:Vue.js在渲染组件之前填充数据 HTML {{n. ...

  4. 遇见 vue.js --------阿文的vue.js学习笔记(8 —1)------- 列表渲染

    ** 新学习新征程,我们一起踏上学习 vue.js的新长征 遇见 vue.js --------阿文的vue.js学习笔记(1)-----初识vue.js 遇见 vue.js --------阿文的v ...

  5. Vue.js 第1章 Vue常用指令学习

    今日目标 能够写出第一个vue应用程序 能够接受为什么需要学vue 能够使用指令 能够通过指定完成简单的业务(增加删除查询) 能够理解mvvm 为什么要学习vue 企业需要 可以提高开发效率 实现vu ...

  6. 遇见 vue.js --------阿文的vue.js学习笔记(4)------模板语法

    ** 新学习新征程,我们一起踏上学习 vue.js的新长征 遇见 vue.js --------阿文的vue.js学习笔记(1)-----初识vue.js 遇见 vue.js --------阿文的v ...

  7. 【Vue】服务器端渲染

    一.什么是服务器端渲染? server side render 前端页面的产生是由服务器端生成的,我们就称之为服务端渲染 1.1 新建server文件夹 server 1.2 生成一个node项目 n ...

  8. Vue.js 列表渲染

    用 v-for 把一个数组对应为一组元素 我们用 v-for 指令根据一组数组的选项列表进行渲染.v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 i ...

  9. Vue.js 条件渲染 v-if、v-show、v-else

    v-if v-if 完全根据表达式的值在DOM中生成或移除一个元素.如果v-if表达式赋值为false,那么对应的元素就会从DOM中移除:否则,对应元素的一个克隆将被重新插入DOM中. <!DO ...

最新文章

  1. 将基于 .NET Framework 的 WPF 项目迁移到基于 .NET Core 3
  2. Codeforces Round #700 (Div. 1Div. 2)
  3. spring对事务的控制 AOP
  4. steam有没有c语言软件,【图片】在steam吧你甚至可以讨论c语言_steam吧_百度贴吧...
  5. 重读GhostNet:使用轻量操作代替部分传统卷积层生成冗余特征以减少计算量
  6. RxHttp 一条链发送请求之注解处理器 Generated API(四)
  7. 数据结构c语言版题库含答案,求数据结构c语言版的习题和答案?
  8. 【Python笔记】字符串常见操作
  9. 不借助第三个变量进行两个变量的换位输出
  10. AForge处理视频和拍照(暂时没有音频)
  11. xml python et_python xml处理
  12. Hadoop集群安装配置教程_Hadoop2.6.0_UbuntuCentOS(林子雨教授,超级详细)
  13. DCDC和LDO的区别
  14. 电商场景化营销主要从哪几方面展开行无疆带你了解
  15. Android自定义IM聊天界面
  16. 白鹭[egret]项目目录介绍)
  17. 计算点到直线/线段的距离
  18. G-Transformer for Document-level Machine Translation
  19. python中的None与False
  20. 工业级参数8.4V-24V电压降压到5V或3.3V降压芯片

热门文章

  1. 国外程序员推荐的免费编程书籍资源
  2. 我对OpenGL教程的学习(入门篇)
  3. 数据库授予用户增删改查的权限的语句_MySQL授予权限(Grant语句)
  4. 致给迷茫与失落时的的自己
  5. 专业名词解释 - DNS,A记录,子域名,CNAME别名,PTR,MX,TXT,SRV 记录,TTL
  6. 苏嵌学习日志06 07.14
  7. 【Android】之【延时执行的几种方法】
  8. 附录3:RMA算法原理
  9. 你手上有50万,你会干什么?
  10. 【独行秀才】macOS Big Sur 11.5 正式版(20G71)原版镜像