MonkeyBinBin

被程式設計的猴子

Nuxt.js

Nuxt 系列 - #2 關於 nuxt.config.js 的設定


官方提供了很多可設定的項目,不會講到全部的項目,主要是說明我在開發 blog 時用到的一些設定,提供給大家參考。透過一些實例來理解為何要設定與如何設定。

build

在建立網頁應用程式時,依據需要自定義 Webpack 配置。以下為目前有使用到的設定屬性。

analyze - 用來啟用 webpack-bundle-analyzer 套件設定,分析打包後的 js 檔案內各個 module 佔的大小。當需要調校效能或觀察載入套件的檔案大小時很好用。

  • Type: Boolean or Object
  • Default: false
export default {
  build: {
    analyze: true,
    // or
    analyze: {
      analyzerMode: 'static'
    }
  }
}

extend - 擴充 webpack 設定,可能是增加 loader 或是增加其他 webpack plugins 的設定。

  • Type: Function

依據官方的說法,此方法會被呼叫2次,一次是 server bundle,另一次是 client bundle
此方法會傳入2個參數,第一個為 Webpack config object,第二個為包含 isDev、isClient、isServer、loaders 屬性的 object
透過 isDev、isClient、isServer 來判斷在什麼狀況下要做什麼 webpack 設定的調整

export default {
  build: {
    extend (config, { isClient, isServer, isDev, loaders: { vue } }) {
      // Extend only webpack config for development and client-bundle
      if (isDev && isClient) {
        config.module.rules.push({
          enforce: 'pre',
          test: /\.(js|vue)$/,
          loader: 'eslint-loader',
          exclude: /(node_modules)/
        })
      }

      // Extend only webpack config for client-bundle
      if (isClient) {
        vue.transformAssetUrls.video = ['src', 'poster']
      }

      config.plugins.push(
        new webpack.ProvidePlugin({
          '$': 'jquery',
          '_': 'lodash',
          'moment': 'moment'
        })
      )
    }
  }
}

extractCSS - 設定是否使用 extract-css-chunks-webpack-plugin,用來將 css 提取至單獨文件,通常一個組件一個檔案,與 js 檔分開載入增加效能。

  • Type: Boolean
  • Default: false

建議在開發期間設定為 false,才會有熱更新的效果
利用 process.env.DEPLOY_ENV 透過 package.json 中的 scripts 設定傳入值,以達到不同環境使用不同設定的需求

export default {
  build: {
    extractCSS: process.env.DEPLOY_ENV === 'production'
  }
}

optimization - webpack 優化相關設定。

  • Type: Object
  • Default:
    {
    minimize: false,
    minimizer: undefined,
    splitChunks: {
      chunks: 'all',
      automaticNameDelimiter: '.',
      name: undefined,
      cacheGroups: {
        commons: {}
      }
    }
    }

調整為開發時不做最小化壓縮,但打包正式環境版本時則要做最小化壓縮
利用 process.env.DEPLOY_ENV 透過 package.json 中的 scripts 設定傳入值,以達到不同環境使用不同設定的需求

export default {
  optimization: {
    minimize: process.env.DEPLOY_ENV === 'production'
  }
}

css

設定全域 css 檔案來源,如果要使用 sass,專案需安裝 node-sass 與 sass-loader 套件。

export default {
  css: [
    // 載入fontawesome樣式
    '@fortawesome/fontawesome-svg-core/styles.css',
    // 載入bootstrap
    'bootstrap/scss/bootstrap.scss',
    'bootstrap-vue/dist/bootstrap-vue.css',
    // 載入highlight.js樣式
    'highlight.js/styles/zenburn.css',
    // 載入aos樣式
    'aos/src/sass/aos.scss',
    // 主要css樣式(自訂的樣式)
    '~/assets/sass/main.scss'
  ]
}

env

配置在客戶端和伺服器端共享的環境變數。通過 process.env.baseUrl 或 context.env.baseUrl 來使用 baseUrl 環境變數。

  • Type: Object
export default {
  env: {
    baseUrl: '/',
    title: '被程式設計的猴子'
  }
}

注意事項:
Nuxt 使用 webpack definePlugin 定義環境變數。

generate

與靜態化打包時(npm run generate)相關的設定,動態路由產生靜態 html 之設定、發現未知路由時的錯誤頁面之設定…等等。

fallback - 設置錯誤頁面,當 nuxt 呈現未知路由時,會轉至此文件。

  • Type: String or Boolean
  • Default: 200.html

當未設定或設定為 false,錯誤頁面的檔名為 200.html
設置為 true,錯誤頁面的檔名為 404.html
設置為字串,錯誤頁面的檔名就會是此設置的字串

注意事項:
官方建議使用 npm run generate 方式使用 nuxt 時,應設置為 true,使用 404.html 為檔案名稱。

export default {
  generate: {
    fallback: true
  }
}

routes - nuxt 執行 generate 指令時,動態路由會被忽略,所以這邊要去指定所有想要輸出靜態化 html 的路由。

  • Type: Array

使用一個返回 Promise 對象的 function

import axios from 'axios'

export default {
  generate: {
    routes () {
      return axios.get('https://my-api/users')
        .then((res) => {
          return res.data.map((user) => {
            return '/users/' + user.id
          })
        })
    }
  }
}

使用一個 callback(err, params) 的 function

import axios from 'axios'

export default {
  generate: {
    routes (callback) {
      axios.get('https://my-api/users')
        .then((res) => {
          const routes = res.data.map((user) => {
            return '/users/' + user.id
          })
          callback(null, routes)
        })
        .catch(callback)
    }
  }
}

使用 payload 加速動態路由生成
nuxt.config.js 設置回傳路由與 payload

import axios from 'axios'

export default {
  generate: {
    routes () {
      return axios.get('https://my-api/users')
        .then((res) => {
          return res.data.map((user) => {
            return {
              route: '/users/' + user.id,
              payload: user
            }
          })
        })
    }
  }
}

/users/_id.vue 取得 payload 供程式在生成靜態 html 使用,所以要判斷 payload 是否有值

async asyncData ({ params, error, payload }) {
  if (payload) return { user: payload }
  else return { user: await backend.fetchUser(params.id) }
}

定義網頁 head tags,相關資訊可參考 vue-meta documentation。例如:script、link、meta、title,這邊為通用的設定也就是所有頁面都會生效,另外也可在 pages 組件中定義各別的 head 設定。

  • Type: Object or Function
export default {
  head: {
    title: config.title,
    meta: [
      { 'http-equiv': 'Content-Type', content: 'text/html; charset=UTF-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' },
      { name: 'author', content: 'MonkeyBinBin' },
      { property: 'fb:app_id', content: '' },
      { hid: 'keywords', name: 'keywords', content: 'demo,demo1,demo2' },
      { hid: 'description', name: 'description', content: 'description' },
      { hid: 'og:title', property: 'og:title', content: 'document title' },
      { hid: 'og:type', property: 'og:type', content: 'article' },
      { hid: 'og:url', property: 'og:url', content: 'https://monkeybinbin.github.io/' },
      { hid: 'og:image', property: 'og:image', content: 'https://monkeybinbin.github.io/img/fb.jpg' },
      { hid: 'og:image:width', property: 'og:image:width', content: '474' },
      { hid: 'og:image:height', property: 'og:image:height', content: '474' },
      { hid: 'og:description', property: 'og:description', content: 'description' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: `/favicon.ico` }
    ]
  }
}

loading

可設定載入進度效果,有三種選擇分別為關閉、啟用預設效果並調整效果或自訂載入效果組件。

  • Type: Boolean or Object or String

如果有開啟,在路由變換時會觸發此效果。
可利用 this.$nuxt.$loading.start() 與 this.$nuxt.$loading.finish() 來觸發出現此效果。

export default {
  mounted () {
    this.$nextTick(() => {
      this.$nuxt.$loading.start()

      setTimeout(() => this.$nuxt.$loading.finish(), 500)
    })
  }
}

關閉載入進度效果

export default {
  loading: false
}

使用內建載入進度效果,並且可自訂部份設定
可配置項目與說明

屬性名稱 類型 預設值 說明
color String 'black' 進度條顏色
failedColor String 'red' 頁面加載失敗時的顏色(data 或 fetch 方法返回錯誤時)
height String '2px' 進度條高度
throttle Number 200 以毫秒為單位,顯示進度條之前等待的時間,防止閃爍
duration Number 5000 以毫秒為單位,進度條最大的顯示時間
continuous Boolean false 當加載時間超過 duration,繼續顯示進度條的動態效果
css Boolean true 是否套用進度條預設樣式
rtl Boolean false 進度條動態效果為由右到左
export default {
  loading: {
    color: 'blue',
    height: '5px'
  }
}

自定義載入進度效果組件
可新建一個組件替代預設載入進度效果組件,只需設定組件路徑
自定義組件需實現以下方法

方法 是否必須 說明
start() 觸發啟動進度條時呼叫,在此方法內顯示組件
finish() 觸發關閉進度條時呼叫,在此方法內隱藏組件
fail(error) 發生錯誤時呼叫
increase(num) 在載入過程中呼叫,num 為小於100的整數

在 components 目錄下建立自定義載入效果組件,例如 components/loading/index.vue

<template lang="html">
  <div class="loading-page" v-if="loading">
    <p>Loading...</p>
  </div>
</template>

<script>
export default {
  data: () => ({
    loading: false
  }),
  methods: {
    start () {
      this.loading = true
    },
    finish () {
      this.loading = false
    }
  }
}
</script>

<style scoped>
.loading-page {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.8);
  text-align: center;
  padding-top: 200px;
  font-size: 30px;
  font-family: sans-serif;
}
</style>

更新 nuxt.config.js 設定

export default {
  loading: '~/components/loading/index.vue'
}

mode

設定應用程式模式是否要使用 server side rendering。

  • Type: String
  • Default: universal

可設定值:

  • spa:一般的單頁應用程式,不使用 server side rendering
  • universal:server side rendering 搭配 client side navigation 一起使用
export default {
  mode: 'universal'
}

modules

設定要使用的 nuxt modules,不同的 module 會有不同的設定參數,因此詳細使用方式就參照各個 module 的使用說明。

export default {
  modules: [
    '@nuxtjs/sitemap',
    ['@nuxtjs/google-tag-manager', { id: 'GTM-N24F89P' }],
    // global 載入sass的資源(variables、functions、mixins…)使用的套件相關設定在 styleResources
    '@nuxtjs/style-resources',
    ['nuxt-fontawesome', {
      component: 'fa',
      imports: [
        {
          set: '@fortawesome/free-solid-svg-icons',
          icons: ['fas']
        }
      ]
    }]
  ]
}

plugins

設定實例化 vue 需要載入的 Javascript 插件,每當你需要使用 Vue.use()時,就應該在 plugins 增加程式碼與設定。

  • Type: Array
  • 陣列元素 Type: String or Object

陣列元素 Type 為 String,直接設置 plugins 的程式路徑
陣列元素 Type 為 Object 具備以下屬性

  • src: String(程式路徑)
  • mode: String(值可以為 client 或 server),用來定義此 plugins 在 client 或 server 使用。
export default {
  plugins: [
    '~/plugins/bootstrap-vue.js',
    '~/plugins/filters.js',
    '~/plugins/disqus.js',
    { src: '~/plugins/scrollspy.js', mode: 'client' },
    '~/plugins/font-awesome.js'
  ]
}

router

自定義路由(vue-router)相關設定。

base - 配置應用程式根目錄。

  • Type: String
  • Default: '/'
export default {
  router: {
    base: '/app/'
  }
}

scrollBehavior - 配置當頁面跳轉至目標頁面渲染後都會呼叫此方法。所以可以用來設定換頁後頁面 scroll 的位置。

  • Type: Function

指定換頁後 scroll 位置捲動至最上方

export default {
  router: {
    // 換頁將網頁捲至最上方
    scrollBehavior: function (to, from, savedPosition) {
      return { x: 0, y: 0 }
    }
  }
}

非同步配置

由於設定檔內有一些項目設定需要由 api 取得相關資料,所以必需另外在 nuxt.config.js 內 import 套件呼叫 api 來取得資料。

/* 
axios-module cannot be used in nuxt.config.js
You need to import axios and configure it again
*/
import axios from 'axios'

export default async () => {
  const data = await axios.get('endpoint')
  return {
    head: {
      title: data.head.title
    }
  }
}

參考資料

Nuxt.js - Configuration
webpack