美文网首页
nuxt基于vuejs的seo动静态优化

nuxt基于vuejs的seo动静态优化

作者: 颂温暖 | 来源:发表于2019-09-18 10:54 被阅读0次

    我之前的一篇文章,《Vue-cli3基于webpack + prerender-spa-plugin + vue-meta-info的seo优化》,是对静态页面的seo处理,但是也存在很多弊端。比如上线之后浏览器右键查看源代码,会看不到dom结构,比如动态加载head中的meta和title源码也会显示undefined。原因是因为浏览器处理的时候,dom还没有加载完毕。相信下面的nuxt看完之后你会放弃上面这篇文章

    本文涉及的主要有,nuxt框架的初始化搭建,局域网访问配置,全局axios配置(包括asyncData(),接口请求),swiper插件使用,引入字体包,动态路由--参数配置---generate打包,cross-env开发和线上环境配置,nuxt并不是最终的优化方案

    本文内容较长,没有必要全部看完,可以只看需要的,还有下面的配置信息,第二次做的时候,配置起来有少许的出入,so懂理论就好了

    背景

    2016 年 10 月 25 日,zeit.co 背后的团队对外发布了 Next.js,一个 React 的服务端渲染应用框架。几小时后,与 Next.js 异曲同工,一个基于 Vue.js 的服务端渲染应用框架应运而生,我们称之为:Nuxt.js

    定义

    Nuxt.js 是一个基于 Vue.js 的通用应用框架。为基于 Vue.js 的应用提供生成对应的静态站点的功能。通过asyncData钩子函数可以生成利于seo优化的动静态站点

    搭建

    Nuxt.js团队创建了脚手架工具 create-nuxt-app

    确保安装了npx(npx在NPM版本5.2.0默认安装了):
    安装之前请先检查一下npm的版本

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

    或者用yarn :

    $ yarn create nuxt-app <项目名>
    

    npx create-nuxt-app nuxt1
    npx: 341 安装成功,用时 115.532 秒
    create-nuxt-app v2.10.1
    ✨ Generating Nuxt.js project in nuxt1
    1 Project name nuxt1
    2 Project description My doozie Nuxt.js project
    3 Author name smook
    4 Choose the package manager Npm
    5 Choose UI framework None
    6 Choose custom server framework None (Recommended)
    7 Choose Nuxt.js modules (Press <space> to select, <a> to toggle all, <i> to invert selection)
    8 Choose linting tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
    9 Choose test framework None
    10 Choose rendering mode Universal (SSR)
    11 Choose development tools (Press <space> to select, <a> to toggle all, <i> to invert selection)
    � Successfully created project nuxt1

    To get started:

        cd nuxt1
        npm run dev
    

    To build & start for production:

        cd nuxt1
        npm run build
        npm run start
    

    10步骤这里我的经验是选SSR,因为我本身就是奔着seo优化来的,所以SSR服务端渲染这块应该是这个

    -上面是一整个安装流程-nuxt官网都有,我多此一举多安装一遍而已

    安装完之后--项目目录如下:


    image.png

    ├── assets // 资源文件。用于组织未编译的静态资源入LESS、SASS 或 JavaScript

    ├── components // 组件。用于自己编写的Vue组件,比如滚动组件,日历组件,分页组件
    │ └── logo.vue // 默认logo组件

    ├── layouts // 布局。页面都需要有一个布局,默认为 default。它规定了一个页面如何布局页面。所有页面都会加载在布局页面中的 <nuxt /> 标签中。
    │ └── default.vue // 默认模板页面,类似mvc中的layout

    ├── middleware // 中间件。存放中间件。可以在页面中调用: middleware: 'middlewareName'

    ├── pages   // 页面。一个 vue 文件即为一个页面。也会根据pages里面的文件结构自动生成路由
    │ └── index.vue // 默认首页面

    ├── plugins // 用于存放JavaScript插件的地方,或者一些必要的配置,全局配置

    ├── static // 用于存放静态资源文件,比如图片,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。

    ├── store   // 用于组织应用的Vuex 状态管理。

    ├── .editorconfig // 开发工具格式配置

    ├── .eslintrc.js // ESLint的配置文件,用于检查代码格式

    ├── .gitignore // 配置git不上传的文件

    ├── nuxt.config.js // 用于组织Nuxt.js应用的个性化配置,比如网站title,已便覆盖默认配置

    ├── package.json // npm包管理配置文件

    └── README.md // 说明文档

    上面的结构是整个新建项目的目录图,和我网上找的和自己总结的目录中每个的作用

    现在我们运行下面的代码可以进行项目初体验

    cd nuxt1
    npm run dev
    

    然后好像默认的是localhost:3000,在浏览器打开就可以了

    修改局域网配置

    使用localhost:3000访问之后,有疑问的同学会发现,你发给在同一个局域网的同事,他们是打不开你的项目的,跟vue-cli创建的项目不一样!其实这里可以通过修改一下config来修改,具体配置如下:

    在package.json中新添加

    这个就是你本地的地址,同一局域网是访问不到
    "config": {
        "nuxt": {
          "host": "127.0.0.1",
          "port": "8080"
        }
      }
    
    这个是0.0.0.0配置之后,重新运行,同一局域网可以访问
    "config": {
        "nuxt": {
          "host": "0.0.0.0",
          "port": "8080"
        }
      }
    

    具体的效果,可以本地测试一下

    全局axios配置

    个人见解

    根据前面安装的步骤,已经安装了axios,或者可以去package.json中去检查一下

    npm install axios --save
    

    安装好之后在/plugins目录下新建baseUrl.js

    // 这里是一个默认的url,可以没有
    let baseUrl = ''
    
    // window对象要在.vue文件的mounted生命周期之后才可以获取,mounted之前就不行
    // let hostnames = location.hostname   
    // process
    switch (process.env.NODE_ENV) {
      case 'development':
        // 开发环境url
        baseUrl = 'https://开发域名'
        break
      case 'production':
        // 生产环境url
        baseUrl = 'https://生产域名'
        break
    }
    
    export default baseUrl
    
    

    然后再在/plugins目录下新建axios.js

    import * as axios from 'axios'
    import qs from 'qs'
    import baseUrl from './baseUrl'
    
    axios.defaults.baseURL = baseUrl
    axios.defaults.timeout = 20000
    // 默认是否允许携带cookie
    axios.defaults.withCredentials = true
    axios.defaults.headers = {
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    }
    
    axios.interceptors.request.use(
      config => {
        // 若是有做鉴权token , 就给头部带上token
        // var token = localStorage.getItem('token')
        // if (token !== null) {
        //   if (token !== '') {
        //     config.headers.token = token
        //   }
        // }
        // store.dispatch('showLoading', '加载中')
        return config
      },
      error => {
        // store.dispatch('hideLoading')
        return Promise.reject(error)
      }
    )
    
    axios.interceptors.response.use(
      response => {
        // let getVisitor = localStorage.getItem('getVisitor')
        // if (getVisitor === '游客') {
        //   if (response.data.code === 400) {
        //     return Promise.reject({
        //       message: response.data.msg
        //     })
        //   }
        // } else if (getVisitor === null) {
        //   if (response.data.code === 400) {
        //     router.push({
        //       name: 'auth'
        //     })
        //     return Promise.reject({
        //       message: response.data.msg
        //     })
        //   }
        // }
        return response
      },
      error => {
        if (!error.response) {
          return Promise.reject ({
            message: '请求无响应'
          })
        }
        let message
        switch (error.response.status) {
          case 400:
            message = '错误请求'
            break
          case 401:
            message = '未授权'
            break
          case 403:
            message = '拒绝访问'
            break
          case 404:
            message = '请求路径未找到'
            break
          case 500:
            message = '服务器异常'
            break
          default:
            message = '未知错误'
        }
        return Promise.reject(error)
      }
    )
    
    const http = {
      get (url, payload = undefined) {
        return axios({
          method: 'get',
          url: url,
          params: payload,
          paramsSerializer: params => {
            return qs.stringify(params, { indices: false })
          }
        })
      },
      post (url, payload = undefined) {
        return axios({
          method: 'post',
          url: url,
          data: payload,
          transformRequest: [
            data => {
              return qs.stringify(data, { indices: false })
            }
          ]
        })
      },
      put (url, payload = undefined) {
        return axios({
          method: 'post',
          url: url,
          data: payload
        })
      },
      delete (url, payload = undefined) {
        return axios({
          method: 'delete',
          url: url,
          data: payload
        })
      },
      postJson (url, payload = undefined) {
        return axios({
          method: 'post',
          url: url,
          data: payload,
          headers: {
            'Content-Type': 'application/json;charset=UTF-8'
          }
        })
      },
      postFile (url, payload = undefined) {
        return axios({
          method: 'post',
          url: url,
          data: payload,
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        })
      },
      all (promises) {
        return Promise.all(promises)
      },
      getBase () {
        return baseUrl
      }
    }
    
    export default http
    
    

    这里还需要安装qs

    npm install qs --save
    

    然后再在/plugins目录下新建main.js

    
    // 设置全局变量
    import Vue from 'vue' // vue 文件引入 - 方便在vue方法内容直接 this 调取
    import http from './axios'
    
    // 全局http
    let mainHttp = {
        install(Vue){
            Vue.prototype.$http = http  // 变量的内容 后期可以在vue中 this->$api.xxx 使用
        }
    }
    
    Vue.use(mainHttp)
     
    // 这里是 为了在 asyncData 方法中使用
    export default ({ app }, inject) => {
        // Set the function directly on the context.app object
        app.$http = http
    }
    

    现在配置完了,看一下/plugins目录的文件结构


    image.png

    然后在nuxt.config.js中plugins注册一下

    plugins: [
        {
          src: '~/plugins/main',
          ssr: true
        }
      ],
    

    然后我们来看.vue文件中,接口的使用和调用
    asyncData

    <template>
      <div
         class="recent_lists"
         @mouseenter="moveB($event)"
         @mouseleave="moveO($event)"
         v-for="(item, index) of testList"
         :key="index">
          <div class="lists_info">
            <li>{{item.exam_name}}</li>
            <a :href="item.enroll_url" v-if="item.enroll_url">{{item.exam_enroll}}</a>
            <li v-else>{{item.exam_enroll}}</li>
            <a :href="item.result_url" v-if="item.result_url">{{item.exam_result}}</a>
            <li v-else>{{item.exam_result}}</li>
            <a :href="item.face_url" v-if="item.face_url">{{item.exam_face}}</a>
            <li v-else>{{item.exam_face}}</li>
            <li v-show="item.course_ids" @click="getTestInfo(item.id, item.course_ids)">课程推荐</li>
          </div>
          <div
             class="lists_map"
             :class="item.key">
              <li>{{item.city_names}}</li>
              <li>{{item.cate_name}}</li>
           </div>
          <div class="recent_line"></div>
      </div>
    </template>
    
    export default{
      async asyncData (params) {
      //  这里通过params.app 就可以找到我们注册的全局$http
     //  因为asyncData方法里面不能读取和使用this关键字,所以我们只能使用
     //  params这个全局属性来获取全局变量
        // console.log(params.app.$http)
        let { data } = await params.app.$http.post('/course/getExamLists', ({
          is_top: 1,
          page: 1,
          page_count: 6
        }))
        console.log(data.data.length)
        return { testList: data.data }
      },
    }
    
    //我测试的是接口这里的传参的参数,我没办法从data()中获取,
    //所以我是写死的,然后就是我这里的接口和下面正常接口是一起加载的,
    //当然这个asyncData是在dom渲染之前就已经加载了,
    //然后这里的testList也不用在data()中定义,因为它运行的时候,data()压根就还没开始运行
    //如果不写这个asyncData函数的话,项目在浏览器运行的时候,右键查看源代码,压根源代码里就没有这个接口渲染的dom节点,所以这个方法是必然
    //而下面的正常接口方法,是实现功能的正常接口,asyncData在dom渲染之前就执行了,
    //所以后续的逻辑操作根绝压根用不到它,我个人理解,他的作用就是为了渲染源码dom
    //特指接口渲染的dom
    

    正常的接口调用

    methods: {
        Course () {
          // this.$qs.stringify
          //  这里接口调用只用this.$http就可以随意使用post或者get等等
          this.$http.post('/course/getExamLists', {
            is_top: 1,
            page: this.page,
            page_count: this.page_count
          }).then((res) => {
            this.testList = res.data.data
            this.allNum = res.data.all_num
            if (this.allNum > 0) {
              this.allNum = Math.ceil(Number(this.allNum) / Number(this.page_count))
            }
            this.testList.map((r, index) => {
              for (const key in this.list[0]) {
                if (Number(key) === Number(r.city_id)) {
                  this.testList[index].city_names = this.list[0][key]
                  this.testList[index].key = 'sx' + key
                }
                if (Number(key) === Number(r.province_id) && Number(r.city_id) === 0) {
                  this.testList[index].city_names = this.list[0][key]
                  this.testList[index].key = 'sx' + key
                }
              }
            })
          })
        },
    }
    

    在这里要提一句,上面这种方式,前提是在你设置了同一局域网可以访问的那个配置之后才可以的,不然会报错的,错误好像是什么127.0.0.1:80,所以上面文章不仔细看的,到这里运行报错我只能说,啊,好爽,走我的老路

    还有就是子组件,在子组件中是不可以使用asyncData函数的,因为子组件搭建的时候是放在components目录下面的,而不是pages目录下,所以子组件不可以使用,但是我们可以在父组件中使用asyncData函数,然后通过props函数接收。但是这种有一个问题就是通过props渲染子组件,浏览器查看源代码的时候是没有渲染的这一块的dom结构的,所以不利于seo优化,除非是这个组件的内容是不准备让爬虫爬取的

    这是官方的解释---仅限于页面组件


    image.png

    swiper组件安装

    因为nuxt里面window对象必须在mounted生命周期之后使用,所以这里使用的轮播插件是vue-awesome-swiper

    安装

    npm install vue-awesome-swiper --save
    

    安装完之后在/plugins目录下新建swiper.js--文件名字随意

    import Vue from 'vue'
    import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'
    
    Vue.use(VueAwesomeSwiper)
    

    然后再在nuxt.config.js中注册一下

    module.exports = {
      // some nuxt config...
      plugins: [
        { src: '~/plugins/swiper.js', ssr: false },
      ],
      // some nuxt config...
      css: [
        'swiper/dist/css/swiper.css'
      ],
      // some nuxt config...
    }
    这里的ssr要设置成false,如果为true的话可能会报window is undefined类似的错误
    

    然后就是在.vue的文件中写轮播了

    <template>
      <!-- You can find this swiper instance object in current component by the "mySwiper"  -->
      <div v-swiper:mySwiper="swiperOption">
         <div class="swiper-wrapper">
           <div class="swiper-slide" v-for="(item, index) in banner" :key="index">
             <a :href="item.link" target="_blank">
               <img :src="item.image_url" :alt="item.description">
             </a>
           </div>
         </div>
         <div class="swiper-pagination" slot="pagination"></div>
       </div>
    </template>
    
    <script>
      export default {
        data () {
          return {
            swiperOption: {
              loop: true,
              autoplay: {
                delay: 3000
              },
              pagination: {
                el: '.swiper-pagination',
                clickable: true,
                // 自定义分页器, bulletClass 是常规的分页名字, bulletActiveClass是active时候的名字
                bulletClass: 'my-bullet',
                bulletActiveClass: 'my-bullet-active'
              }
            },
            banners: []
          }
        },
        created () {
          this.Infor()
        }
        mounted() {
          Infor () {
            this.$http.post('/index/wwwIndex').then((result) => {
              this.banner = result.data.data.pc_www_top_banner.img_lists
            })
          }
        }
      }
    </script>
    
    //这里的样式可能不太对,所以不要太在意,我这里写是为了说明一个原因
    //是style中的scoped要去掉,如果要自定义按钮的话
    //我这里的.my-bullet和.my-bullet-active是自定义的按钮,如果scoped不去掉的话,是没办法在轮播中显示的!唯一的遗憾
    <style lang="scss">
    .swiper-pagination{
      height: 20px;
      display: flex;
      flex-direction: row;
      align-items: center;
      // justify-content: center;
      z-index: 9;
      box-sizing: border-box;
      padding-left: 400px;
    }
    .swiper-pagination .my-bullet{
      // border-radius: 50%;
      width: 30px;
      height: 4px;
      margin: 4px;
      background: rgba(0,0,0,0.35);
      display: block;
    }
    .swiper-pagination .my-bullet-active{
      display: block;
      background: rgba(0,0,0,0.75);
      width: 30px;
      height: 4px;
      // border-radius: 2px;
    }
    .my-swiper {
       height: 300px;
       width: 100%;
       .swiper-slide {
         text-align: center;
         font-size: 38px;
         font-weight: 700;
         background-color: #eee;
         display: flex;
         justify-content: center;
         align-items: center;
      }
      .swiper-pagination {
         > .swiper-pagination-bullet {
           background-color: red;
         }
       }
    }
    </style>
    

    问题1:

    有时候点击分页器,轮播就不能继续了,根本原因是是少了一个属性

    autoplay: {
      delay: 5000,
    //加上这句就好了
      disableOnInteraction: false
    },
    

    asyncData一次请求多个接口怎么办,asyncData多并发请求如下:

    async asyncData (ctx) {
        let [data, data1, data2, data3] = await Promise.all([
          ctx.app.$http.post('/index/wwwIndex'),
          ctx.app.$http.post('/course/getExamLists', {
            is_top: 1,
            page: 1,
            page_count: 6
          }),
          ctx.app.$http.post('/news/newsLists', {
            news_type: 1,
            is_top: 1
          })
        ])
        // console.log(data2.data)
        // testList: data.data,
        return {
          banner: data.data.data.pc_www_top_banner.img_lists,
          testList: data1.data.data,
          newList: data2.data.data,
          teacher_lists: data.data.data.teacher_lists,
          knowList: data.data.data.link_article_list
        }
    

    swiper插件也可以单纯的使用swiper组件,这个不需要上面swiper的Vue.user(swiper)注入,
    只需要在nuxt.config.js中把css注入就好了,然后在.vue文件中直接import swiper from 'swiper'
    就可以正常使用swiper了,我写这篇文章的页面有很多轮播,就不多做介绍了,自己摸索,都差不多

    引入字体包

    在/assets目录下新建 font文件夹把字体文件放进去,同事新建一个css/scss文件font
    font.scss

    @font-face {
      font-family: 'DIN Alternate Bold';
      src: url('DINAlternateBold.ttf');
      font-weight: normal;
      font-style: normal;
    }
    
    

    然后在nuxt.config.js中注入路径

    css: [
        '@/assets/font/font.scss'
    ]
    

    这样在.vue文件中,就可以使用了

    .foot_right .top1 li p{
      font-size: 20px;
      font-family:'DIN Alternate Bold';
      margin-bottom: 4px;
    }
    
    image.png

    这里有个地方需要注意一下,在vue-cli脚手架下面,font文件夹下面的字体文件名字是可以识别空格的,例如'DIN Alternate Bold.ttf。但是在nuxt中要重命名,把空格去掉,不然会一直报错

    路由配置传参(动态路由)--以及generate打包

    这个路由配置比较麻烦一点,由于不熟悉花了将近2天的时间来搞这个

    前面介绍了/pages目录的设计会自动生成路由,去.nuxt目录下的route.js就可以看到,今天要说的就是参数的传递(动态路由)和generate打包生成静态页面

    以我项目为例
    http://192.168.0.150:8080/exam/2340/0这是本地的链接,/exam/2340/0其中的2340和0是传入的参数id和cid,/exam/是要跳转的路由

    配置如下

    就是在/pages目录下新建exam文件夹,然后在exam中新建_id文件夹,然后在_id文件夹中新建_cid.vue文件,保存之后可以去/.nuxt目录下打开route.js,里面的路由已经自动生成,文件路径和路由如下图

    image.png
    image.png

    然后在_cid.vue中随便写几个字,打开/exam/2340/0就可以看到了,文件配置完成

    这里要注意下,this.$route.name获取的路由名称不再是exam,而是exam-id-cid

    路由页面获取参数

    这里做的功能是城市和类型选择,遍历拼接的地址

    在_cid.vue中,路由的跳转,在nuxt中是使用<nuxt-link></nuxt-link>,用法跟<router-link></router-link>一样
    本地的项目是如下图


    image.png
    image.png

    上面的路由跳转是:to=""拼接的路由路径,参数就是接口的id,cid。id是地区的标志,cid是类型的标志

    咱们做的项目优化nuxt的是以seo优化为前提的,所以要使用asyncData()来渲染dom和head(),但是我们前面知道asyncData()是不能获取data中的参数的,

    但是如果是路由传参,这里可以是可以接受参数的,如下图

    image.png

    用上图的这种写法,传入参数{app, params},app这里是前面ctx下面的app结构。params就是要接受的参数
    使用console.log(params)打印可以看到浏览器控制台打印出{id: 2340, cid: 0},这样前面遍历的地区就可以获取参数了,这样的话,我不管是点击地区或者类型,参数都会传过来,这样浏览器查看源代码就可以看到渲染了dom。

    开发中遇到一个问题,就是刷新浏览器的时候报错,request to....500,记不太清楚了!这个错误的原因是asyncData()方法在项目运行的时候,请求到的接口有问题,跟前端无关,跟前端无关,跟前端无关,说三遍。不要傻乎乎的在前端配置文件或者代码中找错误,是接口的问题!把asyncData()方法注释,在methods钩子函数中走一遍方法,F12,network中查看接口请求,就可以看到接口报错了!这时候通知后台修改接口!

    generate打包

    动态传参完成之后,我们要验证我们之前写的asyncData()渲染的dom是否发布到线上也能正常渲染

    //运行
    npm run generate
    

    预期的打包之后的结构是exam->下面有很多id子文件夹,id子文件夹里面有cid文件夹,cid文件夹里面是index.html,结构如下:


    image.png

    我们看到项目中多了一个dist文件夹,。这就是generate之后的打包的文件,但是我们在项目中真正看到的结果并不是这个样子的,并没有exam文件夹,或者/exam里面一个exam.vue

    不能显示的真正原因是因为没有配置generate属性

    在nuxt.config.js中设置generate属性配置

    我们这里先写死这几个
    export default {
      generate: {
        routes: [
          '/exam/2340/0',
          '/exam/2341/0',
          '/exam/2352/0'
        ]
      }
    }
    

    上面设置了这三条之后,再运行npm run generate . 生成的dist文件夹中的路径,就跟我前面的那张图结构一样了,这样你把dist文件夹内容放到线上,这三个路由切换的时候,右键查看源代码就可以看到渲染的dom了,下图是线上查看源代码之后的dom结构

    image.png

    然后如果有成百上千路由的话,可以和后台配合合作,大致就是后台通过接口给你返回所有的可配置的路由,你配置到generate里面,然后就可以了,这块我项目还没做到,过两天再更新

    下面来说一下动态路由打包的利弊

    上面说过,nuxt.config.js文件中配置了generate属性,打包上线的时候,会根据这个配置生成静态文件,从而实现seo的dom和head渲染,这种方法是与后台接口配合,大致就是,接口提供给你要做的所有的需要seo优化的页面的路由,通过generate配置,打包的时候请求接口,返回路由路径,生成静态文件,如下图


    image.png

    然后这个接口返回的路由数据,如下图


    image.png

    这样npm run generate打包之后,会生成dist文件夹,dist文件夹格式如下图


    image.png
    image.png

    这样发布到线上,打开页面右键---查看源代码,就可以看到dom结构和head了。

    开发(本地)和生产(线上)的环境配置

    上面看到我的generate配置里面使用了process.env.BASE_URL,这个其实是配置了开发和生产环境的部署,需要安装一个依赖cross-env

    npm install cross-env --save
    

    安装完成之后先去package.json中配置一下scripts属性

    "scripts": {
        "dev": "cross-env BASE_URL=https://测试.cn NODE_ENV=development nuxt",
        "test": "cross-env BASE_URL=https://测试.cn NODE_ENV=production nuxt generate",
        "build": "nuxt build",
        "start": "nuxt start",
        "generate": "cross-env BASE_URL=https://生产.cn NODE_ENV=production nuxt generate"
      },
    

    最前面配置的全局axios中/plugins/axios.js要去掉一些语句和修改下

    注释掉baseUrl的加载和默认baseURL配置
    import * as axios from 'axios'
    import qs from 'qs'
    // import baseUrl from './baseUrl'
    
    // axios.defaults.baseURL = baseUrl
    axios.defaults.timeout = 20000
    // 默认是否允许携带cookie
    axios.defaults.withCredentials = true
    axios.defaults.headers = {
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    }
    

    然后axios.js后面的请求方法中添加上process.env.BASE_URL

    get (url, payload = undefined) {
        return axios({
          method: 'get',
          url: process.env.BASE_URL + url,
          params: payload,
          paramsSerializer: params => {
            return qs.stringify(params, { indices: false })
          }
        })
      },
      post (url, payload = undefined) {
        return axios({
          method: 'post',
          url: process.env.BASE_URL + url,
          data: payload,
          transformRequest: [
            data => {
              return qs.stringify(data, { indices: false })
            }
          ]
        })
      },
    

    然后再在nuxt.config.js中添加一下env配置

    export default {
      mode: 'universal',
      env: {
        BASE_URL: process.env.BASE_URL,
        NODE_ENV: process.env.NODE_ENV
      }
    }
    

    这样就好了,.vue文件中的请求接口方式不变,这样项目运行或者打包的话,就可以把package.json中的配置的cross-env进行全局适配,要知道nuxt中配置文件中window和location.name是访问不到的,所以这种办法是很方便的!

    我上面配置的不全,感兴趣的可以去搜搜别的攻略
    使用npm run dev这是运行的本地(开发)环境,接口域名对应的是测试接口
    使用npm run test这是打包测试的,然后发布到测试环境,同样的接口也是使用的测试接口---注意后面的nuxt generate
    使用npm run generate这是打包正式的,然后发布到测试,测试没问题之后,再发布到正式,接口域名是正式(线上)接口

    并不是最终的优化方案

    但是上面这个也有一个弊端,并不能做到真正的动态化!你想,如果我的后台操作系统,添加了一篇文章,那么在前台显示的时候,这篇文章是一个新的路由/路径,那么这个新增的文章,后台添加完成之后,前台是看不到seo的效果的,要再重新打包一次,发布线上才可以,还有就是如果文件,和路径少了还好说,如果有上千,上万,几百万的时候,生成的静态文件我觉得服务器会爆炸,所以我的建议如果要使用nuxt,就要考虑你是否是要真正的实现动态化seo优化。看了b站的,还有掘金的,目前还没搞懂他们的技术点。所以建议是服务端渲染,通过后台或者node渲染生成html,渲染到前台!

    后续配置和操作优化seo持续更新

    相关文章

      网友评论

          本文标题:nuxt基于vuejs的seo动静态优化

          本文链接:https://www.haomeiwen.com/subject/mcohuctx.html