Webpack多环境代码打包(测试、预发、正式环境)
2019-04-11 18:21
134 查看
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
在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"' }
prod-pre.env.js 增加环境变量
/** * 预发环境配置 */ 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, }
7、在页面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>
8、打包命令如下
npm run dev 开发环境 npm run test 测试环境 npm run pre 预发环境 npm run build 正式环境
相关文章推荐
- webpack实现开发、测试、生产等环境的打包切换
- webpack配置css单独分离打包——正式环境打包优化
- 详解Webpack多环境代码打包的方法
- Android使用Gradle命令动态修改BASE_URL(测试/正式环境地址)完成打包,不需要修改代码
- webpack实现开发、测试、生产等环境的打包切换
- maven 多套环境 配置(开发、测试、预发、正式)
- IOS-40-测试环境与正式环境的代码通过标示符来区分
- webpack手动搭建 es6+less 开发环境和打包
- VUE 中配置生产环境和发布环境配置不同的接口地址 (运行npm run dev的时候,运行的是测试接口。npm run build打包项目的时候,打包的是服务器正式接口)
- Gulp配合Webpack的时候,如何让Webpack生成生产环境代码
- 分类打包(本地测试、线上测试、正式环境或者更多)
- vue如何自动化打包测试环境和正式环境的dist/test文件
- 通过获取DNS解析的未转义主机名,区分测试环境和正式环境代码
- Video.js + HLS 在production环境下webpack打包后出错的解决方案
- 前端模块化实践----使用webpack打包js代码
- webpack打包代码,弄一天了,终于打包成功了,记录一下,
- 在Android打包中区分测试和正式环境浅析
- Vue + Webpack 根据不同环境打包
- webpack打包不同环境的访问地址
- webpack + typescript + babel打包*.min.js文件的环境配置