项目开发

本文介绍了Vue项目中axios的二次封装,通过config.js和setup.js进行API统一管理。讨论了环境变量和模式,如.env文件的使用,以及process.env.NODE_ENV在确定开发阶段的角色。还涉及项目优化技巧,包括生成打包报告、通过externals加载CDN资源、路由懒加载等,以提升项目性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目开发

.env(在所有的环境中被载入)

# 环境
NODE_ENV = "development"

.env.staging(只在测试环境中被载入)

# staging 预演环境,即线上的dev环境
NODE_ENV = "production"

# publicPath
VUE_APP_PUBLIC_PATH = '/'

.env.production(只在生产环境中被载入)

# 环境
NODE_ENV = "production"
# publicPath
# VUE_APP_PUBLIC_PATH = 'https://cdn.jiaoyihu.com/'
# VUE_APP_PUBLIC_PATH = '/'
VUE_APP_PUBLIC_PATH = 'http://h5.promotion.jiaoyihu.com'

在这里插入图片描述
public-path.js

const publicPath = process.env.VUE_APP_PUBLIC_PATH
module.exports = publicPath

subdirectory-path.js

const time = new Date().getTime()
const serveName = 'promotion-h5'
const subdir = serveName + '/' + time
module.exports = subdir

vue.config.js

module.exports = {
    // 为项目中的所有资源指定一个基础路径,它被称为公共路径(publicPath)
    publicPath: isProduction ? publicpath : '/',
    // 构建文件的目录
    outputDir: 'dist',
    // 生成静态资源的目录
    assetsDir: subdirectoryPath
}

线上静态资源路径:http://h5.promotion.jiaoyihu.com/promotion-h5/1610172249953/img/ic_home_daishou@2x.6ce160ad.png

本地静态资源路径:/promotion-h5/1610077464291/img/ic_home_daishou@2x.6ce160ad.png

创建 axios 实例

可以使用自定义配置新建一个 axios 实例

axios.create([config])

const instance = axios.create({
    // 设置超时时间30秒
    timeout: 30000,
    // 请求的baseUrl
    baseURL: baseUrl,
    // 请求头部信息
    headers: {
        'Content-Type': 'application/json'
    },
    // 修改请求数据
    transformRequest: [
        function (data, headers) {
            return JSON.stringify(data)
        }
    ],
    // 跨域请求时允许携带凭证(cookie)
    withCredentials: process.env.NODE_ENV === 'production'
})

config参数详情

全局的 axios 默认值

axios.defaults.baseURL = 'https://api.example.com'
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

data和contentType配合使用:

contentType: "application/x-www-form-urlencoded"
// 对应的data类型
data: "name='张三'&age=20"
contentType: "application/json"
// 对应的data类型
data: JSON.stringify({name: "张三",age: 20})即data: {"name": "张三","age": 20}

例子:

data: {
	name: '张三',
	age: 18
}
// 修改请求数据
transformRequest: [function (data, headers) {
    let ret = ''
    for (let it in data) {
        // 去除空字符串的请求字段
        if (data[it] !== '' && data[it] !== undefined) {
            if (ret !== '') ret += '&'
            ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it])
        }
    }
    return ret	// "name='张三'&age=18"
}]

Vue项目中axios的二次封装

为什么要二次封装???axios不是对ajax封装了一次吗???

api统一管理,不管接口有多少,所有的接口都可以非常清晰,易于项目后期的维护以及迭代

config.js

const prodConfigs = {
    // 开发一套,推dev1分支
    'promotion-h5.dev1.fe.sdh-dev.com': {
        apiHost: 'http://promotion-oms.dev1.server.sdh-dev.com',
        vconsole: false
    },
    // 测试一套
    'promotion-h5.test1.fe.sdh-test.com': {
        apiHost: 'http://promotion-oms.test1.server.sdh-test.com',
        vconsole: false
    },
    // 预发还没配
    'www-pre.zjyushi.com': {
        apiHost: 'https://zjyushi-oms-server-pre.youximao.com',
        vconsole: false
    },
    // 正式还没配
    'www.zjyushi.com': {
        apiHost: 'https://zjyushi-oms-server.youximao.com',
        vconsole: false
    }
}

// 线上环境默认的配置
const defaultConfig = {
    // apiHost: 'http://zjyushi-oms-server.youximao.com',
    apiHost: 'http://promotion-server.promotion.jiaoyihu.com',
    vconsole: false
}

// 本地环境配置
const localConfig = {
    apiHost: 'http://yapi.youximao.cn/mock/823',
    vconsole: false
}

let hostConfig = prodConfigs[location.hostname] || defaultConfig
if (process.env.NODE_ENV === 'development') hostConfig = localConfig

export default hostConfig

setup.js

import axios from 'axios'
import hostConfig from '@apis/config.js'

const baseUrl = hostConfig.apiHost

// 正式环境 -- 请使用真实请求 -- start
const instance = axios.create({
    // 设置超时时间30秒
    timeout: 30000,
    // 请求的baseUrl
    baseURL: baseUrl,
    // 请求头部信息
    headers: {
        'Content-Type': 'application/json'
    },
    // 修改请求数据
    transformRequest: [
        function (data, headers) {
            // 对传参 data 进行任意转换处理
            // let ret = ''
            // for (const it in data) {
            //     if (ret !== '') ret += '&'
            //     if (Object.prototype.toString.call(data[it]) === '[object Array]' && !data[it].length) {
            //         ret += encodeURIComponent(it) + '=' + '[]'
            //     } else {
            //         ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it])
            //     }
            // }
            return JSON.stringify(data)
        }
    ],
    // 跨域请求时允许携带凭证(cookie)
    withCredentials: process.env.NODE_ENV === 'production'
})

// 响应拦截器
instance.interceptors.response.use(
    res => {
        return res.data
    },
    error => {
        return Promise.reject(error)
    }
)

// 前端阻止重复请求的最核心的方法是CanelToken
const CancelToken = axios.CancelToken
function addCancel (config, $this, cancel) {
    if ($this) {
        config.CancelToken = new CancelToken(function executor (c) {
            $this[cancel] = c
        })
    }
}

function createAPI (url, method, data, $this, cancel) {
    let config = {}
    if (method === 'post' || method === 'POST') {
        config = {
            method: 'post',
            url: url,
            data
        }
    } else {
        config = {
            method: 'post',
            url: url,
            params: data
        }
    }
    addCancel(config, $this, cancel)
    return instance(config)
}
// 正式环境 -- 请使用真实请求 -- end

export default createAPI

公共响应参数

参数类型是否必填最大长度描述示例值
codeString4见协议状态码定义2000
messageString32状态码描述,code 码状态为成功状态时,可不返回些字段success
dataString19数组、对象、布尔值等。为空时返回空数组或者空对象

code码

code码状态信息操作
2000成功
2001未登录统一跳转登录页面
2002权限不足
2003不在白名单内
2004处理异常

CSS @import用法

在Vue单文件组件中使用( ; 必须要有

<style lang="less" scoped>
@import "./home.less";
</style>

Vue中的 @

Vue项目中默认定义了 @ 和 vue$ 两个别名,@就代表着到src这个文件夹的路径
在这里插入图片描述
在vue.config.js中配置自定义路径别名

const path = require('path')
function resolve(dir) {
  return path.join(__dirname, dir)
}
module.exports = {
  lintOnSave: true,
  chainWebpack: (config) => {
    config.resolve.alias
      .set('@', resolve('src'))
      .set('@assets',resolve('src/assets'))
  }
}

Vue中的 ~

~ 是 stylus-loader 的东西,~ 是相对于其他路径(文件)的

~@/assets/scss/_variables.scss 表示相对于 @ 下的 assets/scss/_variables.scss

Vue使用import…from…来导入组件,库,变量等

在这里插入图片描述

extensions指定了from后可导入的文件类型,上面定义的这3类可导入文件,js和vue是可以省略后缀的,json不可以省略后缀

import test from './test.vue' 等同于 import test from './test'

import test from './test.js' 等同于 import test from './test'

若test.js,test.vue同时存在于同一个文件夹下,则import的导入优先级是:js > vue

from后的来源除了文件,还可以是文件夹:import test from './components'

该情况下的逻辑是:

if(package.json存在 && package.main字段存在 && package.main指定的js存在) {package.main指定的js作为from的来源,即使该js可能格式或内容错误
} else if(index.js存在){
    取index.js作为from的来源
} else {
    取index.vue作为from的来源
}

因此若from的来源是文件夹,那么在package.json存在且设置正确的情况下,会默认加载package.json;若不满足,则加载index.js;若不满足,则加载index.vue

注意加载文件夹的形式与上面省略后缀的形式是完全相同的,所以一个省略后缀的from来源有可能是 .vue .js 或者文件夹

环境变量和模式

下列文件来指定环境变量:

.env                # 在所有的环境中被载入
.env.local          # 在所有的环境中被载入,但会被 git 忽略
.env.[mode]         # 只在指定的模式中被载入
.env.[mode].local   # 只在指定的模式中被载入,但会被 git 忽略

如 .env 文件:

# 环境
NODE_ENV = "development"

被载入的环境变量将会对 vue-cli-service 的所有命令、插件和依赖可用

环境加载属性

为一个特定模式准备的环境文件(例如.env.production文件)将会比一般的环境文件(例如.env)拥有更高的优先级,此外Vue CLI 启动时已经存在的环境变量拥有最高优先级,并不会被 .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 ,一个模式可以包含多个环境变量

你可以通过传递 --mode 选项参数为命令行覆写默认的模式,如果你想要在构建命令中使用开发环境变量,请在你的 package.json 脚本中加入

"dev-build": "vue-cli-service build --mode development"

process.env.NODE_ENV

process对象是全局变量,它提供当前 node.js 的有关信息,以及控制当前 node.js 的有关进程。因为是全局变量,它对于node应用程序是始终可用的,无需require()。process是一个对象,env是它的一个属性,这个属性返回包含用户环境信息的对象。在终端输入node后,在输入process.env可以看到打印出来的信息

NODE_ENV不是process.env对象上原有的属性,它是我们自己添加上去的一个环境变量,用来确定当前所处的阶段。一般生产阶段设为production,开发阶段设为develop,然后在脚本中读取process.env.NODE_ENV

项目优化

生成打包报告

打包时,为了直观地发现项目中存在的问题,可以在打包时生成报告,生成报告的方式有两种:

  • 在package.json中配置的方式,生成report.html以帮助分析打包报告

    "scripts": {
    	"build": "vue-cli-service build --report"
    }
    
  • 在可视化的Vue CLI面板的控制台和分析直接查看报告

通过externals加载外部CDN资源

默认情况下,通过import语法导入的第三方依赖包,最终会被打包合并到同一个文件(chunk-vendors.js)中,从而导致打包成功后,单文件体积过大的问题

解决方法:可通过webpack的externals节点,来配置并加载外部的CDN资源,凡是声明在externals中的第三方依赖包,都不会被打包

在vue.config.js中配置

module.exports = {
    chainWebpack: config => {
        //发布模式
        config.when(process.env.NODE_ENV === 'production', config => {
           	config.entry('app').clear().add('./src/main-prod.js')
           	config.set('externals',{
                vue: 'Vue',
                'vue-router': 'VueRouter',
                axios: axios,
                echarts: 'echarts',
                nprogress: 'NProgress'
            })
		})
    }
}

然后需要在public/index.html文件的头部,添加如下的CDN资源引用:

<!-- nprogress的样式表文件 -->
<link href="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.0.2/vue.cjs.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.4.8/vue-router.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.0.0-beta.2/echarts.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>

Element-UI组件按需加载或通过CDN加载Element-UI

虽然启用了element-ui组件的按需加载,尽可能的减少了打包的体积,但是那些被按需加载的组件还是占用了较大的文件体积。此时可以将element-ui中的组件通过CDN形式来加载,能够进一步减小打包后的文件体积

在main-prod.js中,将element-ui按需加载的代码(*import* './plugins/element.js')删除

在public/index.html文件的头部,添加如下的CDN资源引用:

<!-- element-ui的样式表文件 -->
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.0/theme-chalk/index.css" rel="stylesheet">
<!-- element-ui的js文件 -->
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.0/index.js"></script>

路由懒加载

首页内容定制

nprogress插件添加进度条效果

只在发布(生产)阶段移除所有的console

babel.config.js是全局共享的配置文件,不管是项目开发阶段还是发布阶段 babel.config.js 配置文件都会生效

  • 安装:npm install babel-plugin-transform-remove-console --sav-dev

  • 在babel.config.js中配置

    const prodPlugins = []
    if(process.env.NODE_ENV === 'production'){
        prodPlugins.push('transform-remove-console')
    }
    module.exports = {
        plugins: [
            //发布阶段需要用到的插件数组
            ...prodPlugins
        ]
    }
    

通过vue.config.js修改Vue项目中webpack的默认配置

为开发模式和发布模式指定不同的打包入口

默认情况下,Vue项目的开发模式与发布模式共用同一个打包的入口文件。为了将项目的开发过程和发布过程分离,可以为两种模式,各自指定打包的入口文件

在vue.config.js中配置

module.exports = {
    chainWebpack: config => {
        //发布模式
        config.when(process.env.NODE_ENV === 'production', config => {
           	config.entry('app').clear().add('./src/main-prod.js')
		})
        //开发模式
        config.when(process.env.NODE_ENV === 'development', config => {
           	config.entry('app').clear().add('./src/main-dev.js')
		})
    },
    configureWebpack: () => {}
}

chainWebpack和configureWebpack的作用相同,唯一的区别就是它们修改webpack配置的方式不同

  • chainWebpack通过链式编程的形式来修改默认的webpack配置
  • configureWebpack通过操作对象的形式来修改默认的webpack配置

项目上线相关配置

  • 通过node创建web服务器
  • 开启gzip配置
  • 配置https服务
  • 使用pm2管理应用

参考文章

Vue项目中路径使用的@和~的区别

Vue中import from的来源:省略后缀与加载文件夹

Vue CLI环境变量和模式

process.env.NODE_ENV

Vue CLI指南

axios中取消请求及阻止重复请求的方法

Axios请求配置参数详解

axios API

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值