Vue-CLI-2.x全家桶架构,支持打包后自动部署到服务器构建案例
今天有时间分享一些平时自己开发上的一些构建配置,我们以Vue-CLI-2.x来构建开发环境。
好,我们先来看一下我们要做哪些工作。
现附上源码地址,https://github.com/749264345/...
1.Vue,Vuex,vue-router,axios通过CDN引入;优化打包后文件过大的问题
2.开发环境区分开发,测试,生产;提高开发效率
3.打包区分测试与生产
4.实现项目打包后自动部署到远程服务器
5.模块化构建vuex状态管理
6.打包后自动清除console.log()
7.项目默认基于Element-ui,对相关组件二次封装
8.模块化构建axios请求响应拦截器
一寸光阴一寸金,寸金难买寸光阴~
废话不多说,直接撸起袖子就是干~~
1.Vue,Vuex,vue-router,axios通过CDN引入
在过去我们都习惯使用npm或者cnpm安装依赖,因为这种操作非常方便,但是有利必有弊,有些小伙伴在将项目打包后会发现打包后的js文件非常庞大,有些甚至达到了几兆,所以最终导致应用打开时首屏加载非常慢,因此我们可以使用传统的引入方式,也就是CDN引入。
Vue,Vuex,vue-router,axios,这些均为静态资源,我们从它们官网下载适合的版本后放入项目根目录【static】文件夹,然后修改几个地方:
首先,index.html
<!--兼容ie--> <script src="./static/libs/polyfill.min.js"></script> <script src="./static/libs/eventsource.js"></script> <!--vue--> <script src="./static/libs/vue.js"></script> <script src="./static/libs/vue-router.min.js"></script> <script src="./static/libs/element-ui/element-ui.js"></script> <script src="./static/libs/axios.js"></script> <script src="./static/libs/vuex.js"></script>
然后修改,build/webpack.base.conf.js
module.exports = { externals: { 'vue': 'Vue', 'vuex': 'Vuex', 'vue-router': 'VueRouter', 'axios': 'axios' }, ... }
到这里基本配置已经完成,最后一步需要在main.js中删除原先对这些模块的import操作即可。这样后再打包项目,你会发现页面非常丝滑,几乎秒开。
2.开发环境区分开发,测试,生产;提高开发效率
在调试接口,或者debug的时候我们经常会切换环境,而且在打包的时候又要改成生产的接口,这样没有效率,所以我们可以做如下配置。
在config/dev.env.js文件中,
const TARGET = process.env.npm_lifecycle_event; //开发环境 if (TARGET === 'dev') { var data = { NODE_ENV: '"dev"', API: '"http://www.dev.com"' } } //测试环境 if (TARGET === 'test') { var data = { NODE_ENV: '"test"', API: '"http://www.test.com"' } } //生产环境 if (TARGET === 'prod') { var data = { NODE_ENV: '"prod"', API: '"http://www.prod.com"' } }
我们从process.env.npm_lifecycle_event中获得当前node执行的环境来区分项目运行的环境,这样我们可以用来区分接口环境,因此我们添加相关指令。
在根目录package.json文件中,
"scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "test": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "prod": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js" },
添加三条指令,分别为dev,test,prod对应config/dev.env.js文件中添加的三个环境。
到这里我们完成了开发环境的区分。
3.打包区分测试与生产
原理和上面一致,
在config/prod.env.js文件中,
const TARGET = process.env.npm_lifecycle_event; //测试环境 if (TARGET === 'build:test') { module.exports = { NODE_ENV: '"build:test"', NODE_NAME: '"测试"', API: '"http://www.test.com"' } } //生产环境 if (TARGET === 'build:prod') { module.exports = { NODE_ENV: '"build:prod"', NODE_NAME: '"生产"', API: '"http://www.prod.com"' } }
同时在根目录package.json文件中,
"scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "test": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "prod": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "build:test": "node build/build.js", "build:prod": "node build/build.js" },
我们看到添加了最后2条指令,这里我么就可以直接打测试包,与生产包。
而不需要每次在项目中修改代码。
4.实现项目打包后自动部署到远程服务器
首先安装
npm install scp2 --save-dev
然后修改项目build/build.js
添加如下代码,
var scpClient = require('scp2'); var serverConf = require('../config/prod.env'); const spinner2 = ora('正在发布到' + serverConf.NODE_NAME + '服务器...'); spinner2.start(); scpClient.scp('dist/', serverConf.server, function (err) { spinner2.stop(); if (err) { console.log(chalk.red('发布失败.\n')); throw err; } else { var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); var hour = date.getHours(); var minute = date.getMinutes(); var second = date.getSeconds(); console.log(chalk.green( 'Success! 成功发布到' + serverConf.NODE_NAME + '服务器! \n' + year + '年' + month + '月' + day + '日 ' + hour + ':' + minute + ':' + second )); } } );
另外,我们添加了发布后显示当期时间的功能,方便我们查看。
我们远程服务器的配置信息放在在config/prod.env.js文件中,如下,
//测试环境 if (TARGET === 'build:test') { module.exports = { NODE_ENV: '"build:test"', NODE_NAME: '"测试"', API: '"http://192.168.1.123:8080"', server: { host: '192.168.1.123', port: 3122, username: 'root', password: '2019111', path: '/usr/local/nginx/html/test' } } }
到这里我们完成了,自动部署的功能,命令行输入
npm run build:test
稍等片刻,
OK,完美~
5.模块化构建vuex状态管理
由于篇幅,以及对于vuex的配置有很多,这里不再做阐述。
6.打包后自动清除console.log()
打开build/webpack.prod.conf.js添加一个插件,
plugins:[ new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false, drop_console: true, pure_funcs: ['console.log'] } }, sourceMap: config.build.productionSourceMap, parallel: true }), ]
这样,项目打包后的console.log()将不会出现在控制台,很干净。
7.项目默认基于Element-ui,对相关组件二次封装
这里我们以element-ui分页组件为例,
我们新建一个vue文件,
<template> <el-pagination background style="text-align:right;margin-top:10px;" popper-class="pagination" layout="total, prev, pager, next,sizes, jumper" :total="total" :page-sizes="[10, 20, 30, 40,50]" :page-size="size" :current-page="current" @size-change="sizeChange" @current-change="currentChange"></el-pagination> </template> <script> export default { data() { return { pageSize: this.size, pageCurrent: this.current } }, props: { total: { type: Number, default: 0 }, current: { type: Number, default: 1 }, size: { type: Number, default: 10 } }, methods: { currentChange(current) { this.pageCurrent = current; this.emit(); }, sizeChange(size) { this.pageSize = size; this.pageCurrent = 1; this.emit(); }, emit() { this.$emit('pageChange', { pageSize: this.pageSize, pageCurrent: this.pageCurrent }) } } } </script>
我们通过emit()方法将组件内的状态发送给父组件,父组件通过事件订阅来监听,我们来看父组件,
<script> <template> <!-- 分页 --> <Pagination v-on:pageChange="pageChange" :total="total" :current="pageCurrent" :size="pageSize"></Pagination> </template> //引入组件 import Pagination from "../components/Pagination"; export default { components: { Pagination }, data() { return { //分页数据 total: 0, pageSize: 10, pageCurrent: 1 }; }, methods: { //分页发生改变 pageChange(res) { this.pageSize = res.pageSize; this.pageCurrent = res.pageCurrent; } } }; </script>
我们使用pageChange()来监听,这样不论是代码篇幅还是逻辑都变得更清晰。
8.模块化构建axios请求响应拦截器
我们新建一个文件,interceptors.js
// 接口请求拦截器 axios.interceptors.request.use((config) => { //每次请求发起前为当前接口创建,取消请求的实例 const CancelToken = axios.CancelToken; const source = CancelToken.source(); Vue.prototype.$requestCancel = function () { source.cancel('canceled'); }; config.cancelToken = source.token; // 接口添加头信息 config.headers.Authorization = localStorage.getItem('token'); return config; }, (err) => { return Promise.reject(err); } ); // 接口响应拦截器 axios.interceptors.response.use((response) => { if (response.data.code == 200) { localStorage.setItem('token', response.headers.authorization); } else { Vue.prototype.$message.error(response.data.msg); } return response; }, (error) => { return Promise.reject(error.response.data); } );
我们通过拦截器实现token信息的统一获取和请求携带,统一提示错误信息,并且记录当前请求,并且在路由跳转时取消上一张页面的请求,提高当前页面的有效展现。
由于篇幅问题,具体其他配置请移步我的github~
源码地址,https://github.com/749264345/...
如有更优的配置方案请求在下方留言~