在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 正式環境