做者:Maxime Laboissonnierecss
原文地址: Vue.js Tutorial: An Example to Build and Prerender an SEO-Friendly Sitehtml
譯者:jeneser前端
「我受不了了!咱們的內部報告面板太爛了」jquery
產品經理很生氣。他從這個即將崩潰的應用程序中拉取數據的操做是災難性的。webpack
「Max,咱們須要更好的報告。你能修嗎?」laravel
「老實說,我更願意創建一個全新的應用」,我笑着回答說。git
「好,請便。全權委託,老鐵」github
我笑着,搓了搓手。最後,在一個須要使用JS框架的場景中,你們一致選擇了Vue.js
。web
最近,我完成該應用的代碼,我對它簡直愛不釋手。
我花了一些時間爲社區寫了一個vue.js教程,這些教程的靈感所有來自於我最近對vue的實踐。在這裏,我主要討論如下兩點:
如何使用Vue.js構建精簡的Web應用程序
如何使用prerender-spa-plugin
來處理Vue.js應用的預渲染與SEO
更具體地說,我將帶您建立一個小商店,它將具有SEO友好的產品頁面。我會提供在線演示以及相關代碼。
在咱們開發的最新版Headless CMS中我接觸過一些vue,這一次咱們會更加的深刻,我很興奮!
更新:咱們正在將Snipcart的前端從Backbone遷移到Vue.js,瞭解更多
咱們先來爲那些不熟悉漸進式框架(Vue.js)的同窗作一下簡單的介紹。
Vue.js是一套幫助你構建用戶界面的輕量級,漸進式的JavaScript框架
不要被「JS框架」這必定義所愚弄。Vue與目前流行的React.js & Angular.js是大相徑庭的。對於初學者來講,它不是Google&Facebook等商業技術巨頭的開源副產品。
Evan You(尤雨溪)在2014年首次發佈了它,旨在建立一個「增量開發」的現代JS庫。Vue最強大的功能之一是:建立可複用的組件,你能夠在其餘項目中重用這些組件而不用再次編寫。全部開發人員均可以在項目中嘗試Vue,而不用擔憂這會對現有的代碼庫產生危害或是增長額外的負擔。
拋開模式和術語,我以爲Vue有如下提論:
1. 一開始你不知道整個應用的架構狀態
2. 應用數據必定會在運行時發生改變
正是圍繞這些提論,vue塑造了自身:它是漸進式,基於組件和響應式的。組件的粒度劃分可讓你輕鬆地分離應用邏輯,同時又保持它們的可重用性。更重要的是,它將您的數據原生綁定到視圖,以便在須要時「神奇」地更新(經過watcher)。雖然許多響應式前端框架擁有一樣的功能,可是我發現Vue更優雅的實現了它,而且,對於個人大多數用例,它每每表現的更好。
Vue還具備更加平滑的學習曲線,對於React來講,咱們須要掌握JSX模板等的相關知識。甚至能夠說Vue是React減去了比較複雜的部分。
Vue官方文檔提供了與其餘JS框架(React, Angular, Ember, Knockout, Polymer, Riot)更加深刻的對比。查看官方文檔
最後但一樣重要的是:得益於高性能&強大的開發工具,Vue爲咱們提供了最佳的編碼體驗。它能如此流行也就不足爲奇了!
從開源項目Laravel&PageKit,到企業,如Gitlab&Codeship(更不用說阿里巴巴和百度這些巨頭了),許多組織正在使用Vue。
OK,如今是時候來看看咱們將如何使用它了。
在本節中,我會告訴你如何使用Vue 2.0 & Snipcart
創建一個小型的電子商務應用程序。咱們還將看到如何確保產品頁面被搜索引擎正確「抓取」。
瞭解一些Vue.js相關知識,還不瞭解?
基本瞭解vuex & vue-router
一個Snipcart賬戶(測試模式永久免費)
若是你想深刻了解 Vue 2.0 相關知識,能夠查看Laracasts上的這個系列。
首先,咱們將使用vue-cli來構建基本的Vue應用程序。在你喜歡的終端裏,輸入:
npm install -g vue-cli vue init webpack-simple vue-snipcart
這將建立一個新的vue-snipcart文件夾,其中包含使用vue-loader的基本配置,它將能使咱們編寫單文件組件(template/js/css在同一個.vue
文件中)。
咱們但願這個示例儘量真實,所以,咱們將在本應用中增長兩個普遍應用於大型項目的模塊:vuex
和vue-router
。
vuex是類Flux架構的狀態管理器 - 輕量級,很是強大。它受到了Redux的影響,你能夠在這裏瞭解更多。
vue-router容許您定義路由以動態處理應用程序的組件。
要安裝這些,請先進入vue-snipcart
項目文件夾,而後運行如下命令:
npm install --save vue-router npm intsall --save vuex
接下來要安裝的是prerender-spa-plugin
,這將使咱們可以預渲染「蜘蛛」將要爬行的路徑:
npm install --save prerender-spa-plugin
快要完成了,最後四個包:
pug - 模板引擎,相對於HTML我更喜歡它。
vuex-router-sync-to - 輕鬆保持vue-router和vuex存儲同步。
copy-webpack-plugin-to - 輕鬆包含咱們在dist文件夾中的靜態文件。
babel-polyfill - 在PhantomJS中運行Vue(經過咱們的預渲染插件使用)。
運行這些:
npm install --save pug npm install --save vuex-router-sync npm install --save copy-webpack-plugin npm install --save babel-polyfill
安裝完成後請檢查是否安裝正確。以後,即可以處理咱們的商店數據了。
先從vuex
的store
開始,咱們將使用它來存儲/訪問咱們的產品信息。
在本演示中,咱們將使用靜態數據,若是咱們要取而代之,它仍然能夠工做。
注:關於Snipcart,咱們使用基本的JS代碼段注入購物車,並使用簡單的HTML屬性定義產品。
在src
中建立一個store
文件夾,包含如下3個文件:
state.js - 定義咱們的靜態產品數據
getters.js - 定義get
函數,經過ID檢索產品
index.js - 組合前兩個文件
//state.js export const state = { products: [ { id: 1, name: 'The Square Pair', price: 100.00, description: 'Bold & solid.', image: 'https://snipcart.com/media/10171/glasses1.jpeg' }, { id: 2, name: 'The Hip Pair', price: 110.00, description: 'Stylish & fancy.', image: 'https://snipcart.com/media/10172/glasses2.jpeg' }, { id: 3, name: 'The Science Pair', price: 30, description: 'Discreet & lightweight.', image: 'https://snipcart.com/media/10173/glasses3.jpeg' } ] } //getters.js export const getters = { getProductById: (state, getters) => (id) => { return state.products.find(product => product.id == id) } } //index.js import Vue from 'vue' import Vuex from 'vuex' import { state } from './state.js' import { getters } from './getters.js' Vue.use(Vuex) export default new Vuex.Store({ state, getters })
咱們將保持商店儘量簡單:展現產品列表的首頁以及每一個產品的詳細信息頁面。咱們須要在路由器中註冊兩條路由來處理這些路由:
import VueRouter from 'vue-router' import Vue from 'vue' import ProductDetails from './../components/productdetails.vue' import Home from './../components/home.vue' Vue.use(VueRouter) export default new VueRouter({ mode: 'history', routes: [ { path: '/products/:id', component: ProductDetails }, { path: '/', component: Home }, ] })
咱們尚未建立這些組件,不用擔憂,立刻就來,;)
請注意,咱們在VueRouter
聲明中使用了mode:'history'
。這一點很重要,不然咱們的prerender
插件將不會工做。其區別在於路由器將使用history API
而不是hashbang
來導航。
如今,咱們有了數據(store)和路由器,咱們須要把他們註冊到應用中。更新你的src/main.js
文件:
import Vue from 'vue' import App from './App.vue' import router from './router' import { sync } from 'vuex-router-sync' import store from './store' sync(store, router) new Vue({ store, router, render: h => h(App) }).$mount('#app')
很簡單吧!正如前面提到的,vuex-router-sync
中的sync
方法從咱們的store
中注入狀態到當前的路由中。咱們稍後再用。
有數據感受真棒,但將它顯示出來將會更好。咱們即將用到的三個組件:
Home - 展現產品列表
Product - 單個產品信息,將被用在Home
組件中
ProductDetails - 產品詳情頁
他們將被包含在src/components
文件夾中。
//Home.vue <template lang="pug"> div(class="products") div(v-for="product in products", class="product") product(:product="product") </template> <script> import Product from './../components/Product.vue' export default { name: 'home', components: { Product }, computed: { products(){ return this.$store.state.products } } } </script>
以上,咱們使用store
中的狀態來獲取咱們的產品,並對它們進行迭代,來渲染每個產品。
//Product.vue <template lang="pug"> div(class="product") router-link(v-bind:to="url").product img(v-bind:src="product.image" v-bind:alt="product.name" class="thumbnail" height="200") p {{ product.name }} button(class="snipcart-add-item" v-bind:data-item-name="product.name" v-bind:data-item-id="product.id" v-bind:data-item-image="product.image" data-item-url="/" v-bind:data-item-price="product.price") | Buy it for {{ product.price }}$ </template> <script> export default { name: 'Product', props: ['product'], computed: { url(){ return `/products/${this.product.id}` } } } </script>
經過路由器,咱們連接到其餘頁面(ProductDetails
),來看看咱們的最後一個組件:
//ProductDetails.vue <template lang="pug"> div(class="product-details") img(v-bind:src="product.image" v-bind:alt="product.name" class="thumbnail" height="200") div(class="product-description" v-bind:href="url") p {{ product.name }} p {{ product. description}} button(class="snipcart-add-item" v-bind:data-item-name="product.name" v-bind:data-item-id="product.id" v-bind:data-item-image="product.image" data-item-url="/" v-bind:data-item-price="product.price") | Buy it for {{ product.price }}$ </template> <script> export default { name: 'ProductDetails', computed: { id(){ return this.$store.state.route.params.id }, product(){ return this.$store.getters.getProductById(this.id) } } } </script>
這一節的邏輯要稍微複雜些:咱們從路由中獲取當前的ID,而後經過以前建立的getter
獲取相關的產品信息。
咱們開始使用剛纔建立的組件。
打開App.vue
文件,其內容是腳手架(vue init webpack-simple
)生成的默認內容。咱們來修改它:
<template lang="pug"> div(id="app") TopContext router-view </template> <script> import TopContext from './components/TopContext.vue' export default { name: 'app', components: { TopContext } } </script>
TopContext
組件不是很重要,它僅僅是一個header
。關鍵部分是router-view
:它將經過VueRouter
動態加載組件,而以前與之關聯的組件將被替換。
最後咱們來更新一下index.html
。對於咱們的用例來講,咱們在src
中建立新的目錄static
,移動index.html
文件至static
並將其更新爲以下內容:
<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title>vue-snipcart</title> </head> <body> <div id="app"> </div> <script src="/build.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> <script src="https://cdn.snipcart.com/scripts/2.0/snipcart.js" data-api-key="YjdiNWIyOTUtZTIyMy00MWMwLTkwNDUtMzI1M2M2NTgxYjE0" id="snipcart"></script> <link href="https://cdn.snipcart.com/themes/2.0/base/snipcart.min.css" rel="stylesheet" type="text/css" /> </body> </html>
你能夠看到,咱們在index.html
中添加了Snipcart
的必要腳本。若是將他們精細的劃分到各個組件之中代碼看起來會更加乾淨,但,因爲咱們全部的View都須要它們,咱們便這樣作了。
咱們應用中的全部內容都是使用JS動態渲染的,這很不利於搜索引擎優化(SEO):網頁中的異步內容不能被「蜘蛛」(search engine bots)有效的識別並抓取,這樣的話,咱們的電子商務網站錯過了全部有用的「網絡爬蟲」,這不是一個明智的選擇!
讓咱們使用prerendering技術來爲咱們的Vue.js應用程序帶來更多的SEO機會。
相對於Vue的SSR(服務器端渲染),prerendering則更容易使用。坦率地說,前者有些矯枉過正了,除非你有大量的路由要處理。另外,這兩種技術在實現SEO層面所達到的效果是類似的。
預渲染將使咱們可以保持咱們的前端做爲一種快速,輕量級的靜態網站,以便於「蜘蛛」進行爬取。
讓咱們來看看如何使用它:轉到WebPack
配置文件,在plugin
配置項中添加如下配置:
plugins: [ new CopyWebpackPlugin([{ from: 'src/static' }]), new PrerenderSpaPlugin( path.join(__dirname, 'dist'), [ '/', '/products/1', '/products/2', '/products/3'] ) ]
好吧,它是如何工做的呢?
CopyWebpackPlugin
將會複製static
文件夾中的文件到dist
文件夾中(只包含引用Vue App
的應用程序的視圖)。而後,PrerenderSpaPlugin
使用PhantomJS
加載網頁的內容,並將結果做爲咱們的靜態資源。
瞧!咱們如今已經爲咱們的Vue應用程序提供了預渲染的,SEO友好的產品頁面。
咱們使用以下命令來進行測試:
npm run build
這將生成一個dist
文件夾,其中包含生產環境所需的一切。
考慮爲您的頁面添加適當的meta
標記和站點地圖(sitemap)。您能夠在「postProcessHtml」函數(prerender-spa-plugin插件的配置項)中瞭解有關meta
標記的更多信息。
恰當的內容在現代SEO中起了重要做用。建議您確保應用程序中的內容易於建立,編輯和優化。爲了受權內容編輯者,請考慮將headless CMS
放入組合中並用來構建真正的JAMstack。
如今,HTTPS鏈接正式成爲Google的排名因素。咱們在Netlify上託管這個演示,Netlify爲咱們提供了免費的SSL證書。
Mobile-first indexing和 mobile-friendliness也是排名的重要因素。確保您的移動體驗與桌面版同樣快速完整!
來吧,這裏是在線演示及代碼倉庫的地址!
我以前使用過Vue,本教程的製做過程仍是至關順利的。我花了一個小時在Demo上,在使用CopyWebpackPlugin
時遇到了困難,好在我在他們的文檔中找到了答案。
我但願這篇文章能鼓勵開發人員在一些項目中開始使用Vue。就像我說的,您能夠經過開發一個現有項目的一小部分來逐步地開始,我認爲這絕對值得一試。咱們的開發主管正在使用Vue編寫最新的商業儀表盤功能,他很是喜歡Vue。另外,若是配置正確,Vue徹底能夠驅動具備良好SEO結果的應用程序。
若是你受到了啓發,能夠看看Awesome-vue,它包含了Vue示例和相關項目。
若是你真的喜好Vue,cop some swag 或 support the creator
若是你以爲這篇文章有價值,請花一點時間分享到Twitter上。有什麼遺漏或錯誤的?有關於Vue的?或其餘框架處理SEO的一些想法?如今評論區是你的了!
End
原文地址: Vue.js Tutorial: An Example to Build and Prerender an SEO-Friendly Site
譯者:jeneser
譯者GitHub:https://github.com/jeneser
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)
勘誤&討論: New issue