业务需求
最近公司要求开发web版的app,由于app是偏向内容方面,而且带了一个聊天模块,所以一般的多页开发不是很适合,而且主要是手机浏览,对加载速度或者用户体验来说都比较苛刻。调研了很多框架和模式,最后自己东拼西凑搞出来了这么一个玩意。
服务端
毫无疑问使用node,使用typescript可以有效的在编码同时查错,强类型语言写服务端毫无压力。
#app.ts 只贴重要代码 var webpack = require(\'webpack\') var webpackDevMiddleware = require(\'webpack-dev-middleware\') var WebpackConfig = require(\'./webpack.config\') import * as index from \"./routes/index\"; import * as foo from \"./routes/foo\"; import * as bar from \"./routes/bar\"; var app = express(); //启动服务的时候 打包并监听客户端用到的文件,webpackDevMiddleware是开发模式,他会打包js在内存里面,你改了文件,它也会重新打包 app.use(webpackDevMiddleware(webpack(WebpackConfig), { publicPath: \'/__build__/\', stats: { colors: true } })); //一般的配置项 app.set(\'views\', __dirname + \'/views\'); app.set(\'view engine\', \'ejs\'); app.set(\'view options\', { layout: false }); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(methodOverride()); app.use(express.static(__dirname + \'/public\')); var env = process.env.NODE_ENV || \'development\'; if (env === \'development\') { app.use(errorHandler()); } //路由配置 app.get(\'/\', index.index); app.get(\'/foo\', foo.index); app.get(\'/bar\', bar.index); app.listen(3000, function(){ console.log(\"Demo Express server listening on port %d in %s mode\", 3000, app.settings.env); }); export var App = app;
服务端渲染页面
#index.ts import express = require(\"express\") import vueServer = require(\"vue-server\") //服务端渲染vue的插件 var Vue = new vueServer.renderer(); //创建一个服务端的vue export function index(req: express.Request, res: express.Response) { //创建一个组件 var vm = new Vue({ template: ` <p>This is index!</p> ` }); //等待html渲染完成,再返回给浏览器 vueServer.htmlReady是vue-server的自带事件 vm.$on(\'vueServer.htmlReady\', function(html:string) { //这里用的是ejs模板 可以把需要用到的数据设置成window下的全局变量,方便客户端的js访问。 res.render(\'layout\',{server_html:html,server_data:\'window.cm_data = {name:\"张三\"}\'}) }); };
#layout.ejs 访问这个SPA的所有url返回的都是这个页面 <meta>标签都可以动态设置,只要传参数进来就可以 <!DOCTYPE html> <html lang=\"en\"> <head> <meta charset=\"utf-8\"> <title>Vue Router Example</title> <style> .v-link-active { color: red; } </style> <script> //定义一些前端需要用到的全局属性,文章ID或用户信息什么的 //index.ts中传过来的是 window.cm_data = {name:\"张三\"} //前端就能访问到了 <%-server_data%> </script> </head> <body> //这里的id是前端需要用到的一个标识 <div id=\"app\"> <h1>Hello App!</h1> <p> <a v-link=\"{ path: \'/foo\' }\">Go to Foo</a> <a v-link=\"{ path: \'/bar\' }\">Go to Bar</a> </p> //router-view是客户端vue-router需要解析的dom //server_html是根据访问url地址生成的html,是做SEO的重点,不加载下面的app.js也可以看到内容 <router-view> <%-server_html%> </router-view> </div> //webpack打包好的js,主要是路由配置 <script src=\"/__build__/app.js\"></script> </body> </html>
客户端
#app.js 这个是/__build__/app.js,可以用es6编写,webpack会转换的 import Vue from \'./vue.min\' //客户端的vue.js import VueRouter from \'./vue-router.min\' //vue的路由插件,配合webpack可以很简单实现懒加载 //懒加载路由 只有访问这个路由才会加载js import Foo from \'bundle?lazy!../../components/foo\' //配合webpack的bundle-loader,轻松实现懒加载 import Bar from \'bundle?lazy!../../components/bar\' import Index from \'bundle?lazy!../../components/index\' var App = Vue.extend({}) Vue.use(VueRouter) var router = new VueRouter({ //这里要好好说一下,一定要设置html5模式,不然前后端URL不统一会发生问题 //比如访问 http://localhost:3000/ 服务端定义是访问index.ts这个路由文件 //如果不是html5模式的话,经过客户端js运行之后会变成http://localhost:3000/#!/ //在比如直接浏览器输入 http://localhost:3000/foo 服务端定义是访问.ts这个路由文件 //如果不是html5模式的话,经过客户端js运行之后会变成 http://localhost:3000/foo/#!/ //设置了html5模式后,加载完js后不会加上#!这2个类似锚点的字符,实现前后端路由统一如果用户刷新浏览器的话,服务端也能渲染出相应的页面。 history: true, //html5模式 去掉锚点 saveScrollPosition: true //记住页面的滚动位置 html5模式适用 }) //定义路由,要和服务端路由路径定义的一样 router.map({ \'/\' : { component: Index //前端路由定义, }, \'/foo\': { component: Foo }, \'/bar\': { component: Bar } }) //启动APP router.start(App, \'#app\')
需要完善的地方
前后端统一模板,已经找到方法了把html分离出来,node端用fs.readFileSync方法获取,客户端用webpack的raw-loader获取html内容
不放源码都是瞎扯。
源码地址
https://github.com/yjj5855/node-vue-server-webpack
本文地址:https://www.stayed.cn/item/2023
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我