溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

詳解vue-cli腳手架中webpack配置方法

發(fā)布時(shí)間:2020-10-01 18:08:08 來源:腳本之家 閱讀:221 作者:xiaoqi77 欄目:web開發(fā)

什么是webpack

webpack是一個(gè)module bundler(模塊打包工具),所謂的模塊就是在平時(shí)的前端開發(fā)中,用到一些靜態(tài)資源,如JavaScript、CSS、圖片等文件,webpack就將這些靜態(tài)資源文件稱之為模塊

webpack支持AMD和CommonJS,以及其他的一些模塊系統(tǒng),并且兼容多種JS書寫規(guī)范,可以處理模塊間的以來關(guān)系,所以具有更強(qiáng)大的JS模塊化的功能,它能對(duì)靜態(tài)資源進(jìn)行統(tǒng)一的管理以及打包發(fā)布,在官網(wǎng)中用這張圖片介紹:

詳解vue-cli腳手架中webpack配置方法

它在很多地方都能替代Grunt和Gulp,因?yàn)樗軌蚓幾g打包CSS,做CSS預(yù)處理,對(duì)JS的方言進(jìn)行編譯,打包圖片,代碼壓縮等等。所以在我接觸了webpack之后,就不太想用gulp了

為什么使用webpack

總結(jié)如下:

  • 對(duì) CommonJS 、AMD 、ES6的語法做了兼容;
  • 對(duì)js、css、圖片等資源文件都支持打包;
  • 串聯(lián)式模塊加載器以及插件機(jī)制,讓其具有更好的靈活性和擴(kuò)展性,例如提供對(duì)CoffeeScript、ES6的支持;
  • 有獨(dú)立的配置文件webpack.config.js;
  • 可以將代碼切割成不同的chunk,實(shí)現(xiàn)按需加載,降低了初始化時(shí)間;
  • 支持 SourceUrls 和 SourceMaps,易于調(diào)試;
  • 具有強(qiáng)大的Plugin接口,大多是內(nèi)部插件,使用起來比較靈活;
  • webpack 使用異步 IO 并具有多級(jí)緩存。這使得 webpack 很快且在增量編譯上更加快;

webpack主要是用于vue和React較多,其實(shí)它就非常像Browserify,但是將應(yīng)用打包為多個(gè)文件。如果單頁面應(yīng)用有多個(gè)頁面,那么用戶只從下載對(duì)應(yīng)頁面的代碼. 當(dāng)他么訪問到另一個(gè)頁面, 他們不需要重新下載通用的代碼。

基于本人項(xiàng)目使用

vue webpack的配置文件的基本目錄結(jié)構(gòu)如下:

config
├── dev.env.js //dev環(huán)境變量配置
├── index.js // dev和prod環(huán)境的一些基本配置
└── prod.env.js // prod環(huán)境變量配置
build
├── build.js // npm run build所執(zhí)行的腳本
├── check-versions.js // 檢查npm和node的版本
├── logo.png
├── utils.js // 一些工具方法,主要用于生成cssLoader和styleLoader配置
├── vue-loader.conf.js // vueloader的配置信息
├── webpack.base.conf.js // dev和prod的公共配置
├── webpack.dev.conf.js // dev環(huán)境的配置
└── webpack.prod.conf.js // prod環(huán)境的配置

Config文件夾下文件詳解

dev.env.js

config內(nèi)的文件其實(shí)是服務(wù)于build的,大部分是定義一個(gè)變量export出去

use strict //[采用嚴(yán)格模式]
/**
* [webpack-merge提供了一個(gè)合并函數(shù),它將數(shù)組和合并對(duì)象創(chuàng)建一個(gè)新對(duì)象
] 
*/
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
 NODE_ENV: '"development"'
})

prod.env.js

當(dāng)開發(fā)時(shí)調(diào)取dev.env.js的開發(fā)環(huán)境配置,發(fā)布時(shí)調(diào)用prod.env.js的生產(chǎn)環(huán)境配置

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

index.js

const path = require('path')
module.exports = {
 /**
  * [開發(fā)環(huán)境配置]
  */
dev: {
  assetsSubDirectory: 'static', // [子目錄,一般存放css,js,image等文件]
assetsPublicPath: '/', // [根目錄]
/**
* [配置服務(wù)代理] 
*/
  proxyTable: {
   '/hcm': {
    target: 'https://127.0.0.1:8448',
    changeOrigin: true,
    secure: false
   },
   headers: {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
    "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
   }
  },
  host: '127.0.0.1', // [瀏覽器訪問地址]
  port: 8083, // [端口號(hào)設(shè)置,端口號(hào)占用出現(xiàn)問題可在此處修改]
  autoOpenBrowser: true, // [是否在編譯(輸入命令行npm run dev)后打開http://127.0.0.1:8083/頁面]
  errorOverlay: true, // [瀏覽器錯(cuò)誤提示]
  notifyOnErrors: true, // [跨平臺(tái)錯(cuò)誤提示]
  poll:false, // [使用文件系統(tǒng)(file system)獲取文件改動(dòng)的通知devServer.watchOptions] 
  useEslint: true, // [是否啟用代碼規(guī)范檢查]
  showEslintErrorsInOverlay: false, // [是否展示eslint的錯(cuò)誤提示]
  devtool: 'eval-source-map', // [增加調(diào)試,該屬性為原始源代碼]
  cacheBusting: true, // [使緩存失效]
  cssSourceMap: false // [代碼壓縮后進(jìn)行調(diào)bug定位將非常困難,于是引入sourcemap記錄壓縮前后的位置信息記錄,當(dāng)產(chǎn)生錯(cuò)誤時(shí)直接定位到未壓縮前的位置,將大大的方便我們調(diào)試]
 },
/**
* [生產(chǎn)環(huán)境配置] 
*/
 build: {
 /**
* [index、login、license、forbidden、notfound、Internal.licenses編譯后生成的位置和名字,根據(jù)需要改變后綴] 
*/
  index: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/index.html'),
  login: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/login.html'),
  license: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/license.html'),
  forbidden: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/error/403.html'),
  notfound: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/error/404.html'),
  internal: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/error/500.html'),
  licenses: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/docs/licenses.html'),
/**
* [編譯后存放生成環(huán)境代碼的位置] 
*/
  assetsRoot: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources'),
  assetsSubDirectory: 'static', //js、css、images存放文件夾名
  assetsPublicPath: './', //發(fā)布的根目錄,通常本地打包dist后打開文件會(huì)報(bào)錯(cuò),此處修改為./。如果是上線的文件,可根據(jù)文件存放位置進(jìn)行更改路徑
  productionSourceMap: true,
  devtool: '#source-map',
  productionGzip: false, //unit的gzip命令用來壓縮文件,gzip模式下需要壓縮的文件的擴(kuò)展名有js和css
  productionGzipExtensions: ['js', 'css'],
  bundleAnalyzerReport: process.env.npm_config_report //打包分析
 }
}

build文件夾下文件詳解

build.js

該文件作用,即構(gòu)建生產(chǎn)版本。package.json中的scripts的build就是node build/build.js,輸入命令行npm run build對(duì)該文件進(jìn)行編譯生成生產(chǎn)環(huán)境的代碼。

require('./check-versions')() //check-versions:調(diào)用檢查版本的文件。加()代表直接調(diào)用該函數(shù)
process.env.NODE_ENV = 'production' //設(shè)置當(dāng)前是生產(chǎn)環(huán)境
/**
*下面定義常量引入插件
*/
const ora = require('ora') //加載動(dòng)畫
const rm = require('rimraf') //刪除文件
const path = require('path')
const chalk = require('chalk') //對(duì)文案輸出的一個(gè)彩色設(shè)置
const webpack = require('webpack')
const config = require('../config') //默認(rèn)讀取下面的index.js文件
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...') //調(diào)用start的方法實(shí)現(xiàn)加載動(dòng)畫,優(yōu)化用戶體驗(yàn)
spinner.start()
//先刪除dist文件再生成新文件,因?yàn)橛袝r(shí)候會(huì)使用hash來命名,刪除整個(gè)文件可避免冗余
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,
   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'
  ))
 })
})

check-versions.js

該文件用于檢測node和npm的版本,實(shí)現(xiàn)版本依賴

const chalk = require('chalk') 
const semver = require('semver') //對(duì)版本進(jìn)行檢查
const packageConfig = require('../package.json')
const shell = require('shelljs')
function exec (cmd) {
 //返回通過child_process模塊的新建子進(jìn)程,執(zhí)行 Unix 系統(tǒng)命令后轉(zhuǎn)成沒有空格的字符串
 return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
 {
  name: 'node',
  currentVersion: semver.clean(process.version), //使用semver格式化版本
  versionRequirement: packageConfig.engines.node //獲取package.json中設(shè)置的node版本
 }
]
if (shell.which('npm')) {
 versionRequirements.push({
  name: 'npm',
  currentVersion: exec('npm --version'), // 自動(dòng)調(diào)用npm --version命令,并且把參數(shù)返回給exec函數(shù),從而獲取純凈的版本號(hào)
  versionRequirement: packageConfig.engines.npm
 })
}
module.exports = function () {
 const warnings = []
 for (let i = 0; i < versionRequirements.length; i++) {
  const mod = versionRequirements[i]
  if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
   //上面這個(gè)判斷就是如果版本號(hào)不符合package.json文件中指定的版本號(hào),就執(zhí)行下面錯(cuò)誤提示的代碼
warnings.push(mod.name + ': ' +
    chalk.red(mod.currentVersion) + ' should be ' +
    chalk.green(mod.versionRequirement)
   )
  }
 }
 if (warnings.length) {
  console.log('')
  console.log(chalk.yellow('To use this template, you must update following to modules:'))
  console.log()
  for (let i = 0; i < warnings.length; i++) {
   const warning = warnings[i]
   console.log(' ' + warning)
  }
  console.log()
  process.exit(1)
 }
}

utils.js

utils是工具的意思,是一個(gè)用來處理css的文件。

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 || {}
//使用了css-loader和postcssLoader,通過options.usePostCSS屬性來判斷是否使用postcssLoader中壓縮等方法

 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',
  //Object.assign是es6語法的淺復(fù)制,后兩者合并后復(fù)制完成賦值
    options: Object.assign({}, loaderOptions, {
     sourceMap: options.sourceMap
    })
   })
  }
  // Extract CSS when that option is specified
  // (which is the case during production build)
if (options.extract) {
//ExtractTextPlugin可提取出文本,代表首先使用上面處理的loaders,當(dāng)未能正確引入時(shí)使用vue-style-loader
   return ExtractTextPlugin.extract({
    use: loaders,
    fallback: 'vue-style-loader',
    publicPath: '../../'
   })
} else {
//返回vue-style-loader連接loaders的最終值
   return ['vue-style-loader'].concat(loaders)
  }
 }
 // https://vue-loader.vuejs.org/en/configurations/extract-css.html
 return {
  css: generateLoaders(),//需要css-loader 和 vue-style-loader
  postcss: generateLoaders(),//需要css-loader和postcssLoader 和 vue-style-loader
  less: generateLoaders('less'), //需要less-loader 和 vue-style-loader
  sass: generateLoaders('sass', { indentedSyntax: true }), //需要sass-loader 和 vue-style-loader
  scss: generateLoaders('sass'), //需要sass-loader 和 vue-style-loader
  stylus: generateLoaders('stylus'), //需要stylus-loader 和 vue-style-loader
  styl: generateLoaders('stylus') //需要stylus-loader 和 vue-style-loader
 }
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
 const output = []
 const loaders = exports.cssLoaders(options)
//將各種css,less,sass等綜合在一起得出結(jié)果輸出output
 for (const extension in loaders) {
  const loader = loaders[extension]
  output.push({
   test: new RegExp('\\.' + extension + '$'),
   use: loader
  })
 }
 return output
}
exports.createNotifierCallback = () => {
//發(fā)送跨平臺(tái)通知系統(tǒng)
 const notifier = require('node-notifier')
 return (severity, errors) => {
if (severity !== 'error') return
//當(dāng)報(bào)錯(cuò)時(shí)輸出錯(cuò)誤信息的標(biāo)題,錯(cuò)誤信息詳情,副標(biāo)題以及圖標(biāo)
  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')
  })
 }
}

vue-loader.conf.js

該文件的主要作用就是處理.vue文件,解析這個(gè)文件中的每個(gè)語言塊(template、script、style),轉(zhuǎn)換成js可用的js模塊。

const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
 ? config.build.productionSourceMap
 : config.dev.cssSourceMap
//處理項(xiàng)目中的css文件,生產(chǎn)環(huán)境和測試環(huán)境默認(rèn)是打開sourceMap,而extract中的提取樣式到單獨(dú)文件只有在生產(chǎn)環(huán)境中才需要
module.exports = {
 loaders: utils.cssLoaders({
  sourceMap: sourceMapEnabled,
  extract: isProduction
 }),
 cssSourceMap: sourceMapEnabled,
 cacheBusting: config.dev.cacheBusting,
// 在模版編譯過程中,編譯器可以將某些屬性,如 src 路徑,轉(zhuǎn)換為require調(diào)用,以便目標(biāo)資源可以由 webpack 處理
 transformToRequire: {
  video: ['src', 'poster'],
  source: 'src',
  img: 'src',
  image: 'xlink:href'
 }
}

webpack.base.conf.js

webpack.base.conf.js是開發(fā)和生產(chǎn)共同使用提出來的基礎(chǔ)配置文件,主要實(shí)現(xiàn)配制入口,配置輸出環(huán)境,配置模塊resolve和插件等

const path = require('path')
const utils = require('./utils')
/**
* [引入index.js文件路徑] 
*/
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

/**
 * [獲取文件路徑]
 * @param dir [文件名稱]
 *_dirname為當(dāng)前模塊文件所在目錄的絕對(duì)路徑* 
 *@return 文件絕對(duì)路徑
*/
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: {
/**
    * [入口文件路徑, babel-polyfill是對(duì)es6語法的支持]
   */
  app: ['babel-polyfill', './src/main.js'],
  login: ['babel-polyfill', './src/loginMain.js'],
  license: ['babel-polyfill', './src/licenseMain.js']
 },
/**
  * [文件導(dǎo)出配置]
*/
 output: {
  path: config.build.assetsRoot,
  filename: '[name].js',
  publicPath: process.env.NODE_ENV === 'production'
   ? config.build.assetsPublicPath
   : config.dev.assetsPublicPath //公共存放路徑
 },
 resolve: {
  /**
    * [extensions: 配置文件的擴(kuò)展名,當(dāng)在important文件時(shí),不用需要添加擴(kuò)展名]
   */
extensions: ['.js', '.vue', '.json'],
/**
    * [alias 給路徑定義別名]
*/
  alias: {
   'vue$': 'vue/dist/vue.esm.js',
   '@': resolve('src')
  }
 },
/**
*使用插件配置相應(yīng)文件的處理方法
*/
 module: {
rules: [
   ...(config.dev.useEslint ? [createLintingRule()] : []),
/**
   * [使用vue-loader將vue文件轉(zhuǎn)化成js的模塊]
*/
   {
    test: /\.vue$/,
    loader: 'vue-loader',
    options: vueLoaderConfig
   },
/**
    * [通過babel-loader將js進(jìn)行編譯成es5/es6 文件]
*/
   {
    test: /\.js$/,
    loader: 'babel-loader',
    include: [resolve('src'), resolve('test')]
   },
/**
   * [圖片、音像、字體都使用url-loader進(jìn)行處理,超過10000會(huì)編譯成base64]
*/
   {
    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]')
    }
   },
/**
    * [canvas 解析]
*/
   {
    test: path.resolve(`${resolve('src')}/lib/jtopo.js`),
    loader: ['exports-loader?window.JTopo', 'script-loader']
   }
  ]
 },
//以下選項(xiàng)是Node.js全局變量或模塊,這里主要是防止webpack注入一些Node.js的東西到vue中 
 node: {
  setImmediate: false,
  dgram: 'empty',
  fs: 'empty',
  net: 'empty',                           
  tls: 'empty',
  child_process: 'empty'
 }
}

webpack.dev.conf.js

const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
//通過webpack-merge實(shí)現(xiàn)webpack.dev.conf.js對(duì)wepack.base.config.js的繼承
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')
//美化webpack的錯(cuò)誤信息和日志的插件
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// 查看空閑端口位置,默認(rèn)情況下搜索8000這個(gè)端口
const portfinder = require('portfinder')
// processs為node的一個(gè)全局對(duì)象獲取當(dāng)前程序的環(huán)境變量,即host
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
function resolveApp(relativePath) {
 return path.resolve(relativePath);
}
const devWebpackConfig = merge(baseWebpackConfig, {
 module: {
//規(guī)則是工具utils中處理出來的styleLoaders,生成了css,less,postcss等規(guī)則
  rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
 },
// 增強(qiáng)調(diào)試
 devtool: config.dev.devtool,
// 此處的配置都是在config的index.js中設(shè)定好了
 devServer: {
//控制臺(tái)顯示的選項(xiàng)有none, error, warning 或者 info
clientLogLevel: 'warning',
//使用 HTML5 History API
historyApiFallback: true,
hot: true, //熱加載
compress: true, //壓縮
  host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser, //調(diào)試時(shí)自動(dòng)打開瀏覽器
  overlay: config.dev.errorOverlay
   ? { warnings: false, errors: true }
   : false,
  publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,//接口代理
quiet: true, //控制臺(tái)是否禁止打印警告和錯(cuò)誤,若用FriendlyErrorsPlugin 此處為 true  watchOptions: {
   poll: config.dev.poll, // 文件系統(tǒng)檢測改動(dòng)
  }
 },
 plugins: [
  new webpack.DefinePlugin({
   'process.env': require('../config/dev.env')
  }),
new webpack.HotModuleReplacementPlugin(),//模塊熱替換插件,修改模塊時(shí)不需要刷新頁面
new webpack.NamedModulesPlugin(), // 顯示文件的正確名字
new webpack.NoEmitOnErrorsPlugin(), //當(dāng)webpack編譯錯(cuò)誤的時(shí)候,來中端打包進(jìn)程,防止錯(cuò)誤代碼打包到文件中
// https://github.com/ampedandwired/html-webpack-plugin
// 該插件可自動(dòng)生成一個(gè) html5 文件或使用模板文件將編譯好的代碼注入進(jìn)去 
new HtmlWebpackPlugin({
   filename: 'index.html',
   template: 'index.html',
   inject: true,
   chunks: ['app']
  }),
  new HtmlWebpackPlugin({
   filename: 'login.html',
   template: 'login.html',
   inject: true,
   chunks: ['login']
  }),
  new HtmlWebpackPlugin({
   filename: 'license.html',
   template: 'license.html',
   inject: true,
   chunks: ['license']
  }),
  new HtmlWebpackPlugin({
   filename: 'licenses.html',
   template: 'licenses.html',
   inject: true,
   chunks: []
  }),
  new HtmlWebpackPlugin({
   filename: '404.html',
   template: path.resolve(__dirname, '../errors/404.html'),
   favicon: resolveApp('favicon.ico'),
   inject: true,
   chunks: []
  }),
  new HtmlWebpackPlugin({
   filename: '403.html',
   template: path.resolve(__dirname, '../errors/403.html'),
   favicon: resolveApp('favicon.ico'),
   inject: true,
   chunks: []
  }),
  new HtmlWebpackPlugin({
   filename: '500.html',
   template: path.resolve(__dirname, '../errors/500.html'),
   favicon: resolveApp('favicon.ico'),
   inject: true,
   chunks: []
  })
 ]
})

module.exports = new Promise((resolve, reject) => {
 portfinder.basePort = process.env.PORT || config.dev.port
//查找端口號(hào)
 portfinder.getPort((err, port) => {
  if (err) {
   reject(err)
} else {
//端口被占用時(shí)就重新設(shè)置evn和devServer的端口
   process.env.PORT = port
   // add port to devServer config
   devWebpackConfig.devServer.port = port
//友好地輸出信息
   devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
    compilationSuccessInfo: {
     messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
    },
    onErrors: config.dev.notifyOnErrors
    ? utils.createNotifierCallback()
    : undefined
   }))
   resolve(devWebpackConfig)
  }
 })
})

webpack.prod.conf.js

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')
function resolveApp(relativePath) {
 return path.resolve(relativePath);
}
const webpackConfig = merge(baseWebpackConfig, {
 module: {
  rules: utils.styleLoaders({
   sourceMap: config.build.productionSourceMap,//開啟調(diào)試的模式。默認(rèn)為true
   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 //警告:true保留警告,false不保留
    }
   },
   sourceMap: config.build.productionSourceMap,
   parallel: true
  }),
// extract css into its own file
//抽取文本。比如打包之后的index頁面有style插入,就是這個(gè)插件抽取出來的,減少請(qǐng)求
new ExtractTextPlugin({
   filename: utils.assetsPath('css/[name].[contenthash].css'),
   allChunks: true,
}),
//優(yōu)化css的插件
  new OptimizeCSSPlugin({
   cssProcessorOptions: config.build.productionSourceMap
    ? { safe: true, map: { inline: false } }
    : { safe: true }
  }),
  //html打包
  new HtmlWebpackPlugin({
   filename: config.build.index,
   template: 'index.html',
   inject: true,
//壓縮
   minify: {
    removeComments: true, //刪除注釋
    collapseWhitespace: true, //刪除空格
    removeAttributeQuotes: true //刪除屬性的引號(hào)
   },
   chunks: ['vendor', 'manifest', 'app'],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  new HtmlWebpackPlugin({
   filename: config.build.login,
   template: 'login.html',
   inject: true,
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunks: ['vendor', 'manifest', 'login'],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  new HtmlWebpackPlugin({
   filename: config.build.license,
   template: 'license.html',
   inject: true,
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunks: ['vendor', 'manifest', 'license'],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  new HtmlWebpackPlugin({
   filename: config.build.notfound,
   template: path.resolve(__dirname, '../errors/404.html'),
   inject: true,
   favicon: resolveApp('favicon.ico'),
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunks: [],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  new HtmlWebpackPlugin({
   filename: config.build.forbidden,
   template: path.resolve(__dirname, '../errors/403.html'),
   inject: true,
   favicon: resolveApp('favicon.ico'),
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunks: [],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  new HtmlWebpackPlugin({
   filename: config.build.internal,
   template: path.resolve(__dirname, '../errors/500.html'),
   inject: true,
   favicon: resolveApp('favicon.ico'),
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunks: [],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  new HtmlWebpackPlugin({
   filename: config.build.licenses,
   template: 'licenses.html',
   inject: true,
   minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
   },
   chunks: [],
   // necessary to consistently work with multiple chunks via CommonsChunkPlugin
   chunksSortMode: 'dependency'
  }),
  // keep module.id stable when vender modules does not change
  new webpack.HashedModuleIdsPlugin(),
  // enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
//抽取公共的模塊, 提升你的代碼在瀏覽器中的執(zhí)行速度。
  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
}),
// 預(yù)編譯所有模塊到一個(gè)閉包中, 
 new webpack.optimize.CommonsChunkPlugin({
   name: 'app',
   async: 'vendor-async',
   children: true,
   minChunks: 3
  }),
//復(fù)制,比如打包完之后需要把打包的文件復(fù)制到dist里面
  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
  })
 )
}
// 提供帶 Content-Encoding 編碼的壓縮版的資源
if (config.build.bundleAnalyzerReport) {
 const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
 webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI