Vue-Cli 项目基础搭建

写在开头的开头

目标搭建一个Vue Cli 中后台项目的基础。一步一步搭建,众多知识点已经有不少文字,这里会综合比较多的链接。接触的点会多,可是篇幅,不但愿太大。
学习的时候,但愿多翻阅文档,资料地址也会引入到原文

资料

后台多是这样的以 iview-admin 为栗子在线 Demo

拆解(结合将要作的作一个iView 拆解)

  • 侧边栏菜单权限过滤,这部分实现须要配合路由,权限数据保存,跨组件通讯(iview 使用了vuex)
  • 标签页,这部分也须要吧打开的页面使用数据存起来,也搭配 keep-alive 附录中的 VUE 9个性能优化秘密?(vue-9-perf-secrets) 其中之一优化办法就是 keep-alive

将要作什么

@vue/cli 建立项目

开发环境:
+ Win10 x64
+ node v10.15.3
+ npm v6.4.1
+ @vue/cli 3.6.3
复制代码
vue create project-name
复制代码

缩减篇幅,省略具体建立过程。html

  1. step.1 选择设置,默认设置或者自定义Manually
  1. step.2 自定义配置,有 TypeScript支持,也有PWA。
  1. step.3 路由模式选择 history
  1. step.4 CSS 编译器选择
  1. step.5 ESLint 以及配置选择
  1. step.6 什么时候检查 Lint
  1. step.7 ESLint 配置文件写在哪里,能够单独文件,也能够在package.json
  1. step.8 是否保存配置信息,下次项目使用 N
  2. 自动安装依赖

目录规划

.
├── build  项目构建配置
├── public  打包所需静态资源
└── src
    ├── api  AJAX请求
    └── assets  项目静态资源
        ├── icons  SVG 图标资源
        ├── fonts  字体图标资源
        └── images  图片资源
    ├── components  业务组件
    ├── config  项目运行配置
    ├── directive  自定义指令
    ├── libs  封装工具函数
    ├── router  路由配置
    ├── store  Vuex配置
    └── views  页面文件
复制代码

字体库 && SVG

main.js 引入全局 阿里 Ant 图标字体库

SVG

图标字体,也能够用SVG代替,方案能够作一个SVG组件,经过名字,载入不一样的 SVG图标,经过size,控制图标大小,color,控制颜色便可vue


网络请求 axios封装api

给axios作个挺靠谱的封装(报错,鉴权,跳转,拦截,提示) iview-admin axios 用继承封装。当中亮点,对请求队列作了处理,屡次请求同一个地址,会节流。node

// 安装
npm i axios
复制代码
  • 统一捕获接口报错 : 用的axios内置的拦截器
  • 弹窗提示: 引入 Element UI的Message组件
  • 报错重定向: 路由钩子
  • 基础鉴权: 服务端过时时间戳和token,还有借助路由的钩子
  • 客户端支持防止 CSRF/XSRF
  • 表单序列化: 我这边直接用qs(npm模块),你有时间也能够本身写
  • 号外,对请求队列优化,尤为是翻页时屡次请求。(未完成)

请求拦截器 Axios.interceptors.request

带上本身须要的参数,好比CSRF/XSRF,基础鉴权 token,请求时间戳
对请求数据作处理,转表单,或转Json
对错误的状况统一处理webpack

响应拦截器 Axios.interceptors.interceptors

对响应结果统一处理,响应结果状态status 判断解封装,错误处理等ios

axios可配置

iview-admin libs/axios.jsgit

import axios from 'axios'
import store from '@/store'
// import { Spin } from 'iview'
const addErrorLog = errorInfo => {
  const { statusText, status, request: { responseURL } } = errorInfo
  let info = {
    type: 'ajax',
    code: status,
    mes: statusText,
    url: responseURL
  }
  if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
}

class HttpRequest {
  constructor (baseUrl = baseURL) {
    this.baseUrl = baseUrl
    this.queue = {}
  }
  getInsideConfig () {
    const config = {
      baseURL: this.baseUrl,
      headers: {
        //
      }
    }
    return config
  }
  destroy (url) {
    delete this.queue[url]
    if (!Object.keys(this.queue).length) {
      // Spin.hide()
    }
  }
  interceptors (instance, url) {
    // 请求拦截
    instance.interceptors.request.use(config => {
      // 添加全局的loading...
      if (!Object.keys(this.queue).length) {
        // Spin.show() // 不建议开启,由于界面不友好
      }
      this.queue[url] = true
      return config
    }, error => {
      return Promise.reject(error)
    })
    // 响应拦截
    instance.interceptors.response.use(res => {
      this.destroy(url)
      const { data, status } = res
      return { data, status }
    }, error => {
      this.destroy(url)
      let errorInfo = error.response
      if (!errorInfo) {
        const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))
        errorInfo = {
          statusText,
          status,
          request: { responseURL: config.url }
        }
      }
      addErrorLog(errorInfo)
      return Promise.reject(error)
    })
  }
  request (options) {
    const instance = axios.create()
    options = Object.assign(this.getInsideConfig(), options)
    this.interceptors(instance, options.url)
    return instance(options)
  }
}
export default HttpRequest


复制代码

Vuex 数据管理

面试一般都会被问到,数据通讯的问题,跨组件之间如何实现数据管理。github

固然方法不止 vuex ,web

  • props
  • provide / inject
  • 本地存储Local Storage,Cookies 也能够实现。
  • vuex,项目比较简单时,store 都在一个文件中,或者 getter,actions,mutations,mutations-types,state拆分。应用比较大的时候,能够按模块拆分。

扩展阅读

没有废话的vue高级进阶( 二 ) 8种组件通讯详解面试

import Vue from 'vue'
import Vuex from 'vuex'
// 按模块拆分
import app from './module/app'
// 打开 vuex logs
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
  state: {

  },
  mutations: {

  },
  actions: {

  },
  // 按模块引入
  modules: {
    app
  },
  strict: debug,
  plugins: debug ? [createLogger()] : []
})
复制代码

Vue Router. 作好路由守卫

包含的功能:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的连接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

高级进阶

  • 导航守卫
  • 路由元信息
  • 过分动效
  • 数据获取
  • 滚动行为
  • 路由懒加载

咱们能够作什么

  • 嵌套路由/视图表,子路由 children 能够更好的组织页面
  • 路由参数,跳转,传参,匹配
  • 过渡效果,滚动行为
  • 导航守卫,权限限定
  • 路由懒加载,结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载
  • 判断用户是否已经登陆,控制进入权限页面。
  • 定义路由的时候能够配置 meta 字段,个性化定制一些功能
  • 等等

全局前置守卫

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // todo 在路由守卫中,能够判断用户登陆状况,鉴权,
})
复制代码

菜单栏权限过滤

iview-admin 中侧边菜单栏权限,是在 router meta增长一个字段,ajax

流程

  • vuex 搭配使用 vuex-persistedstate vuex 数据持久化
  • 1.用户登陆后,获取用户权限,权限列表(列表必须能和,router meta 字段对比)
  • 2.提交用户数据,权限等到 Vuex(数据中心)
  • 3.用户权限和 router meta 生成权限列表,提交到vuex
  • 4.菜单栏页面,getter 到数据变化,更新菜单栏
  • 5.注意:思考是否须要,数据须要本地化一份,在用户刷新页面,或者vuex(数据中心)数据丢失时,还要能拿到用户权限,token等数据。

vue.config.js

Vue CLI.

调整 webpack 配置最简单的方式就是在 vue.config.js 中的 configureWebpack 选项提供一个对象:

// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      new MyAwesomeWebpackPlugin()
    ]
  }
}
复制代码

该对象将会被 webpack-merge 合并入最终的 webpack 配置。

文档中,说起链式操做 (高级)、修改 Loader 选项、替换Loader、新建Loader、修改插件,等等。

环境变量和模式

NODE_ENV
若是在环境中有默认的 NODE_ENV,你应该移除它或在运行 vue-cli-service 命令的时候明确地设置 NODE_ENV。

模式

模式是 Vue CLI 项目中一个重要的概念。默认状况下,一个 Vue CLI 项目有三个模式:

  • development 模式用于 vue-cli-service serve
  • production 模式用于 vue-cli-service buildvue-cli-service test:e2e
  • test 模式用于 vue-cli-service test:unit

注意模式不一样于 NODE_ENV,一个模式能够包含多个环境变量。也就是说,每一个模式都会将 NODE_ENV 的值设置为模式的名称——好比在 development 模式下 NODE_ENV 的值会被设置为 "development"

你能够经过为 .env 文件增长后缀来设置某个模式下特有的环境变量。好比,若是你在项目根目录建立一个名为 .env.development 的文件,那么在这个文件里声明过的变量就只会在 development 模式下被载入。

你能够经过传递 --mode 选项参数为命令行覆写默认的模式。例如,若是你想要在构建命令中使用开发环境变量,请在你的 package.json 脚本中加入:

"dev-build": "vue-cli-service build --mode development",
复制代码

在客户端侧代码中使用环境变量

只有以 VUE_APP_ 开头的变量会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中。你能够在应用的代码中这样访问它们:

console.log(process.env.VUE_APP_SECRET)
复制代码

vue.config.js

  • 有了 NODE_ENV 能够对不一样环境作出不一样的配置
  • 文件夹别名 resolve.alias
  • 设置代理 devServer,解决跨域开发问题
const path = require('path')
// Webpack包文件分析器
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

function resolve (dir) {
  return path.join(__dirname, './', dir)
}

// 项目部署基础 (webpack 的 devServer 地址)
// process.env.NODE_ENV
// 正式环境 production
// 开发环境 development
// 默认状况下,咱们假设你的应用将被部署在域的根目录下,
// 例如:https://www.my-app.com/
// 默认:'/'
// 若是您的应用程序部署在子路径中,则须要在这指定子路径
// 例如:https://www.foobar.com/my-app/
// 须要将它改成'/my-app/'
const BASE_URL = process.env.NODE_ENV === 'production'
  ? '/my-app/'
  : '/'

module.exports = {
  // 这里是对环境的配置,不一样环境对应不一样的BASE_API,以便 axios 的请求地址不一样 baseUrl 从 Vue CLI 3.3 起已弃用,请使用publicPath
  publicPath: BASE_URL,
  // tweak internal webpack configuration.
  // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
  // 若是你不须要使用eslint,把lintOnSave设为false便可
  lintOnSave: false,

  /**
   * 对内部的 webpack 配置进行更细粒度的修改
   * https://github.com/neutrinojs/webpack-chain see
   * https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
   * @param config
   */
  chainWebpack: (config) => {
    // key,value自行定义,好比.set('@@', resolve('src/components'))
    config.resolve.alias
      .set('@', resolve('src'))
      .set('api', resolve('src/api'))
      .set('common', resolve('src/common'))
      .set('components', resolve('src/components'))
  },
  /**
   * 调整 webpack 配置
   * https://cli.vuejs.org/zh/guide/webpack.html#%E7%AE%80%E5%8D%95%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F
   * @param config
   */
  configureWebpack: config => {
    // 生产and测试环境
    let pluginsPro = [
      // Webpack包文件分析器(https://github.com/webpack-contrib/webpack-bundle-analyzer)
      // new BundleAnalyzerPlugin()
    ]
    // 开发环境
    let pluginsDev = []
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置... process.env.NODE_ENV !== 'development'
      config.plugins = [...config.plugins, ...pluginsPro]
    } else {
      // 为开发环境修改配置...
      config.plugins = [...config.plugins, ...pluginsDev]
    }
  },
  // 打包时不生成.map文件
  productionSourceMap: false,
  // webpack-dev-server 相关配置 https://webpack.js.org/configuration/dev-server/
  // 这里写你调用接口的基础路径,来解决跨域,若是设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串
  // devServer: {
  //   proxy: 'localhost:3000'
  // }
  devServer: {
    // host: 'localhost',
    host: '0.0.0.0',
    port: 8000, // 端口号
    https: false, // https:{type:Boolean}
    open: true, // 配置自动启动浏览器
    hotOnly: true, // 热更新
    // 配置跨域处理,只有一个代理
    proxy: {
      '/my-app/*': {
        target: 'http://xxx.xxx.xxx.xxx:xxxx/',
        changeOrigin: true,
        pathRewrite: {
          '^/my-app': ''
        }
      },
      '/SocketWeb/*': {
        target: 'http://xxx.xxx.xxx.xxx:xxxx',
        changeOrigin: true,
        // websocket支持
        ws: true,
        secure: false
      }
    }
  }
}

复制代码
开发基础环境能够了,开发中遇到的文件夹别名,请求跨域的问题解决了,自定义配置,也能够更具本身公司的状况配置。还有比较自定义的部分能够参照文档配置。

webpack-bundle-analyzer

安装

$ npm intall webpack-bundle-analyzer --save-dev
复制代码
  1. 配置vue.config.js 打开注释 webpack-bundle-analyzer 的部分。
  2. 在script中添加
// 在运行 build 时,后台面添加  --report
npm run build --report
// 或者在script中添加新命令
"analyze": "npm_config_report=true npm run build"
复制代码

VUE 9个性能优化秘密?(vue-9-perf-secrets)