@vue cli-init创建项目学习webpack配置

vue的webpack

先来看一下目录结构:

  • build
    • 第一个是build打包
    • 第二个为检查node版本
    • 第三个为工具一会儿看代码
    • loader 配合utils
    • vue loader
    • webpack公共配置
    • webpack开发配置
    • webpack生产配置
  • config
    • dev
    • 配置文件
    • prod
    • test

在这里插入图片描述
下面来看下各个文件,这里就不按照顺序了

build

build

'use strict'
require('./check-versions')()  // 检查node版本 

process.env.NODE_ENV = 'production'

const ora = require('ora') // 主要用来实现node.js命令行环境的loading效果,和显示各种状态的图标等
const rm = require('rimraf') // 用于删除dist目录的旧文件
const path = require('path')
const chalk = require('chalk') // chalk 包的作用是修改控制台中字符串的样式,包括:字体样式(加粗、隐藏等) 字体颜色  背景颜色
const webpack = require('webpack')
const config = require('../config') // dev和build
const webpackConfig = require('./webpack.prod.conf') // 导入prod.conf生产配置

const spinner = ora('building for production...')
spinner.start()

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
    
     // 删除之前的dist
  if (err) throw err
  webpack(webpackConfig, (err, stats) => {
    
     // 开始打包 生产webpack  
    spinner.stop() // 停止加载动画
    if (err) throw err
    process.stdout.write(stats.toString({
    
    
      // console.log 就是基于该api封装
      // process.stdout.write 函数只接受字符串 nodejs提供的api
      // process.stdout.write 函数默认不会换行
      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) // 退出状态 0为正常退出其他数字为非正常退出
    }

    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

'use strict'
const chalk = require('chalk') // 定义颜色
const semver = require('semver') // 处理版本相关的工作。
const packageConfig = require('../package.json')
const shell = require('shelljs') // Shelljs是Node.js下的脚本语言解析器 直接解析shell

function exec (cmd) {
    
    
 return require('child_process').execSync(cmd).toString().trim() // 调用cmd
}

const versionRequirements = [
 {
    
    
   name: 'node',
   currentVersion: semver.clean(process.version), // 清除版本号
   versionRequirement: packageConfig.engines.node  // package.json中的node版本
 }
]

if (shell.which('npm')) {
    
    
 // which 命令的作用是在 PATH 变量指定的路径中搜索某个系统命令的位置并且返回第一个搜索结果。
 // 也就是说使用 which 命令就可以看到某个系统命令是否存在以及执行的到底是哪一个位置的命令
 versionRequirements.push({
    
    
   name: 'npm',
   currentVersion: exec('npm --version'), // cmd执行 npm -version
   versionRequirement: packageConfig.engines.npm   // package.json中的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)) {
    
     // 判断node版本是否在某个范围
     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)  // 非正常退出程序
 }
}

webpack.prod.conf

'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config') // 导入config配置
const merge = require('webpack-merge') // 合并webpack配置
const baseWebpackConfig = require('./webpack.base.conf') // 导入webpack base配置

// webpack的copy-webpack-plugin插件的作用是将项目中的某单个文件或整个文件夹在打包的时候
// 复制一份到打包后的文件夹中(即复制一份到dist目录下)。
// 简单的说不需要经过loader或者plugin处理的文件直接复制到dist文件夹下
const CopyWebpackPlugin = require('copy-webpack-plugin')

// 核心plugin HtmlWebpackPlugin 简化了 HTML 文件的创建,以便为你的 webpack 包提供服务。
// 这对于那些文件名中包含哈希值,并且哈希值会随着每次编译而改变的 webpack 包特别有用。
// 你可以让该插件为你生成一个 HTML 文件,使用 lodash 模板提供模板,或者使用你自己的 loader。
// 为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题\
// 可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口
// 地址: https://webpack.docschina.org/plugins/html-webpack-plugin/
const HtmlWebpackPlugin = require('html-webpack-plugin')

// 该插件的主要是为了抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象
// 目前已经MiniCssExtractPlugin取代
const ExtractTextPlugin = require('extract-text-webpack-plugin')

// 单独压缩css文件
// 地址: https://blog.csdn.net/weixin_36185028/article/details/82182352
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')

// 此插件使用uglify-js进行js文件的压缩。
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const env = process.env.NODE_ENV === 'testing'
  ? require('../config/test.env')
  : require('../config/prod.env')

const webpackConfig = merge(baseWebpackConfig, {
    
     // baseWebpackConfig
  module: {
    
     // module 配置如何处理模块
    rules: utils.styleLoaders({
    
    
      sourceMap: config.build.productionSourceMap, // 是否开启 SourceMap
      extract: true, // 是否使用ExtractTextPlugin插件
      usePostCSS: true // 是否使用postCss
    })
  },
  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
    // DefinePlugin 允许创建一个在编译时可以配置的全局常量。
    new webpack.DefinePlugin({
    
    
      'process.env': env
    }),
    new UglifyJsPlugin({
    
     // 压缩js
      uglifyOptions: {
    
    
        compress: {
    
    
          warnings: false
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
    
     // 抽离css
      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({
    
     // 压缩css
      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({
    
     // 生成html
      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
    // https://webpack.docschina.org/plugins/hashed-module-ids-plugin/
    // 这个插件将基于模块的相对路径生成哈希值,生成一个4个字符的字符串作为模块id。建议在生产中使用。
    new webpack.HashedModuleIdsPlugin(),
    // enable scope hoisting
    // 这个插件会在 webpack 中实现以上的预编译功能
    new webpack.optimize.ModuleConcatenationPlugin(),
    // split vendor js into its own file
    // 打包第三方控件
    // 1,vendor则是通过提取公共模块插件来提取的代码块(webpack本身带的模块化代码部分),
    // 而manifest则是在vendor的基础上,再抽取出要经常变动的部分,比如关于异步加载js模块部分的内容。
    // 2,我们可以加上hash来查看,在未变动的情况下,是否又重新打包;
    // 3,第三方控件只用打包一次就可以了。
    // https://webpack.docschina.org/plugins/commons-chunk-plugin/#root
    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
    // CommonsChunkPlugin 已在 webpack v4 legato 中删除
    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: ['.*']
      }
    ])
  ]
})

// 准备资产的压缩版本以使用内容编码为它们提供服务。
// https://webpack.docschina.org/plugins/compression-webpack-plugin/#minratio
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   // 仅处理压缩率高于此比率的资产
    })
  )
}

// 生成代码分析报告,帮助提升代码质量和网站性能。
// 一个 plugin 和 CLI 工具,它将 bundle 内容展示为一个便捷的、交互式、可缩放的树状图形式。
// https://webpack.docschina.org/guides/code-splitting/#bundle-analysis
if (config.build.bundleAnalyzerReport) {
    
    
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

webpack.base.conf

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')   // 自定义loader配置

function resolve (dir) {
    
    
  return path.join(__dirname, '..', dir)
}


// eslint-loader
const createLintingRule = () => ({
    
    
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    
    
    // eslint-friendly-formatter 可以让eslint的错误信息出现在终端上
    formatter: require('eslint-friendly-formatter'),
    // 忽略警告
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})


// webpack 核心
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
  },
  resolve: {
    
     // 解析模块规则配置
    extensions: ['.js', '.vue', '.json'],  // 忽略后缀
    alias: {
    
     // 别名
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    // 告诉 webpack 解析模块是去找哪个目录
    //  modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
  },
  module: {
    
    
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),    // 是否使用eslint
      {
    
    
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig   // 使用vueloader
      },
      {
    
    
        test: /\.js$/,
        loader: 'babel-loader',   // babel es6 => es5
        // include 表示哪些目录中的 .js 文件需要进行 babel-loader
        // exclude 表示哪些目录中的 .js 文件不要进行 babel-loader
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
    
    
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',  // url-loader
        // 比如我们一般会把小于8kb的图片才做base64转换,这个东西通过limit来控制(当然我们是小于100kb),
        // name就是自定义image的路径以及name,include就是你想让哪个文件夹里面的图片进行url-loader转换,
        // 建议写上include,如果不写就会全局搜索,效率低下,而且文件夹不写全也会报错。
        // 当然还有一种格式是可以直接写到loader中的,就是以query的形式去拼装options。
        // https://v4.webpack.js.org/loaders/url-loader/
        // 已弃用 v5:请考虑迁移到asset modules.
        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]')
        }
      }
    ]
  },

  // 这些选项配置是 polyfill 还是模拟某些Node.js 全局变量和模块。
  // 这允许最初为 Node.js 环境编写的代码在浏览器等其他环境中运行。
  // 这个特性是由 webpack 的内部NodeStuffPlugin插件提供的。
  // 如果目标是“web”(默认)或“webworker”,NodeSourcePlugin插件也会被激活。
  // 这是一个对象,其中每个属性都是 Node 全局或模块的名称,每个值可能是以下之一...
  // true: 提供一个 polyfill。
  // 'mock':提供实现预期接口但功能很少或没有功能的模拟。
  // 'empty': 提供一个空对象。
  // false: 什么都不提供。需要此对象的代码可能会因ReferenceError. 尝试导入模块的代码require('modulename')可能会触发Cannot find module "modulename"错误。
  // 地址: https://v4.webpack.js.org/configuration/node/#root
  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'
  }
}

vue-loader

'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
  ? config.build.productionSourceMap
  : config.dev.cssSourceMap

module.exports = {
    
    
  loaders: utils.cssLoaders({
    
    
    sourceMap: sourceMapEnabled,   //是否开始sourceMap 用来调试
    extract: isProduction     // 是否单独提取css
  }),
  //记录压缩的代码,用来找到源码位置
  cssSourceMap: sourceMapEnabled,
  cacheBusting: config.dev.cacheBusting, // 是否破坏缓存
  //transformToRequire的作用是在模块编译的过程中,编译器可以将某些属性,比如src转换为require调用
  transformToRequire: {
    
      // https://blog.csdn.net/weixin_46382167/article/details/108970308
    video: ['src', 'poster'],  // 无需导入img video  可以直接使用地址
    source: 'src',
    img: 'src',
    image: 'xlink:href'
  }
}

utils

'use strict'
const path = require('path')
const config = require('../config')
// 将css模块和js模块分开打包。在webpack4中,建议用mini-css-extract-plugin替代
// 插件解释: https://blog.csdn.net/weixin_41134409/article/details/88416356
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) {
    
     // cssLoaders
  options = options || {
    
    }

  const cssLoader = {
    
    
    loader: 'css-loader',
    options: {
    
    
      sourceMap: options.sourceMap
    }
  }

  const postcssLoader = {
    
      // postcss sass less等
    loader: 'postcss-loader',
    options: {
    
    
      sourceMap: options.sourceMap
    }
  }

  // generate loader string to be used with extract text plugin
  // css转换器
  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
    // 是否提取css
    // (which is the case during production build)
    if (options.extract) {
    
    
      return ExtractTextPlugin.extract({
    
    
        use: loaders, // 指需要什么样的loader去编译文件
        fallback: 'vue-style-loader' // fallback: 这里表示不提取的时候,使用什么样的配置来处理css
        // publicfile:用来覆盖项目路径,生成该css文件的文件路径这里不需要
      })
    } 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')
    })
  }
}

webpack.dev.conf

'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
// https://webpack.docschina.org/plugins/copy-webpack-plugin/
// 同prod.conf
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 友好的错误提示插件
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// 自动获取端口
const portfinder = require('portfinder')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {
    
     // 合并基础config
  module: {
    
    
    rules: utils.styleLoaders({
    
     sourceMap: config.dev.cssSourceMap, usePostCSS: true })  // 使用styleLoader
  },
  // cheap-module-eval-source-map is faster for development
  devtool: config.dev.devtool,  // 解析配置

  // these devServer options should be customized in /config/index.js
  // 核心 通过 webpack-dev-server 的这些配置,能够以多种方式改变其行为。
  // 这是一个基本的示例,利用 gzips 压缩 public/ 目录当中的所有内容并提供一个本地服务(serve):
  // https://webpack.docschina.org/configuration/dev-server/
  // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
  devServer: {
    
    
    clientLogLevel: 'warning',
    //使用HTML5 History API 时,index.html可能必须提供页面来代替任何404响应。
    //devServer.historyApiFallback通过将其设置为启用true:
    historyApiFallback: {
    
    
      rewrites: [
        {
    
     from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    hot: true,  // 热更新
    // 该配置项指定了服务器资源的根目录,如果不配置contentBase的话,
    // 那么contentBase默认是当前执行的目录,一般是项目的根目录。
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,  //是否启用gzip压缩
    host: HOST || config.dev.host,  // host
    port: PORT || config.dev.port, // 端口
    open: config.dev.autoOpenBrowser, // 是否自动打开网页
    // 该属性是用来在编译出错的时候,在浏览器页面上显示错误。该属性值默认为false,需要的话,设置该参数为true。
    overlay: config.dev.errorOverlay
      ? {
    
     warnings: false, errors: true }
      : false,
    // publicPath路径下的打包文件可在浏览器中访问。
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,  // 代理
    // 开启后,除了初始启动信息之外的任何内容都不会被打印到控制台
    quiet: true, // necessary for FriendlyErrorsPlugin
    // 此选项允许您配置 globs/目录/文件列表以监视文件更改。
    watchOptions: {
    
    
      poll: config.dev.poll,
    }
  },
  plugins: [
    new webpack.DefinePlugin({
    
    
      'process.env': require('../config/dev.env')
    }),
    // 热更新模块 webpack官方文档(devserverhot)中介绍,使用hmr的时候,需要满足两个条件:
    new webpack.HotModuleReplacementPlugin(),
    // 这个插件的作用是在热加载时直接返回更新文件名,而不是文件的id。
    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    // 在编译出现错误时,使用 NoEmitOnErrorsPlugin 来跳过输出阶段。
    // 这样可以确保输出资源不会包含错误。对于所有资源,统计资料(stat)的 emitted 标识都是 false
    new webpack.NoEmitOnErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
    
    
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
    
    
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ]
})

module.exports = new Promise((resolve, reject) => {
    
    
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    
    
    if (err) {
    
    
      reject(err)
    } else {
    
    
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      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)
    }
  })
})

config

dev.env

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

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

prod.env

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

test.env

'use strict'
const merge = require('webpack-merge')
const devEnv = require('./dev.env')

module.exports = merge(devEnv, {
    
    
  NODE_ENV: '"testing"'
})

index

'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: {
    
    },

    // 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-

    // Use Eslint Loader?
    // If true, your code will be linted during bundling and
    // linting errors and warnings will be shown in the console.
    useEslint: true,
    // 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: {
    
    
    // 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
  }
}

小结

  • vue采用了env全局变量来确定是开发环境还是生产环境
  • vue将模块进行了拆分 本质上仍然是webpack的5个核心入口 出口 模块 loader plugin的灵活使用
  • 最重要的两部分就是loader和plugin的使用,目前很多都被进行了升级或者淘汰
  • 下次总结vue3webpack的变化

猜你喜欢

转载自blog.csdn.net/shadowfall/article/details/120085183
今日推荐