Vue.js与 ASP.NET Core 服务端渲染功能整合


Posted in Javascript onNovember 16, 2017

http://mgyongyosi.com/2016/Vuejs-server-side-rendering-with-aspnet-core/
原作者:Mihály Gyöngyösi
译者:oopsguy.com

我真的很喜欢在前端使用 Vue.js,Vue 服务端渲染直到第二个版本才被支持。 在本例中,我想展示如何将 Vue.js  服务端渲染功能整合 ASP.NET Core。 我们在服务端使用了 Microsoft.AspNetCore.SpaServices 包,该包提供 ASP.NET Core API,以便于我们可以使用上下文信息调用 Node.js 托管的 JavaScript 代码,并将生成的 HTML 字符串注入渲染页面。

在此示例中,应用程序将展示一个消息列表,服务端只渲染最后两条消息(按日期排序)。可以通过点击“获取消息”按钮从服务端下载剩余的消息。

项目结构如下所示:

.
├── VuejsSSRSample
| ├── Properties
| ├── References
| ├── wwwroot
| └── Dependencies
├── Controllers
| └── HomeController.cs
├── Models
| ├── ClientState.cs
| ├── FakeMessageStore.cs
| └── Message.cs
├── Views
| ├── Home
| | └── Index.cshtml
| └── _ViewImports.cshtml
├── VueApp
| ├── components
| | ├── App.vue
| | └── Message.vue
| ├── vuex
| | ├── actions.js
| | └── store.js
| ├── app.js
| ├── client.js
| ├── renderOnServer.js
| └── server.js
├── .babelrc
├── appsettings.json
├── Dockerfile
├── packages.json
├── Program.cs
├── project.json
├── Startup.cs
├── web.config
├── webpack.client.config.js
└── webpack.server.config.js

正如你看到的,Vue 应用位于 VueApp 文件夹下,它有两个组件、一个包含了一个 mutation 和一个 action 的简单 Vuex store 和一些我们接下来要讨论的其他文件:app.js、client.js、 renderOnServer.js、server.js。

实现 Vue.js 服务端渲染

Vue.js与 ASP.NET Core 服务端渲染功能整合

要使用服务端渲染,我们必须从 Vue 应用创建两个不同的 bundle:一个用于服务端(由 Node.js 运行),另一个用于将在浏览器中运行并在客户端上混合应用。

app.js

引导此模块中的 Vue 实例。它由两个 bundle 共同使用。

import Vue from 'vue';
import App from './components/App.vue';
import store from './vuex/store.js';
const app = new Vue({
 store,
 ...App
});
export { app, store };

server.js

此服务端 bundle 的入口点导出一个函数,该函数有一个 context 属性,可用于从渲染调用中推送任何数据。

client.js

客户端 bundle 的入口点,其用一个名为 INITIAL_STATE 的全局 Javascript 对象(该对象将由预渲染模块创建)替换 store 的当前状态,并将应用挂载到指定的元素(.my-app)。

import { app, store } from './app';
store.replaceState(__INITIAL_STATE__);
app.$mount('.my-app');

Webpack 配置

为了创建 bundle,我们必须添加两个 Webpack 配置文件(一个用于服务端,一个用于客户端构建),不要忘了安装 Webpack,如果尚未安装,则:npm install -g webpack。

webpack.server.config.js
const path = require('path');
module.exports = {
 target: 'node',
 entry: path.join(__dirname, 'VueApp/server.js'),
 output: {
 libraryTarget: 'commonjs2',
 path: path.join(__dirname, 'wwwroot/dist'),
 filename: 'bundle.server.js',
 },
 module: {
 loaders: [
  {
  test: /\.vue$/,
  loader: 'vue',
  },
  {
  test: /\.js$/,
  loader: 'babel',
  include: __dirname,
  exclude: /node_modules/
  },
  {
  test: /\.json?$/,
  loader: 'json'
  }
 ]
 },
};
webpack.client.config.js
const path = require('path');
module.exports = {
 entry: path.join(__dirname, 'VueApp/client.js'),
 output: {
 path: path.join(__dirname, 'wwwroot/dist'),
 filename: 'bundle.client.js',
 },
 module: {
 loaders: [
  {
  test: /\.vue$/,
  loader: 'vue',
  },
  {
  test: /\.js$/,
  loader: 'babel',
  include: __dirname,
  exclude: /node_modules/
  },
 ]
 },
};

运行 webpack --config webpack.server.config.js, 如果运行成功,则可以在 /wwwroot/dist/bundle.server.js 找到服端 bundle。获取客户端 bundle 请运行 webpack --config webpack.client.config.js,相关输出可以在 /wwwroot/dist/bundle.client.js 中找到。

实现 Bundle Render

该模块将由 ASP.NET Core 执行,其负责:

渲染我们之前创建的服务端 bundle

将 **window.__ INITIAL_STATE__** 设置为从服务端发送的对象

process.env.VUE_ENV = 'server';
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, '../wwwroot/dist/bundle.server.js')
const code = fs.readFileSync(filePath, 'utf8');
const bundleRenderer = require('vue-server-renderer').createBundleRenderer(code)
module.exports = function (params) {
 return new Promise(function (resolve, reject) {
 bundleRenderer.renderToString(params.data, (err, resultHtml) => { // params.data is the store's initial state. Sent by the asp-prerender-data attribute
  if (err) {
  reject(err.message);
  }
  resolve({
  html: resultHtml,
  globals: {
   __INITIAL_STATE__: params.data // window.__INITIAL_STATE__ will be the initial state of the Vuex store
  }
  });
 });
 });
};

实现 ASP.NET Core 部分

如之前所述,我们使用了 Microsoft.AspNetCore.SpaServices 包,它提供了一些 TagHelper,可轻松调用 Node.js 托管的 Javascript(在后台,SpaServices 使用 Microsoft.AspNetCore.NodeServices 包来执行 Javascript)。

Views/_ViewImports.cshtml

为了使用 SpaServices 的 TagHelper,我们需要将它们添加到 _ViewImports 中。

@addTagHelper "*, Microsoft.AspNetCore.SpaServices"
Home/Index
public IActionResult Index()
{
 var initialMessages = FakeMessageStore.FakeMessages.OrderByDescending(m => m.Date).Take(2);
 var initialValues = new ClientState() {
 Messages = initialMessages,
 LastFetchedMessageDate = initialMessages.Last().Date
 };
 return View(initialValues);
}

它从 MessageStore(仅用于演示目的的一些静态数据)中获取两条最新的消息(按日期倒序排序),并创建一个 ClientState 对象,该对象将被用作 Vuex store 的初始状态。

Vuex store 默认状态:

const store = new Vuex.Store({
 state: { messages: [], lastFetchedMessageDate: -1 },
 // ...
});

ClientState 类:

public class ClientState
{
 [JsonProperty(PropertyName = "messages")]
 public IEnumerable<Message> Messages { get; set; }

 [JsonProperty(PropertyName = "lastFetchedMessageDate")]
 public DateTime LastFetchedMessageDate { get; set; }
}

Index View

最后,我们有了初始状态(来自服务端)和 Vue 应用,所以只需一个步骤:使用 asp-prerender-module 和 asp-prerender-data TagHelper 在视图中渲染 Vue 应用的初始值。

@model VuejsSSRSample.Models.ClientState
<!-- ... -->
<body>
 <div class="my-app" asp-prerender-module="VueApp/renderOnServer" asp-prerender-data="Model"></div>
 <script src="~/dist/bundle.client.js" asp-append-version="true"></script>
</body>
<!-- ... -->

asp-prerender-module 属性用于指定要渲染的模块(在我们的例子中为 VueApp/renderOnServer)。我们可以使用 asp-prerender-data 属性指定一个将被序列化并发送到模块的默认函数作为参数的对象。

您可以从以下地址下载原文的示例代码:

http://github.com/mgyongyosi/VuejsSSRSample

总结

以上所述是小编给大家介绍的Vue.js与 ASP.NET Core 服务端渲染功能整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript prototype,executing,context,closure
Dec 24 Javascript
JavaScript 学习笔记(十一)
Jan 19 Javascript
关于JavaScript中var声明变量作用域的推断
Dec 16 Javascript
js实现的仿新浪微博完美的时间组件升级版
Dec 20 Javascript
js获取页面传来参数的方法
Sep 06 Javascript
js实现的简单radio背景颜色选择器代码
Aug 18 Javascript
php 修改密码实现代码
May 24 Javascript
JavaScript设计模式之装饰者模式定义与应用示例
Jul 25 Javascript
jQuery Migrate 插件用法实例详解
May 22 jQuery
angular异步验证防抖踩坑实录
Dec 01 Javascript
详解ES6数组方法find()、findIndex()的总结
May 12 Javascript
如何配置vue.config.js 处理static文件夹下的静态文件
Jun 19 Javascript
使用3D引擎threeJS实现星空粒子移动效果
Sep 13 #Javascript
vue.js项目打包上线的图文教程
Nov 16 #Javascript
Three.js基础学习教程
Nov 16 #Javascript
three.js实现3D视野缩放效果
Nov 16 #Javascript
three.js中3D视野的缩放实现代码
Nov 16 #Javascript
js的函数的按值传递参数(实例讲解)
Nov 16 #Javascript
React/Redux应用使用Async/Await的方法
Nov 16 #Javascript
You might like
收音机的保养
2021/03/01 无线电
文件系统基本操作类
2006/11/23 PHP
php下用cookie统计用户访问网页次数的代码
2010/05/09 PHP
php控制linux服务器常用功能 关机 重启 开新站点等
2012/09/05 PHP
使用php将某个目录下面的所有文件罗列出来的方法详解
2013/06/21 PHP
浅谈php正则表达式中的非贪婪模式匹配的使用
2014/11/25 PHP
PHP中in_array函数使用的问题与解决办法
2016/09/11 PHP
laravel5.5安装jwt-auth 生成token令牌的示例
2019/10/24 PHP
JavaScript进阶教程(第四课第一部分)
2007/04/05 Javascript
javascript 一个函数对同一元素的多个事件响应
2009/07/25 Javascript
Javascript读取cookie函数代码
2010/10/16 Javascript
基于jQuery实现的当离开页面时出现提示的实现代码
2011/06/27 Javascript
纯JavaScript实现HTML5 Canvas六种特效滤镜示例
2013/06/28 Javascript
将查询条件的input、select清空
2014/01/14 Javascript
自动完成的搜索框javascript实现
2016/02/26 Javascript
全面解析Javascript无限添加QQ好友原理
2016/06/15 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
js简单时间比较的方法
2016/08/02 Javascript
JS多文件上传的实例代码
2017/01/11 Javascript
详解微信小程序开发之城市选择器 城市切换
2017/01/17 Javascript
Swiper实现轮播图效果
2017/07/03 Javascript
vue实现商城上货组件简易版
2017/11/27 Javascript
vue 实现在函数中触发路由跳转的示例
2018/09/01 Javascript
如何使用vuex实现兄弟组件通信
2018/11/02 Javascript
JavaScript原型对象原理与应用分析
2018/12/27 Javascript
jQuery实现简单日历效果
2020/07/05 jQuery
Python动态加载模块的3种方法
2014/11/22 Python
Python 3.x读写csv文件中数字的方法示例
2017/08/29 Python
Python数据分析之双色球中蓝红球分析统计示例
2018/02/03 Python
python文件转为exe文件的方法及用法详解
2019/07/08 Python
torch 中各种图像格式转换的实现方法
2019/12/26 Python
Django实现将views.py中的数据传递到前端html页面,并展示
2020/03/16 Python
婚鞋、新娘鞋、礼服鞋、童鞋:Nina Shoes
2019/09/04 全球购物
银行开业庆典方案
2014/02/06 职场文书
禁烟标语大全
2014/06/11 职场文书
党的群众路线对照检查材料范文
2014/09/24 职场文书