# 前言
为什么要用nuxt呢?可能绝大部分原因都是运用nuxt来解决我们spa项目seo不友好问题,nuxt可以在服务端将页面渲染成html,再返回给浏览器,spa项目是返回大量js文件,通过js文件在客户端浏览器动态渲染html。js动态渲染模式百度爬虫是无法爬取到渲染完成后的内容的。所以在做有seo需求的项目时,nuxt可能是一个不错的选择。
优点
- 有利于SEO。
- 首屏加载速度快。因为SPA引用需要在首屏获取所有资源,而服务器端渲染直接拿了成品展示出来就行了。
- 无需占用客户端资源。解析模板工作交给服务器完成,对于客户端资源占用更少,尤其是移动端,也可以更省电。
缺点
- 所有用户的页面请求都需要在服务端渲染,增加服务端压力。
- 学习成本相对较高
安装运行
npx在NPM版本5.2.0默认安装了
npx create-nuxt-app <项目名>
具体配置项可以参考 zh.nuxtjs.org/guide/insta…
笔者配置如下:
进入项目文件夹
cd <项目名>
安装依赖
npm install
运行
npm run dev
nuxt默认运行在3000端口,尝试访问localhost:3000,启动成功
按需加载安装element.ui
项目中可能会使用到element中的一些组件,新建项目时默认在nuxt集成element的话,打包后会将整个element包全部打包进我们的项目,对首屏加载速度不太友好,我们通过配置实现按需加载element组件,只将需要用到的element组件打包进我们的项目。
1. 本地安装按需加载插件babel-plugin-component(已安装的忽略次步骤)
npm install babel-plugin-component -D-S
2.配置nuxt.config.js
// nuxt.config.js
build: {
...other
// 按需引入element-ui
babel: {
plugins: [
[ "component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
},
},
3.修改plugins/element-ui.js
在第一步创建nuxt项目时候我选择了 Element做为ui,所以在创建的新项目里有这个文件plugins/element-ui.js,如果在创建项目的时候没有选择element作为ui框架的话只需要手动创建这个element.js,并在nuxt.config.js新增配置 plugins: ['@/plugins/element-ui'],
//element.js
import Vue from "vue";
import {
Button,
} from "element-ui";
Vue.use(Button);
4.在index.vue文件中使用
<el-button type="" >测试</el-button>
axios引入
在创建项目时默认选择安装了@nuxtjs/axios,这里@nuxtjs/axios的使用方法与axios一致,所以这里不在需要另外安装axios(在package.json中名称为@nuxtjs/axios,实际引入我们在项目中通过import AXIOS from 'axios' 引入即可)
封装 新增文件:@/api/index.js
1.安装@nuxtjs/axios
cnpm install @nuxtjs/axios -S-D
安装封装axios时用到的一个json处理包
cnpm install qs -S-D
安装一个常用函数库(后面封装axios有用到)
cnpm install loadsh -S-D
在assets/js下新增lodash.js
// lodash.js
import _merge from 'lodash/merge'
import _cloneDeep from 'lodash/cloneDeep'
import _maxBy from 'lodash/maxBy'
import _minBy from 'lodash/minBy'
import _throttle from 'lodash/throttle'
import _debounce from 'lodash/debounce'
import _get from 'lodash/get'
import _uniqBy from 'lodash/uniqBy'
import _uniq from 'lodash/uniq'
export const merge = _merge
export const cloneDeep = _cloneDeep
export const maxBy = _maxBy
export const minBy = _minBy
export const throttle = _throttle
export const debounce = _debounce
export const get = _get
export const uniqBy = _uniqBy
export const uniq = _uniq
在assets新增api目录并在此目录下新建两个文件index.js、service.js
//index.js
import AXIOS from 'axios'
import { merge } from '@/assets/js/lodash'
import qs from 'qs'
//后台接口地址
const axios = AXIOS.create({
baseURL: 'localhost:8080'
})
// 请求时的拦截器
axios.interceptors.request.use(
(config) => {
//在这里写发起请求前的拦截
return config
},
(error) => {
console.warn('axios request', error)
return Promise.reject(error)
}
)
axios.interceptors.response.use(
(response) => {
//在这里写响应请求拦截
return response
},
(error) => {
console.warn('axios response', error, error.response)
return Promise.reject(error)
}
)
const httpServer = (opts, data) => {
// http默认配置
const commonOpts = {}
const options = merge({}, commonOpts, opts)
if (options.method === 'get') {
options.params = data
} else if (
options.headers &&
/application\/json/.test(options.headers['content-type'] || '')
) {
options.data = data
} else {
options.data = qs.stringify(data)
}
return axios(options)
}
export default httpServer
export { axios }
在service.js中统一定义我们的请求方法
//service.js
import { axios } from './index'
export function getQueryInfoDetail(page, size) {
const path = '/auth/role/list'
return axios({
url: path,
method: 'get',
params: {
page,
size
}
})
}
使用
import { getQueryInfoDetail } from "@/assets/api/service.js";
getQueryInfoDetail(1, 10).then(res => {
console.log(res);
});
vuex 引入
nuxt默认就安装有vuex模块(diss一下:官网上说需要创建项目配置才会有,我也没见创建项目时候让配置vuex。反正默认就是有(ง •_•)ง )
在store/index.js
//index.js
export const state = () => ({
counter: 0
})
export const mutations = {
increment (state) {
state.counter++
}
}
这里的语法和vue还是有一点点区别,这里我们只需要将vuex的中state、mutations、action等使用export暴露出去,nuxt会帮我们配置好,这里值得注意下的是,state的值应该始终是function,是为了避免返回引用类型,会导致多个实例相互影响,另外vuex默认index.js为根模块,我们需要建立子模块的话只需要在store目录下新增js文件,例如建立user.js子模块,专门用来管理用户信息。
//user.js
export const state = () => ({
userInfo: {
name: '',
avatar: '',
},
})
export const mutations = {
setUserInfo (state, userInfo) {
state.userInfo = userInfo;
},
clearUserInfo(state) {
state.userInfo = {}
},
clearAllUserData(state) {
state.userInfo = {};
},
}
export const getters = {
userInfo(state) {
return state.userInfo;
}
}
在使用字模块的时候需要带上子模块名称(store.commit('user/clearAllUserData')) 具体参考zh.nuxtjs.org/guide/vuex-…
配置filters过滤器
plugins目录下新建filters.js
//filters.js
import Vue from 'vue'
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
nuxt.config.js中新增
plugins: [
{ src: '~/plugins/filters', ssr: false }
],
SSR方式部署到服务器
1.打包项目(会在.nuxt目录下生成dist文件夹)
npm run build
2.将项目.nuxt、static、nuxt.config.js、package.json文件上传至服务器(推荐使用winScp)
3.启动项目(推荐Xshell)
首先进入到我们刚刚上传项目的目录
安装依赖
npm install
启动
npm run start
控制台出现如下,则启动成功
nuxt默认运行在3000端口,作者服务器上3000端口被占用了,所以改成了在3333端口上。更改端口只需要在pageage.json新增"config": { "nuxt": { "host": "0.0.0.0", "port": "3333" } }
测试访问,我们通过 服务器外网ip:端口号访问项目(服务器记得配置端口号的安区组)
问题分析:
问题1: xshell退出当前状态或者关闭时,nuxt服务也被关闭了
解决它: 使用pm2 守护nuxt服务
安装pm2
npm install pm2 –g
pm2 启动nuxt (项目名就是package.json里的name字段)
pm2 start npm --name '项目名' -- run start
再次访问 服务器外网ip:端口号 又能正常访问了, 此时我们退出Xshell时,项目还是能正常的访问。
关闭nuxt方法: 使用pm2 list 查看项目的id, 然后通过pm2 stop id停止,或者通过pm2 delete id删除
pm2基本命令
- pm2 list
- pm2 start id
- pm2 stop id
- pm2 delete id
- pm2 log
问题2:分环境部署(不需要分环境部署的可忽略)
Nuxt 中有process.env.NODE_ENV来区分环境,但默认情况下,这个变量的值要么是 production,要么是 development,分别表示生产环境和开发环境,我们需要的环境可能不止这两种,我们还需要区分测试环境等等,我们先区分打包后的项目中的process.env.NODE_ENV区分,也就是说在我们源码中能通过process.env.NODE_ENV区分 开发环境和测试环境、生成环境
安装cross-env
npm install cross-env –S-D
在package.json中scripts中添加测试和正式的打包命令
"build:test": "cross-env NODE_ENV=test nuxt build",
"build:pro": "cross-env NODE_ENV=production nuxt build",
nuxt.config.js 增加如下配置
env: {
NODE_ENV: process.env.NODE_ENV
},
在项目中使用,区分开发、测试、生成环境分别对应后台接口地址,项目中我们可以通过process.env.NODE_ENV全局变量访问打包命令中定义的变量NODE_ENV的值
举例区分环境使用不同的后台接口地址
项目根目录下新建config.js
config.js需要在跟.nuxt、static、nuxt.config.js、package.json一起上传到服务器
//config.js
if (process.env.NODE_ENV == "development") {
env = "dev"; //本地开发环境
} else if (process.env.NODE_ENV == "test") {
env = "test"; //test环境
} else if (process.env.NODE_ENV == "production") {
env = "production"; //正式环境
}
//接口地址
const baseURLs = {
dev: "https://api.test", //测试环境后台接口地址
test: "https://api.test", //测试环境后台接口地址
production: "https://api" //正式环境后台接口地址
};
const config = {
baseURL: baseURLs[env],
};
module.exports = config;
修改上文引入axios模块中的assets/api/index.js,替换aixos的baseUrl为config.js的动态设置的baseurl
//index.js
import {baseURL} from '@/config'
import AXIOS from 'axios'
import { merge } from '@/assets/js/lodash'
import qs from 'qs'
//后台接口地址
const axios = AXIOS.create({
baseURL: baseURL
})
// 请求时的拦截器
axios.interceptors.request.use(
(config) => {
//在这里写发起请求前的拦截
return config
},
(error) => {
console.warn('axios request', error)
return Promise.reject(error)
}
)
axios.interceptors.response.use(
(response) => {
//在这里写响应请求拦截
return response
},
(error) => {
console.warn('axios response', error, error.response)
return Promise.reject(error)
}
)
const httpServer = (opts, data) => {
// http默认配置
const commonOpts = {}
const options = merge({}, commonOpts, opts)
if (options.method === 'get') {
options.params = data
} else if (
options.headers &&
/application\/json/.test(options.headers['content-type'] || '')
) {
options.data = data
} else {
options.data = qs.stringify(data)
}
return axios(options)
}
export default httpServer
export { axios }
之后我们通过npm run build:test构建后上传的项目,启动后axios的baseUrl就是测试环境的接口地址。
最后
项目地址源码地址: github.com/chenyuhuan1…
谢谢你的观看,欢迎各位的指正,最后麻烦留下你宝贵的一赞┗( ▔, ▔ )┛,如有疑问请在下方留言。