浅谈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 相关文章推荐
javascript实现tabs选项卡切换效果(自写原生js)
Mar 19 Javascript
javascript基于HTML5 canvas制作画箭头组件
Jun 25 Javascript
js实现跟随鼠标移动且带关闭功能的图片广告实例
Feb 26 Javascript
JS判断页面是否出现滚动条的方法
Jul 17 Javascript
jQuery获取浏览器类型和版本号的方法
Jul 05 Javascript
基于openlayers4实现点的扩散效果
Aug 17 Javascript
Vue全局分页组件的实现代码
Aug 10 Javascript
深入浅析Vue 中 ref 的使用
Apr 29 Javascript
vue-element-admin 菜单标签失效的解决方式
Nov 12 Javascript
小程序新版订阅消息模板消息
Dec 31 Javascript
vue基于better-scroll实现左右联动滑动页面
Jun 30 Javascript
Vue2.x和Vue3.x的双向绑定原理详解
Nov 05 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
基于OpenCV的PHP图像人脸识别技术
2009/10/11 PHP
PHP 判断变量类型实现代码
2009/10/23 PHP
PHP提取字符串中的图片地址[正则表达式]
2011/11/12 PHP
php+mysql不用递归实现的无限级分类实例(非递归)
2014/07/08 PHP
php生成不重复随机数、数组的4种方法分享
2015/03/30 PHP
帝国CMS留言板回复后发送EMAIL通知客户
2015/07/06 PHP
详谈php静态方法及普通方法的区别
2016/10/04 PHP
laravel实现按时间日期进行分组统计方法示例
2019/03/23 PHP
Laravel (Lumen) 解决JWT-Auth刷新token的问题
2019/10/24 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
2020/02/27 PHP
自动检查并替换文本框内的字符
2006/06/30 Javascript
Node.js开发指南中的简单实例(mysql版)
2013/09/17 Javascript
JavaScript获取flash对象与网上的有所不同
2014/04/21 Javascript
js判断当前浏览器类型,判断IE浏览器方法
2014/06/02 Javascript
jQuery中andSelf()方法用法实例
2015/01/08 Javascript
javascript函数特点实例分析
2015/05/14 Javascript
jQuery图片轮播滚动切换代码分享
2020/04/20 Javascript
js实现PC端和移动端刮卡效果
2020/03/27 Javascript
ES6新特性八:async函数用法实例详解
2017/04/21 Javascript
ES6学习教程之对象的扩展详解
2017/05/02 Javascript
js实现鼠标单击Tab表单切换效果
2018/05/16 Javascript
JS使用for in有序获取对象数据
2020/05/19 Javascript
使用python编写android截屏脚本双击运行即可
2014/07/21 Python
Python利用正则表达式匹配并截取指定子串及去重的方法
2015/07/30 Python
Python正则表达式如何进行字符串替换实例
2016/12/28 Python
详解Appium+Python之生成html测试报告
2019/01/04 Python
css3让div随鼠标移动而抖动起来
2014/02/10 HTML / CSS
资产评估专业大学生求职信
2013/09/29 职场文书
社区春季防火方案
2014/06/02 职场文书
安全环保演讲稿
2014/08/28 职场文书
青年文明号汇报材料
2014/12/23 职场文书
物业管理交接协议书
2016/03/24 职场文书
Python编写可视化界面的全过程(Python+PyCharm+PyQt)
2021/05/17 Python
HTTP中的Content-type详解
2022/01/18 HTML / CSS
海弦WR-800F
2022/04/05 无线电
详细介绍MySQL中limit和offset的用法
2022/05/06 MySQL