一份关于Vue-Cli5常用配置开发模板,可用作于PC网站开发、移动端网页,后台管理系统,开箱即用

  • 2023-05-22
  • dfer
  • 495

Vue-cli5

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:

  • 通过 @vue/cli 实现的交互式的项目脚手架。
  • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
  • 一套完全图形化的创建和管理 Vue.js 项目的用户界面

安装依赖

npm install 

如果本地网络卡顿,使用临时镜像,当命令行窗口关闭即失效

npm --registry http://mirrors.cloud.tencent.com/npm/ install express

开发模式

npm run dev 
or
npm run serve

打包模式

npm run build

自动上传

需要在gulpfile.js配置服务器信息

npm run upload

项目配置功能

  • ?开启文件Gzip压缩
  • ?编译去掉注释
  • ?开发服务配置
  • ?编辑器别名设置
  • ?配置环境变量
  • ?多页面应用配置
  • ?请求路由动态添加
  • ?网络请求封装
  • ?网络异常重连
  • ?配置全局less
  • ?开启分析打包日志
  • ?打包进度
  • ?全局组件通信
  • ?注入全局变量
  • ?打包CDN替换NPM包
  • ?拷贝文件
  • ?添加可选链运算符
  • ?抽离重复文件合并
  • ?配置px转换rem
  • ?动态修改主题
  • ?自动上传服务器
  • ?Nginx配置
  • ?全局事件通信

完整配置

Vue-cli5常用配置开发模板

开启文件Gzip压缩

config.plugin('CompressionPlugin')
    .use('compression-webpack-plugin', [{
        filename: '[path][base].gz',
        algorithm: 'gzip',
        test: /.js$|.css$|.html$/,
        threshold: 10240, // 只处理比这个值大的资源。按字节计算
        minRatio: 0.8 // 只有压缩率比这个值小的资源才会被处理
    }])

编译去掉注释

config.optimization.minimizer[TerserPluginIndex] = new TerserPlugin({
    terserOptions: {
        warnings: false,
        format: {
            comments: false,
        },
        compress: {
            drop_debugger: true, // 注释console
            drop_console: true,
            pure_funcs: ['console.log'], // 移除console
        },
    },
    extractComments: false, // 是否将注释提取到一个单独的文件中
    parallel: true, // 是否并?打包
});

开发服务配置

module.exports = {
    devServer: {
        open: false, // 自动启动浏览器
        host: "0.0.0.0",
        port: 9007, // 端口号
        proxy: {
            "/api": {
                target: "https://www.api.com", // 目标代理接口地址
                pathRewrite: {
                    "^/api": "/"
                }
            }
        },
        hot: true,// 热更新
        headers: {
            'Access-Control-Allow-Origin': '*', // 微前端应用调试
        },
    }
}

编辑器别名设置

放置在根目录下,文件名为jsconfig.json

{
    "compilerOptions": {
        "target": "es5",
        "module": "esnext",
        "baseUrl": "./",
        "moduleResolution": "node",
        "paths": {
            "@/*": [
                "src/*"
            ],
            "__ROOT__/*": [
                "*"
            ]
        },
        "lib": [
            "esnext",
            "dom",
            "dom.iterable",
            "scripthost"
        ]
    }
}

配置环境变量

放置在根目录下,.env.development.env.production.env.test,等等模式文件

命令切换

vue-cli-service build --mode development
vue-cli-service build --mode production
vue-cli-service build --mode test

配置环境文件

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

多页面应用配置

module.exports = {
    pages: {
        index: {
            // page 的入口
            entry: 'src/index/main.js',
            // 模板来源
            template: 'public/index.html',
            // 在 dist/index.html 的输出
            filename: 'index.html',
            // 当使用 title 选项时,
            // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
            title: 'Index Page',
            // 在这个页面中包含的块,默认情况下会包含
            // 提取出来的通用 chunk 和 vendor chunk。
            chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        // 当使用只有入口的字符串格式时,
        // 模板会被推导为 `public/subpage.html`
        // 并且如果找不到的话,就回退到 `public/index.html`。
        // 输出文件名会被推导为 `subpage.html`。
        subpage: 'src/subpage/main.js'
    }
}

网络请求封装

文件放置http/request.js

  • 基于axios封装
  • 网络请求拦击
  • 网络响应拦截
  • 封装常用post、get、upload、download、并发请求
const http = axios.create({
    timeout: 1000 * 60,
    withCredentials: true, // 表示跨域请求时是否需要  使用凭证
    headers: {
        "Content-Type": "application/json",
    }
});

网络异常重连

基于axios发生异常重连

config.reconnectCount = config.reconnectCount || 1;
if (config.reconnectCount >= 3) { // 检查重试次数是否达到最大值
    return Promise.reject(error)
}
const backoff = new Promise(function (resolve) {  // 创建新的Promise来处理
    setTimeout(function () {
        resolve()
    }, 2000)
})
config.reconnectCount += 1  // 增加重试次数
return backoff.then(function () {  // 返回promise,其中调用axios来重试请求
    return http(config)
})

配置全局less

module.exports = {
    css: {
        loaderOptions: {
            less: {
                lessOptions: {
                    javascriptEnabled: true,
                    modifyVars: {}, // 这里也阔以声明less变量
                },
                additionalData: ` @import "~@/assets/css/variables.less";`,
            },
        }
    },
}

开启分析打包日志

npm i webpack-bundle-analyzer -D
const WebpackBundleanAlyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins.push(new WebpackBundleanAlyzer({analyzerPort: 9601}))

打包进度

npm i webpackbar -D
const WebpackBar = require('webpackbar');
plugins.push(new WebpackBar({name: 'PC', color: '#07c160'}))

全局组件通信

npm i mitt -S
import mitt from 'mitt'

app.provide('$mitt', mitt())

注入全局变量

new webpack.DefinePlugin({
    __APP__: JSON.stringify({
        lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss')
    })
})
// 在Vue单页面中
console.log(lastBuildTime) // 2023-02-23 20:22:48

打包CDN替换NPM包

使用vue inspect --plugins查看html是否在结果数组中

// 见多页面应用
Object.keys(pages).forEach(key => {
    config.plugin(`html-${key}`).tap(args => {
        args[0].cdn = isBuild ? cdn.build : cdn.dev;
        return args;
    });
})
// 单页面应用
config.plugin(`html`).tap(args => {
    args[0].cdn = isBuild ? cdn.build : cdn.dev;
    return args;
});
<!DOCTYPE html>
<html lang="">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vue-cli5模板</title>
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
    <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"/>
    <% } %>
</head>
<body>
<noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
</body>
</html>

拷贝文件

npm i copy-webpack-plugin -D
const CopyWebpackPlugin = require('copy-webpack-plugin')
plugins.push(new CopyWebpackPlugin({
    patterns: [
        {from: resolve('./README.md'), to: resolve('./dist')}
    ],
    options: {concurrency: 100}, // 并发数
}))

添加可选链运算符

npm i @babel/plugin-proposal-optional-chaining -D
module.exports = {
    presets: [
        '@vue/cli-plugin-babel/preset'
    ],
    plugins: [
        "@babel/plugin-proposal-optional-chaining" // 添加该插件
    ]
}

抽离重复文件合并

config.optimization.splitChunks({
    cacheGroups: {
        styles: {
            name: 'styles',
            test: /.(s?css|less|sass)$/,
            chunks: 'all',
            priority: 10
        },
        common: {
            name: 'chunk-common',
            chunks: 'all',
            minChunks: 2, // 拆分前必须共享模块的最小 chunks 数。
            maxInitialRequests: 5, // 打包后的入口文件加载时,还能同时加载js文件的数量(包括入口文件)
            minSize: 0, // 生成 chunk 的最小体积
            priority: 1, // 优化将优先考虑具有更高 priority(优先级)的缓存组
            reuseExistingChunk: true // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
        },
        vendors: {
            name: 'chunk-vendors',
            test: /[\/]node_modules[\/]/,
            chunks: 'all',
            priority: 2,
            reuseExistingChunk: true
        },
    }
})

配置px转换rem

npm i postcss-pxtorem -D
npm i lib-flexible -S

在入口文件引入

import 'lib-flexible/flexible'

在根目录新建.postcssrc.js文件

module.exports = {
    plugins: {
        'postcss-pxtorem': {
            rootValue: 37.5, //换算基数,
            unitPrecision: 3, //允许REM单位增长到的十进制数字,小数点后保留的位数。
            propList: ['*'],
            exclude: /(node_module)/,  //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
            selectorBlackList: ['.van'], //要忽略并保留为px的选择器,本项目我是用的vant ui框架,所以忽略他
            mediaQuery: false,  //(布尔值)允许在媒体查询中转换px。
            minPixelValue: 1 //设置要替换的最小像素值
        }
    }
}

动态修改主题


<template>
   <a-config-provider>
      <router-view></router-view>
   </a-config-provider>
</template>
<script setup>
import {ConfigProvider} from 'ant-design-vue';

ConfigProvider.config({
   theme: {
      primaryColor: '#25b864',
   },
});
</script>

自动上传服务器

执行命令

npm run upload

配置自己的服务器账号和密码

const gulp = require("gulp")
const ftp = require("gulp-ftp");

//服务器配置信息
const serverSeting = {
    host: "服务器域名",
    port: 21, //虚拟主机默认21,服务器默认22
    user: "用户名",
    pass: "密码",
    remotePath: "/dist/"
};

//把打包好的文件上传到服务器
gulp.task("server", () => {
    // 远程目录
    return gulp.src("/home/usr/www/**/*").pipe(ftp(serverSeting));
});

gulp.task('upload', gulp.series('server'))

Nginx配置

nginx常用的操作命令

#修改配置reload后看服务启动是否正常
nginx -t;
#重载nginx
nginx reload
#启动 nginx
start nginx      
#重启 nginx 
nginx -s reload   
#快速停止 nginx
nginx -s stop     
#完整有序地停止 nginx
nginx -s quit      

这里列举一份比较常用的nginx配置,具体的实际,需要看具体

server {
    listen       9999; # 监听端口
    server_name  localhost; # 域名可以有多个,用空格隔开
    
    location / {
      root   C:\工作\project\client_admin_system\dist;     #站点根目录,即网页文件存放的根目录, 默认主页目录在nginx安装目录的html子目录。
      index  index.html index.htm;    #目录内的默认打开文件,如果没有匹配到index.html,则搜索index.htm,依次类推
    }
    
    # 反向代理
    location /api {
        rewrite  ^.+api/?(.*)$ /$1 break;
        proxy_pass  http://192.168.1.100:7001;    #node api server 即需要代理的IP地址
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    #error_page  404              /404.html;    #对错误页面404.html 做了定向配置
    
    # redirect server error pages to the static page /50x.html
    #将服务器错误页面重定向到静态页面/50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   html;
    }
}

UI组件

Ant-Design-Vue

修改css变量

document.documentElement.style.setProperty('--primary-color', 'red');

如果使用Vue-cli3搭建的项目请看 一份完整的Vue-cli3项目基础配置项

如果使用Vite搭建的项目请看 一份完整的Vite3项目基础配置项