基于鸿洋大佬的 api ,从零开始实现一个 nuxt ,偏实战,项目的设计思路和主要实现步骤,列出坑点, 基础 api 请参照官方文档。有需要的小伙伴可以从零实现自己 nuxt(实现起来并不复杂,该教程只是提供思路,并非最佳实践)
Github:传送门
演示地址:传送门
nuxt 官网:Nuxt.js docs.
vue: 三选一,毕竟是 nuxt。
vuex: 状态管理
sass: 样式
element-ui: 优秀
lodash: 工具类
swiper: 知名滑动插件, 不要用最新的 6 版本, 有 坑
nginx: 端口转发
docker: 部署
基于 nuxt 官网搭建,详细步骤请查看官网, 我这里只展示有差异的地方。
我的触发点是搭建一套环境,多项目部署,省事。使用到了npm-run-all
|--v1
|-- api // 接口目录
|-- assets // 文件
|-- components // 组件
|-- layout // 页面布局
|-- middleware // 中间件
|-- page // 页面
|-- plugins // 插件
|-- static // 静态文件
|-- store // 状态管理
|-- util // 常用工具集合
|--v2
这里简单介绍下使用npm-run-all进行多项目并行打包,结合Dockerfile打包镜像,部署项目,实现简化版本 CI/CD
使用--parallel参数执行并行操作 cx:v1是本地测试用的,本地调试也就是 npm dev:v1
// .package.json
"dev:v1": "nuxt --config-file v1/nuxt.config.js",
"build:v1": "nuxt build --config-file v1/nuxt.config.js",
"start:v1": "nuxt start --config-file v1/nuxt.config.js",
"cx:v1": "npm run build:v1 && npm run start:v1",
"dev:v2": "nuxt --config-file v2/nuxt.config.js",
"build:v2": "nuxt build --config-file v2/nuxt.config.js",
"start:v2": "nuxt start --config-file v2/nuxt.config.js",
"cx:v2": "npm run build:v2 && npm run start:v2",
"all": "npm-run-all --parallel cx:*",
"all-start": "npm-run-all --parallel start:*",
打包成 docker 容器,拷贝项目到创建的文件夹,npm i, 设置环境变量, 打包项目 暴漏端口,坐等启动,这里需要 dockerhub 账号关联 github,监听分支提交,自动打包。github 今年新出的 action 也很好用。小伙伴们可以试一试
// .Dockerfile
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# 拷贝
COPY package*.json /usr/src/app/
COPY yarn.lock /usr/src/app/
RUN npm install
ENV NODE_ENV production
ENV NUXT_HOST 0.0.0.0
# 拷贝
COPY . /usr/src/app/
# build
RUN npm run build:v1
RUN npm run build:v2
EXPOSE 3001 3002
# Running the app
CMD "npm" "run" "all-start"
简单介绍下 nuxt.config.js 的属性
server : 端口设置
server: {
port: 3001, // default: 3000
host: '0.0.0.0', // default: localhost
},
buildDir: 启动路径
buildDir: `.nuxt/v1`,
head: 网站 seo 设置
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' }],
},
css : 样式文件
css: [
'element-ui/lib/theme-chalk/index.css',
'~/static/iconfont/iconfont.css',
{
src: '~/assets/style/reset.scss',
lang: 'scss',
},
{
src: '~/assets/style/common.scss',
lang: 'scss',
},
],
public: 插件
plugins: [
'~/plugins/element-ui',
'~/plugins/swiper',
'~/plugins/vue-global.js',
'~/plugins/axios',
// '~/plugins/sticky',
// { src: '~/plugins/sticky', ssr: false },
{ src: '~/static/iconfont/iconfont.js', ssr: false },
],
modules: nuxt 提供的插件 axios 处理前后接口,auth 官方提供的权限管理,proxy 提供处理跨域
modules: [
// Doc: https://axios.nuxtjs.org/usage
// Doc: https://github.com/nuxt/content
'@nuxtjs/axios',
'@nuxtjs/auth',
'@nuxtjs/proxy',
'@nuxtjs/pwa',
'@nuxtjs/svg',
'@nuxt/content',
[
'@nuxtjs/component-cache',
{
max: 10000,
maxAge: 1000 * 60 * 60,
},
],
],
axios: 接口
axios: {
proxy: true,
credentials: true,
},
proxy:转发解决跨域
proxy: {
'/api': {
target: baseURL,
pathRewrite: {
'^/api': '/',
},
},
},
build: 引入 UI 组件
build: {
transpile: [/^element-ui/],
extend(config, ctx) {
}
}
router: 路由, 这里会用到中间件,处理路由拦截
router: {
middleware: ['auth'],
},
auth:路由的中间件, 拦截路由,里面配置比较多 配置说明请看 官方 auth 验证模块
auth: {
plugins: ['~/plugins/auth.js'], // 扩展auth插件
localStorage: false,
cookie: {
prefix: '123cookie.', // 自定义cookie名称
options: {
path: '/',
expires: 2 / 24 / 60, // 两分钟 兼容ie 用户不操作后 用户操作就一直更新
// maxAge: 2 * 60, // 两分钟
},
},
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/',
},
strategies: {
local: {
autoFetchUser: false, // 登录后请求用户接口
// tokenRequired: false, // 此选项可用于禁用所有令牌处理
// tokenType: Bearer, // 在axios请求中使用的授权标头类型
globalToken: false, // 为所有axios请求设置授权标头
endpoints: {
login: {
url: '/api/user/login',
method: 'post',
propertyName: false,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
// Referer: 'https://www.wanandroid.com/index',
},
},
logout: { url: '/api/user/logout/json', method: 'get' },
user: { url: '/api/friend/json', method: 'get', propertyName: false },
},
},
},
},
api 自动化, 这里没有另外引入 axios, 毕竟 nuxt 已经提供了封装好的 axios
// api 自动化
const ctx = require.context('.', false, /.api.js$/)
const APIS = {}
ctx.keys().forEach((item) => {
const name = item.split('.')[1].slice(1)
const config = ctx(item)
const dft = config.default || config
APIS[name] = dft
})
export default APIS
api 设计 增删改查
// ./api/repository
export default ($axios) => (resource) => ({
index() {
return $axios.$get(`${resource}`)
},
show(id) {
return $axios.$get(`${resource}/${id}`)
},
create(payload) {
return $axios.$post(`${resource}`, payload)
},
update(id, payload) {
return $axios.$post(`${resource}/${id}`, payload)
},
delete(id) {
return $axios.$delete(`${resource}/${id}`)
},
})
处理 async/await 异常 , 让代码更优雅
// ./api/test.api.js
const to = (promise) => {
return promise
.then((data) => {
return [null, data]
})
.catch((err) => [err, null])
}
// 首页banner
getBanner() {
return to($axios.$get(`${resource}/banner/json`))
},
使用
// ./page/index.vue
const [err, resList] = await ctx.app.$api_wanandroid.getAllIndex(page - 1)
if (err) return
组件自动化,省事省心
// ./components/common/index.js
// 组件自动化
export default {
install(Vue) {
const components = require.context('~/components/common', false, /\.vue$/)
// components.keys() 获取文件名数组
components.keys().forEach((path) => {
// 获取组件文件名
const fileName = path.replace(/(.*\/)*([^.]+).*/gi, '$2')
// components(path).default 获取 ES6 规范暴露的内容,components(path) 获取 Common.js 规范暴露的内容
Vue.component(fileName, components(path).default || components(path))
})
},
}
- 停止容器:docker stop <CONTAINER>
- 删除容器:docker rm <CONTAINER>
- 更新镜像:docker pull <IMAGE>
- 启动容器:docker run <ARG> ... <IMAGE>
// 单项目部署
docker run --name web-nuxt01 -p 49168:3001 -d caniuse/web-nuxt:0.0.1
// 多项目部署
docker run --name web-nuxt01 -p 43001:3001 -p 43002:3002 -d caniuse/web-nuxt:0.0.1
这里推荐一款自动更新所有镜像的镜像 watchtower 常用的命令
docker run -d \
--name watchtower \
--restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--cleanup \
-i 3600
docker run -d \
--name watchtower \
--restart always \
-e TZ=Asia/Shanghai \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--cleanup \
-s "0 0 1 * * *"
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower -cR \
web01
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--cleanup \
--run-once \
web01
注意指定容器需填写 容器名 ,并非镜像名.由于部分容器启动时可能没有定义 --name 参数,请执行 docker ps 查询核对容器名.
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--cleanup \
--run-once
auth 验证模块 https://auth.nuxtjs.org/#getting-started
$axios 接口模块
https://axios.nuxtjs.org/helpers
websocket 文档 https://nuxt-socket-io.netlify.app/
选用@auxtjs/axios 而非 axios 作为 nuxt 的请求模块 方案 https://blog.lichter.io/posts/nuxt-api-call-organization-and-decoupling/
jwt+cookie 的安全处理 https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
// Nuxt.js + SockJs 实现 webSocket 订单实时消息 语音播报 https://blog.csdn.net/lq099526/article/details/96480959
nuxt sticky 粘性插件没找到合适的 https://github.com/mehwww/vue-sticky-directive/issues/27
nuxt 的性能问题 https://www.zhihu.com/question/323485389
nuxt 性能 https://www.cnblogs.com/lessfish/p/12411497.html
Content type
Image
Digest
Size
476.1 MB
Last updated
about 5 years ago
docker pull caniuse/web-nuxt:v0.0.3