Vue現有項目改造爲Nuxt項目

公司項目,最初只爲了實現先後端分離式開發,直接選擇了vue框架進行開發,然而如今項目基本完成了,發現蜘蛛根本就抓取不到網站數據,搜索引擎搜出來,都是一片空白沒有數據,須要對項目作SEO優化。css

本人第一次接觸SEO的優化,徹底是零基礎,開啓了小白菜的SEO探索之旅,記錄一下一路的過程,方便本身回顧與你們的探討,若有不度之處,還請路過的大神指導一下。html

經常使用SEO優化方式

在查閱了一些資料後,常見的SEO優化有如下兩種:vue

  • prerender-spa-plugin客戶端預渲染
  • ssr服務端渲染

在選擇預渲染模式仍是服務端渲染的模式時,簡單作了個demo進行了一下測試,因爲公司項目以檢索爲主的產品,後期須要蜘蛛抓取的界面太龐大,最終選擇用vue提供的nuxt.js框架去改造現有的項目。jquery

簡單寫一下prerender-spa-plugin客戶端預渲染的過程webpack

prerender-spa-plugin客戶端預渲染

相關文檔可查看:prerender-spa-pluginios

安裝

直接在vue項目中,經過npm或者yarn進行安裝
##### Yarn
$ yarn add prerender-spa-plugin
##### NPM
$ npm i prerender-spa-plugin -S

配置

在webpack.prod.js中配置

頂部引入:git

const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer

在plugins中配置github

new PrerenderSPAPlugin({
    //生成的預渲染html文件存放路徑
    staticDir: path.join(__dirname, '../dist'),
    //須要預渲染的界面路徑(router)
    routes: ['/', '/index'],
    //跨域轉發配置,預渲染時獲取數據的api地址
    server: {
        proxy: {
          '/api': {
            target: 'http://192.168.1.223:9002',
            changeOrigin: true,
            pathRewrite: {
              '^/api': '/'
            }
          }
        }
     },
    //在必定時間後再捕獲頁面信息,使得頁面數據信息加載完成,
    必選,否則界面依然會沒有數據
    captureAfterTime: 5000,
    //忽略打包錯誤
    maxAttempts: 10,
    renderer: new Renderer({
        //可選,頁面在被搜索時的關鍵詞
        inject: {
          foo: 'bar'
        },
        //可選,無桌面系統可去掉
        headless: false,
        //必選,‘render-event'必須與main.js中mounted下的配置名稱一致
        renderAfterDocumentEvent: 'render-event'
    })
})
在main.js中的配置
new Vue({
    el: '#app',
    router,
    store,
    template: '<App/>',
    mounted () {
      document.dispatchEvent(new Event('render-event'))
    }
})
config下index.js配置

// build時須要將'/'切換爲'./'
assetsPublicPath: './'web

到此整個預渲染模式,改造完成了。
這次demo中還沒有處理meta信息,須要配置meta信息的,可查看文檔vue-meta-info,這是一個基於vue 2.0的插件,它會讓你更好的管理你的vue頁面裏面的meta信息,詳細配置過程可參考:muwoo做者寫的「處理 Vue 單頁面 Meta SEO的另外一種思路」文章,裏邊整個過程寫的挺詳細的express

Nuxt.js框架改造現有Vue項目

做爲新手,並不介意本身動手去配置環境,建議直接用nuxt.js提供的腳手架(create-nuxt-app)進行快速搭建項目,具體搭建過程可查看官網文檔:Nuxt.js

nuxt.js項目搭建

確保安裝了npx(npx在NPM版本5.2.0默認安裝了)

$ npx create-nuxt-app <項目名>

或者

$ yarn create nuxt-app <項目名>

以後會有一系列的選項:

  1. 在集成的服務器端框架之間進行選擇:

  2. 選擇您喜歡的UI框架:

  3. 選擇你想要的Nuxt模式 (Universal or SPA),不懂此選項的能夠看一下這篇文章render mode的區別
  4. 添加 axios module 以輕鬆地將HTTP請求發送到您的應用程序中。
  5. 添加 EsLint 以在保存時代碼規範和錯誤檢查您的代碼。
  6. 添加 Prettier 以在保存時格式化/美化您的代碼。

官網都有詳細的講解,根據本身的需求選擇就行了,當安裝完後,項目就能夠直接運行了

npm run dev
問題
在啓動時遇到以下問題:

clipboard.png

找了一圈,發現搭建項目時默認的element-ui版本過低,直接用npm uninstall element-ui卸載當前版本,從新使用npm install element-ui@版本號安裝便可,版本號使用2.7.2及以上都可

項目目錄簡介

既然是對現有Vue項目的改造,就先看一下nuxt.js各目錄的功能及vue項目目錄的對比吧

nuxt.js的目錄結構

├── assets                         // 資源文件。用於組織未編譯的靜態資源入LESS、SASS 或 JavaScript
│   └── logo.jpg                   // 默認logo圖片
├── components                     // 組件。用於本身編寫的Vue組件,好比滾動組件,日曆組件,分頁組件
│   └── AppLogo.vue                // 默認logo組件
├── layouts                        // 佈局。頁面都須要有一個佈局,默認爲 default。它規定了一個頁面如何佈局頁面。全部頁面都會加載在佈局頁面中的 <nuxt /> 標籤中。
│   └── default.vue                // 默認模板頁面,相似mvc中的layout
├── middleware                     // 中間件。存放中間件。能夠在頁面中調用: middleware: 'middlewareName' 。
├── pages                         // 頁面。一個 vue 文件即爲一個頁面。
│   └── index.vue                  // 默認首頁面
├── plugins                        // 用於存放JavaScript插件的地方
│   └── element-ui.js              // 上邊咱們安裝的UI框架
├── static                         // 用於存放靜態資源文件,好比圖片,此類文件不會被 Nuxt.js 調用 Webpack 進行構建編譯處理。 服務器啓動的時候,該目錄下的文件會映射至應用的根路徑 / 下。
├── store                         // 用於組織應用的Vuex 狀態管理。
├── .editorconfig                  // 開發工具格式配置
├── .eslintrc.js                   // ESLint的配置文件,用於檢查代碼格式
├── .gitignore                     // 配置git不上傳的文件
├── nuxt.config.js                 // 用於組織Nuxt.js應用的個性化配置,好比網站title,已便覆蓋默認配置
├── package.json                   // npm包管理配置文件
└── README.md                      // 說明文檔

nuxt.js目錄與vue.js目錄的對比

clipboard.png

總體來看,目錄結構沒有太大的變更,區別比較大的就是router文件夾,nuxt.js項目中並無router路由的配置,這個就是 nuxt 框架的獨到之處,爲了能實現更好的SSR渲染,它使用的是根據頁面結構,自動路由,因此你的文件名,就是你的路由名稱,具體規則可查看官網文檔路由

好了,nuxt項目啓動了,目錄結構也清楚了,接下來就是整個現有Vue項目的遷移了。

遷移項目

目錄結構重組

由於以前寫習慣了vue項目,並不太想改動目錄結構,就簡單粗暴的在nuxt目錄下新建了一個src目錄,將assets、components、layouts、middleware、pages、plugins以及store所有拖到了src中,src繼續保持與static同級,這樣整個項目結構跟vue沒有啥區別了。

最終的項目結構以下如:
image.png

PS:在添加了src後須要修改一下項目的啓動配置,在nuxt.config.js中修改srcDir爲'src/'
image.png

已有vue頁面遷移

將vue中對應的頁面放到如今的nuxt目錄下對應的位置,注意一下vue文件的命名就能夠

全局配置文件及第三方組件的遷移

vue項目中有用到一些全局配置文件和第三方文件,這部分js的話,直接放在plugins中,以擴展組件的形式在項目啓動時,掛載到全局中

1.自定義的配置文件修改

將自定義的變量綁定到vue的原型中,Vue.use註冊到vue項目中,在vue文件中能夠直接用$config(自定義的變量名)調用該變量,而不須要再單獨去import了;最後用export default拋出該變量,是爲了在其餘js中使用。
image.png

PS:只有在vue頁面中使用該變量時不須要import,若是要在其餘的js中使用,仍是須要import進來的。

2.第三方組件的遷移

直接用npm install將第三方組件加載到項目中,在須要的vue界面用import載入就能夠,可是須要注意的一點是,第三方組件中可能用到了document、window等瀏覽器對象,而nuxt項目是須要在客戶端和服務端都要進行運行的,服務端並無window等對象,在服務端運行時會報錯,因此第三方組件也跟自定義組件相似的用plugins組件的形式載入比較安全,在plugins下單首創建一個同名的js文件,斷定是客戶端時再去加載該組件就好了。
image.png

plugins中擴展組件的相關配置

在plugins中建立的js須要再項目啓動時註冊到項目中,也就是在nuxt.config.js中的plugins中進行配置

plugins: [
    { src: '@/plugins/config.js', ssr: true },
    { src: '@/plugins/d3.js', ssr: true }
]

全局樣式文件遷移

全局樣式文件css,在nuxt.config.js配置文件中的css中引入

css: [
    '@/assets/index.css'
]

用戶登陸狀態store的遷移

項目比較着急,實在懶得用nuxt提供的方式再去改造這部分代碼,直接沿用了vue中mutations和actions方式,暫時項目並無出現問題(後期若是有問題再作修改

PS:若是該js中用到了window等瀏覽器的對象,加個process.client去判斷就行,其他的能夠不用修改

element-ui的遷移

跟vue同樣先npm install element-ui --save,以後再plugins下新建一個element-ui.js文件,內容以下:

import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'

Vue.use(Element, { locale })

而後再nuxt.config.js中進行配置:

plugins: [
    { src: '@/plugins/element-ui', ssr: true }
],
css: [
    'element-ui/lib/theme-chalk/index.css'
]

防止element-ui屢次被打包,在nuxt.config.js下的build中進行配置

build: {
    vendor: ['element-ui']
}

jquery的使用

npm install jquery --save
而後再nuxt.config.js下的build中配置

build: {
    plugins: [
        new webpack.ProvidePlugin({
        '$': 'jquery',
        'jQuery': 'jquery',
        'window.jQuery': 'jquery'
      })
    ]
}

axios和$axios的使用

由於vue中用了axios,後期也沒有修改原來的api請求,因此就繼續使用了axios,直接npm install axios --save安裝,在須要使用的地方import便可。
若是在vue項目中已經封裝了axios,直接能夠把vue中寫的關於api的js都挪到plugins下,把export default axios拋出,再在nuxt.config.js下按照擴展的配置在plugins中添加就能夠正常使用了。

plugins: [
    { src: '@/plugins/api/index.js', ssr: true }
],

正常客戶端的請求使用axios並無什麼問題,而在asyncData預加載服務端請求時就比較麻煩了,在asyncData請求中使用了nuxt默認集成的$axios,這個須要再nuxt.config.js下的modules中配置

modules: [
    '@nuxtjs/axios',
    '@gauseen/nuxt-proxy'
],

跨域代理配置:

proxyTable: {
    '/api/': {
      target: '數據請求的ip地址',
      ws: false,
      pathRewrite: {
        '^/api': '/'
      }
    }
  },

asyncData下數據請求
單個請求:

async asyncData ({ app, params }) {
     let { data } = await app.$axios.get(url).then(res => {...})
}

多個請求:

async asyncData ({ app, query }) {
    // 請求帶參數時的寫法,query指的是當前訪問的url中攜帶的參數
      let searchQuery = {
        type: query.searchTag,
        q: query.searchKeys,
        page: 1
      }
      const [nounList, resultList] = await Promise.all([
        app.$axios.get('請求的api地址', { params: { q: query.searchKeys }}),
        app.$axios.get(`/api/search/${searchQuery.type}`, { params: searchQuery })
      ])
      return {
        nounList: nounList.data,
        resultList: resultList.data
      }
    }

通常狀況下數據請求

this.$axios.get(url).then(res =>  {...})

PS:整個項目中能夠同時使用axios和nuxt默認集成的$axios,能夠根據本身的需求合理使用

總結

到如今整個vue項目基本上都改造完了,能夠正常使用了。
第一次接觸nuxt,對其中的一些原理不是很懂,查閱了大量的文檔和別人的博客,雖然完成了此次的改造,但整個項目仍是存在一些瑕疵,還在不斷的改善中。

細節

  • data中數據的初始化定義,不能直接使用location、window等去賦值,也不能用自定義的config配置文件中的變量直接去賦值,也不能直接require圖片;這些賦值均可以挪到mounted鉤子函數中完成。
  • 不一樣界面的title等設置,每一個vue界面都提供了head鉤子函數

    head () {
          return {
            title: '百度--搜了個啥',
            meta: [
              { hid: 'index', name: 'index', content: 'index page'}
            ]
          }
        },

遺留的問題

  • static中的html靜態文件無法直接訪問,查詢了不少網站,都沒有找到相關的文檔,心塞塞中.......

PS:目前整個項目還在持續測試和完善中,後續會將遇到的問題和解決方案不按期的更新,有問題或者不完善的地方隨時歡迎各位小夥伴提意見,咱們一塊兒探討呀

相關文章
相關標籤/搜索