vue2项目SEO优化指南
nuxt是一个基于node和vue的ssr框架,运行在node环境
公司要求vue2官网做seo优化,2025年nuxt的默认版本是4.x,不支持vue2。因此选择nuxt2版本
nuxt2官网地址:v2.nuxt.com/ ,没有官翻中文文档,加上部署有些坑,因此整理本文档供记录和参考。
1. 创建项目
- 1.1 Node版本:目前已知的支持nuxt2的node版本:v16.20.2,这也是我用的服务器最高支持的版本
- 1.2 新建一个目录 取名
nuxt-ssr,也可以根据自己需要取名 - 1.3
cd nuxt-ssr - 1.4 创建一个
package.json文件,内容如下:
{
"name": "my-app",
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"generate": "nuxt generate",
"start": "nuxt start"
},
"dependencies": {
"nuxt": "^2.18.1"
},
}
- 1.5 安装依赖
npm install - 1.6 在根目录新建一个
/pages目录,用于存放路由文件。
mkdir pages
touch pages/index.vue
不习惯命令行创建也可以手动新建文件夹
创建一个index.vue文件,内容如下:
<template>
<h1>Hello world!</h1>
</template>
执行npm run dev启动项目
访问http://localhost:3000/,就可以看到你的Hello world页面了
2.路由配置
- 2.1 用脚手架创建的话,nuxt2项目会自动生成一个
/pages目录,用于存放路由文件。手动创建的话没有,就自己手动建一个。 - 2.2 路由示例:
-| pages/
---| index.vue
---| posts.vue
---| posts/
-----| _slug.vue
-----| index.vue
这样的目录会被nuxt自动解析为:
Route Page
/ ~/pages/index.vue
/posts ~/pages/posts.vue (parent) + ~/pages/posts.vue (child route)
/posts/ ~/pages/posts.vue (parent) + ~/pages/posts.vue (child route)
/posts/foo ~/pages/posts.vue (parent) + ~/pages/_slug.vue (child route)
/posts/foo/ ~/pages/posts.vue (parent) + ~/pages/_slug.vue (child route)
上面的解析说明是摘自nuxt官网的解释,其实简单一句话就是,浏览器访问/a/b,那么就会指向pages/a/b/index.vue这个文件解析后的页面。
- 2.3 路由基础路径,对应nginx的location。编辑
nuxt.config.js文件,并添加以下内容:
export default {
router: {
base: '/your-base-path/'
}
}
3. 添加全局静样式。编辑nuxt.config.js文件,并添加以下内容:
export default {
// 添加全局 Less 文件(可选)
css: [
'~/assets/less/main.less', // 你的全局 Less 文件路径
],
}
4. 使用element-ui。
- 4.1 安装element-ui。
npm install element-ui --save
- 4.2 引入element-ui。在plugin目录下新建一个element-ui.js文件,内容如下:
// plugins/element-ui.js
import Vue from 'vue';
// import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
import { Backtop, Timeline, TimelineItem,Carousel,CarouselItem,Dialog,Pagination } from 'element-ui'; // 只引入需要的组件
Vue.component(Backtop.name, Backtop);
Vue.component(Timeline.name, Timeline);
Vue.component(TimelineItem.name, TimelineItem);
Vue.component(Carousel.name, Carousel);
Vue.component(CarouselItem.name, CarouselItem);
Vue.component(Dialog.name, Dialog);
Vue.component(Pagination.name, Pagination);
// 全局注册 Element UI
// Vue.use(ElementUI);
其中被注释掉的是全局的注册方式,我的项目采用的是按需引入方式
- 4.3 编辑
nuxt.config.js文件,并添加以下内容:
export default {
// 添加全局 Less 文件(可选)
plugins: [
{ src: '~/plugins/element-ui', ssr: true },// SSR 模式
],
// 配置构建选项
build: {
...
babel: {
plugins: [
[
"component",
{
libraryName: "element-ui",
styleLibraryName: "theme-chalk"
}
]
]
},
}
}
- 4.4 使用element-ui。经过上述操作后就可以在vue文件中直接使用element-ui组件了
<el-backtop target=".el-main"></el-backtop>
<el-timeline>
5. 数据请求。推荐使用@nuxtjs/axios库
关于请求可以参考nuxt2官网:v2.nuxt.com/docs/direct…
- 5.1 安装@nuxtjs/axios库。
npm install @nuxtjs/axios --save
- 5.2 创建plugins目录,并添加axios.js文件,内容如下:
// plugins/axios.js
export default function ({ $axios, redirect }) {
$axios.onError(error => {
if (error.response.status === 500) {
redirect('/sorry') //这里是接口请求失败后的页面
}
})
}
- 5.3 编辑
nuxt.config.js文件,并添加以下内容:
// nuxt.config.js
export default {
...
modules: ['@nuxtjs/axios'],
plugins: ['~/plugins/axios.js']
}
- 5.4 使用axios。
做完以上操作,你会发现在vue文件中可以通过
this.$axios访问axios对象了。
注意: 凡是需要服务端完成的请求都要放在官方提供的fetch勾子中,或者在asyncData中完成。fetch推荐component目录下的vue文件使用,asyncData推荐在pages目录下的vue文件使用。 其中fetch勾子的用法:
<template>
<h1>{{ post.title }}</h1>
</template>
<script>
let baseUrl = 'xxxx' //java或者其他后端服务地址
export default {
data() {
return {
post: {}
};
},
async fetch ({ $axios, params }) {
const response = await this.$axios.get(baseUrl + 'aaa/bbb?id=' +'需要的参数')
if(response.status === 200){
this.post = response.data.data //这里只是示例,实际根据返回结构获取
}
},
fetchKey: 'join-us', //每个页面唯一
fetchOnServer: true, //设置为true代表服务器端渲染
}
</script>
asyncData的用法:(在表示页面的组件中)
export default {
name: "newsDetail",
data() {
return {
newsDetail: {}
};
},
async asyncData({ query, $axios }) {
const res = await $axios.get(baseUrl + '/ccc/ddd?id=' + '需要的参数')
if (res.data.code == 200) {
return { newsDetail: res.data.data }
}
},
fetchKey: 'news-detail',
fetchOnServer: true,
...
}
这样使用后,数据就会在服务端完成请求从而返回给浏览器完整的html。
6.部署服务器(通过宝塔面板)
- 6.1 打开宝塔面板,左侧菜单选择网站,选择node项目,点击node版本管理器,安装需要的node版本,本项目的版本是v16.20.2
- 6.2 创建一个目录,将以下文件放入:
package.json
nuxt.config.js
package-lock.json
- 6.3 执行npm install --production,安装生产所需要的依赖
- 6.4 在本地环境执行npm run build,生成.nuxt目录
- 6.5 上传.nuxt目录到服务器
- 6.6 在宝塔面板中创建一个node项目,目录就选我们上传的目录,启动命令为npm start
- 6.7 也可以用pm2启动
- 6.8 访问http:// + 你的IP或域名 + 你的routebase路径,即可看到页面
注意:调试出一个功能就要在服务器部署一下,看能不能正常用,比如第一个页面调好了,第一个二级路由调好了,第一个请求写好了,element-ui装好了,这些关键环节都建议在服务器上看效果后再继续,免得全部写完再部署发现一堆问题。
以上,nuxt项目就可以在服务端正常访问了,且访问时会返回完整的html内容而不是通过ajax从客户端请求。
7.关于页面源信息,带参数页面,二级页面等细节
-
7.1. 带参数页面如何处理参数并请求数据?
可以参考上面的asyncData的示例代码:
async asyncData({ query, $axios }) { const res = await $axios.get(baseUrl + '/ccc/ddd?id=' + query.id) if (res.data.code == 200) { return { newsDetail: res.data.data } } },
asyncData和fetch都会在参数中获取contenxt上下文,其中query属性就是页面的参数。
- 7.2. 页面源信息如何设置?
统一设置: 可以在nuxt.config.js中添加head属性,内容如下:
export default {
head: {
title: '****官网',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: 'my website description'
}
],
link: [{ rel: 'icon', type: 'image/png', href: '/sss/logo.png' }]
},
}
单独设置 可以在pages下面的文件中单独添加meta和其他head信息,例如在pages/index.vue中:
// pages/index.vue
<script>
export default {
head: {
title: 'Home page',
meta: [
{
hid: 'description',
name: 'description',
content: 'Home page description'
}
],
}
}
</script>
如果两种途径都设置了,单独设置的配置会优先生效。
-
7.3 二级页面跳转 有5种方式跳转:
- 7.3.1. nuxt-link跳转
<nuxt-link :to="`/detail/${item.id}`">{{ item.title }}</nuxt-link>- 7.3.2. 新页面跳转
const route = this.$router.resolve({ path:'/sss/aaa', query: { id: id } }) window.open(route.href, '_blank')- 7.3.3. a标签跳转:
<a href="/detail/1">跳转</a>- 7.3.4. 重定向(服务端跳转)
// 在中间件中 export default function ({ redirect }) { redirect('/detail/1'); } // 在页面逻辑中 async asyncData({ redirect }) { if (!userLoggedIn) { redirect('/login'); } }- 7.3.5. 客户端跳转:
window.location.href = `/detail/${id}`; //
8. 关于网站的robots.txt文件和sitemap.xml文件
robots.txt代表爬虫协议,sitemap.xml文件是网站地图文件,用于告诉爬虫网站有哪些页面。
- 8.1. 如何设置?分为静态和动态两种:先说下静态设置:
在项目根目录的 static/ 文件夹下创建 robots.txt(Nuxt 会自动将该文件夹下的文件映射到网站根路径),
User-agent: *
Allow: /
Sitemap: https://你的域名.com/sitemap.xml
在 static/ 下创建 sitemap.xml,内容示例:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://你的域名.com/</loc>
<priority>1.0</priority>
</url>
<url>
<loc>https://你的域名.com/about</loc>
<priority>0.8</priority>
</url>
</urlset>
注意如果nginx设置了代理,那么需要在域名后面加上你的代理路径,如:https://你的域名.com/proxy/
- 8.2. 接下来介绍一下动态生成方案(基于nuxt2.18.1)
npm install @nuxtjs/sitemap@2.4.0 --save
npm install @nuxtjs/robots@2.4.0 --save
在nuxt.config.js中添加以下代码:
export default {
...
modules: [ '@nuxtjs/robots', '@nuxtjs/sitemap'],
robots: {
UserAgent: '*',
Allow: '/',//允许爬虫访问代理路径下的所有内容
Disallow: ['/admin', '/test2', '/test3'],//屏蔽代理路径下的敏感目录
Sitemap: 'http://xxx.com/sitemap.xml'
},
// sitemap 配置
sitemap: {
hostname: 'http://xxx.com',//站点域名
exclude: ['/**'], // 禁用所有自动生成的路由,按需要配置
cacheTime: 1000 * 60 * 15, // 缓存15分钟
gzip: true, // 生成 sitemap.xml.gz
// 百度专用优化参数
baidu: true, // 启用百度专用扩展
defaults: {
changefreq: 'daily',
priority: 0.8,//优先级默认值
lastmod: new Date().toISOString() // 必须包含最后修改时间
},
routes: [
{ url: '/xxx/home', priority: 1 }, // 首页最高优先级
{ url: '/xxx/news', priority: 0.6 },
// 动态路由示例(需自行实现数据获取)
// ...getDynamicRoutes()
]
},
}
设置完成后执行
npm run build,然后将.nuxt目录上传到服务器,服务器执行npm install --production,将nuxt.config.js内容同步到服务器,然后在宝塔运行,访问 xxx.com/sitemap.xml 和 xxx.com/robots.txt 就可以在浏览器看到最新的sitemap.xml和robots.txt文件了。注意这个文件并不是静态的,而是是动态生成的,每次访问都会生成新的文件。
9. pm2 启动
创建ecosystem.config.js 文件
module.exports = {
apps: [
{
name: "my-nuxt-app",
script: "node_modules/nuxt/bin/nuxt.js",
args: "start",
exec_mode: "fork", // 或 "cluster"(多进程)
instances: 2,
autorestart: true,
watch: false,
max_memory_restart: "1G",
env: {
NODE_ENV: "production",
},
},
],
};
执行以下命令
pm2 start ecosystem.config.js
启动了2个进程的集群,可在pm2的面板看到集群的运行情况
可以配置多个实例、最大内存、最大进程数量、启动顺序、环境变量、日志文件、错误文件、重启策略等等。
10. 环境变量配置。
在根目录新建.env文件,写入环境变量。如
NUXT_PROTOCOL=https
NUXT_ROUTER_BASE=/
NUXT_DOMAIN_NAME=www.xxx.com
NUXT_PORT=3001
nuxt2默认集成了dotenv。在nuxt.config.js中引入dotenv,并调用dotenv.config()方法。
require('dotenv').config({ path: path.resolve(__dirname, `.env.${env}`) })
//然后就能获取到对应的环境变量了
const NUXT_ROUTER_BASE = process.env.NUXT_ROUTER_BASE
const NUXT_PROTOCOL = process.env.NUXT_PROTOCOL
const NUXT_DOMAIN_NAME = process.env.NUXT_DOMAIN_NAME
const NUXT_PORT = process.env.NUXT_PORT
//可以根据获取到的变量动态地配置项目的路由、域名、端口等信息,如:
export default {
server: {
port: NUXT_PORT,
host: '0.0.0.0'
},
router: {
base: NUXT_ROUTER_BASE,
},
}
接下来需要修改package.json文件,修改部分如下:
{
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"build:uat": "cross-env NODE_ENV=uat nuxt build",
"build:prod": "cross-env NODE_ENV=production nuxt build",
"generate": "nuxt generate",
"start:dev": "cross-env NODE_ENV=development nuxt start",
"start:uat": "cross-env NODE_ENV=uat nuxt start",
"start:prod": "cross-env NODE_ENV=production nuxt start",
"startbypm2": "pm2 start npm --name \"my-app\" -- run start"
}
}
这里用到了一个cross-env库,它可以在不同的平台为我们设置环境变量,是一个好用的跨平台工具,可以通过npm install cross-env --save-dev安装
注意: 如果线上环境没有动态读取env文件的需求,那么在start时直接执行nuxt start即可,不需要再执行cross-env NODE_ENV=production nuxt start
11. 重定向。
这里推荐的重定向配置是在nuxt.config.js文件中配置的,具体代码如下:
export default {
...
router: {
base: NUXT_ROUTER_BASE,//路由基础路径
extendRoutes(routes, resolve) {
// 添加重定向规则
routes.push({
path: '/',
redirect: '/home'
})
}
},
}
通过这样的配置,即可使发往NUXT_ROUTER_BASE的请求自动跳转到/home。
注意:如果你的NUXT_ROUTER_BASE是/,则需要在nginx中设置默认首页为/home