Nuxt項目總結

公司最近要作一個新產品的官網,要求要對SEO友好,首先想到的是作服務端渲染,Vue.js的服務端渲染vue-server-renderer須要node服務.本身搭建是至關複雜的,因此咱們使用了Nuxt.js。css

Nuxt.js簡介:html

  • Nuxt.js是基於Vue的服務端渲染應用框架.
  • 集成了Vue2,Vue-Router,Vue SSR,Vuex,Vue-Meta.
  • 能夠輕鬆地經過配置實現服務端渲染或單頁模式.
  • Nuxt.js根據pages文件目錄自動生成路由配置.
  • 經過nuxt generate命令依據應用的路由配置將每個路由編譯成爲對應的 HTML 文件,實現Vue應用的靜態化.

搭建過程:vue

  • 首先用NUXT的腳手架create-nuxt-app生成項目
yarn create nuxt-app <項目名>
執行命令後,會提示你進行一系列的選擇,按項目須要進行選擇便可
須要注意的是選擇Nuxt模式(Universal or SPA),由於咱們要作服務端渲染,因此選擇Universal,選擇以後在nuxt.config.js配置文件中會生成配置mode:'universal'
複製代碼
  • 而後會生成這樣的一個項目結構(紅框的目錄是根據須要本身建的) node

    Nuxt.js的文件打包和頁面路由都是依據目錄來生成的,因此若是沒有額外配置,不要修改目錄的名稱

  • 下面依次介紹下生成的目錄:android

    assets:該目錄下能夠放css,scss,img,js,打包時會被編譯處理webpack

    components:放組件,單純的vue文件,沒有Nuxt的擴展,不能執行asyncData之類的ios

    layouts:佈局文件,默認有default.vue,若是不配置,pages裏的頁面文件默認的佈局文件都是default.vue,若是想自定義佈局文件,須要在layouts中新建佈局文件,並在pages的頁面文件中進行配置,好比新建error佈局文件:nginx

    //layouts/error.vue
    <template>
      <div>
        <nuxt />
      </div>
    </template>
    //pages/404.vue
    export default {
        layout:'error'
    }
    複製代碼

    middleware:中間件目錄,中間件文件中容許自定義一個函數在頁面渲染以前執行,能夠在layouts,pages和nuxt.config.js中配置,中間件接收 context 做爲第一個參數,栗子:web

    //middleware/stats.js
    export default function (context) {
      context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent
    }
    //nuxt.config.js
    router: {
      middleware: 'stats'
    }
    複製代碼

    pages:頁面目錄,Nuxt.js會自動讀取該目錄下的文件,生成路由配置,好比目錄結構是這樣的:vuex

    pages/
      --| mobile/
        -----| index.vue
        -----| one.vue
      --| index.vue
    複製代碼

    Nuxt.js會自動解析成路由:

    router: {
      routes: [
        {
          name: 'index',
          path: '/',
          component: 'pages/index.vue'
        },
        {
          name: 'mobile',
          path: '/mobile',
          component: 'pages/mobile/index.vue'
        },
        {
          name: 'mobile-one',
          path: '/mobile/one',
          component: 'pages/mobile/one.vue'
        }
      ]
    }
    複製代碼

    Nuxt.js還支持比較複雜的動態路由,能夠參考官方文檔進行目錄配置.

    Nuxt.js還擴展了頁面組件,最經常使用的是asyncData,能夠在服務端或者路由更新時執行,支持異步數據處理,其餘的還有當前頁面的head,middle,切換動畫transition配置等等,全部的擴展配置以下,能夠根據須要進行頁面的個性化配置,覆蓋nginx.config.js中的全局配置.

    plugins:插件目錄,配置完後能夠全局調用,ui插件,或者js插件,像element-ui,vue-lazyload,均可以在這裏進行配置,配置方法:

    //使用swiper插件
    //plugins/vue-swiper.js
    import Vue from 'vue'
    import VueAwesomeSwiper from 'vue-awesome-swiper'
    Vue.use(VueAwesomeSwiper)
    
    //nuxt.config.js
    css:['swiper/dist/css/swiper.css'],
    plugins:[{ src: '~plugins/vue-swiper', ssr: false }]
    ssr:默認是true,表示在服務端執行,設置false表示該文件只在客戶端打包引入
    複製代碼

    static:靜態文件目錄,不須要webpack構建編譯處理的文件,好比在head中引入的icon就放在這個文件下

    store:Vuex文件目錄,經過新建store/index.js激活Vuex,簡單的能夠像下面這樣使用,若是數據較多,能夠把模塊分解爲單獨的文件state.js,actions.js,mutations.js和getters.js,參考官方文檔進行配置.

    //store/index.js
    export const state = () => ({
      counter: 0
    })
    export const mutations = {
        increment (state) {
          state.counter++
        }
    }
    export const actions = {
        getData (state) {
           //使用@nuxt/axios能夠直接調用this.$axios
           this.$axios.post('/xxx')
        }
    }
    export const getters = {}
    複製代碼

    nuxt.config.js:全局的配置文件,會覆蓋nuxt的默認配置

  • 項目中用到的nuxt.config.js配置

    1.head(對SEO友好的配置,PWA配置)

    head: {
                title: 'xxx',
                meta: [
                  { charset: 'utf-8' },
                  { name: 'viewport', content: 'width=device-width, initial-scale=1' },
                  { hid: 'description', name: 'description', content: 'xxxx' },
                  { hid: 'keywords', name: 'keywords', content: 'xxx' }
                ],
                link: [
                  {
                    rel: 'icon',
                    type: 'image/png',
                    sizes: '16x16',
                    href: '/favicon-16x16.png'
                  },
                  {
                    rel: 'icon',
                    type: 'image/png',
                    sizes: '96x96',
                    href: '/favicon-96x96.png'
                  },
                  {
                    rel: 'icon',
                    type: 'image/png',
                    sizes: '32x32',
                    href: '/favicon-32x32.png'
                  },
                  {
                    rel: 'icon',
                    type: 'image/png',
                    sizes: '192x192',
                    href: '/android-icon-192x192.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '57x57',
                    href: '/apple-icon-57x57.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '60x60',
                    href: '/apple-icon-60x60.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '72x72',
                    href: '/apple-icon-72x72.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '76x76',
                    href: '/apple-icon-76x76.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '114x114',
                    href: '/apple-icon-114x114.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '120x120',
                    href: '/apple-icon-120x120.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '144x144',
                    href: '/apple-icon-144x144.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '152x152',
                    href: '/apple-icon-152x152.png'
                  },
                  {
                    rel: 'apple-touch-icon',
                    sizes: '180x180',
                    href: '/apple-icon-180x180.png'
                  },
                  {
                    rel: 'manifest',
                    href: '/manifest.json'
                  }
                ]
            },
    複製代碼

    如今有些瀏覽器支持將網頁添加到主屏幕,方便用戶直接打開.
    apple-touch-icon和manifest是配置添加到主屏幕的顯示的圖標和名稱等信息.
    app-touch-icon是針對safari瀏覽器的.

    mainfest文件格式:

    {
        "short_name": "短名稱",
        "name": "這是一個完整名稱",
        "icon": [
            {
                "src": "icon.png",
                "type": "image/png",
                "sizes": "48x48"
            }
            ...//多個不一樣大小的圖標
        ],
        "start_url": "index.html"
    }
    複製代碼

    關於mainfest的介紹

    2.css

    //引入全局的css文件
    css: ['~/assets/css/normalize.css']
    //若是要使用sass,須要安裝node-sass和sass-loader
    npm install --save-dev node-sass sass-loader
    css: ['~/assets/css/main.scss']
    Nuxt.js會自動識別引入的文件擴展名,webpack會使用相應的預處理器進行解析
    須要注意的是若是要寫一些scss的變量或函數,就須要在build中進行一些配置
    複製代碼

    3.使用swiper插件

    //plugins/vue-swiper.js
    import Vue from 'vue'
    import VueAwesomeSwiper from 'vue-awesome-swiper'
    Vue.use(VueAwesomeSwiper)
    
    //nuxt.config.js
    css:['swiper/dist/css/swiper.css'],
    plugins:[{ src: '~plugins/vue-swiper', ssr: false }]
    複製代碼

    4.配置404頁面

    由於項目使用靜態部署,因此Nuxt官網上說的方式(在layouts中寫error.vue頁面),由於並無在pages中新加頁面,構建時並不會生成對應的靜態頁,因此這種方式並不起做用.能夠實現的方法是在plugins中監聽路由,若是沒有匹配到已經存在的路由,跳轉到404頁面

    //pages/error/index.vue
    <template>
        <div>
            404了
        </div>
    </template>
    
    //plugins/route.js
    export default ({ app }) => {
      const {context} = app
      const {matched} = context.route
      if(!matched.length) {
        window.location.href='/error'
      }
    }
    //nuxt.config.js
    plugins:[{ src: '~plugins/route.js', ssr: false}]
    複製代碼

    5.設置代理

    //nuxt.config.js
    modules: ['@nuxtjs/proxy'],
    proxy: {
        '/api': {
          target: 'https://http://xxx.com',
          changeOrigin: true
         }
    }
    複製代碼

    6.NUXT有自帶的axios模塊@nuxtjs/axios,若是要用自帶的模塊,能夠這樣配置axios和proxy

    modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy'
    ],
    //axios的一些配置
    axios: {
        proxy: true,
        retry: { retries: 1 }//失敗重試次數
    },
    proxy: {
        '/api': {
          target: 'https://xxx.com',
          changeOrigin: true
        }
    }
    若是要對axios請求設置統一攔截器,能夠在插件中配置
    //plugins/axios.js
    export default function ({ $axios, redirect }) {
      $axios.setHeader('Content-Type', 'application/json', ['post'])
      $axios.setToken('123', 'Bearer', ['post'])
      $axios.onRequest(config => {
        //設置請求攔截
      })
      $axios.onError(error => {
        //設置報錯處理
      })
      window.$axios = $axios //掛載到window上,方便在任何js文件中調用
    }
    //nuxt.config.js
    plugins:[{src:'~plugins/axios',ssr:false}]
    //在vue文件中使用
    mounted() {
      this.$axios.post('/xxx')
    }
    asyncData({app}) {
      app.$axios.post('/xxx')
    }
    //在store/actions中使用
    export const actions = {
        getData (state) {
           this.$axios.post('/xxx')
        }
    }
    複製代碼

    可是發現@nuxtjs/axios在asyncData中使用執行nuxt generate靜態構建時會失敗,目前項目中仍是使用的是axios,在api目錄中封裝了axios的調用,像在通常的Vue項目中使用同樣

    7.自定義服務端口

    server: {
        port: 8000, // default: 3000
    }
    複製代碼

    nuxt.config.js還能夠進行不少其餘的配置,後面再學習補充.

相關文章
相關標籤/搜索