一、安裝cross-env (cross-env能跨平臺地設置及使用環境變量)cnpm/npm i cross-env -Dcss
二、新建模板 紅色的爲相關文件html
三、配置各個文件vue
(1)config下面的index.jsnode
'use strict'
// Template version: 1.3.1 // see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path') module.exports = { dev: { // Paths
assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: { '/api': { target: 'http://xxxxx', //須要代理的後臺地址 解決跨域設置
changeOrigin: true, pathRewrite: { '^/api': '' } } }, // Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 9999, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: true, errorOverlay: true, notifyOnErrors: true, poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: false, // If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false, /** * 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: { prodEnv: require('./prod.env'), //新增 testEnv: require('./test.env'),//新增 devEnv: require('./dev.env'), //新增 // Template for index.html
index: path.resolve(__dirname, '../dist/index.html'), // Paths
assetsRoot: path.resolve(__dirname, '../dist'), assetsSubDirectory: 'static', assetsPublicPath: './', // 前面加.
/** * Source Maps */ productionSourceMap: true, // 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 } }
(2)config下面的 dev.evn.jswebpack
'use strict' const merge = require('webpack-merge') const prodEnv = require('./prod.env') module.exports = merge(prodEnv, { NODE_ENV: '"development"', ENV_CONFIG: '"dev"', // 新增 BASE_URL: '"api"', // 新增 DEV
})
(3)config下面的 test.evn.jsios
'use strict' const merge = require('webpack-merge') const devEnv = require('./dev.env') module.exports = merge(devEnv, { NODE_ENV: '"testing"', ENV_CONFIG: '"test"', //新增 BASE_URL: '"http://www.test.com"', // test測試地址
})
(4)config下面的 prod.evn.jsgit
'use strict' module.exports = { NODE_ENV: '"production"', ENV_CONFIG: '"prod"', // 新增
BASE_URL: '"http://www.produciton.com"', // prod
}
(5)build下面的 build.jsgithub
'use strict' require('./check-versions')() // process.env.NODE_ENV = 'production' // 本來的註釋掉
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...') // 本來的註釋掉
const spinner = ora('building for' + process.env.NODE_ENV + 'of' + process.env.env_config + 'mode...') // 新增
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' )) }) })
(6)build下面的 webpack.base.conf.jsweb
'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) } const createLintingRule = () => ({ test: /\.(js|vue)$/, loader: 'eslint-loader', enforce: 'pre', include: [resolve('src'), resolve('test')], options: { formatter: require('eslint-friendly-formatter'), emitWarning: !config.dev.showEslintErrorsInOverlay } }) 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
// : config.dev.assetsPublicPath // 註釋原有
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath : (process.env.NODE_ENV === 'testing' || process.env.NODE_ENV === 'development' ? config.build.assetsPublicPath : config.dev.assetsPublicPath) // 新增判斷
}, resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } }, module: { rules: [ ...(config.dev.useEslint ? [createLintingRule()] : []), { 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]') } } ] }, 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' } }
(7)build下面的 webpack.prod.conf.jsnpm
'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 = process.env.NODE_ENV === 'testing' // ? require('../config/test.env') // : require('../config/prod.env') // 註釋原有
const env = config.build[process.env.env_config + '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, 'process.env.BASE_URL': JSON.stringify(process.env.BASE_URL), //增長此行 (可加可不加)
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_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: process.env.NODE_ENV === 'testing'
? 'index.html' : 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
(8)build下面的 utils.js
'use strict' const path = require('path') const config = require('../config') const ExtractTextPlugin = require('extract-text-webpack-plugin') const packageConfig = require('../package.json') exports.assetsPath = function (_path) { const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory : config.dev.assetsSubDirectory return path.posix.join(assetsSubDirectory, _path) } exports.cssLoaders = function (options) { options = options || {} const cssLoader = { loader: 'css-loader', options: { sourceMap: options.sourceMap } } const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: options.sourceMap } } // generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) { const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] if (loader) { loaders.push({ loader: loader + '-loader', options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) } // Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader', publicPath:'../../' // 新增配置 防止打包圖片(如背景圖片)路徑報錯
}) } else { return ['vue-style-loader'].concat(loaders) } } // https://vue-loader.vuejs.org/en/configurations/extract-css.html
return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders('less'), sass: generateLoaders('sass', { indentedSyntax: true }), scss: generateLoaders('sass'), stylus: generateLoaders('stylus'), styl: generateLoaders('stylus') } } // Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) { const output = [] const loaders = exports.cssLoaders(options) for (const extension in loaders) { const loader = loaders[extension] output.push({ test: new RegExp('\\.' + extension + '$'), use: loader }) } return output } exports.createNotifierCallback = () => { const notifier = require('node-notifier') return (severity, errors) => { if (severity !== 'error') return const error = errors[0] const filename = error.file && error.file.split('!').pop() notifier.notify({ title: packageConfig.name, message: severity + ': ' + error.name, subtitle: filename || '', icon: path.join(__dirname, 'logo.png') }) } }
(9)api下面的 axios.js
import axios from 'axios' import qs from 'qs'
// 生成一個 axios 實例
const instance = axios.create({ baseURL: process.env.BASE_URL, // api 的 base_url
timeout: 5000 // 請求 超時配置
}) // 請求 攔截器
instance.interceptors.request.use(config => { config.withCredentials = true
if (config.headers['Content-Type'] === 'application/json') { config.data = JSON.stringify(config.data) } if (config.headers['Content-Type'] === 'multipart/form-data') { return config } if (config.method === 'post' || config.method === 'put' || config.method === 'delete') { if (typeof (config.data) !== 'string') { config.data = qs.stringify(config.data) } } return config }, error => { Promise.reject(error) }) // 響應 攔截器
axios.interceptors.response.use(response => { // 對響應數據作處理
return response }, error => { // 對響應錯誤作處理
return Promise.reject(error) }) export default instance
(10)api下面的 http.js
import instance from './axios'
// get請求
export function getList(params) { return instance({ url: `/xxxx`, method: 'get', params }) } // post請求
export function getpostList(data) { return instance({ url: '/xxx', method: 'post', headers: { 'Content-Type': 'application/json' }, data }) }
(11)package.json配置
"scripts": { "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", "start": "npm run dev", "unit": "jest --config test/unit/jest.conf.js --coverage", "e2e": "node test/e2e/runner.js", "test": "npm run unit && npm run e2e", "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs", "build": "node build/build.js", "build:dev": "cross-env NODE_ENV=development env_config=dev node build/build.js", // 新增 "build:test": "cross-env NODE_ENV=testing env_config=test node build/build.js", // 新增 "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js" // 新增 },
完整的分環境打包就完成了。。。。
執行對應的命令
一、cnpm/npm run build:dev ------本地包打包完成
二、cnpm/npm run build:test ------測試包打包完成
三、cnpm/npm run build:prod ------生產包打包完成