手摸手,带你用 vue 撸后台 系列一 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
PanJiaChen
V2EX    前端开发

手摸手,带你用 vue 撸后台 系列一

  •  2
     
  •   PanJiaChen
    PanJiaChen 2017-05-03 14:52:55 +08:00 8360 次点击
    这是一个创建于 3159 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目地址

    前言

    说好的教程终于来了,第一篇文章主要来说一说在开始写业务代码前的一些准备工作吧,但这里不会教你 webpack 的基础配置,热更新怎么做,webpack 速度优化等等,有需求的请自行 google。

    目录结构

    ├── build // 构建相关 ├── config // 配置相关 ├── src // 源代码 │ ├── api // 所有请求 │ ├── assets // 主题 字体等静态资源 │ ├── components // 全局公用组件 │ ├── directive // 全局指令 │ ├── filtres // 全局 filter │ ├── mock // mock 数据 │ ├── router // 路由 │ ├── store // 全局 store 管理 │ ├── styles // 全局样式 │ ├── utils // 全局公用方法 │ ├── view // view │ ├── App.vue // 入口页面 │ └── main.js // 入口 加载组件 初始化等 ├── static // 第三方不打包资源 │ ├── jquery │ └── Tinymce // 富文本 ├── .babelrc // babel-loader 配置 ├── eslintrc.js // eslint 配置项 ├── .gitignore // git 忽略项 ├── favicon.ico // favicon 图标 ├── index.html // html 模板 └── package.json // package.json 

    这里来简单讲一下 src 文件

    api 和 views

    简单截取一下公司后台项目,现在后台大概有三十多个 api 模块 Paste_Image.png 如图可见,模块是很多的,而且随着业务的迭代,模块会越来越多。 所以这里建议根据业务模块来划分 views,并且将 views 和 api 两个模块一一对应,方便维护.如下图 Paste_Image.png

    如 article 模块下放的都是文章相关的 api,这样不管项目怎么累加,api 和 viede 的维护还是清晰的,当然也有一些全区公用的 api 模块,如七牛 upload,remoteSearch 等等,这些单独放置就行。

    components

    这里的 components 放置的都是全局公用的一些组件,如上传组件,富文本等等。一些页面级的组件建议还是放在各自 views 文件下,如图 Paste_Image.png

    store

    这里我个人建议不要为了用 vuex 而用 vuex。就拿我司的后台项目来说,它虽然比较庞大,二三十个业务模块,十几种权限,但业务之间的耦合度是很低的,文章模块和评论模块几乎是俩个独立的东西,所以根本没有必要使用 vuex 来存储 data,每个页面里存放自己的 data 就行。当然有些数据还是需要用 vuex 来统一管理的,如登录 token,用户信息,或者是一些全局个人偏好设置等,还是用 vuex 管理更加的方便,具体当然还是要结合自己的业务场景的。总之还是那句话,不要为了用 vuex 而用 vuex !


    webpack

    这里是用 vue-cli 为基础模板构建的,如果你对这个有什么疑惑请自行 google,相关的配置介绍文章已经很详细了,这里就不再展开了。简单说一说需要注意到地方。

    jquery

    管理后台不同于前台项目,会经常用到一些第三方插件,但有些插件是不得不依赖 jquery 的,如市面上好的富文本基都是依赖 jquery 的,所以干脆就直接引入到项目中省事(gzip 之后只有 34kb,而且常年 from cache,不要考虑那些吹毛求疵的大小问题,这几 kb 和提高的开发效率根本不能比)。但是如果第三方库的代码中出现$.xxx 或 jQuery.xxx 或 window.jQuery 或 window.$则会直接报错。要达到类似的效果,则需要使用 webpack 内置的 ProvidePlugin 插件,配置很简单,只需要

     new webpack.ProvidePlugin({ $: 'jquery' , 'jQuery': 'jquery' }) 

    这样当 webpack 碰到 require 的第三方库中出现全局的$、jQeury 和 window.jQuery 时,就会使用 node_module 下 jquery 包 export 出来的东西了。

    alias

    当项目逐渐变大之后,文件与文件直接的引用关系会很复杂,这时候就需要使用 alias 了。 有的人喜欢 alias 指向 src 目录下,再使用相对路径找文件

    resolve: { alias: { '~': resolve(__dirname, 'src') } } //使用 import stickTop from '~/components/stickTop' 

    我习惯于

    alias: { 'src': path.resolve(__dirname, '../src'), 'components': path.resolve(__dirname, '../src/components'), 'api': path.resolve(__dirname, '../src/api'), 'utils': path.resolve(__dirname, '../src/utils'), 'store': path.resolve(__dirname, '../src/store'), 'router': path.resolve(__dirname, '../src/router') } //使用 import stickTop from 'components/stickTop' import getArticle from 'api/article' 

    没有好与坏对与错,纯看个人喜好和团队规范。


    eslint

    不管是多人合作还是个人项目,代码规范是很重要的。这样做不仅可以很大程度地避免基本语法错误,也保证了代码的可读性。这所谓工欲善其事,必先利其器,个人推荐 eslint+vscode 来写 vue,绝对有种飞一般的感觉。效果如图: eslintGif.gif 每次保存,vscode 就能标红不符合 eslint 规则的地方,同时还会做一些简单的自我修正。安装步骤如下:

    首先安装 eslint 插件 eslint1.png

    安装并配置完成 ESLint 后,我们继续回到 VSCode 进行扩展设置,依次点击 文件 > 首选项 > 设置 打开 VSCode 配置文件,添加如下配置

     "files.autoSave":"off", "eslint.validate": [ "Javascript", "Javascriptreact", "html", {"language":"vue","autoFix":true} ], "eslint.options": { "plugins": ["html"] } 

    这样每次保存的时候就可以根据根目录下.eslintrc.js 你配置的 eslint 规则来检查和做一些简单的 fix。这里提供了一份我平时的 eslint 规则地址,都简单写上了注释。每个人和团队都有自己的代码规范,统一就好了,去打造一份属于自己的 eslint 规则上传到 npm 吧,如饿了么团队的config,vue 的config


    封装 axios

    我们经常遇到一些线上的 bug,但测试环境很难模拟。其实可以通过简单的配置就可以在本地调试线上环境。 这里结合业务封装了 axios,线上代码

    import axios from 'axios'; import { Message } from 'element-ui'; import store from '../store'; import router from '../router'; export default function _fetch(options) { return new Promise((resolve, reject) => { const instance = axios.create({ baseURL: process.env.BASE_API, //通过 env 环境变量切换 api 地址 // timeout: 2000, //请求超时时间 headers: { 'X-Ivanka-Token': store.getters.token }//后台项目,每个请求都需要 token,判断权限 }); instance(options) .then(respOnse=> { const res = response.data; //我司通过自定义 code 来判断 如:code 不等于 20000 就被试为异常 if (res.code !== 20000) { console.log(options); // for debug Message({ message: res.message, type: 'error', duration: 5 * 1000 }); // 50014:Token 过期了 50012:其他客户端登录了 50008:非法的 token if (res.code === 50008 || res.code === 50014 || res.code === 50012) { Message({ message: res.message, type: 'error', duration: 5 * 1000 }); // 登出 store.dispatch('FedLogOut').then(() => { router.push({ path: '/login' }) }); } reject(res); } resolve(res); }) .catch(error => { Message({ message: '发生异常错误,请刷新页面重试,或联系程序员', type: 'error', duration: 5 * 1000 }); console.log(error); // for debug reject(error); }); }); } 
    //使用 export function getInfo(token) { return _fetch({ url: '/user/info', method: 'get', params: { token } }); } 

    比如后台项目,每一个请求都是要带 token 来验证权限的,这样封装以下的话我们就不用每个请求都手动来塞 token,或者来做异常处理,一劳永逸。 而且因为我们的 api 是更具 env 环境变量动态切换的,如果以后线上出现了 bug,我们只要将配置 dev.env.js

    module.exports = { NODE_ENV: '"development"', BASE_API: '"https://api-dev"', //修改为'"https://api-prod"'就行了 APP_ORIGIN: '"https://wallstreetcn.com"' //为公司打个广告 pc 站为 vue+ssr } 

    妈妈再也不用担心我调试线上 bug 了。 当然这里只是简单举了个例子,axios 还可以执行多个并发请求,拦截器什么的,大家自行去研究吧。


    多环境

    vue-cli 默认只提供了 dev 和 prod 两种环境。但其实正真的开发流程可能还会多一个 sit 环境,就是所谓的测试环境。所以我们就要简单的修改一下代码。其实很简单就是设置不同的环境变量

    "build:prod": "NODE_ENV=production node build/build.js", "build:sit": "NODE_ENV=sit node build/build.js", 

    之后在代码里自行判断,想干就干啥

    var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv 

    新版的 vue-cli 也内置了 webpack-bundle-analyzer一个模块分析的东西,相当的好用。使用方法也很简单,和之前一样封装一个 npm script 就可以。

    //package.json "build:sit-preview": "NODE_ENV=sit npm_config_preview=true npm_config_report=true node build/build.js" //之后通过 process.env.npm_config_report 来判断是否来启用 webpack-bundle-analyzer var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 

    效果图 analyzer.png webpack-bundle-analyzer 这个插件还是很有用的,对后期的代码优化什么的,最重要的是它够装逼~


    前后端交互

    每个公司都有自己一套的开发流程,没有绝对的好与坏。这里我来讲讲我司的前后端开发流程。

    跨域问题

    首先前后端交互不可避免的就会遇到跨域问题,我司现在全是用 cors 来解决的,如果你司后端嫌麻烦不肯配置的话,dev 环境也可以通过 webpack-dev-server 的 proxy 来解决,开发环境用 nginx 反代理一下就好了,具体配置这里就不展开了。

    前后端的交流问题

    其实大家也知道,平时的开发中交流成本占据了我们很大一部分时间,但前后端如果有一个好的协作方式的话能解决很多时间。我司开发流程都是前后端和产品讨论项目,之后 后端 mock api 生成好文档,我们前端才是对接接口的。这里推荐一个文档生成器swagger swagger是一个 REST APIs 文档生成工具,可以在许多不同的平台上从代码注释中自动生成,开源,支持大部分语言,社区好,总之就是一个神奇,给大家透露一下我司的 api 文档(swagger 自动生成,ui 忽略)

    Paste_Image.png url 地址,需要传是没参数,需要的传参类型,返回的数据格式什么都一清二楚了,我们大前端终于不用再看后端的脸色了~

    前端自行 mock

    如果后端不肯来帮你 mock 数据的话,前端自己来 mock 也是很简单的。你可以使用 mock server 或者使用mockjs+rap也是很方便的。


    iconfont

    element-ui 默认的 icon 不是很多,这里要安利一波阿里的iconfont简直是神器,不管是公司项目还是个人项目都在使用。它提供了 png,ai,svg 三种格式,同时使用也支持 unicode,font-class,symbol 三种方式。由于是管理后台对兼容性要求不高,楼主平时都喜欢用 symbol,就是用 svg 的方式引入 iconfont.js,之后就能欢快的去选 icon 了,还能自己上传 icon。晒一波我司后台的图标(都是楼主自己发挥的)。 iconfont.png


    router-view

    different router the same component vue。真实的业务场景中,这种情况很多。比如router-view.png 我创建和编辑的页面使用的是同一个 component,默认情况下当这两个页面切换时并不会触发 vue 的 created 或者 mounted 钩子,官方说你可以通过 watch $route 的变化来做处理,但其实说真的还是蛮麻烦的。后来发现其实可以简单的在 router-view 上加上一个唯一的 key,来保证路由切换时都会重新渲染触发钩子了。这样简单的多了。

    <router-view :key="key"></router-view> computed: { key() { return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date() } } 

    优化

    有些人会觉得现在构建是不是有点慢,我司现在技术栈是容器服务,后台项目会把 dist 文件夹里的东西都会打包成一个 docker 镜像,基本步骤为

    npm install npm run build:prod 加打包镜像,一共是耗时如下 

    Paste_Image.png

    还是属于能接受时间的范围。 主站 PC 站基于 nodejs、Vue 实现服务端渲染,所以不仅需要依赖 nodejs,而且需要利用 pm2 进行 nodejs 生命周期的管理。为了加速线上镜像构建的速度,我们利用 taobao 源 https://registry.npm.taobao.org 进行加速, 并且将一些常见的 npm 依赖打入了基础镜像,避免每次都需要重新下载。 这里注意下 建议不要使用 cnpm install 或者 update 它的包都是一个 link,反正会有各种诡异的 bug,这里建议这样使用

    npm install --registry=https://registry.npm.taobao.org 

    如果你觉得慢还是有可优化的空间如使用 webpack dll 或者把那些第三方 vendor 单独打包 external 出去,或者我司现在用的是 http2 可以使用 AggressiveSplittingPlugin 等等,这里有需求的可以自行优化。


    占坑

    常规占坑,这里是手摸手,带你用 vue 撸后台 系列一,下一篇会主要讲讲搭建用户系统,二次登录,权限验证这些东西,有时间的话,还会写一下基于 element-ui 动态换肤的实现方案。或者大家可以留言说说想要看一些什么。

    13 条回复    2017-06-13 16:03:18 +08:00
    code4life
        1
    code4life  
       2017-05-03 14:57:16 +08:00
    不错,强烈前排支持!!!
    准备顺着你的路子学下去,楼主一定要及时更新,加油!
    kslr
        2
    kslr  
       2017-05-03 15:03:46 +08:00
    ESLint 有时候会破坏掉代码,所以默认开自动修正不会有问题吗
    Olive
        3
    Olive  
       2017-05-03 15:06:07 +08:00
    手摸手,好可怕
    loading
        4
    loading  
       2017-05-03 15:08:00 +08:00 via Android
    只要是 vuejs 相关的都要支持。
    PanJiaChen
        5
    PanJiaChen  
    OP
       2017-05-03 15:10:09 +08:00
    @kslr 个人习惯了 养成习惯就好。也可以写完一个模块之后统一 npm run lint
    Mbin
        6
    Mbin  
       2017-05-03 15:58:44 +08:00
    楼主写得很不错,赞一个
    HLT
        7
    HLT  
       2017-05-03 16:14:42 +08:00 via iPhone
    凑表脸的 还摸我手
    Tunar
        8
    Tunar  
       2017-05-03 16:28:31 +08:00 via Android
    别摸我,痒~
    forzalianjunting
        9
    forzalianjunting  
       2017-05-03 16:30:48 +08:00
    赞,和我司目前某个项目的后台结构很像,去年刚接手的时候直接就上的 vue+element-ui,开发效率直线上升
    lyseky
        10
    lyseky  
       2017-05-03 23:07:23 +08:00
    前端膜拜一下
    billyu
        11
    billyu  
       2017-05-04 09:33:46 +08:00
    node -v7.7.3
    npm -v4.1.2

    npm install:
    npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0 (node_modules\chokidar\node_modules\fsevents):
    npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

    请问这是啥情况?
    PanJiaChen
        12
    PanJiaChen  
    OP
       2017-05-04 09:56:26 +08:00
    @billyu npm 依赖问题,只是一个 warning 忽略就可以了
    DearTanker
        13
    DearTanker  
       2017-06-13 16:03:18 +08:00
    看了一圈过去,感觉都是针对后台的框架,有没有针对前台的框架可以推荐的?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3556 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 00:13 PVG 08:13 LAX 16:13 JFK 19:13
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86