浅谈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 相关文章推荐
图片按比例缩放函数
Jun 26 Javascript
最佳6款用于移动网站开发的jQuery 图片滑块插件小结
Jul 20 Javascript
Extjs4中的分页应用结合前后台
Dec 13 Javascript
JavaScript正则表达式匹配 div  style标签
Mar 15 Javascript
Bootstrap基本样式学习笔记之图片(6)
Dec 07 Javascript
JavaScript中数组Array方法详解
Feb 27 Javascript
微信小程序 引入es6 promise
Apr 12 Javascript
vue.js利用defineProperty实现数据的双向绑定
Apr 28 Javascript
vue2 前端搜索实现示例
Feb 26 Javascript
使用bootstrap实现下拉框搜索功能的实例讲解
Aug 10 Javascript
JavaScript内置对象math,global功能与用法实例分析
Jun 10 Javascript
Javascript ParentNode和ChildNode接口原理解析
Mar 16 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
PHP经典的给图片加水印程序
2006/12/06 PHP
jQuery 源码分析笔记
2011/05/25 PHP
PHP中把错误日志保存在系统日志中(Windows系统)
2015/06/23 PHP
php版微信自定义回复功能示例
2016/12/05 PHP
JavaScript 应用类库代码
2008/06/02 Javascript
网站页面自动跳转实现方法PHP、JSP(下)
2010/08/01 Javascript
jquery获取下拉列表的值为null的解决方法
2011/03/18 Javascript
Js实现动态添加删除Table行示例
2014/04/14 Javascript
php常见的页面跳转方法汇总
2015/04/15 Javascript
JS实现网页上随机产生超链接地址的方法
2015/11/09 Javascript
30分钟快速掌握Bootstrap框架
2016/05/24 Javascript
js获取元素下的第一级子元素的方法(推荐)
2017/03/05 Javascript
vue-cli的webpack模板项目配置文件分析
2017/04/01 Javascript
使用JS中的Replace()方法遇到的问题小结
2017/10/20 Javascript
Angular之toDoList的实现代码示例
2017/12/02 Javascript
详解vue-cli@2.x项目迁移日志
2019/06/06 Javascript
JS用最简单的方法实现四舍五入
2019/08/27 Javascript
详解node和ES6的模块导出与导入
2020/02/19 Javascript
使用Python来编写HTTP服务器的超级指南
2016/02/18 Python
asyncio 的 coroutine对象 与 Future对象使用指南
2016/09/11 Python
对sklearn的使用之数据集的拆分与训练详解(python3.6)
2018/12/14 Python
详解python实现小波变换的一个简单例子
2019/07/18 Python
python 多线程死锁问题的解决方案
2020/08/25 Python
新加坡第一大健康与美容零售商:屈臣氏新加坡(Watsons Singapore)
2020/12/11 全球购物
存储过程的优缺点是什么
2015/01/10 面试题
求职简历自荐信
2013/10/20 职场文书
女大学生个人求职信
2013/12/09 职场文书
会计实习生自我鉴定
2013/12/12 职场文书
触摸春天教学反思
2014/02/03 职场文书
银行开户授权委托书格式
2014/10/10 职场文书
2014年物业管理工作总结
2014/11/21 职场文书
新学期家长寄语2016
2015/12/03 职场文书
运动会口号霸气押韵
2015/12/24 职场文书
老舍《猫》教学反思
2016/02/17 职场文书
入党转正申请书范文
2019/05/20 职场文书
图文详解nginx日志切割的实现
2022/01/18 Servers