Webpack多环境代码打包(测试、预发、正式环境)

在package.json文件的scripts中,会提供开发环境与生产环境两个命令。但是实际使用中会遇见 测试版、预发布版以及正式版代码相继发布的情况,这样反复更改服务器地址,偶尔忘记更改url会给工作带来很多不必要的麻烦。这样就需要在生产环境中配置 测试版本打包命令、预发布版本打包命令与正式版本打包命令。

具体步骤如下:

1. Package.json 文件中 增加命令行命令,并指定路径。

"scripts": {
	"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",  //开发环境打包命令
	"start": "npm run dev",
	"test": "node build/build-test.js", //测试环境打包命令
	"pre": "node build/build-pre.js",  //预发布环境打包命令
	"build": "node build/build.js", //正式环境打包命令
  },

2. 在build文件中添加相应文件

build-test.js

/**
 * 测试版
 */

'use strict'
require('./check-versions')()

process.env.NODE_ENV = 'production-test'

const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')

const spinner = ora('building for production...')
spinner.start()

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
  if (err) throw err
  webpack(webpackConfig, (err, stats) => {
	spinner.stop()
	if (err) throw err
	process.stdout.write(stats.toString({
	  colors: true,
	  modules: false,
	  children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
	  chunks: false,
	  chunkModules: false
	}) + '\n\n')

	if (stats.hasErrors()) {
	  console.log(chalk.red('  Build failed with errors.\n'))
	  process.exit(1)
	}

	console.log(chalk.cyan('  Build complete.\n'))
	console.log(chalk.yellow(
	  '  Tip: built files are meant to be served over an HTTP server.\n' +
	  '  Opening index.html over file:// won\'t work.\n'
	))

	console.log(chalk.yellow(
		'  Tip: built files are meant to be served over an HTTP server.\n' +
		' '+ process.env.NODE_ENV
	  ))
  })
})

build-pre.js

/**
 * 预发布版
 */

'use strict'
require('./check-versions')()

process.env.NODE_ENV = 'production-pre'

const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')

const spinner = ora('building for production...')
spinner.start()

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
  if (err) throw err
  webpack(webpackConfig, (err, stats) => {
	spinner.stop()
	if (err) throw err
	process.stdout.write(stats.toString({
	  colors: true,
	  modules: false,
	  children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
	  chunks: false,
	  chunkModules: false
	}) + '\n\n')

	if (stats.hasErrors()) {
	  console.log(chalk.red('  Build failed with errors.\n'))
	  process.exit(1)
	}

	console.log(chalk.cyan('  Build complete.\n'))
	console.log(chalk.yellow(
	  '  Tip: built files are meant to be served over an HTTP server.\n' +
	  '  Opening index.html over file:// won\'t work.\n'
	))

	console.log(chalk.yellow(
		'  Tip: built files are meant to be served over an HTTP server.\n' +
		' '+ process.env.NODE_ENV
	  ))
  })
})

build.js

/**
 * 正式版
 */
require('./check-versions')()

process.env.NODE_ENV = 'production'

var ora = require('ora')
var rm = require('rimraf')
var path = require('path')
var chalk = require('chalk')
var webpack = require('webpack')
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf')

var spinner = ora('building for production...')
spinner.start()

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
  if (err) throw err
  webpack(webpackConfig, function (err, stats) {
	spinner.stop()
	if (err) throw err
	process.stdout.write(stats.toString({
	  colors: true,
	  modules: false,
	  children: false,
	  chunks: false,
	  chunkModules: false
	}) + '\n\n')

	console.log(chalk.cyan('  Build complete.\n'))
	console.log(chalk.yellow(
	  '  Tip: built files are meant to be served over an HTTP server.\n' +
	  '  Opening index.html over file:// won\'t work.\n'
	))
	console.log(chalk.yellow(
	  '  Tip: built files are meant to be served over an HTTP server.\n' +
	  ' '+ process.env.NODE_ENV
	))

	 //gulp 正式站 生成 zip文件,
	 var fs = require('fs');
	 function getPackageJsonVersion () {
	   // 这里我们直接解析 json 文件而不是使用 require,这是因为 require 会缓存多次调用,这会导致版本号不会被更新掉
	   return JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
	 };
	 var gulp = require('gulp');
	 var zip = require('gulp-zip');
	 var  filename=(new Date()).toLocaleString().replace(/:/g,'');
	 console.log(chalk.yellow(
	   '  Tip: zipName.\n' +
	   ' '+ filename +getPackageJsonVersion()
	 ))
	 //创建一个文件到V.txt 到 dist 目录

	 fs.writeFile('./dist/ver.txt','版本号:'+getPackageJsonVersion(),function(err){  
	  if(err)  
		  return console.error(err);  
	  console.log('写入文件成功');  
	 });  


	 gulp.task('zip', function() {
			  gulp.src(['dist/**','README.md'])
			 .pipe(zip(`Philips_production_${filename}_v${getPackageJsonVersion()}.zip`))
			 .pipe(gulp.dest('dist1'));
	 });
	//  gulp.run('zip')
  })
})

3、在config文件中增加环境变量配置

prod-test.env.js 增加环境变量

/**
 * 测试环境配置
 */

module.exports = {
	NODE_ENV: '"production-test"',
	publicPath: './'
}

prod-pre.env.js 增加环境变量

/**
 * 预发环境配置
 */

module.exports = {
	NODE_ENV: '"production-pre"',
	publicPath: './'
}

prod.env.js

/**
 * 生产环境配置(正式)
 */

module.exports = {
	NODE_ENV: '"production"',
	publicPath: './'
}

index.js

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require('path')

module.exports = {
  dev: {  // dev开发 环境
	evn:require('./dev.env'),
	// 静态资源文件夹
	assetsSubDirectory: 'static',
	// 发布路径
	assetsPublicPath: '/',
	//配置代理(可跨域)
	proxyTable: {
	  '/api': {
		target: "http://sfe.crmclick.com",// 接口的域名
		// secure: false,  // 如果是https接口,需要配置这个参数
		changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
		pathRewrite: {
		  '^/api': '/'
		}
	  },
	  // 注意: '/api' 为匹配项,target 为被请求的地址,因为在 ajax 的 url 中加了前缀 '/api',而原本的接口是没有这个前缀的,
	  //所以需要通过 pathRewrite 来重写地址,将前缀 '/api' 转为 '/'。如果本身的接口地址就有 '/api' 这种通用前缀,就可以把 pathRewrite 删掉。
	},

	// Various Dev Server settings
	host: 'localhost', // can be overwritten by process.env.HOST
	port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
	autoOpenBrowser: false,
	errorOverlay: true,
	notifyOnErrors: true,
	poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-


	/**
	 * Source Maps
	 */

	// https://webpack.js.org/configuration/devtool/#development
	devtool: 'cheap-module-eval-source-map',

	// If you have problems debugging vue-files in devtools,
	// set this to false - it *may* help
	// https://vue-loader.vuejs.org/en/options.html#cachebusting
	cacheBusting: true,

	cssSourceMap: true
  },

  test: {  // 测试 环境
	evn:require('./prod-test.env'),
	// Template for index.html
	index: path.resolve(__dirname, '../dist/index.html'),

	// Paths
	assetsRoot: path.resolve(__dirname, '../dist'),
	assetsSubDirectory: 'static',
	assetsPublicPath: '/',

	/**
	 * Source Maps
	 */

	productionSourceMap: false,
	// https://webpack.js.org/configuration/devtool/#production
	devtool: '#source-map',

	// Gzip off by default as many popular static hosts such as
	// Surge or Netlify already gzip all static assets for you.
	// Before setting to `true`, make sure to:
	// npm install --save-dev compression-webpack-plugin
	productionGzip: false,
	productionGzipExtensions: ['js', 'css'],

	// Run the build command with an extra argument to
	// View the bundle analyzer report after build finishes:
	// `npm run build --report`
	// Set to `true` or `false` to always turn it on or off
	bundleAnalyzerReport: process.env.npm_config_report
  },

  pre: {  // 预发布 环境
	evn:require('./prod-pre.env'),
	// Template for index.html
	index: path.resolve(__dirname, '../dist/index.html'),

	// Paths
	assetsRoot: path.resolve(__dirname, '../dist'),
	assetsSubDirectory: 'static',
	assetsPublicPath: '/',

	/**
	 * Source Maps
	 */

	productionSourceMap: false,
	// https://webpack.js.org/configuration/devtool/#production
	devtool: '#source-map',

	// Gzip off by default as many popular static hosts such as
	// Surge or Netlify already gzip all static assets for you.
	// Before setting to `true`, make sure to:
	// npm install --save-dev compression-webpack-plugin
	productionGzip: false,
	productionGzipExtensions: ['js', 'css'],

	// Run the build command with an extra argument to
	// View the bundle analyzer report after build finishes:
	// `npm run build --report`
	// Set to `true` or `false` to always turn it on or off
	bundleAnalyzerReport: process.env.npm_config_report
  },

  build: { // production 正式生产 环境
	evn:require('./prod.env'), // 使用 config/prod.env.js 中定义的编译环境
	// Template for index.html
	index: path.resolve(__dirname, '../dist/index.html'), // 编译输入的 index.html 文件

	// Paths
	assetsRoot: path.resolve(__dirname, '../dist'), // 编译输出的静态资源路径
	assetsSubDirectory: 'static', // 编译输出的二级目录
	assetsPublicPath: '/', // 编译发布的根目录,可配置为资源服务器域名或 CDN 域名

	/**
	 * Source Maps
	 */

	productionSourceMap: false, // 是否开启 cssSourceMap
	// https://webpack.js.org/configuration/devtool/#production
	devtool: '#source-map',

	// Gzip off by default as many popular static hosts such as
	// Surge or Netlify already gzip all static assets for you.
	// Before setting to `true`, make sure to:
	// npm install --save-dev compression-webpack-plugin
	productionGzip: false, // 是否开启 gzip
	productionGzipExtensions: ['js', 'css'], // 需要使用 gzip 压缩的文件扩展名

	// Run the build command with an extra argument to
	// View the bundle analyzer report after build finishes:
	// `npm run build --report`
	// Set to `true` or `false` to always turn it on or off
	bundleAnalyzerReport: process.env.npm_config_report
  }
}

4. 修改 build 文件夹下的 webpack.prod.conf.js

webpack.prod.conf.js

"use strict";
const path = require("path");
const utils = require("./utils");
const webpack = require("webpack");
const config = require("../config");
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

// const env = require('../config/prod.env')

console.log('------------------+'+process.env.NODE_ENV)
console.log('------------------+'+process.env.publicPath)

const env =
  process.env.NODE_ENV === "production"
	? require("../config/prod.env")
	: process.env.NODE_ENV === "production-test"
	? require("../config/prod-test.env")
	: process.env.NODE_ENV === "production-pre"
	? require("../config/prod-pre.env")
	: require("../config/dev.env");

const webpackConfig = merge(baseWebpackConfig, {
  module: {
	rules: utils.styleLoaders({
	  sourceMap: config.build.productionSourceMap,
	  extract: true,
	  usePostCSS: true
	})
  },
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
  output: {
	path: config.build.assetsRoot,
	filename: utils.assetsPath("js/[name].[chunkhash].js"),
	chunkFilename: utils.assetsPath("js/[id].[chunkhash].js")
  },
  plugins: [
	// http://vuejs.github.io/vue-loader/en/workflow/production.html
	new webpack.DefinePlugin({
	  "process.env": env
	}),
	new UglifyJsPlugin({
	  uglifyOptions: {
		compress: {
		  warnings: false
		}
	  },
	  sourceMap: config.build.productionSourceMap,
	  parallel: true
	}),
	// extract css into its own file
	new ExtractTextPlugin({
	  filename: utils.assetsPath("css/[name].[contenthash].css"),
	  // Setting the following option to `false` will not extract CSS from codesplit chunks.
	  // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
	  // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
	  // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
	  allChunks: true
	}),
	// Compress extracted CSS. We are using this plugin so that possible
	// duplicated CSS from different components can be deduped.
	new OptimizeCSSPlugin({
	  cssProcessorOptions: config.build.productionSourceMap
		? { safe: true, map: { inline: false } }
		: { safe: true }
	}),
	// generate dist index.html with correct asset hash for caching.
	// you can customize output by editing /index.html
	// see https://github.com/ampedandwired/html-webpack-plugin
	new HtmlWebpackPlugin({
	  filename: config.build.index,
	  template: "index.html",
	  inject: true,
	  minify: {
		removeComments: true,
		collapseWhitespace: true,
		removeAttributeQuotes: true
		// more options:
		// https://github.com/kangax/html-minifier#options-quick-reference
	  },
	  // necessary to consistently work with multiple chunks via CommonsChunkPlugin
	  chunksSortMode: "dependency"
	}),
	// keep module.id stable when vendor modules does not change
	new webpack.HashedModuleIdsPlugin(),
	// enable scope hoisting
	new webpack.optimize.ModuleConcatenationPlugin(),
	// split vendor js into its own file
	new webpack.optimize.CommonsChunkPlugin({
	  name: "vendor",
	  minChunks(module) {
		// any required modules inside node_modules are extracted to vendor
		return (
		  module.resource &&
		  /\.js$/.test(module.resource) &&
		  module.resource.indexOf(path.join(__dirname, "../node_modules")) === 0
		);
	  }
	}),
	// extract webpack runtime and module manifest to its own file in order to
	// prevent vendor hash from being updated whenever app bundle is updated
	new webpack.optimize.CommonsChunkPlugin({
	  name: "manifest",
	  minChunks: Infinity
	}),
	// This instance extracts shared chunks from code splitted chunks and bundles them
	// in a separate chunk, similar to the vendor chunk
	// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
	new webpack.optimize.CommonsChunkPlugin({
	  name: "app",
	  async: "vendor-async",
	  children: true,
	  minChunks: 3
	}),

	// copy custom static assets
	new CopyWebpackPlugin([
	  {
		from: path.resolve(__dirname, "../static"),
		to: config.build.assetsSubDirectory,
		ignore: [".*"]
	  }
	])
  ]
});

if (config.build.productionGzip) {
  const CompressionWebpackPlugin = require("compression-webpack-plugin");

  webpackConfig.plugins.push(
	new CompressionWebpackPlugin({
	  asset: "[path].gz[query]",
	  algorithm: "gzip",
	  test: new RegExp(
		"\\.(" + config.build.productionGzipExtensions.join("|") + ")$"
	  ),
	  threshold: 10240,
	  minRatio: 0.8
	})
  );
}

if (config.build.bundleAnalyzerReport) {
  const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
	.BundleAnalyzerPlugin;
  webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}

module.exports = webpackConfig;

5. 修改 build 文件夹下的 webpack.base.conf.js

webpack.base.conf.js

"use strict";
const path = require("path");
const utils = require("./utils");
const config = require("../config");
const vueLoaderConfig = require("./vue-loader.conf");

function resolve(dir) {
  return path.join(__dirname, "..", dir);
}

module.exports = {
  context: path.resolve(__dirname, "../"),
  entry: {
	app: "./src/main.js"
  },
  output: {
	path: config.build.assetsRoot,
	filename: "[name].js",
	publicPath:
	  process.env.NODE_ENV === "production"
	  ? config.build.assetsPublicPath
	  : process.env.NODE_ENV === "production-test"
	  ? config.test.assetsPublicPath
	  : process.env.NODE_ENV === "production-pre"
	  ? config.pre.assetsPublicPath
	  : config.dev.assetsPublicPath
  },
  resolve: {
	extensions: ['.js', '.vue', '.json'],
	alias: {
	  vue$: "vue/dist/vue.esm.js",
	  "@": resolve("src")
	}
  },
  module: {
	rules: [
	  {
		test: /\.vue$/,
		loader: "vue-loader",
		options: vueLoaderConfig
	  },
	  {
		test: /\.js$/,
		loader: "babel-loader",
		include: [
		  resolve("src"),
		  resolve("test"),
		  resolve("node_modules/webpack-dev-server/client")
		]
	  },
	  {
		test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
		loader: "url-loader",
		options: {
		  limit: 10000,
		  name: utils.assetsPath("img/[name].[hash:7].[ext]")
		}
	  },
	  {
		test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
		loader: "url-loader",
		options: {
		  limit: 10000,
		  name: utils.assetsPath("media/[name].[hash:7].[ext]")
		}
	  },
	  {
		test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
		loader: "url-loader",
		options: {
		  limit: 10000,
		  name: utils.assetsPath("fonts/[name].[hash:7].[ext]")
		}
	  },
	  {
		test: /\.less$/,
		loader: "style-loader!css-loader!less-loader"
	  }
	]
  },
  node: {
	// prevent webpack from injecting useless setImmediate polyfill because Vue
	// source contains it (although only uses it if it's native).
	setImmediate: false,
	// prevent webpack from injecting mocks to Node native modules
	// that does not make sense for the client
	dgram: "empty",
	fs: "empty",
	net: "empty",
	tls: "empty",
	child_process: "empty"
  }
};

6.创建一个公用的页面,用来增加环境变量判断 以及 对axios进行配置 & 拦截

untils/config.js

import axios from 'axios';
import qs from 'qs';
import VueRouter from 'vue-router';
import routers from '../router';

const router = new VueRouter({
	routers
});

// 设置接口地址
let baseUrl = '';
// 上传图片文件路径
let uploadBaseUrl = '';

if (process.env.NODE_ENV == 'development' || process.env.NODE_ENV == 'production-test') {
	// 开发/测试 环境
	baseUrl = 'http://dev.emmet.pub:18900';
	uploadBaseUrl = 'http://dev.emmet.pub:19001';
}else if(process.env.NODE_ENV == 'production-pre'){
	// 预发 环境
	baseUrl = 'http://pre.51bnh.com:8900';
	uploadBaseUrl = 'http://pre.51bnh.com:9001';
}else if(process.env.NODE_ENV == 'production'){
	// 正式环境
	baseUrl = 'http://api.51bnh.com:8900';
	uploadBaseUrl = 'http://api.51bnh.com:9001';
}

// axios 配置 & 拦截
// 响应时间
axios.defaults.timeout = 20000;
// 请求跨域                       
axios.defaults.withCredentials = true;
// 配置请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// POST传参序列化(添加请求拦截器)
axios.interceptors.request.use((config) => {
	//在发送请求之前强制降低复杂请求
	if(config.method  === 'post'){
		config.data = qs.stringify(config.data);
	}
	return config;
},(error) =>{
	return Promise.reject(error);
});
// 返回状态判断(添加响应拦截器)
axios.interceptors.response.use((res) =>{
	//对响应数据做些事
	if(!res.data){
		return Promise.reject(res);
	}

	if(res.data.respCode == '111'){
		// 登陆 过期
		sessionStorage.removeItem('User');
		alert("登陆已失效,请重新登陆");
		router.go('/');
		return
	}
	return res;
}, (error) => {
	return Promise.reject(error);
});

export {
	baseUrl,
	uploadBaseUrl,
}

7、在页面import baseUrl axios等 即可针对不同环境进行接口调用

8、打包命令如下

npm run dev      开发环境
npm run test     测试环境
npm run pre      预发环境
npm run build    正式环境

转载于:https://my.oschina.net/u/4081961/blog/3035662

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值