Nuxt服务端渲染,采坑之路经验分享!

来源:程序思维浏览:1744次
Nuxt服务端渲染,采坑之路经验分享,面向有vue开发经验的同学。

安装:vue init nuxt-community/starter-template

nuxt目录结构

Nuxt

Nuxt官方

简单来说,Nuxt就是基于Vue的一个应用框架,采用服务端渲染,让你的SPA应用(Vue)也可以拥有SEO

生命周期

众所周知,Vue的生命周期全都跑在客户端(浏览器),而Nuxt的生命周期有些在服务端(Node),客户端,甚至两边都在:

nuxt生命周期

生命周期流程图,红框内的是Nuxt的生命周期(运行在服务端),黄框内同时运行在服务端&&客户端上,绿框内则运行在客户端

实战经验

1. 红框、黄框内的周期都不存在Window对象

<script>
export default {
  asyncData() {
    console.log(window) // 服务端报错
  },
  fetch() {
    console.log(window) // 服务端报错
  },
  created () {
    console.log(window) // undefined
  },
  mounted () {
    console.log(window) // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  }
}
</script>

2. 配置错误页面

你可以通过编辑 layouts/error.vue 文件来定制化错误页面.

<template>
  <div class="container">
    <h1 v-if="error.statusCode === 404">页面不存在</h1>
    <h1 v-else>应用发生错误异常</h1>
    <nuxt-link to="/">首 页</nuxt-link>
  </div>
</template>

<script>
export default {
  props: ['error'],
  layout: 'blog' // 你可以为错误页面指定自定义的布局
}
</script>

3. 自定义Loading页面

nuxt.config.js

module.exports = {
  loading: '~components/loading.vue'
}
loading.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>

4. 校验参数

如果校验失败,则自动跳转到错误页面

<script>
export default {
  validate({ params, query }) {
    return /^d+$/.test(params.id) // must be number
  }
}
</script>

5. Header、Footer等公共组件放哪?

大家都知道,vue-cli入口文件是app.vue,在nuxt开发当中则是./layout/default.vue

<template>
  <div id="app">
    <!-- 公共头部组件 -->
    <xxx-header></xxx-header>
    <!-- 路由视图,相当于router-view -->
    <nuxt/>
    <!-- 公共底部组件 -->
    <xxx-footer></xxx-footer>
  </div>
</template>
6. 没有keep-alive

由于是服务端渲染,所以不支持组件的keep-alive,那自然activated、deactivated这两个生命周期也没了

7. 配置插件

所有插件都写在/plugins目录下,这里以vue-lazyload为例

plugins/lazy-load.js

import Vue from 'vue'
import VueLazyLoad from 'vue-lazyload'

Vue.use(VueLazyLoad, {
  loading: require('~/assets/images/loading.jpg'),
  error: require('~/assets/images/error.jpg')
})

nuxt.config.js

module.expors = {
  plugins = [
    {
      src: "~/plugins/lazy-load",
      ssr: false
    }
  ]
}

8. 使用Axios,并配置全局拦截器,处理跨域

starter-template模板,推荐使用@nuxtjs/axios、@nuxtjs/proxy,不需要在plugins配置

安装依赖

npm install @nuxtjs/axios @nuxtjs/proxy --save
使用、处理跨域

// nuxt.config.js
module.exports = {
  modules: [ '@nuxtjs/axios' ], // 不需要加入@nuxtjs/proxy
  axios: {
    proxy: true,
    prefix: '/api', // baseURL
    credentials: true,
  },
  proxy: {
    '/api/': {
      target: 'http://127.0.0.1:2001', // 代理地址
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      },
    },
  }
}
组件中使用

<script>
export default {
  fetch ({ app }) {
    console.log(app.$axios)
  },
  asyncData ({ app }) {
    console.log(app.$axios)
  },
  created () {
    console.log(this.$axios)
  }
}
</script>

到此为止,我们并不需要在plugins配置axios,但是如果要设置全局拦截器,那么就要新建一个/plugins/axios.js

export default function (app) {
  let axios = app.$axios;
// 基本配置
  axios.defaults.timeout = 10000
  axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

  // 请求回调
  axios.onRequest(config => {})

  // 返回回调
  axios.onResponse(res => {})

  // 错误回调
  axios.onError(error => {})
}
然后在plugins配置它

module.exports = {
  plugins = [
    {
      src: "~/plugins/axios",
      ssr: false
    },
  ]
}
9. 默认Meta标签

nuxt.config.js

module.exports = {
  head: {
    title: 'your project title',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' }
    ],
    link: [
      { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto' }
    ]
  }
}

10. 页面组件特有的Meta标签

<script>
export default {
  head () {
    return {
      meta:
      [
        {
          name: 'keywords',
          content: '最强王者,今晚吃鸡'
        },
      ]
    }
  }
}
</script>

11. 动态路由的Meta标签填充

游戏详情页面举例子,由于数据是异步获取的,我们需要把数据获取写在asyncData钩子,待数据获取成功才会渲染该页面组件

<script>
export default {
  async asyncData ({ app, params }) {
    let data = await app.$axios.get(`/appinfo/${params.id}`);
    return {
      appname: data.appinfo.appname
    }
  },
  head () {
    return {
      meta:
      [
        {
          name: 'keywords',
          content: `${this.appname},无限宝石,无限元宝`
        },
      ]
    }
  }
}
</script>

12. 使用Vuex

nuxt自己集成了vuex,所以不需要安装,在/store目录下新建index.js即可使用

import Vuex from 'vuex'

let store = () => new Vuex.Store({
  state: {
    token: ''
  },
  mutations: {
    setToken (state, token) {
       state.token = token
    }
  }
})

export default store

13. 登录状态?

vue-cli项目中,我们可以用vuex-persistedstate,它可以使vuex的状态持久化,页面刷新都不会丢失,原理当然是localStorage啦!当然我更喜欢用vue-cookies进行保存token,问题来了,nuxt项目怎么保存登录状态呢?当然上面这两种方法我们都可以使用,但是有个问题,由于在created钩子中不存在window对象(获取cookie、localStorage都需要window对象),当你需要判断是否存在token的时候,你必须要在mounted进行操作,这说明页面进来的一瞬间你无法得知是否已经登录了,这会导致显示用户名、组件显示于隐藏都慢半拍

nuxt非常友好,它提供了fetch钩子,还有nuxtServerInit,这两个钩子都运行在服务端并且我们能很快速地操作store

14. fetch的使用

如果页面组件设置了fetch方法,它会在组件每次加载前被调用(在服务端或切换至目标路由之前),此方法需要跟服务端的人员配合

<script>
export default {
  async fetch ({ app, store, params }) {
    let { data } = app.$axios.get('/token');
    store.commit('setToken', data.token);
  }
}
</script>

15. nuxtServerInit

终极无敌方法

import Vuex from 'vuex'

let store = () => new Vuex.Store({
  state: {
    token: ''
  },
  mutations: {
    setToken (state, token) {
       state.token = token
    }
  },
  actions: {
    nuxtServerInit({ commit }, { req }) {
      let cookie = req.headers.cookie;

      // 将cookie转成json对象(自己实现该方法)
      let token = cookieparse(cookie).token;
      commit('setToken', token);
    },
  }
})

export default store

16. 封装属于自己的全局方法


let xielikang = function () {

  /**
   * @method 打印信息方法
   * @param {String} msg 信息
   */
  let message = function (msg) {
    msg && console.log(msg)
  }

  let otherfn = function (msg) {}

  return {
    message,
    otherfn
  }

}

Vue.prototype.$kang= xielikang
组件调用

<script>
export default {
  created() {
    this.$kang.message('小老弟,你怎么回事')
  }
}
</script>
对了,别忘了在plugins中配置,可以回到第7小节查看配置

17. 全局样式

nuxt.config.js

module.exports = {
  css: ['~/assets/stylesheets/main.min.css']
}

18. 使用Element-UI

还是plugins文件夹新建element-ui.js

// 全局引入
import Vue from 'vue'
import ElementUI from 'element-ui'

Vue.use(ElementUI)

// 按需引入
import { Button, Loading, MessageBox } from 'element-ui'

Vue.use(Button)
Vue.prototype.$loading = Loading.service
Vue.prototype.$msgbox = MessageBox
nuxt.config.js

module.exports = {
  css: ['element-ui/lib/theme-chalk/index.css'],
  plugins: [
    {
      src: "~/plugins/element",
      ssr: true
    }
  ]
}

18. 如何使用sass预处理器

安装依赖

npm install node-sass sass-loader --save
组件中使用(不需要其他的配置了)

<style lang="scss" scoped>

</style>

19. fetch、asyncData、validate使用范围

只能在页面组件使用,也就是pages目录下的组件,而不是components目录下的组件,要有所区分

20. 传统部署

npm run build && npm run start

21. pm2部署

它允许您永久保持应用程序活跃,无需停机即可重新加载它们,并不需要传统部署的.nuxt文件夹,该部署方法也跟生产环境一样含热更新

npm install pm2 -g
npm run build
pm2 start ./node_modules/nuxt/bin/nuxt-start

采坑之旅到此结束,希望对大家有帮助!
精品好课
Vue2+Vue3+ES6+TS+Uni-app开发微信小程序从入门到实战视频教程
2021年最新Vue2+Vue3+ES6+TypeScript和uni-app开发微信小程序从入门到实战视频教程,本课程教你如何快速学会VUE和uni-app并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己...
HTML5视频播放器video开发教程
适用人群1、有html基础2、有css基础3、有javascript基础课程概述手把手教你如何开发属于自己的HTML5视频播放器,利用mp4转成m3u8格式的视频,并在移动端和PC端进行播放支持m3u8直播格式,兼容...
React实战视频教程仿京东移动端电商
React是前端最火的框架之一,就业薪资很高,本课程教您如何快速学会React并应用到实战,对正在工作当中或打算学习React高薪就业的你来说,那么这门课程便是你手中的葵花宝典。
最新完整React视频教程从入门到精通纯干货纯实战
React是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习React高薪就...
HTML5基础入门视频教程易学必会
HTML5基础入门视频教程,教学思路清晰,简单易学必会。适合人群:创业者,只要会打字,对互联网编程感兴趣都可以学。课程概述:该课程主要讲解HTML(学习HTML5的必备基础语言)、CSS3、Javascript(学习...
jQuery视频教程从入门到精通
jquery视频教程从入门到精通,课程主要包含:jquery选择器、jquery事件、jquery文档操作、动画、Ajax、jquery插件的制作、jquery下拉无限加载插件的制作等等......
VUE2+VUE3视频教程从入门到精通(全网最全的Vue课程)
VUE是目前最火的前端框架之一,就业薪资很高,本课程教您如何快速学会VUE+ES6并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习VUE高薪就...
最新完整React+VUE视频教程从入门到精,企业级实战项目
React和VUE是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React和VUE并应用到实战,教你如何解决内存泄漏,常用库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习Re...
收藏
扫一扫关注我们