当前位置:Gxlcms > JavaScript > 详解vue-cli脚手架中webpack配置方法

详解vue-cli脚手架中webpack配置方法

时间:2021-07-01 10:21:17 帮助过:10人阅读

什么是webpack

webpack是一个module bundler(模块打包工具),所谓的模块就是在平时的前端开发中,用到一些静态资源,如JavaScript、CSS、图片等文件,webpack就将这些静态资源文件称之为模块

webpack支持AMD和CommonJS,以及其他的一些模块系统,并且兼容多种JS书写规范,可以处理模块间的以来关系,所以具有更强大的JS模块化的功能,它能对静态资源进行统一的管理以及打包发布,在官网中用这张图片介绍:

它在很多地方都能替代Grunt和Gulp,因为它能够编译打包CSS,做CSS预处理,对JS的方言进行编译,打包图片,代码压缩等等。所以在我接触了webpack之后,就不太想用gulp了

为什么使用webpack

总结如下:

  • 对 CommonJS 、AMD 、ES6的语法做了兼容;
  • 对js、css、图片等资源文件都支持打包;
  • 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持;
  • 有独立的配置文件webpack.config.js;
  • 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间;
  • 支持 SourceUrls 和 SourceMaps,易于调试;
  • 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活;
  • webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快;

webpack主要是用于vue和React较多,其实它就非常像Browserify,但是将应用打包为多个文件。如果单页面应用有多个页面,那么用户只从下载对应页面的代码. 当他么访问到另一个页面, 他们不需要重新下载通用的代码。

基于本人项目使用

vue webpack的配置文件的基本目录结构如下:

  1. config
  2. ├── dev.env.js //dev环境变量配置
  3. ├── index.js // dev和prod环境的一些基本配置
  4. └── prod.env.js // prod环境变量配置
  5. build
  6. ├── build.js // npm run build所执行的脚本
  7. ├── check-versions.js // 检查npm和node的版本
  8. ├── logo.png
  9. ├── utils.js // 一些工具方法,主要用于生成cssLoader和styleLoader配置
  10. ├── vue-loader.conf.js // vueloader的配置信息
  11. ├── webpack.base.conf.js // dev和prod的公共配置
  12. ├── webpack.dev.conf.js // dev环境的配置
  13. └── webpack.prod.conf.js // prod环境的配置

Config文件夹下文件详解

dev.env.js

config内的文件其实是服务于build的,大部分是定义一个变量export出去

  1. use strict //[采用严格模式]
  2. /**
  3. * [webpack-merge提供了一个合并函数,它将数组和合并对象创建一个新对象
  4. ]
  5. */
  6. const merge = require('webpack-merge')
  7. const prodEnv = require('./prod.env')
  8. module.exports = merge(prodEnv, {
  9. NODE_ENV: '"development"'
  10. })

prod.env.js

当开发时调取dev.env.js的开发环境配置,发布时调用prod.env.js的生产环境配置

  1. use strict
  2. module.exports = {
  3. NODE_ENV: '"production"'
  4. }

index.js

  1. const path = require('path')
  2. module.exports = {
  3. /**
  4. * [开发环境配置]
  5. */
  6. dev: {
  7. assetsSubDirectory: 'static', // [子目录,一般存放css,js,image等文件]
  8. assetsPublicPath: '/', // [根目录]
  9. /**
  10. * [配置服务代理]
  11. */
  12. proxyTable: {
  13. '/hcm': {
  14. target: 'https://127.0.0.1:8448',
  15. changeOrigin: true,
  16. secure: false
  17. },
  18. headers: {
  19. "Access-Control-Allow-Origin": "*",
  20. "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
  21. "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
  22. }
  23. },
  24. host: '127.0.0.1', // [浏览器访问地址]
  25. port: 8083, // [端口号设置,端口号占用出现问题可在此处修改]
  26. autoOpenBrowser: true, // [是否在编译(输入命令行npm run dev)后打开http://127.0.0.1:8083/页面]
  27. errorOverlay: true, // [浏览器错误提示]
  28. notifyOnErrors: true, // [跨平台错误提示]
  29. poll:false, // [使用文件系统(file system)获取文件改动的通知devServer.watchOptions]
  30. useEslint: true, // [是否启用代码规范检查]
  31. showEslintErrorsInOverlay: false, // [是否展示eslint的错误提示]
  32. devtool: 'eval-source-map', // [增加调试,该属性为原始源代码]
  33. cacheBusting: true, // [使缓存失效]
  34. cssSourceMap: false // [代码压缩后进行调bug定位将非常困难,于是引入sourcemap记录压缩前后的位置信息记录,当产生错误时直接定位到未压缩前的位置,将大大的方便我们调试]
  35. },
  36. /**
  37. * [生产环境配置]
  38. */
  39. build: {
  40. /**
  41. * [index、login、license、forbidden、notfound、Internal.licenses编译后生成的位置和名字,根据需要改变后缀]
  42. */
  43. index: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/index.html'),
  44. login: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/login.html'),
  45. license: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/license.html'),
  46. forbidden: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/error/403.html'),
  47. notfound: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/error/404.html'),
  48. internal: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/error/500.html'),
  49. licenses: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources/docs/licenses.html'),
  50. /**
  51. * [编译后存放生成环境代码的位置]
  52. */
  53. assetsRoot: path.resolve(__dirname, '../../hcm-modules/hcm-web/src/main/resources/META-INF/resources'),
  54. assetsSubDirectory: 'static', //js、css、images存放文件夹名
  55. assetsPublicPath: './', //发布的根目录,通常本地打包dist后打开文件会报错,此处修改为./。如果是上线的文件,可根据文件存放位置进行更改路径
  56. productionSourceMap: true,
  57. devtool: '#source-map',
  58. productionGzip: false, //unit的gzip命令用来压缩文件,gzip模式下需要压缩的文件的扩展名有js和css
  59. productionGzipExtensions: ['js', 'css'],
  60. bundleAnalyzerReport: process.env.npm_config_report //打包分析
  61. }
  62. }

build文件夹下文件详解

build.js

该文件作用,即构建生产版本。package.json中的scripts的build就是node build/build.js,输入命令行npm run build对该文件进行编译生成生产环境的代码。

  1. require('./check-versions')() //check-versions:调用检查版本的文件。加()代表直接调用该函数
  2. process.env.NODE_ENV = 'production' //设置当前是生产环境
  3. /**
  4. *下面定义常量引入插件
  5. */
  6. const ora = require('ora') //加载动画
  7. const rm = require('rimraf') //删除文件
  8. const path = require('path')
  9. const chalk = require('chalk') //对文案
输出的一个彩色设置 const webpack = require('webpack') const config = require('../config') //默认读取下面的index.js文件 const webpackConfig = require('./webpack.prod.conf') const spinner = ora('building for production...') //调用start的方法实现加载动画,优化用户体验 spinner.start() //先删除dist文件再生成新文件,因为有时候会使用hash来命名,删除整个文件可避免冗余 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的版本,实现版本依赖

  1. const chalk = require('chalk')
  2. const semver = require('semver') //对版本进行检查
  3. const packageConfig = require('../package.json')
  4. const shell = require('shelljs')
  5. function exec (cmd) {
  6. //返回通过child_process模块的新建子进程,执行 Unix 系统命令后转成没有空格的字符串
  7. return require('child_process').execSync(cmd).toString().trim()
  8. }
  9. const versionRequirements = [
  10. {
  11. name: 'node',
  12. currentVersion: semver.clean(process.version), //使用semver格式化版本
  13. versionRequirement: packageConfig.engines.node //获取package.json中设置的node版本
  14. }
  15. ]
  16. if (shell.which('npm')) {
  17. versionRequirements.push({
  18. name: 'npm',
  19. currentVersion: exec('npm --version'), // 自动调用npm --version命令,并且把参数返回给exec函数,从而获取纯净的版本号
  20. versionRequirement: packageConfig.engines.npm
  21. })
  22. }
  23. module.exports = function () {
  24. const warnings = []
  25. for (let i = 0; i < versionRequirements.length; i++) {
  26. const mod = versionRequirements[i]
  27. if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
  28. //上面这个判断就是如果版本号不符合package.json文件中指定的版本号,就执行下面错误提示的代码
  29. warnings.push(mod.name + ': ' +
  30. chalk.red(mod.currentVersion) + ' should be ' +
  31. chalk.green(mod.versionRequirement)
  32. )
  33. }
  34. }
  35. if (warnings.length) {
  36. console.log('')
  37. console.log(chalk.yellow('To use this template, you must update following to modules:'))
  38. console.log()
  39. for (let i = 0; i < warnings.length; i++) {
  40. const warning = warnings[i]
  41. console.log(' ' + warning)
  42. }
  43. console.log()
  44. process.exit(1)
  45. }
  46. }

utils.js

utils是工具的意思,是一个用来处理css的文件。

  1. const path = require('path')
  2. const config = require('../config')
  3. const ExtractTextPlugin = require('extract-text-webpack-plugin')
  4. const packageConfig = require('../package.json')
  5. exports.assetsPath = function (_path) {
  6. const assetsSubDirectory = process.env.NODE_ENV === 'production'
  7. ? config.build.assetsSubDirectory
  8. : config.dev.assetsSubDirectory
  9. return path.posix.join(assetsSubDirectory, _path)
  10. }
  11. exports.cssLoaders = function (options) {
  12. options = options || {}
  13. //使用了css-loader和postcssLoader,通过options.usePostCSS属性来判断是否使用postcssLoader中压缩等方法
  14. const cssLoader = {
  15. loader: 'css-loader',
  16. options: {
  17. sourceMap: options.sourceMap
  18. }
  19. }
  20. const postcssLoader = {
  21. loader: 'postcss-loader',
  22. options: {
  23. sourceMap: options.sourceMap
  24. }
  25. }
  26. // generate loader string to be used with extract text plugin
  27. function generateLoaders (loader, loaderOptions) {
  28. const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
  29. if (loader) {
  30. loaders.push({
  31. loader: loader + '-loader',
  32. //Object.assign是es6语法的浅复制,后两者合并后复制完成赋值
  33. options: Object.assign({}, loaderOptions, {
  34. sourceMap: options.sourceMap
  35. })
  36. })
  37. }
  38. // Extract CSS when that option is specified
  39. // (which is the case during production build)
  40. if (options.extract) {
  41. //ExtractTextPlugin可提取出文本,代表首先使用上面处理的loaders,当未能正确引入时使用vue-style-loader
  42. return ExtractTextPlugin.extract({
  43. use: loaders,
  44. fallback: 'vue-style-loader',
  45. publicPath: '../../'
  46. })
  47. } else {
  48. //返回vue-style-loader连接loaders的最终值
  49. return ['vue-style-loader'].concat(loaders)
  50. }
  51. }
  52. // https://vue-loader.vuejs.org/en/configurations/extract-css.html
  53. return {
  54. css: generateLoaders(),//需要css-loader 和 vue-style-loader
  55. postcss: generateLoaders(),//需要css-loader和postcssLoader 和 vue-style-loader
  56. less: generateLoaders('less'), //需要less-loader 和 vue-style-loader
  57. sass: generateLoaders('sass', { indentedSyntax: true }), //需要sass-loader 和 vue-style-loader
  58. scss: generateLoaders('sass'), //需要sass-loader 和 vue-style-loader
  59. stylus: generateLoaders('stylus'), //需要stylus-loader 和 vue-style-loader
  60. styl: generateLoaders('stylus') //需要stylus-loader 和 vue-style-loader
  61. }
  62. }
  63. // Generate loaders for standalone style files (outside of .vue)
  64. exports.styleLoaders = function (options) {
  65. const output = []
  66. const loaders = exports.cssLoaders(options)
  67. //将各种css,less,sass等综合在一起得出结果
输出output 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') }) } }

vue-loader.conf.js

该文件的主要作用就是处理.vue文件,解析这个文件中的每个语言块(template、script、style),转换成js可用的js模块。

  1. const utils = require('./utils')
  2. const config = require('../config')
  3. const isProduction = process.env.NODE_ENV === 'production'
  4. const sourceMapEnabled = isProduction
  5. ? config.build.productionSourceMap
  6. : config.dev.cssSourceMap
  7. //处理项目中的css文件,生产环境和测试环境默认是打开sourceMap,而extract中的提取样式到单独文件只有在生产环境中才需要
  8. module.exports = {
  9. loaders: utils.cssLoaders({
  10. sourceMap: sourceMapEnabled,
  11. extract: isProduction
  12. }),
  13. cssSourceMap: sourceMapEnabled,
  14. cacheBusting: config.dev.cacheBusting,
  15. // 在模版编译过程中,编译器可以将某些属性,如 src 路径,转换为require调用,以便目标资源可以由 webpack 处理
  16. transformToRequire: {
  17. video: ['src', 'poster'],
  18. source: 'src',
  19. img: 'src',
  20. image: 'xlink:href'
  21. }
  22. }

webpack.base.conf.js

webpack.base.conf.js是开发和生产共同使用提出来的基础配置文件,主要实现配制入口,配置输出环境,配置模块resolve和插件等

  1. const path = require('path')
  2. const utils = require('./utils')
  3. /**
  4. * [引入index.js文件路径]
  5. */
  6. const config = require('../config')
  7. const vueLoaderConfig = require('./vue-loader.conf')
  8. /**
  9. * [获取文件路径]
  10. * @param dir [文件名称]
  11. *_dirname为当前模块文件所在目录的绝对路径*
  12. *@return 文件绝对路径
  13. */
  14. function resolve (dir) {
  15. return path.join(__dirname, '..', dir)
  16. }
  17. const createLintingRule = () => ({
  18. test: /\.(js|vue)$/,
  19. loader: 'eslint-loader',
  20. enforce: 'pre',
  21. include: [resolve('src'), resolve('test')],
  22. options: {
  23. formatter: require('eslint-friendly-formatter'),
  24. emitWarning: !config.dev.showEslintErrorsInOverlay
  25. }
  26. })
  27. module.exports = {
  28. context: path.resolve(__dirname, '../'),
  29. /**
  30. * [入口文件配置]
  31. */
  32. entry: {
  33. /**
  34. * [入口文件路径, babel-polyfill是对es6语法的支持]
  35. */
  36. app: ['babel-polyfill', './src/main.js'],
  37. login: ['babel-polyfill', './src/loginMain.js'],
  38. license: ['babel-polyfill', './src/licenseMain.js']
  39. },
  40. /**
  41. * [文件导出配置]
  42. */
  43. output: {
  44. path: config.build.assetsRoot,
  45. filename: '[name].js',
  46. publicPath: process.env.NODE_ENV === 'production'
  47. ? config.build.assetsPublicPath
  48. : config.dev.assetsPublicPath //公共存放路径
  49. },
  50. resolve: {
  51. /**
  52. * [extensions: 配置文件的扩展名,当在important文件时,不用需要添加扩展名]
  53. */
  54. extensions: ['.js', '.vue', '.json'],
  55. /**
  56. * [alias 给路径定义别名]
  57. */
  58. alias: {
  59. 'vue$': 'vue/dist/vue.esm.js',
  60. '@': resolve('src')
  61. }
  62. },
  63. /**
  64. *使用插件配置相应文件的处理方法
  65. */
  66. module: {
  67. rules: [
  68. ...(config.dev.useEslint ? [createLintingRule()] : []),
  69. /**
  70. * [使用vue-loader将vue文件转化成js的模块]
  71. */
  72. {
  73. test: /\.vue$/,
  74. loader: 'vue-loader',
  75. options: vueLoaderConfig
  76. },
  77. /**
  78. * [通过babel-loader将js进行编译成es5/es6 文件]
  79. */
  80. {
  81. test: /\.js$/,
  82. loader: 'babel-loader',
  83. include: [resolve('src'), resolve('test')]
  84. },
  85. /**
  86. * [图片、音像、字体都使用url-loader进行处理,超过10000会编译成base64]
  87. */
  88. {
  89. test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  90. loader: 'url-loader',
  91. options: {
  92. limit: 10000,
  93. name: utils.assetsPath('img/[name].[hash:7].[ext]')
  94. }
  95. },
  96. {
  97. test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
  98. loader: 'url-loader',
  99. options: {
  100. limit: 10000,
  101. name: utils.assetsPath('media/[name].[hash:7].[ext]')
  102. }
  103. },
  104. {
  105. test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  106. loader: 'url-loader',
  107. options: {
  108. limit: 10000,
  109. name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
  110. }
  111. },
  112. /**
  113. * [canvas 解析]
  114. */
  115. {
  116. test: path.resolve(`${resolve('src')}/lib/jtopo.js`),
  117. loader: ['exports-loader?window.JTopo', 'script-loader']
  118. }
  119. ]
  120. },
  121. //以下选项是Node.js全局变量或模块,这里主要是防止webpack注入一些Node.js的东西到vue中
  122. node: {
  123. setImmediate: false,
  124. dgram: 'empty',
  125. fs: 'empty',
  126. net: 'empty',
  127. tls: 'empty',
  128. child_process: 'empty'
  129. }
  130. }

webpack.dev.conf.js

  1. const path = require('path')
  2. const utils = require('./utils')
  3. const webpack = require('webpack')
  4. const config = require('../config')
  5. //通过webpack-merge实现webpack.dev.conf.js对wepack.base.config.js的继承
  6. const merge = require('webpack-merge')
  7. const baseWebpackConfig = require('./webpack.base.conf')
  8. const HtmlWebpackPlugin = require('html-webpack-plugin')
  9. //美化webpack的错误信息和日志的插件
  10. const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
  11. // 查看空闲端口位置,默认情况下搜索8000这个端口
  12. const portfinder = require('portfinder')
  13. // processs为node的一个全局对象获取当前程序的环境变量,即host
  14. const HOST = process.env.HOST
  15. const PORT = process.env.PORT && Number(process.env.PORT)
  16. function resolveApp(relativePath) {
  17. return path.resolve(relativePath);
  18. }
  19. const devWebpackConfig = merge(baseWebpackConfig, {
  20. module: {
  21. //规则是工具utils中处理出来的styleLoaders,生成了css,less,postcss等规则
  22. rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  23. },
  24. // 增强调试
  25. devtool: config.dev.devtool,
  26. // 此处的配置都是在config的index.js中设定好了
  27. devServer: {
  28. //控制台显示的选项有none, error, warning 或者 info
  29. clientLogLevel: 'warning',
  30. //使用 HTML5 History API
  31. historyApiFallback: true,
  32. hot: true, //热加载
  33. compress: true, //压缩
  34. host: HOST || config.dev.host,
  35. port: PORT || config.dev.port,
  36. open: config.dev.autoOpenBrowser, //调试时自动打开浏览器
  37. overlay: config.dev.errorOverlay
  38. ? { warnings: false, errors: true }
  39. : false,
  40. publicPath: config.dev.assetsPublicPath,
  41. proxy: config.dev.proxyTable,//接口代理
  42. quiet: true, //控制台是否禁止打印警告和错误,若用FriendlyErrorsPlugin 此处为 true watchOptions: {
  43. poll: config.dev.poll, // 文件系统检测改动
  44. }
  45. },
  46. plugins: [
  47. new webpack.DefinePlugin({
  48. 'process.env': require('../config/dev.env')
  49. }),
  50. new webpack.HotModuleReplacementPlugin(),//模块热替换插件,修改模块时不需要刷新页面
  51. new webpack.NamedModulesPlugin(), // 显示文件的正确名字
  52. new webpack.NoEmitOnErrorsPlugin(), //当webpack编译错误的时候,来中端打包进程,防止错误代码打包到文件中
  53. // https://github.com/ampedandwired/html-webpack-plugin
  54. // 该插件可自动生成一个 html5 文件或使用模板文件将编译好的代码注入进去
  55. new HtmlWebpackPlugin({
  56. filename: 'index.html',
  57. template: 'index.html',
  58. inject: true,
  59. chunks: ['app']
  60. }),
  61. new HtmlWebpackPlugin({
  62. filename: 'login.html',
  63. template: 'login.html',
  64. inject: true,
  65. chunks: ['login']
  66. }),
  67. new HtmlWebpackPlugin({
  68. filename: 'license.html',
  69. template: 'license.html',
  70. inject: true,
  71. chunks: ['license']
  72. }),
  73. new HtmlWebpackPlugin({
  74. filename: 'licenses.html',
  75. template: 'licenses.html',
  76. inject: true,
  77. chunks: []
  78. }),
  79. new HtmlWebpackPlugin({
  80. filename: '404.html',
  81. template: path.resolve(__dirname, '../errors/404.html'),
  82. favicon: resolveApp('favicon.ico'),
  83. inject: true,
  84. chunks: []
  85. }),
  86. new HtmlWebpackPlugin({
  87. filename: '403.html',
  88. template: path.resolve(__dirname, '../errors/403.html'),
  89. favicon: resolveApp('favicon.ico'),
  90. inject: true,
  91. chunks: []
  92. }),
  93. new HtmlWebpackPlugin({
  94. filename: '500.html',
  95. template: path.resolve(__dirname, '../errors/500.html'),
  96. favicon: resolveApp('favicon.ico'),
  97. inject: true,
  98. chunks: []
  99. })
  100. ]
  101. })
  102. module.exports = new Promise((resolve, reject) => {
  103. portfinder.basePort = process.env.PORT || config.dev.port
  104. //查找端口号
  105. portfinder.getPort((err, port) => {
  106. if (err) {
  107. reject(err)
  108. } else {
  109. //端口被占用时就重新设置evn和devServer的端口
  110. process.env.PORT = port
  111. // add port to devServer config
  112. devWebpackConfig.devServer.port = port
  113. //友好地
输出信息 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

  1. const path = require('path')
  2. const utils = require('./utils')
  3. const webpack = require('webpack')
  4. const config = require('../config')
  5. const merge = require('webpack-merge')
  6. const baseWebpackConfig = require('./webpack.base.conf')
  7. const CopyWebpackPlugin = require('copy-webpack-plugin')
  8. const HtmlWebpackPlugin = require('html-webpack-plugin')
  9. const ExtractTextPlugin = require('extract-text-webpack-plugin')
  10. const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
  11. const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
  12. const env = require('../config/prod.env')
  13. function resolveApp(relativePath) {
  14. return path.resolve(relativePath);
  15. }
  16. const webpackConfig = merge(baseWebpackConfig, {
  17. module: {
  18. rules: utils.styleLoaders({
  19. sourceMap: config.build.productionSourceMap,//开启调试的模式。默认为true
  20. extract: true,
  21. usePostCSS: true
  22. })
  23. },
  24. devtool: config.build.productionSourceMap ? config.build.devtool : false,
  25. output: {
  26. path: config.build.assetsRoot,
  27. filename: utils.assetsPath('js/[name].[chunkhash].js'),
  28. chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  29. },
  30. plugins: [
  31. // http://vuejs.github.io/vue-loader/en/workflow/production.html
  32. new webpack.DefinePlugin({
  33. 'process.env': env
  34. }),
  35. new UglifyJsPlugin({
  36. uglifyOptions: {
  37. compress: {
  38. warnings: false //警告:true保留警告,false不保留
  39. }
  40. },
  41. sourceMap: config.build.productionSourceMap,
  42. parallel: true
  43. }),
  44. // extract css into its own file
  45. //抽取文本。比如打包之后的index页面有style插入,就是这个插件抽取出来的,减少请求
  46. new ExtractTextPlugin({
  47. filename: utils.assetsPath('css/[name].[contenthash].css'),
  48. allChunks: true,
  49. }),
  50. //优化css的插件
  51. new OptimizeCSSPlugin({
  52. cssProcessorOptions: config.build.productionSourceMap
  53. ? { safe: true, map: { inline: false } }
  54. : { safe: true }
  55. }),
  56. //html打包
  57. new HtmlWebpackPlugin({
  58. filename: config.build.index,
  59. template: 'index.html',
  60. inject: true,
  61. //压缩
  62. minify: {
  63. removeComments: true, //删除注释
  64. collapseWhitespace: true, //删除空格
  65. removeAttributeQuotes: true //删除属性的引号
  66. },
  67. chunks: ['vendor', 'manifest', 'app'],
  68. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  69. chunksSortMode: 'dependency'
  70. }),
  71. new HtmlWebpackPlugin({
  72. filename: config.build.login,
  73. template: 'login.html',
  74. inject: true,
  75. minify: {
  76. removeComments: true,
  77. collapseWhitespace: true,
  78. removeAttributeQuotes: true
  79. },
  80. chunks: ['vendor', 'manifest', 'login'],
  81. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  82. chunksSortMode: 'dependency'
  83. }),
  84. new HtmlWebpackPlugin({
  85. filename: config.build.license,
  86. template: 'license.html',
  87. inject: true,
  88. minify: {
  89. removeComments: true,
  90. collapseWhitespace: true,
  91. removeAttributeQuotes: true
  92. },
  93. chunks: ['vendor', 'manifest', 'license'],
  94. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  95. chunksSortMode: 'dependency'
  96. }),
  97. new HtmlWebpackPlugin({
  98. filename: config.build.notfound,
  99. template: path.resolve(__dirname, '../errors/404.html'),
  100. inject: true,
  101. favicon: resolveApp('favicon.ico'),
  102. minify: {
  103. removeComments: true,
  104. collapseWhitespace: true,
  105. removeAttributeQuotes: true
  106. },
  107. chunks: [],
  108. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  109. chunksSortMode: 'dependency'
  110. }),
  111. new HtmlWebpackPlugin({
  112. filename: config.build.forbidden,
  113. template: path.resolve(__dirname, '../errors/403.html'),
  114. inject: true,
  115. favicon: resolveApp('favicon.ico'),
  116. minify: {
  117. removeComments: true,
  118. collapseWhitespace: true,
  119. removeAttributeQuotes: true
  120. },
  121. chunks: [],
  122. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  123. chunksSortMode: 'dependency'
  124. }),
  125. new HtmlWebpackPlugin({
  126. filename: config.build.internal,
  127. template: path.resolve(__dirname, '../errors/500.html'),
  128. inject: true,
  129. favicon: resolveApp('favicon.ico'),
  130. minify: {
  131. removeComments: true,
  132. collapseWhitespace: true,
  133. removeAttributeQuotes: true
  134. },
  135. chunks: [],
  136. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  137. chunksSortMode: 'dependency'
  138. }),
  139. new HtmlWebpackPlugin({
  140. filename: config.build.licenses,
  141. template: 'licenses.html',
  142. inject: true,
  143. minify: {
  144. removeComments: true,
  145. collapseWhitespace: true,
  146. removeAttributeQuotes: true
  147. },
  148. chunks: [],
  149. // necessary to consistently work with multiple chunks via CommonsChunkPlugin
  150. chunksSortMode: 'dependency'
  151. }),
  152. // keep module.id stable when vender modules does not change
  153. new webpack.HashedModuleIdsPlugin(),
  154. // enable scope hoisting
  155. new webpack.optimize.ModuleConcatenationPlugin(),
  156. //抽取公共的模块, 提升你的代码在浏览器中的执行速度。
  157. new webpack.optimize.CommonsChunkPlugin({
  158. name: 'vendor',
  159. minChunks (module) {
  160. // any required modules inside node_modules are extracted to vendor
  161. return (
  162. module.resource &&
  163. /\.js$/.test(module.resource) &&
  164. module.resource.indexOf(
  165. path.join(__dirname, '../node_modules')
  166. ) === 0
  167. )
  168. }
  169. }),
  170. // extract webpack runtime and module manifest to its own file in order to
  171. // prevent vendor hash from being updated whenever app bundle is updated
  172. new webpack.optimize.CommonsChunkPlugin({
  173. name: 'manifest',
  174. minChunks: Infinity
  175. }),
  176. // 预编译所有模块到一个闭包中,
  177. new webpack.optimize.CommonsChunkPlugin({
  178. name: 'app',
  179. async: 'vendor-async',
  180. children: true,
  181. minChunks: 3
  182. }),
  183. //复制,比如打包完之后需要把打包的文件复制到dist里面
  184. new CopyWebpackPlugin([
  185. {
  186. from: path.resolve(__dirname, '../static'),
  187. to: config.build.assetsSubDirectory,
  188. ignore: ['.*']
  189. }
  190. ])
  191. ]
  192. })
  193. if (config.build.productionGzip) {
  194. const CompressionWebpackPlugin = require('compression-webpack-plugin')
  195. webpackConfig.plugins.push(
  196. new CompressionWebpackPlugin({
  197. asset: '[path].gz[query]',
  198. algorithm: 'gzip',
  199. test: new RegExp(
  200. '\\.(' +
  201. config.build.productionGzipExtensions.join('|') +
  202. ')$'
  203. ),
  204. threshold: 10240,
  205. minRatio: 0.8
  206. })
  207. )
  208. }
  209. // 提供带 Content-Encoding 编码的压缩版的资源
  210. if (config.build.bundleAnalyzerReport) {
  211. const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  212. webpackConfig.plugins.push(new BundleAnalyzerPlugin())
  213. }
  214. module.exports = webpackConfig

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

人气教程排行