浅谈Webpack下多环境配置的思路


Posted in Javascript onJune 27, 2018

前言

由于前后端分离的前端应用脱离了后端的支持,在单独开发前端应用时,页面调试时使用固定的开发环境地址还好,如果出现在本地开发时需要调试不同环境的远端API,或者需要将应用部署到不同环境的服务器上时,如果不将这些环境对应的服务器地址、环境专属变量等单独配置,也许每次切换环境都需要修改大量代码。网上关于这部分的资料较少,所以下面将以用vue-cli init命令生成的Vue/Webpack项目作为例子,介绍一下我当前正在使用的简单的多环境配置的思路。

1、理想中的多环境配置

在后端开发中,项目中不同环境对应的参数配置在不同的配置文件中。当需要打包基于Maven的Java项目时,通常只需要在打包命令的后面加上-P参数指定Profile环境,即可打包出对应环境的包,同理前端在使用webpack开发或者打包时如果也能这么做,就会方便很多。

/* maven常用打包命令 */
mvn clean package -P prod

而在前端项目中,调试与打包命令vue-cli init已经为我们在package.json中生成好了。

/* /package.json */
"scripts": {
  "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
  "start": "npm run dev",
  "lint": "eslint --ext .js,.vue src",
  "build": "node build/build.js"
 }

如果可以将这些命令改造成后端中类似的打包命令,就很方便了,例如:

/* 改造后的命令,只是打个比方,实际并不一定是这样 */
"scripts": {
  "start:dev": "npm run dev -P dev",
  "build:test": "node build/build.js -P test"
 }

/* 命令行 */
$ npm run start:dev //本地调试,开发环境
$ npm run build:test //打包,测试环境

所以首先需要解决的是如何把参数传递到调试/打包的脚本中。

注意:这里想特别说明一下的是,vue-cli脚手架帮我们生成好了整个项目,而且也有对应webpack.dev.conf.jswebpack.prod.conf.js两个分离的webpack配置文件,但由于文件的命名问题(dev.conf.js/prod.conf.js),很容易让人误以为这两个文件就是webpack针对不同环境的配置。但实际上这两个文件一个是用于本地调试时的配置文件,另一个是用于打包部署的配置文件。调试/打包两种模式 与 环境(dev/test/pre/prod等)是可以相互组合的。理论上来讲这两个webpack的配置文件我觉得应该叫webpack.debug.conf.jswebpack.build.conf.js会更贴切一点。

2、脚本参数化

node.js中传递参数到脚本中,有多种方法,例如使用process.argv

/* hello.js */
console.log('hello ', process.argv[2]);

/* 命令行 */
$ node ./hello.js tidus
//process.argv = ['node', './hello.js', 'tidus']
hello tidus

虽然process.argv很方便,但可配置性不高,所以这里用的是yargs,它是node.js中的一个组件,可以通过npm直接安装。
===>戳我查看yargs的api文档

$ npm install yargs --dev --save

/* hello.js */
const argv = require('yargs').argv;
console.log('hello ', argv.env);

/* 命令行 */
$ node ./hello.js --env test
hello test

通过yargs可以方便的获取指定名称的命令行参数,接下来就要看看如何利用这个参数实现多文件配置。

3、引入环境变量

首先在Webpack的官网中已经有过简单介绍如何配置环境变量的文档,具体参考Webpack Production。简单的来说就是DefinePlugin插件会将我们源码中所有出现的指定字符串替换为我们提供的对象/字符串,不同环境的配置文件则放在/config目录下。

/* /build/webpack.dev.conf.js: */
plugins: [
  new webpack.DefinePlugin({
   // 源码中所有 process.env 都会被替换为
   // '../config/dev.env'这个module export出来的东西
   'process.env': require('../config/dev.env')
  })
]

/* /config/dev.env.js */
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
 NODE_ENV: '"development"'
})

显然我们可以直接用这个插件为我们的多环境变量服务。

我们可以通过上面传入到脚本中的环境参数,动态加载不同环境的配置文件,以达到切换环境的目的。动态加载不同配置环境的代码:

/* /build/webpack.env.conf.js */
// 定义参数配置
const argv = require('yargs').argv;

// 获取环境变量
const env = argv.e;
process.stdout.write('the env is '+ env +'\n');

// require指定的环境配置文件
const envConfigFile = "../config/" + env + ".env.js";
process.stdout.write('the env config file is '+ envConfigFile +'\n');

// 将require的配置文件原封不动export回出去
module.exports = require(envConfigFile);

接下来要将动态加载的环境文件丢到webpack的配置文件中,由于webpack.dev.conf.jswebpack.prod.conf.js都是继承自webpack.base.conf.js,所以我们直接改写wepack.base.conf.js的插件配置部分,直接添加DefinePlugin插件的配置,并去掉原配置文件该插件的配置:

/* /build/webpack.base.conf.js */

// 引入上面的webpack.env.conf模块
const envConfig = require('./webpack.env.conf')
module.exports = {
 ...
 ,
 // 配置DefinePlugin插件
 plugins: [
  // http://vuejs.github.io/vue-loader/en/workflow/production.html
  new webpack.DefinePlugin({
   'process.env': envConfig
  })
 ],
 ...
}

然后调试/打包的命令还是用回默认生成的命令,只不过在命令后面传入环境参数:

/* /package.json */
"scripts": {
  "start:dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --e dev",
  "start:test": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --e test",
  "start:pre": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --e pre",
  "start:prod": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --e prod",
  "build:dev": "node build/build.js --e dev",
  "build:test": "node build/build.js --e test",
  "build:pre": "node build/build.js --e pre",
  "build:prod": "node build/build.js --e prod",
 }

我们的环境配置文件中的内容可以是这样的:

/* /config/test.env.js */
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
 NODE_ENV: '"test"',
 API_HOST: '"http://test.xx.com:8080"'
})

然后我们就可以在源码中使用process.env.NODE_ENV来获取我们配置的环境变量的值,甚至可以单独抽离一个api模块:

/* /src/api/index.js */
const API_HOST = process.env.API_HOST;

export default {
 api1: `${API_HOST}/path/to/api1`,
 api2: `${API_HOST}/path/to/api2`
}

最后,在我们的Vue组件中就可以很方便的使用这些环境配置了:

/* /src/components/HelloWorld.vue */
 import api from '@/api';
 data () {
   return {
    msg: 'Welcome to Your Vue.js App',
    env: process.env.NODE_ENV,
    api1: api.api1,
    api2: api.api2
   }
  }

4、总结

整个流程下来,我们添加了一个webpack.env.conf.js模块,稍微小修改了一下vue-cli生成的3个webpack配置文件,并在config目录下添加了各个环境的配置文件,项目的结构是这样子的:

浅谈Webpack下多环境配置的思路

目录结构

最终在页面上看到的是这样子的:

浅谈Webpack下多环境配置的思路

输出环境参数

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery实现网页跳转或用命令打开指定网页的解决方法
Jul 09 Javascript
jquery获取html元素的绝对位置和相对位置的方法
Jun 20 Javascript
用jquery修复在iframe下的页面锚点失效问题
Aug 22 Javascript
使用typeof方法判断undefined类型
Sep 09 Javascript
使用javascript实现Iframe自适应高度
Dec 24 Javascript
jQuery插件zoom实现图片全屏放大弹出层特效
Apr 15 Javascript
jquery实现表单验证并阻止非法提交
Jul 09 Javascript
JavaScript操作XML/HTML比较常用的对象属性集锦
Oct 30 Javascript
老生常谈原生JS执行环境与作用域
Nov 22 Javascript
JS设置时间无效问题的解决办法
Feb 18 Javascript
vue父组件点击触发子组件事件的实例讲解
Feb 08 Javascript
通过JS深度判断两个对象字段相同
Jun 14 Javascript
Vue使用vue-area-linkage实现地址三级联动效果的示例
Jun 27 #Javascript
详解关于vue-area-linkage走过的坑
Jun 27 #Javascript
详解nuxt sass全局变量(公共scss解决方案)
Jun 27 #Javascript
Vue引入sass并配置全局变量的方法
Jun 27 #Javascript
详解解决使用axios发送json后台接收不到的问题
Jun 27 #Javascript
vue中v-model的应用及使用详解
Jun 27 #Javascript
JS基于封装函数实现的表格分页完整示例
Jun 26 #Javascript
You might like
深入浅析Yii admin的权限控制
2016/08/31 PHP
Yii框架分页技术实例分析
2019/08/30 PHP
怎么让脚本或里面的函数在所有图片都载入完毕的时候执行
2006/10/17 Javascript
Jquery 组合form元素为json格式,asp.net反序列化
2009/07/09 Javascript
基于jquery的loading 加载提示效果实现代码
2011/09/01 Javascript
javascript数组的使用
2013/03/28 Javascript
jquery如何通过name名称获取当前name的value值
2013/12/20 Javascript
JavaScript使用RegExp进行正则匹配的方法
2015/07/11 Javascript
JS特效实现图片自动播放并可控的效果
2015/07/31 Javascript
JS随机洗牌算法之数组随机排序
2016/03/23 Javascript
文件上传插件SWFUpload的使用指南
2016/11/29 Javascript
vuejs指令详解
2017/02/07 Javascript
Vue.use源码分析
2017/04/22 Javascript
详解使用angular-cli发布i18n多国语言Angular应用
2017/05/20 Javascript
基于vue-simplemde实现图片拖拽、粘贴功能
2018/04/12 Javascript
Vue中使用vux配置代码详解
2018/09/16 Javascript
vue 根据选择条件显示指定参数的例子
2019/11/09 Javascript
Python使用scrapy抓取网站sitemap信息的方法
2015/04/08 Python
使用70行Python代码实现一个递归下降解析器的教程
2015/04/17 Python
详解在Python中处理异常的教程
2015/05/24 Python
浅析python3中的os.path.dirname(__file__)的使用
2018/08/30 Python
python3实现在二叉树中找出和为某一值的所有路径(推荐)
2019/12/26 Python
python GUI库图形界面开发之PyQt5布局控件QGridLayout详细使用方法与实例
2020/03/06 Python
python 浮点数四舍五入需要注意的地方
2020/08/18 Python
Python 如何实现数据库表结构同步
2020/09/29 Python
利用Canvas模仿百度贴吧客户端loading小球的方法示例
2017/08/13 HTML / CSS
Ralph Lauren法国官网:美国高品味时装品牌
2017/12/08 全球购物
家长给孩子的表扬信
2014/01/17 职场文书
模范教师事迹材料
2014/02/10 职场文书
员工三分钟演讲稿
2014/08/19 职场文书
计算机专业自荐信范文
2015/03/26 职场文书
物流业务员岗位职责
2015/04/03 职场文书
小学语文教学随笔
2015/08/14 职场文书
申论不会写怎么办?教您掌握这6点思维和原则
2019/07/17 职场文书
pandas:get_dummies()与pd.factorize()的用法及区别说明
2021/05/21 Python
Python中time标准库的使用教程
2022/04/13 Python