使用node+vue.js實現SPA應用,解決了SPA應用的最大缺點SEO

oytw5533 8年前發布 | 46K 次閱讀 HTML JavaScript開發 webpack

來自: http://segmentfault.com/a/1190000004372736

業務需求

最近公司要求開發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;</pre>

服務端渲染頁面

#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:"張三"}'})
});

};</pre>

#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></pre>

客戶端

#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')</pre>

需要完善的地方

  1. 前后端統一模板,已經找到方法了把html分離出來,node端用fs.readFileSync方法獲取,客戶端用webpack的raw-loader獲取html內容

不放源碼都是瞎扯。

源碼地址

https://github.com/yjj5855/node-vue-server-webpack

</div>

 本文由用戶 oytw5533 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!