nuxt.js是一个基于 Vue.js 的轻量级应用框架,可用来建立服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用——nuxt官网css
根据本身在这上方面一条路走到黑,摸滚带爬的踩坑经验,接下来我将从如下几个方面给各位接触到或者将来接触到这方面知识的码友进行全方位的讲解和剖析。html
最近因公司业务需求,须要对商城官网作seo
优化。由于初版前端用的是纯vue写的,经Vue-cli
集成的webpack
打包还有代码压缩处理后生成一串js的静态文件。因百度蜘蛛没法对纯js的网页进行爬取收录。因此不利于网站的排名。紧接咱们和领导开会拍板使用服务端渲染(如下用ssr指代),nuxt恰好是vue团队打造的基于vue的ssr的框架,简单易于上手,避免了前端攻城狮们本身用node.js搭建服务。但初始咱们采用的是nuxt的静态化部署,nuxt generate
,这样能够解决一部分需求,但每次更新内容后都要前端手动执行命令打包。并且经过百度蜘蛛爬取趋势图显示这种方式并不理想。最后,咱们仍是在原来的基础上采用nuxt的第二种方式前端作ssr处理,上线后经百度蜘蛛爬取趋势图显示有很大程度的提升,利于seo
,且官网被百度收录的页面也逐渐增长。由此告一段落。前端
nuxt做为一个框架,则集成了vue2
、vue-route
、vuex
、vue
ssr
、vue-meta
等组件/框架,其是用webpack
、和vue-loader
、babel-loader
来处理代码的自动化构建工做(打包、代码分层、压缩等) nuxt框架提供了两种部署方式: 1. 静态化部署(预渲染)-- 经过 nuxt generate
命令实现。该命令依据应用的路由配置将每个路由静态化成为对应的 HTML
文件 2. ssr部署 -- 先经过nuxt build
编译构建再经过nuxt start
开启一个web服务 在服务端调取接口时,主要是用到了asyncData/fetch
方法。使得咱们能够在设置组件的数据以前能异步获取或处理数据。vue
asyncData
方法会在组件(限于页面组件)每次加载以前被调用。它能够在服务端或路由更新以前被调用。 在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你能够利用asyncData
方法来获取数据,Nuxt.js 会将asyncData
返回的数据融合组件data
方法返回的数据一并返回给当前组件。node
asyncData
方法是在组件 初始化 前被调用的,因此在方法内是没有办法经过 this 来引用组件的实例对象。
fetch
方法用于在渲染页面前填充应用的状态树(store
)数据, 与asyncData
方法相似,不一样的是它不会设置组件的数据。 类型:Function
若是页面组件设置了fetch
方法,它会在组件每次加载前被调用(在服务端或切换至目标路由以前)。fetch
方法的第一个参数是页面组件的上下文对象context
,咱们能够用fetch
方法来获取数据填充应用的状态树。为了让获取过程能够异步,你须要返回一个Promise
,Nuxt.js 会等这个promise
完成后再渲染组件。react
警告: 您没法在内部使用this获取组件实例,fetch是在组件初始化以前被调用 webpack
大概了解了这些知识就能够作ssr工做了,路由环境配置等可到nuxt中文官网 查阅ios
百度蜘蛛是百度搜索引擎的一个自动化程序,它会不断的访问收集互联网上的网页、文章、视频等,经过抓取连接来收录网站,计算网站的权重和排名。纯html等静态化网站对百度蜘蛛比较友好,且百度蜘蛛几乎不会爬取js动态的网站,如vue/react构建的且经webpack/gulp等构建工具压缩处理过的网站。百度蜘蛛爬取网站是从主站开始爬,一次根据网站暴露的内链依次往深层次爬取。meta的设置,以及网站TDK的优化,网站结构优化,外链,文章原创等一样对SEO有很大做用,但本文主要是从技术层面入手,则主要是针对网站内链的处理以及基于vue等如今技术流作ssr处理。nginx
我这里采用nuxt.js团队建立的脚手架creat-nuxt-app
搭建。git
注: 开发必备环境 npx (npm v5.2.0+) node (v4.0+)
个人开发环境npm v5.5.1 node v8.9.1 win10 在终端输入如下命令
npx create-nuxt-app nuxt-demo
复制代码
而后你会看到
npm run dev
复制代码
当你看到以下图恭喜你成功搭建起项目
proxy
利用本地
node服务器
作个反向代理 在
nuxt.config.js
中配置
module.exports= {
modules: [
'@nuxtjs/axios'
],
axios: {
proxy: true, //开启代理
credentials: true, //跨域请求需使用凭证
},
proxy: [
['/api',{
target: 'http://example.com/api', // (后端请求地址)
changeOrigin: true,
pathRewrite: {'^/api': ''}
}]
]
}
复制代码
附上刚搭建完的nuxt.config.js
和package.json
// nuxt.config.js
module.exports = {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
'element-ui/lib/theme-chalk/index.css'
],
/*
** Plugins to load before mounting the App
*/
plugins: [
'@/plugins/element-ui'
],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module',
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios',
'@nuxtjs/pwa',
// Doc: https://github.com/nuxt-community/dotenv-module
'@nuxtjs/dotenv',
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {
},
/*
** Build configuration
*/
build: {
transpile: [/^element-ui/],
/*
** You can extend webpack config here
*/
extend (config, ctx) {
}
}
}
复制代码
//package.json
{
"name": "nuxt-demo",
"version": "1.0.0",
"description": "for a nuxt demo about ssr",
"author": "kevin xie",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
"build": "nuxt build",
"start": "cross-env NODE_ENV=production node server/index.js",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"test": "jest"
},
"dependencies": {
"nuxt": "^2.0.0",
"cross-env": "^5.2.0",
"express": "^4.16.4",
"element-ui": "^2.4.11",
"@nuxtjs/axios": "^5.3.6",
"@nuxtjs/pwa": "^3.0.0-0",
"@nuxtjs/dotenv": "^1.4.0"
},
"devDependencies": {
"nodemon": "^1.18.9",
"@nuxtjs/eslint-config": "^2.0.0",
"@nuxtjs/eslint-module": "^1.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^6.1.0",
"eslint-plugin-nuxt": ">=0.4.2",
"@vue/test-utils": "^1.0.0-beta.27",
"babel-jest": "^24.1.0",
"jest": "^24.1.0",
"vue-jest": "^4.0.0-0"
}
}
复制代码
若是你不须要作ssr处理的话直接执行nuxt generate
则nuxt会为你生成静态化页面,而后再执行nuxt build
打包后将dist文件
夹推上服务器就能够上线了,但这种seo
不太友好但比以前vue构建好一点。 但要作ssr处理的话就需换种方式处理也就是nuxt提供的第二种方式,在服务器搭个node服务器而后直接在上面跑。这样的话,配置须要改,且与后台的请求也须要改,改成nuxt给咱们提供asyncData/fetch
。由于nuxt也是基于vue开发的,因此生命周期也同样,但nuxt在服务端中会触发beforeCreate
、created
两个生命周期。其次,nuxt有本身一套服务器渲染流程。
Nuxt.js 提供了几种不一样的方法来使用 asyncData
方法,你能够选择本身熟悉的一种来用:
Promise
, nuxt.js会等待该Promise
被解析以后才会设置组件的数据,从而渲染组件.async
或 await
export default {
asyncData ({ params }) {
return axios.get(`https://my-api/posts/${params.id}`)
.then((res) => {
return { title: res.data.title }
})
}
}
复制代码
export default {
async asyncData ({ params }) {
const { data } = await axios.get(`https://my-api/posts/${params.id}`)
return { title: data.title }
}
}
复制代码
export default {
asyncData ({ params }, callback) {
axios.get(`https://my-api/posts/${params.id}`)
.then((res) => {
callback(null, { title: res.data.title })
})
}
}
复制代码
另外,还要注意一下在作登陆处理等须要获取cookie或者服务端存储的session时,须要使用到vuex状态树,在状态树中有个方法很是有用 nuxtServerInit
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}
复制代码
由于在一个工程项目中咱们都是有开发、测试、生产这样的验收流程的。而每每咱们测试和生产所链接的数据库都是不一样的,且请求域也不同。所以为了开发方便咱们就很须要多环境的配置。在spa中咱们能够在package.json
中经过cross-env
这个node环境变量设置,但在ssr中这个在服务端请求时不生效,这里我当时找了好久google之类最后仍是经过 @nuxtjs/dotenv
解决了。还有特别注意到 @nuxtjs/axios
中有提供环境变量API_URL
来复写baseURL
和API_URL_BROWSER
来复写browserBaseURL
,这在多环境配置中颇有用。 你能够在nuxt.config.js
中引入而且在module
中使用。
require('dotenv').config({path: '.env'})
module.exports={
modules: [
'@nuxtjs/axios',
['@nuxtjs/dotenv', {
filename: process.env.NODE_ENV == 'production' ? '.env.prod' : process.env.NODE_ENV == 'test' ? '.env.test' : '.env.dev'
}]
]
}
复制代码
同时你能够在根目录下配置相关环境配置文件。
.env.dev
NODE_ENV=development
API_URL_BROWSER=http://localhost:3000
API_URL=http://localhost:3000/api
复制代码
.env.test
NODE_ENV=test
API_URL_BROWSER=http://test.example.com
API_URL=http://test.example.com/api
复制代码
.env.prod
NODE_ENV=production
API_URL_BROWSER=https://www.example.com
API_URL=https://www.example.com/api
复制代码
当你用axios作跨域请求时,你就能够自动根据环境给axios配置baseURL。
import axios from 'axios';
const axiosInstance = axios.create({
timeout: 10000,
baseURL: process.env.API_URL
})
复制代码
在某些须要跳转的连接nuxt-link
或a
连接中你能够声明一个变量对域名作统一处理。
export default {
data () {
return {
BASE_PATH: process.env.API_URL_BROWSER
}
}
}
复制代码
在生成环境中,我须要使用到nginx
作代理服务器,解决跨域。由于咱们的项目的先后端可能部署在不一样的服务上。
upstream nodenuxt {
server 127.0.0.1:3000; #nuxt项目 监听端口
keepalive 64;
}
server {
listen 80;
server_name https://www.example.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; #反向代理
}
}
复制代码
当咱们配置以上内容后在服务端执行npm start
项目能够跑起来,但咱们的项目总会挂掉的,为了使咱们服务进程常驻,咱们要用到pm2
来守护node
进程。而且能够用它来作自动重启、性能监控以及负载均衡。 你能够全局安装npm install pm2 -g
其余麻油说 执行命令能够成功,但我这边仍是没成功pm2 start npm --name "nuxt-demo" -- run start //(nuxt-demo为你的package.json中的项目名)
咱们知道package.json
这个文件,当咱们执行npm run dev
的时候,其实使用npm
去启动了./node_modules/nuxt/bin/nuxt
这个文件。当咱们cd
到咱们的项目目录以后,咱们最终能够执行以下命令来启动:
pm2 start ./node_modules/nuxt/bin/nuxt.js -- start
复制代码
这样能够将项目跑起来,但当项目报错时咱们没法看到日志,所以我这里在根目录经过配置pm2.config.js
。
module.exports = {
apps: [
{
name: 'nuxt-demo',//项目名称
cwd: './',//当前工做路径
script: 'npm',//实际启动脚本
args: 'run start',//参数
autorestart: true, //自动重启
error_file: 'logs/nuxt-demo-err.log',//错误日志
out_file: 'logs/nuxt-demo-out.log', //正常运行日志
exec_mode: 'cluster_mode',// 应用启动模式,支持fork和cluster模式
min_uptime: '60s', //应用运行少于时间被认为是异常启动
restart_delay: '60s',//重启时延
instance: 4,//开启4个实例,仅在cluster模式有效,用于负载均衡
watch: true,//监控变化的目录,一旦变化,自动重启
watch: ['.nuxt', 'nuxt.config.js'],//监控变化的目录
watch_delay: 1000,//监控时延
ignore_watch: ['node_modules'],//从监控目录中排除
watch_options: { // 监听配置
'followSymlinks': false,
'usePolling': true
}
}
]
}
复制代码
这里我是在package.json
中引用这个配置文件的。在服务器中执行命令就行。(如有报错可能须要安装babel
转译
npm install babel-cli babel-core babel-preset-es2015 --save-dev
复制代码
{
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server --exec babel-node",
"build": "nuxt build",
"start:test": "cross-env NODE_ENV=test node server/index.js pm2 start pm2.config.js --exec babel-node",
"start:prod": "cross-env NODE_ENV=production node server/index.js pm2 start.config.js --exec babel-node",
}
}
复制代码
创建Dockerfile 参考这篇文章
FROM node:alpine
RUN mkdir -p /usr/local/service/nuxtdemo
RUN chomd -R 777 /usr/local/service/nuxtdemo
WORKDIR /usr/local/service/nuxtdemo
COPY nuxt_demo.tar.gz /usr/local/service/nuxtdemo
RUN cd /usr/local/service/nuxtdemo && tar xf nuxt_demo.tar.gz
RUN rm -rf nuxt_demo.tar.gz
ENV HOST "0.0.0.0"
RUN npm config set registry https://registry.npm.taobao.org
RUN npm install -g pm2
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["npm", "run", "start:test"]
#CMD ["npm", "run", "start:prod"]
复制代码
而后构建镜像
docker build -t nuxt-demo
复制代码
启动容器
docker run -dt -p 3000:3000 nuxt-demo
复制代码
注意:这里服务端部署后须要0.0.0.0:3000访问,则咱们前端还需配置主机号和端口,我这边在package.json中没成功,在nuxt.config.js中配置成功了。
module.exports = {
server: {
host: '0.0.0.0',
port: 3000
}
}
复制代码
总得来讲,在coding world中要不断的学习,没什么问题解决不了,坚持就对了。如有小伙伴对以上内容有不解欢迎评论,我会尽力为你答疑解惑的。最后喜欢这篇文章的小伙伴关注一下小生并点个赞。 附:
己亥末,庚子春,荆楚大疫,染者数万,众惶恐,举国防,皆闭户,道无车舟,万巷空寂。然外狼亦动,垂涎而候,华夏腹背芒刺。幸龙魂不死,风雨而立。医无私,警无畏,民齐心!政者,医者,兵者,扛鼎逆行勇战矣!商客,名家,百姓,仁义者,邻邦献物捐资,叹山川异域,风月同天,岂曰无衣,与子同裳!能者竭力,万民同心。月余,疫除,终胜。此后百年,风调雨顺,国泰民安!