使用 nuxt 编写美团 PC 端(vue+ssr+egg)
前置
nuxt 安装
npx create-nuxt-app <projectName>
or yarn create nuxt-app <projectName>
nuxt 启动
为了使 node 文件支持 es6 语法和 async,await,需要使用 babel 配置一下。npm i babel-cli -g
,然后在 package.json 里面的 dev 和 start 命令的最后面加上--exec babel-node
,根目录新建一个.babelrc
文件。
1 | { |
因为安装的 eslint-plugin-vue 这个 eslint 校验规则是能自闭和的元素就自闭和,我个人不习惯,所以要重新设置一下.eslintrc.js
,rules 里面添加上这段代码
1 | 'vue/html-self-closing': ["error", { |
安装npm i babel-preset-es2015 babel-plugin-transform-runtime babel-runtime -D
,然后就可以执行npm run dev
了。
安装 redis
运行brew install redis
安装。
Linux:cd 到 redis 的 src 目录 ./redis-server &
(添加&后台启动) or ./redis-server & ../redis.conf
(配置文件启动)
运行brew services start redis
后台运行 redis 服务,运行brew services sop redis
停止后台服务。redis-server
服务端运行命令,redis-cli
运行客户端。quit
退出服务端。
nrm
npm install -g nrm
一个能切换仓库源的工具。nrm ls
列出仓库源。nrm use ***
使用源。
mongoDB
在数据文件目录使用命令导入数据表 mongoimport -d meituan -c areas areas.dat
meituan 是数据库名字 areas 是集合(表名) areas.dat 是数据文件。
导出导入操作集合
技巧
curl -d "name=lily" http://*****
一个 linux 命令,发送 post 请求。
如果发送 get 请求则不用加-d。
项目中遇到的问题
让 node 支持 es6 导入语法
npm i babel-cli babel-preset-es2015 --save
根目录新建一个文件.babelrc 内容
1
2
3{
"presets": ["es2015"]
}package.json 的 script 启动项里面命令行最后面添加
--exec babel-node
组件引入 css
如果使用 sass、less、stylus 一般平时可以使用@/alias
的方式引入样式表,但是新版 nuxt 已经不支持如此引入方式。
请注意: 从 Nuxt 2.0 开始,〜/alias 将无法在 CSS 文件中正确解析。你必须在 url CSS 引用中使用
assets(没有斜杠)或@别名,即 background:url(“assets/banner.svg”)
不过实际测试@不好使..
或者使用styleResources
来处理样式的变量和mixin
。yarn add @nuxtjs/style-resources
&& yarn add stylus-loader stylus
,nuxt.config.js
1 | export default { |
这样就能随处使用定义过的变量或者函数…
axios 封装及报错
axios 报错Cannot read property 'cancelToken' of undefined
,原因是因为 request 拦截没有 return config
。
优雅的切换 baseUrl,由于这个项目的登录接口在本地做了一次转发,因此在登录的时候请求的是本地的接口,其他时候都是请求的 egg 接口,因此我们要根据情况适当的切换 baseUrl,但是由于前端项目对 axios 进行了一遍封装,因此简单的引入 axios 设置 baseUrl 是无效的,我们需要引入 request.js 里面的 request 对象,然后request.defaults.baseURL = url.Api
设置 baseUrl,同理 token 也可以如此设置:request.defaults.headers.Authorization = 'Bearer ' + res.token
第三方模块全局引入
没有找到设置全局模块的 webpack 配置,不过 nuxt 的 plugin 使用说明里面提供了几种全局使用第三方模块的方式。例如将第三方模块注入 Vue 或者 ctx 实例,这样就能在客户端或者服务端使用该模块。
例子:npm install good-storage --save
1 | // plugin/storage.js |
1 | // nuxt.config.js |
使用:this.$storage.set(key,value)
页面字体图标引入
1 | @font-face { |
首先引入对应的组件图标并重命名,然后
1 | .home-category-iconfont { |
单独写一个字体图标对应的 css 文件,并且在需要用到字体图标的组件引入,每个图标有单独对应的 css 语句,需要去审查美团网并复制。
页面组件开发
使用template
包裹代码块做v-for
循环,不会产生多余的 dom 结构。
使用crypto-js
模块进行密码加密。
npm i -save crypto-js
let CryptoJS = require('crypto-js')
CryptoJS.MD5(***).toString()
问题
Nuxt 不支持组件获取异步数据,所以要么在 mounted 里面写(不支持 ssr),要么在 store 的 index 的 nuxtServerInit 方法里面写,但是这样会延迟首屏渲染时间(猜的,这个方法阻塞),要么在页面里面获取数据然后使用 prop 或者存到 vuex 里面,但是 Nuxt 只有页面是支持预渲染请求数据的,组件并不支持,因此若想获取并保存和渲染数据,需要在最一开始使用到次组件的页面获取该组件的数据。这里我选择存 vuex 里面。
vuex
vuex 使用模块功能时注意是否设置命名空间,注意 state 里面多了一层嵌套数据。
Nuxt 使用 vue-awesome-swiper 做轮播等设置
照一般的组件设置后,使用方式如下
使用方式
div 标签上面加v-swiper
指令设置
后台业务开发
注册
用户表的几个字段,例如手机号、邮箱、昵称等字段,除了手机号是唯一但不必需的,手机号必需,因为这几个字段要用来进行登录等操作。同时因为注册的时候只使用手机号进行注册,为了避免因为邮箱、昵称等字段重复引起的注册失败,所以美团自己给用户的昵称设置了一个乱码,邮箱置为空,待以后填写。
登录
mongoose 进行一个值多个字段的查询,用途是根据用户输入的一个值来进行手机号、邮箱、昵称的查询:
1 | let user = await ctx.model.User.find({ |
问题
大部分页面和接口并不是一定要登录才能看到的,因此状态校验需要单独写在那些页面里面,包括后台路由校验 token 也是同理。
Nuxt 和 eggjs 的部署
部署 eggjs
- 首先编译
总结
emmm,这个项目新建的时候不该用 axios module,它将 axios 又处理了一下,跟平常的使用习惯有较大差别。
用 MongoDB 有点不大好,MongoDB 本身文档资料较少,初步上手问题较多。
Jokcy 老师说前后端分离开发约定的数据基本就是扯淡,后端会改,弄得前端很麻烦,建议前端定义自己的数据格式然后请求接口的时候做一层映射。
☆☆☆☆☆ 这个项目思想出了问题
nuxt 我选择 vue+koa 混合的方式创建项目,我的后端使用 eggjs 进行编写,然而我忽略了一个问题,那就是:这个项目本身是基于 koa(后端项目)做的前端 Vue 项目(前端占比大),前后端共用一个端口(cookie 不能跨域),共用一套路由,一些身份校验、token 保存要使用 cookie 来做,但是 cookie 一般不能跨域,即 3000 的 nuxt 端口无法直接向 7001 的 eggjs 服务端口发送 cookie,这样用户的登录态的保存就是个问题。
不过幸运的是可以换其他的方式进行解决。
Nuxt 前后端分离开发 前端刷新判断用户状态 nuxt 做接口转发
由于采用前后端分离式开发,nuxt 项目刷新的时候会将 vuex 数据刷新掉,页面渲染之前又无法取得 localStorage 保存的本地值,如果采用等页面渲染完成时候,再获取本地值请求接口获得用户数据的方式不安全也不优雅。经过网上查找之后我选择如下文章采用的方式,使用创建的 nuxt 项目自带的 koa 进行一下请求转发,然后由 koa 设置 cookie,用 nuxtServerInit 函数进行状态判断。