Webpack多環境代碼打包(測試、預發、正式環境)

在package.json文件的scripts中,會提供開發環境與生產環境兩個命令。可是實際使用中會碰見 測試版、預發佈版以及正式版代碼相繼發佈的狀況,這樣反覆更改服務器地址,偶爾忘記更改url會給工做帶來不少沒必要要的麻煩。這樣就須要在生產環境中配置 測試版本打包命令、預發佈版本打包命令與正式版本打包命令。css

具體步驟以下:html

1. Package.json 文件中 增長命令行命令,並指定路徑。vue

"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文件中添加相應文件node

build-test.jswebpack

/**
 * 測試版
 */

'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.jsios

/**
 * 預發佈版
 */

'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.jsgit

/**
 * 正式版
 */
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')
  })
})

三、在config文件中增長環境變量配置 github

prod-test.env.js 增長環境變量web

/**
 * 測試環境配置
 */

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

prod-pre.env.js 增長環境變量ajax

/**
 * 預發環境配置
 */

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

prod.env.js

/**
 * 生產環境配置(正式)
 */

module.exports = {
	NODE_ENV: '"production"'
}

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
  },

  build: { // 測試 預發佈 正式生產 環境
	evn:process.env.NODE_ENV == "production"
	? require('./prod.env')
	: process.env.NODE_ENV == "production-pre"
	? require('./prod-pre.env')
	: process.env.NODE_ENV == "production-test"
	? require('./prod-test.env')
	: require('./prod-test.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)

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 === "development"
	 ? config.dev.assetsPublicPath
	 : config.build.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 = '';
// alert(process.env.NODE_ENV)
if (process.env.NODE_ENV == 'development' || process.env.NODE_ENV == 'production-test') {
	// 開發/測試 環境
	baseUrl = 'https://sfe.crmclick.com';
	uploadBaseUrl = 'http://sfe.crmclick.com/uploadNoZip.aspx';
}else if(process.env.NODE_ENV == 'production-pre'){
	// 預發 環境
	baseUrl = 'xxxx';
	uploadBaseUrl = 'xxxx';
}else if(process.env.NODE_ENV == 'production'){
	// 正式環境
	baseUrl = 'xxxx';
	uploadBaseUrl = 'xxxx';
}

// axios 配置 & 攔截
// 響應時間
axios.defaults.timeout = 20000;
// 是否容許攜帶cookie
// withCredentials爲true的狀況下,後端要設置Access-Control-Allow-Origin爲你的源地址,例如http://localhost:8080,不能是*,
// 並且還要設置header('Access-Control-Allow-Credentials: true');              
axios.defaults.withCredentials = false;
// 配置請求頭
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,
}

七、在頁面import baseUrl axios等 便可針對不一樣環境進行接口調用

<script>
import axios from 'axios';
import { baseUrl } from '../untils/config';
import HeaderMenu from './common/HeaderMenu';//引用子組件

export default {
	name: 'Gift',
	data() {
		return {
			title:"禮品展現",
			PageIndex:1,
			PageSize:10,
			GiftList:[],
			loading:false,
			LoadMore:true,
		}
	},
	components: {
		"V-Menu": HeaderMenu,
	},
	created() {
		this.GetGiftList();
	},
	mounted() {

	},
	methods: {
		GetImg(url){
			return baseUrl + url;
		},
		GetGiftList() {
			axios.post(baseUrl+"/suzhou/Handler/Points.ashx",{
				op: "GiftList", 
				PageIndex: this.PageIndex, 
				PageSize:this.PageSize
			}).then(res => {
				if (res.data.state == 1) {
					if(this.PageIndex==1){
						this.GiftList = res.data.rows;
					}else{
						var newGiftArr = this.GiftList.slice(0);
						if(res.data.rows.length>0){
							for(var i=0;i<res.data.rows.length;i++){
								newGiftArr.push(res.data.rows[i]);
							}
						}
						this.GiftList = newGiftArr;
					}
					if(res.data.rows.length < this.PageSize){
						this.LoadMore = false;
					}
				}else if(res.data.rows == -1){
					this.$toast.warning(res.data.msg);
				}
			})
			.catch(error => {
				debugger
				this.$toast.error(error);
			});
		},
		load:function(){
			if(this.LoadMore){
				this.loading = true;
				setTimeout(function() {
					this.loading = false;
					this.PageIndex ++;
					this.GetGiftList();
				}, 2000)
			}
		},
	}
}
</script>

八、打包命令以下

npm run dev      開發環境
npm run test     測試環境
npm run pre      預發環境
npm run build    正式環境
相關文章
相關標籤/搜索