vue seo优化之nuxt脱坑指南

前言

公司的项目需要做seo,经过翻阅nuxt文档 、相关资料及自己实战后,特意整理分享这篇文章,方便入坑的同学脱坑,同时自己也做下笔记,如有说错的地方,还望指点。

没有了解过seo和ssr服务器渲染的同学,建议先把基础知识给补一下

vue ssr指南  ssr相关知识

站长工具 查相关网站的seo 收录

nuxt中文网 nuxt中文网

一、nuxt和vue有什么区别?

1.服务器端渲染和客户端渲染

Nuxt: ssr(服务器端渲染),正如字面上的意思,需要把自己编写的代码放在服务器上跑,对服务器性能有一定的要求,需要node环境配合pm2 nginx部署;

vue: spa单页应用程序(客户端渲染),npm run build 成功后即可把dist目录的静态文件放在服务器部署;

2.应用框架

Vue多数用于开发spa单页应用程序,不利于搜索引擎的seo操作;对ssr服务器端渲染的支持并不是很友好,听说在vue3会对这方面有很大的提高,这也让我很期待;

而nuxt简单来说,就是在vue的基础上加上了服务器端渲染的能力,再扩展自己的特点,如生命周期 路由 es2015+语法支持等

二、nuxt项目搭建和配置

1.项目搭建

为了快速入门,Nuxt.js团队创建了脚手架工具 create-nuxt-app。

npn create-nuxt-app <项目名>

详细流程可以参考nuxt官网,在此就不累赘说明了

2.nuxt.config.js配置文件

module.exports = {

 globalName: "hq",

 mode: "universal",

 server: {

   port: 3000,

   // host: "127.0.0.1"

   host: "localhost"

 },

 // buildDir: 'nuxt-dist', // Build 发布目录

 /*

  ** Headers of the page

  */

 head: {

   title: "",

   meta: [

     { charset: "utf-8" },

     /*优先使用 IE 最新版本和 Chrome*/

     { "http-equiv": "X-UA-Compatible", content: "IE=edge,chrome=1" },

     { name: "format-detection", content: "telephone=no" },

     { hid: "renderer", name: "renderer", content: `webkit` },

     {

       hid: "viewport",

       name: "viewport",

       content:

         "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0,user-scalable=no"

     },

     {

       hid: "keywords",

       name: "keywords",

       content: ` `

     },

     {

       hid: "description",

       name: "description",

       content:

         ""

     }

   ],

   // 使用外部资源文件,自动生成 script 标签

   script: [],

   link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }]

 },

 /*

  ** Customize the progress-bar color

  */

 loading: { color: "#fa6e32", height: "2px" },//进行ajax请求时顶部进度条的颜色

 render: {

   resourceHints: false

 },

 /*

  ** Global CSS

  */

 css: [

   { src: "ant-design-vue/dist/antd.less", lang: "less" },

   "~/assets/css/common.css",

   "~/assets/css/hover.css",

   "~/assets/iconfont/iconfont.css",

   { src: "~/assets/scss/public.scss", lang: "scss" },

   { src: "~/assets/less/theme.less", lang: "less" }

 ],

 /*

  ** 引入插件

  ** ssr: false 表示只在客户端生效

  */

 plugins: [

   "@/plugins/antd-ui",

   "@/plugins/router",

   "@/plugins/axios.js",

   { src: "@/plugins/polyfill", ssr: false },

   { src: "@/plugins/vueQr.js", ssr: false },

   { src: "@/plugins/vue-lazyload.js", ssr: false  },

   { src: "@/plugins/swiper.js", ssr: false }

 ],

 // 配置路由中间件

 router: {

   middleware: ["i18n"]

   // base:"/en/"

   // base:"/"

 },

 /*

  ** Nuxt.js dev-modules

  */

 buildModules: [

   // Doc: https://github.com/nuxt-community/eslint-module

 ],

 /*

  ** Nuxt.js modules

  */

 modules: [

   // nuxt 模块扩展

   // Doc: https://axios.nuxtjs.org/usage

   "@nuxtjs/axios",

   "@nuxtjs/style-resources",

   ["cookie-universal-nuxt", { parseJSON: false }]

 ],

 styleResources: {

   //预处理器配置 一般用于加载全局变量之类

   // style

   stylus: "./assets/css/css.styl",

   scss: ["./assets/scss/public.scss"]

 },

 /*

  ** Axios module configuration

  ** See https://axios.nuxtjs.org/options

  */

 axios: {

   // 是否允许跨域

   proxy: true

 },

 proxy: {},

 /*

  ** Build configuration

  */

 build: {

   vendor: ["axios"], // 为防止重复打包

   transpile: [/^ant-design-vue/],

   //提取css到单独link文件

   extractCSS: {

     allChunks: true

   },

   loaders: {

     less: {

       javascriptEnabled: true,

       /**

        * ant-design-vue 修改样式变量

        */

       modifyVars: {

         "primary-color": "#fa6e32" // 全局主色

       }

     }

   },

   /*

    ** You can extend webpack config here

    */

   extend(config, ctx) {}

 }

};

3.axios配置

import { notification, Modal } from "ant-design-vue";

import configSettings from "@/config/defaultSettings";

import { getToken} from "@/utils/fn";

import { isBrowser } from "~/environment";

const ERRORS = new Map([

 [500, "服务器异常..."],

 [404, "未找到对应资源"],

 [401, "未鉴权"]

]);

export default function({ $axios, redirect, store }) {

 // 基本配置

 // $axios.defaults.baseURL = 'https://xxxx'; //正式

 $axios.defaults.baseURL = "http://xxxx:8070"; //测试

 $axios.defaults.timeout = 20000;

 // 请求回调

 $axios.onRequest(config => {

   const token = getToken();

//设置请求头公共toeken

   if (token) {

     config.headers.common[configSettings.token] = token;

   }

   return config;

 });

 // 返回回调

 $axios.onResponse(response => {

   return res;

 });

 // 错误回调

 $axios.onError(error => {

   return Promise.reject(error.response);

 });

}

4.默认HTML文件

在根目录下新建app.html





 

 

   

   

   

   {{ HEAD }}

 

 

   {{ APP }}

 

 


app.html跟vue脚手架生成后的public目录里面的index.html是一样的功能,只不过nuxt的脚手架没有默认生成该文件,注意:这里的{{HEAD}} 、{{APP}}是区别大小写的,不要去动他;

5.配置error页面

在根目录找到layouts并创建error.vue文件


</p><p>export default {</p><p> name: 'Error',</p><p> props: ['error'],</p><p> computed: {},</p><p> data() {</p><p> return {</p><p> type: {</p><p> 403: {</p><p> img:</p><p> "https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg",</p><p> title: "403",</p><p> desc: "抱歉,你无权访问该页面",</p><p> },</p><p> 404: {</p><p> img:</p><p> "https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg",</p><p> title: "404",</p><p> desc: "抱歉,你访问的页面不存在或仍在开发中",</p><p> },</p><p> 500: {</p><p> img:</p><p> "https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg",</p><p> title: "500",</p><p> desc: "抱歉,服务器出错了",</p><p> },</p><p> },</p><p> };</p><p> },</p><p> mounted() {</p><p> },</p><p> methods: {}</p><p>}</p><p>

</p><p> @import "~ant-design-vue/lib/style/index";</p><p> .exception {</p><p> display: flex;</p><p> align-items: center;</p><p> height: 80%;</p><p> min-height: 500px;</p><p> .imgBlock {</p><p> flex: 0 0 56.5%;</p><p> width: 56.5%;</p><p> padding-right: 152px;</p><p> zoom: 1;</p><p> &::before,</p><p> &::after {</p><p> content: ' ';</p><p> display: table;</p><p> }</p><p> &::after {</p><p> clear: both;</p><p> height: 0;</p><p> font-size: 0;</p><p> visibility: hidden;</p><p> }</p><p> }</p><p> .imgEle {</p><p> float: right;</p><p> width: 100%;</p><p> max-width: 430px;</p><p> height: 360px;</p><p> background-repeat: no-repeat;</p><p> background-position: 50% 50%;</p><p> background-size: contain;</p><p> }</p><p> .content {</p><p> flex: auto;</p><p> h1 {</p><p> margin-bottom: 24px;</p><p> color: #434e59;</p><p> font-weight: 600;</p><p> font-size: 72px;</p><p> line-height: 72px;</p><p> }</p><p> .desc {</p><p> margin-bottom: 16px;</p><p> color: @text-color-secondary;</p><p> font-size: 20px;</p><p> line-height: 28px;</p><p> }</p><p> .actions {</p><p> button:not(:last-child) {</p><p> margin-right: 8px;</p><p> }</p><p> }</p><p> }</p><p> }</p><p> @media screen and (max-width: @screen-xl) {</p><p> .exception {</p><p> .imgBlock {</p><p> padding-right: 88px;</p><p> }</p><p> }</p><p> }</p><p> @media screen and (max-width: @screen-sm) {</p><p> .exception {</p><p> display: block;</p><p> text-align: center;</p><p> .imgBlock {</p><p> margin: 0 auto 24px;</p><p> padding-right: 0;</p><p> }</p><p> }</p><p> }</p><p> @media screen and (max-width: @screen-xs) {</p><p> .exception {</p><p> .imgBlock {</p><p> margin-bottom: -24px;</p><p> overflow: hidden;</p><p> }</p><p> }</p><p> }</p><p>

三、nuxt生命周期

Nuxt.js 是一个基于 Vue.js 的通用应用框架,支持vue生命周期的同时,扩展了服务端的钩子,特别是asyncData,使得你能够在渲染组件之前异步获取数据。

export default {

 middleware () {}, //服务端

 validate () {}, // 服务端

 asyncData () {}, //服务端 nuxtjs进行服务器渲染关键钩子,只支持page目录下的文件,不支持components目录下的组件

 fetch () {}, // store数据加载

 beforeCreate () {  // 服务端和客户端都会执行},

 created () { // 服务端和客户端都会执行 },

 beforeMount () {},

 mounted () {} // 客户端执行

}

四、页面模板

export default {

 components: { },

 head() {

   return {

     title: this.college.title,

     meta: [

       {

         hid: 'description',

         name: 'description',

         content: this.college.title

       },

       {

         hid    : 'keywords',

         name   : 'keywords',

         content: this.college.title

       }

     ]

   }

 },

 watchQuery: ['collegeId'],//路由上该参数发生改变时,asyncData fetch 会重新执行

 async asyncData({app}) {

   const query = app.context.query;

   let [college,'回调1','回调2'] = await Promise.all([

     app.$axios.get('/web/api/college', {

       params: {

         collegeId: query.collegeId,

       }

     }),

     //可多个请求

   ]);

   return {

     college:college,

   }

 },

 data() {

   return {};

 },

 created() {},

 watch: {},

 mounted() {

 },

};

五、项目部署

1.确保本地代码无误后,运行命令打包,成功后会在根目录出现 .nuxt的目录;

npm run build

2.除了node_modules和其他没必要的文件夹以外,其他文件全部上传到服务器新建好的目录下

nuxt文件目录.png

3.安装nodejs

4.在上传的根目录里cmd运行命令安装依赖包

npm install -production

5.运行npm start,出现http://localhost:3000 证明成功,在服务器访问预览正常后即可关闭服务

npm start

6.安装pm2,没有了解过这个的东西可以先百度下 了解更多pm2

npm i pm2 -g

7.设置pm2开机自启

安装并配置pm2-windows-service

npm i -g pm2-windows-service

添加系统环境变量(右键 [我的电脑] - [属性] - [高级系统设置] - [环境变量] - 新建 [系统变量] )

PM2_HOME=C:\Users\Administrator.pm2 //路径默认在当前用户下的.pm2

以管理员权限打开新的cmd命令行窗口,执行以下命令来安装服务

pm2-service-install

提示Perform environment setup ? 选 n, 继续,此时, PM2服务已安装成功并已启动, 可以通过 [win + r] - [services.msc]

来查看,服务名称为PM2

8.使用pm2在根目录启动nuxt项目,很多人因为命令报错会卡在这里,这里就相当于第五点的npm start ,

启动成功后,再运行pm2 save,

pm2 start ./node_modules/nuxt/bin/nuxt.js -- start //启动项目nodejs服务

pm2 save //保存当前pm2 正在启动的NodeJS服务

9.配置Nginx

完成以上操作后,基本上已经结束了,接下来需要用Nginx配置下项目,没有安装的同学可自行百度;

worker_processes  1;

   events {

       worker_connections  1024;

   }

   http {

       include       mime.types;

       default_type  application/octet-stream;

       sendfile        on;

       keepalive_timeout  65;

       upstream nodenuxt {

           server 127.0.0.1:3000; # nuxt 项目启动后地址

           keepalive 64;

       }

       server {

           listen       80;

           server_name  www.baidu.com;#项目的域名

           location / {

               proxy_http_version 1.1;

               proxy_set_header Upgrade $http_upgrade;

               proxy_set_header Connection "upgrade";

               proxy_set_header Host $host;

               proxy_set_header X-Nginx-Proxy true;

               proxy_cache_bypass $http_upgrade;

               proxy_pass http://nodenuxt;

           }

       }

   }

修改配置文件后再重新启动Nginx,如果出现报错,应该是服务器的80端口被占用了,可修改配置文件的listen 端口,也可以查看是哪个服务占用再去禁用该服务,看个人项目需求

start nginx //启动nginx

nginx -s reload //重新载入nginx(当配置信息发生修改时)

nginx -s quit //停止nginx

nginx -h 查看帮助信息

nginx 启动成功后,就可以通过域名访问项目了,大功告成!

总结

本文并非原创,欢迎转载,记录下学习nuxt的过程,也可以让入门的同学少走弯路,后面有时间我会整理相关nuxt的代码发布一套demo出来给大家参考,希望能帮助到大家,拜拜!

——By

kkc_hq


本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):