Vue基于Webpack的相关目录及配置解读

如今webpack已经成为前端项目开发过程中必不可少的一部分,一直以来都是大概了解一些内容,没有做详细的分析,这篇文章总结一下我的所获。

1、build文件(我们最终会把所有要发布的代码放到这里)

1.1 build.js (生产环境配置脚本-打包过程需要引入的配置信息)

const ora = require('ora') 
//Elegant terminal spinner 优雅的终端微调器 打包开始提示对cli进行输出一个带spinner的文案,告诉用户正在打包中

const rm = require('rimraf') 
//The UNIX command rm -rf for node.以包的形式包装rm -rf命令,就是用来删除文件和文件夹的,不管文件夹是否为空,都可以删除。
// 去除先前的打包,这个模块是用来清除之前的打的包,
// 因为在vue-cli中每次打包会生成不同的hash,每次打包都会生成新的文件,那就不对了,
// 我们要复盖原先的文件,因为hash不同复盖不了,所以要清除

const path = require('path')
// 模块提供了一些工具函数,用于处理文件与目录的路径。

const chalk = require('chalk')
// Terminal string styling done right,更好的命令行字符串格式

const webpack = require('webpack') 
// 把webpack模块包引入

const config = require('../config') 
//引入config文件

const spinner = ora('building for production...正在打包')
spinner.start()

// 对cli进行输出一个带spinner的文案,告诉用户正在打包中,也可以这样设置多个值
// const spinner = ora({
// color: 'green',
//   text: '正为生产环境打包,耐心点,不然自动关机。。。'
// })
// spinner.start()

1.2 check-versions.js(检测node和npm的版本)

const chalk = require('chalk') 
// chalk插件,作用是在控制台中输出不同颜色的字,
// 大致这样用chalk.blue('Hello world'),这款插件只能改变命令行中的字体颜色

const semver = require('semver') 
// The semantic versioner for npm
// semver插件,是用来对特定的版本号做判断的,
// 比如 semver.gt('1.2.3','9.8.7') false 1.2.3版本比9.8.7版本低
// semver.satisfies('1.2.3','1.x || >=2.5.0 || 5.0.0 - 7.2.3') true 1.2.3的版本符合后面的规则

const packageConfig = require('../package.json')
// 上面是导入package.json文件,要使用里面的engines选项,
// 要注意require是直接可以导入json文件的,并且requrie返回的就是json对象


const shell = require('shelljs') 
// Unix shell commands for Node.js
// 上面这个插件是shelljs,作用是用来执行Unix系统命令

function exec (cmd) { 

// 脚本可以通过 child_process 模块新建子进程,从而执行 Unix 系统命令
// 下面这段代码实际就是把cmd这个参数传递的值转化成前后没有空格的字符串,也就是版本号
// https://nodejs.org/api/child_process.html这是nodejs的子进程教程
// require('child_process') node的模块,execSync(cmd)创建同步进程

  return require('child_process').execSync(cmd).toString().trim()   

// child_process.execSync(command[, options])
}
var versionRequirements = [
  {
    name: 'node',
    currentVersion: semver.clean(process.version), 
    // 使用semver插件吧版本信息转化成规定格式,也就是 ' =v1.2.3 ' -> '1.2.3' 这种功能
    versionRequirement: packageConfig.engines.node 
    // 这是规定的pakage.json中engines选项的node版本信息 "node":">= 4.0.0"
  },
]

/*shell.which('npm')  返回:C:\PROGRAM FILES\NODEJS\NPM.CMD 返回绝对路径,否则返回null*/
if (shell.which('npm')) { 
    // shell.which方法是去环境变量搜索有没有参数这个命令
  versionRequirements.push({
    name: 'npm',
    currentVersion: exec('npm --version'),
    // 自动调用npm --version命令,并且把参数返回给exec函数,从而获取纯净的版本号
    versionRequirement: packageConfig.engines.npm 
    // 这是规定的pakage.json中engines选项的node版本信息 "npm": ">= 3.0.0"
  })
}

module.exports = function () {
  var warnings = []
  for (var i = 0; i < versionRequirements.length; i++) {
    var mod = versionRequirements[i]
    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
      // 如果版本号不符合package.json文件中指定的版本号,就执行下面的代码
      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 (var i = 0; i < warnings.length; i++) {
      var warning = warnings[i]
      console.log('  ' + warning)
    }
    console.log()
    process.exit(1)
  }
}

1.3 utils.js(定义了项目编译过程中会用到公用工具函数,主要用来处理css-loader和vue-style-loader)

const path = require('path') 
// 引入nodejs路径模块
const config = require('../config') 
// 引入config目录下的index.js配置文件
const ExtractTextPlugin = require('extract-text-webpack-plugin') 
// 引入extract-text-webpack-plugin插件,用来将css提取到单独的css文件中



// exports其实就是一个对象,用来导出方法的最终还是使用module.exports,此处导出assetsPath
exports.assetsPath = function (_path) {
  // 如果是生产环境assetsSubDirectory就是'static',否则还是'static'
  const assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory
  // path.join和path.posix.join的区别就是,前者返回的是完整的路径,后者返回的是完整路径的相对根路径
  // 也就是说path.join的路径是C:a/a/b/xiangmu/b,那么path.posix.join就是b
  return path.posix.join(assetsSubDirectory, _path)
  // 所以这个方法的作用就是返回一个干净的相对根路径
}

// 下面是导出cssLoaders的相关配置
exports.cssLoaders = function (options) {
  options = options || {}
  const cssLoader = {
    loader: 'css-loader',
    options: {
      minimize: process.env.NODE_ENV === 'production',
      sourceMap: options.sourceMap
    }
    // options是用来传递参数给loader的
    // minimize表示压缩,如果是生产环境就压缩css代码
    // minimize: process.env.NODE_ENV === 'production',
    // 是否开启cssmap,默认是false
  }

  // generate loader string to be used with extract text plugin
  function generateLoaders (loader, loaderOptions) {
    // 将上面的基础cssLoader配置放在一个数组里面
    const loaders = [cssLoader]
    if (loader) { 
    // 如果该函数传递了单独的loader就加到这个loaders数组里面,这个loader可能是less,sass之类的
      loaders.push({
        loader: loader + '-loader',// 加载对应的loader
        options: Object.assign({}, loaderOptions, { 
    // Object.assign是es6的方法,主要用来合并对象的,浅拷贝
          sourceMap: options.sourceMap
        })
      })
    }

    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
    // 注意这个extract是自定义的属性,可以定义在options里面,
    // 主要作用就是当配置为true就把文件单独提取,false表示不单独提取,这个可以在使用的时候单独配置
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
      // 上面这段代码就是用来返回最终读取和导入loader,来处理对应类型的文件
    }
  }

  // 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) {
  // 下面这个主要处理import这种方式导入的文件类型的打包,上面的exports.cssLoaders是为这一步服务的
  const output = []
  const loaders = exports.cssLoaders(options)
  // 把每一种文件的loader都提取出来
  for (var extension in loaders) {
    var loader = loaders[extension]
    output.push({
      // 把最终的结果都push到output数组中
      test: new RegExp('\\.' + extension + '$'),
      use: loader
    })
  }
  return output
}

1.4 vue-loader.conf.js(根据当前的开发环境对webpack的vue-loader进行配置,主要用来解决各种css文件,定义了诸如css,less,sass之类的和样式有关的loader)

const utils = require('./utils') // utils配置文件用来解决css相关文件loader
const config = require('../config') // 生产和开发环境的相关属性 
const isProduction = process.env.NODE_ENV === 'production'

module.exports = {
    // 调用utils配置文件中的cssLoaders方法,用来返回配置好的css-loader和vue-style-loader
  loaders: utils.cssLoaders({
    // 根据所处环境是否生成sourceMap用于代码调试
    sourceMap: isProduction
      ? config.build.productionSourceMap
      : config.dev.cssSourceMap,
    extract: isProduction 
    // 这一项是自定义配置项,设置为true表示生成单独样式文件
  }),
  transformToRequire: {
    video: 'src',
    source: 'src',
    img: 'src',
    image: 'xlink:href'
  }
}

1.5 webpack.base.conf.js(基础配置)

const path = require('path')
const webpack = require('webpack');
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

// 此函数是用来返回当前目录的平行目录的路径,因为有个'..'
function resolve (dir) {
  return path.join(__dirname, '..', dir)
}
function getPublicPath(nodeEnv) {
    const pathKeyMap = {
        'production': 'build',
        'test': 'test',
        'dev': 'dev'
    }
    let configKey = pathKeyMap[nodeEnv] || 'dev';
    return config[configKey].assetsPublicPath

}
module.exports = {
  entry: { // 入口文件是src目录下的main.js
    app: './src/main.js'
  },
  output: { // 路径是config目录下的index.js中的build配置中的assetsRoot,也就是dist目录
    path: config.build.assetsRoot,
    filename: '[name].js', // 文件名称这里使用默认的name也就是main
    publicPath: getPublicPath(process.env.NODE_ENV) // 上线地址,也就是真正的文件引用路径,如果是production生产环境,其实这里都是 '/'
  },
  resolve: {
    // resolve是webpack的内置选项,顾名思义,决定要做的事情,也就是说当使用 import "jquery",
    // 该如何去执行这件事情就是resolve配置项要做的,
    // import jQuery from "./additional/dist/js/jquery"
    // 这样会很麻烦,可以起个别名简化操作
    extensions: ['.js', '.vue', '.json'],
    alias: {
      //后面的$符号指精确匹配,
      // 也就是说只能使用 import vuejs from "vue"
      // 这样的方式导入vue.esm.js文件,不能在后面跟上 vue/vue.js
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src')
    }
  },

  // module用来解析不同的模块
  module: {
    rules: [
      {
        // 也就是说,对.js和.vue文件在编译之前进行检测,检查有没有语法错误'eslint-loader'
        // enforce: 'pre'选项可以确保,eslint插件能够在编译之前检测,如果不添加此项,就要把这个配置项放到末尾,确保第一个执行
        
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        // 对vue文件使用vue-loader,该loader是vue单文件组件的实现核心,专门用来解析.vue文件的
        // 将vueLoaderConfig当做参数传递给vue-loader,就可以解析文件中的css相关文件
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        // 对js文件使用babel-loader转码,该插件是用来解析es6等代码
        test: /\.js$/,
        loader: 'babel-loader',
        // 指明src和test目录下的js文件要使用该loader
        include: [resolve('src'), resolve('test')],
        exclude: /node_modules(?!\/quill-image-drop-module|quill-image-resize-module)/,
      },
      {
        // 对图片相关的文件使用 url-loader 插件,这个插件的作用是将一个足够小的文件生成一个64位的DataURL
        // 可能有些老铁还不知道 DataURL 是啥,当一个图片足够小,为了避免单独请求可以把图片的二进制代码变成64位的
        // DataURL,使用src加载,也就是把图片当成一串代码,避免请求,神不神奇??

        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: { // 限制 10000 个字节一下的图片才使用DataURL
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        },
        exclude: [resolve('src/assets/img/cms')]
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
          test: /\.svg$/,
          loader: 'svg-inline-loader',
          include: [resolve('src/assets/img/cms')]
      },
      // {
      //   test: /\.(less)$/,
      //   use: ExtractTextPlugin.extract({
      //       fallback: 'style-loader',
      //       use: [
      //         { loader: 'css-loader',  query: { importLoaders: 2, minimize: false } },
      //         { loader: 'postcss-loader' },
      //         { loader: 'less-loader' }
      //       ]
      //   })
      // },
      // https://vue-loader.vuejs.org/en/configurations/extract-css.html
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
        'window.Quill': 'quill'
    })
  ]
}

1.6 webpack.dev.conf.js(在基础配置基础上完善了开发环境的配置)

/* 
在webpack.base.conf的基础上增加完善了开发环境下面的配置,主要包括下面几件事情:
将webpack的热重载客户端代码添加到每个entry对应的应用
合并基础的webpack配置
配置样式文件的处理规则,styleLoaders
配置Source Maps
配置webpack插件
*/

const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge') // 引入webpack-merge插件用来合并webpack配置对象,也就是说可以把webpack配置文件拆分成几个小的模块,然后合并
const baseWebpackConfig = require('./webpack.base.conf') // 引入当前目录下的webpack.base.conf.js配置文件,主要配置的是打包各种文件类型的配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
/* 下面是一个自动生成html的插件,能够把资源自动加载到html文件中
 (1)html-webpack-plugin插件是用来生成html文件的,有很灵活的配置项,下面是基本的一些用法
 plugins: [
   new HtmlWebpackPlugin(), // Generates default index.html
   new HtmlWebpackPlugin({  // Also generate a test.html
     filename: 'test.html', // 生成的文件的名称
     title: 'Custom template', // 文件的标题
          template: 'my-index.ejs' //可以指定模块html文件
      })
  ]
 */


// 下面这个插件是用来把webpack的错误和日志收集起来,漂亮的展示给用户
// friendly-errors-webpack-plugin插件,把webpack编译出来的错误展示给我们,方便调试
// 安装 npm install friendly-errors-webpack-plugin --save-dev
// 基本使用
// plugins: [
//   new FriendlyErrorsWebpackPlugin(),
// ]
// 注意点,使用这个插件要遵守下点
// 您需要关闭所有的错误日志记录,将webpack配置静默选项设置为true
// 也就是遵循以下三点即可
// 在使用webpack-dev-middleware插件,关于这个插件的解释在我的dev-sever-js配置文件中有解释,设置以下内容
// app.use(require('webpack-dev-middleware')(compiler, {
//   quiet: true, // 必须设置
//   publicPath: config.output.publicPath,
// }));
// 使用webpack-dev-server时设置如下
// {
//   devServer: {
//     quiet: true
//   }
// }
// 使用webpack-hot-middleware中间件,关于这个插件的解释也在我的dev-server-js文章中
// app.use(require('webpack-hot-middleware')(compiler, {
//   log: () => {}
// }));

const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
  module: {
    // 下面是把utils配置中的处理css类似文件的处理方法拿过来,并且不生成cssMap文件
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // cheap-module-eval-source-map is faster for development
  // debtool是开发工具选项,用来指定如何生成sourcemap文件,cheap-module-eval-source-map此款soucemap文件性价比最高
  devtool: '#source-map',
  plugins: [
    // DefinePlugin内置webpack插件,专门用来定义全局变量的,下面定义一个全局变量 process.env 

    new webpack.DefinePlugin({
      'process.env': config.dev.env
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'views/index.art',
      inject: true //设置为true表示把所有的js文件都放在body标签的屁股
    }),
    new FriendlyErrorsPlugin()
  ]
})

1.7 webpack.prod.conf.js(生产环境的核心配置文件)

// webpack生产环境的核心配置文件
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
// 下面是webpack.base.conf.js配置文件,用来处理不同类型文件的loader
const baseWebpackConfig = require('./webpack.base.conf') 
const CopyWebpackPlugin = require('copy-webpack-plugin') // copy-webpack-plugin使用来复制文件或者文件夹到指定的目录的
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
// optimize-css-assets-webpack-plugin插件的作用是压缩css代码的,还能去掉extract-text-webpack-plugin插件抽离文件产生的重复代码,
// 因为同一个css可能在多个模块中出现所以会导致重复代码,换句话说这两个插件是两兄弟
// optimize-css-assets-webpack-plugin插件
// 在生产环境中使用extract-text-webpack-plugin,最好也使用这个插件
// 使用方法如下
// 安装 npm install --save-dev optimize-css-assets-webpack-plugin
// 还要安装 cssnano 这是一个css编译器 npm install --save-dev cssnano 这个vue-cli脚手架并没有使用cssnano,但是这个插件的官方说要安装cssnano,这是不是一个bug??
//   new OptimizeCssAssetsPlugin({
//     assetNameRegExp: /\.optimize\.css$/g, // 不写默认是/\.css$/g
//     cssProcessor: require('cssnano'), // 编译器选项,不写默认是cssnano,所以使用这个插件不管怎样都要cssnano
//     cssProcessorOptions: { discardComments: {removeAll: true } }, // 传递给编译器的参数
//     canPrint: true // 是否能够输出信息
//   })
const env = config.build.env
// 把当前的配置对象和基础的配置对象合并
const webpackConfig = merge(baseWebpackConfig,
{
    module:
    {
        // 下面就是把utils配置好的处理各种css类型的配置拿过来,和dev设置一样,就是这里多了个extract: true,此项是自定义项,设置为true表示,生成独立的文件
        rules: utils.styleLoaders(
        {
            sourceMap: config.build.productionSourceMap,
            extract: true
        })
    },
    // devtool开发工具,用来生成个sourcemap方便调试
    // 按理说这里不用生成sourcemap多次一举,这里生成了source-map类型的map文件,只用于生产环境
    devtool: config.build.productionSourceMap ? '#source-map' : false,
    output:
    {
        // 打包后的文件放在dist目录里面
        path: config.build.assetsRoot,
        filename: utils.assetsPath('js/[name].[chunkhash].js'),  // 文件名称使用 static/js/[name].[chunkhash].js, 其中name就是main,chunkhash就是模块的hash值,用于浏览器缓存的
        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') // chunkFilename是非入口模块文件,也就是说filename文件中引用了chunckFilename
    },
    plugins: [
    // 下面是利用DefinePlugin插件,定义process.env环境变量为env
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin(
        {
            'process.env': env
        }),
    new webpack.optimize.UglifyJsPlugin(  // UglifyJsPlugin插件是专门用来压缩js文件的
        {
            compress:
            {
                warnings: false
            },
            sourceMap: true
        }),
    // extract css into its own file
    new ExtractTextPlugin(
        // 生成独立的css文件,下面是生成独立css文件的名称
        {
            filename: utils.assetsPath('css/[name].[contenthash].css')
        }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin(
        // 压缩css文件
        {
            cssProcessorOptions:
            {
                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
    // 生成html页面
    new HtmlWebpackPlugin(
        {
            filename: config.build.index,
            template: 'views/index.art',
            inject: true,// 将js文件放到body标签的结尾
            minify:
            {
                // 压缩产出后的html页面
                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
            // 分类要插到html页面的模块
            chunksSortMode: 'dependency'
        }),
    // split vendor js into its own file
    // 下面的插件是将打包后的文件中的第三方库文件抽取出来,便于浏览器缓存,提高程序的运行速度
    new webpack.optimize.CommonsChunkPlugin(
        {
            name: 'vendor',
            minChunks: function(module, count)
            {
                // any required modules inside node_modules are extracted to vendor
                // 将所有依赖于node_modules下面文件打包到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
    // 把webpack的runtime代码和module manifest代码提取到manifest文件中,
    // 防止修改了代码但是没有修改第三方库文件导致第三方库文件也打包的问题

    new webpack.optimize.CommonsChunkPlugin(
        {
            name: 'manifest',
            chunks: ['vendor']
        }),
    // copy custom static assets
    // 下面是复制文件的插件,我认为在这里并不是起到复制文件的作用,而是过滤掉打包过程中产生的以.开头的文件
    new CopyWebpackPlugin([
            {
                from: path.resolve(__dirname, '../static'),
                to: config.build.assetsSubDirectory,
                ignore: ['.*']
      }
    ])
  ]
})

if (config.build.productionGzip)
{
    // 开启Gzi压缩打包后的文件,老铁们知道这个为什么还能压缩吗??,就跟你打包压缩包一样,把这个压缩包给浏览器,浏览器自动解压的
    // 你要知道,vue-cli默认将这个神奇的功能禁用掉的,理由是Surge 和 Netlify 静态主机默认帮你把上传的文件gzip了

    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)
{
    // 打包编译后的文件打印出详细的文件信息,vue-cli默认把这个禁用了,可以自行配置
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

2、config文件(webpack配置)

2.1 dev.env.js

var merge = require('webpack-merge')
var prodEnv = require('./prod.env')
// 首先引入的是webpack的merge插件,该插件是用来合并对象,也就是配置文件用的,相同的选项会被后者覆盖,
// 导入prod.env.js配置文件
module.exports = merge(prodEnv, {
  NODE_ENV: '"development"'
})
// 将两个配置对象合并,最终结果是 NODE_ENV: '"development"'

2.2 index.js

// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path') // path是node.js的路径模块,用来处理路径统一的问题 
const proxyTable = require('./proxyTable');
module.exports = {
  // 下面是build也就是生产编译环境下的一些配置
  build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../dist/index.html'), 
    // 上面是相对路径的拼接,假如当前根目录是config,那么下面配置的index属性的属性值就是dist/index.html
    //path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径。
    assetsRoot: path.resolve(__dirname, '../dist'), // 下面定义的是静态资源的根目录 也就是dist目录
    assetsSubDirectory: 'static',// 下面定义的是静态资源的公开路径,也就是真正的引用路径
    assetsPublicPath: '/frontend/',
    productionSourceMap: false, // 下面定义是否生成生产环境的sourcmap,sourcmap是用来debug编译后文件的,通过映射到编译前文件来实现
    // 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,// 下面是是否在生产环境中压缩代码,如果要压缩必须安装compression-webpack-plugin
    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
    // 下面是用来开启编译完成后的报告,可以通过设置值为true和false来开启或关闭
    bundleAnalyzerReport: process.env.npm_config_report
  },
  dev: {
    env: require('./dev.env'),
    port: 8081,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: proxyTable,
    // CSS Sourcemaps off by default because relative paths are "buggy"
    // with this option, according to the CSS-Loader README
    // (https://github.com/webpack/css-loader#sourcemaps)
    // In our experience, they generally work as expected,
    // just be aware of this issue when enabling this option.
    cssSourceMap: false
  }
}

2.3 prod.env.js

module.exports = {
    NODE_ENV: '"production"'
};
// 作用很明显,就是导出一个对象,NODE_ENV是一个环境变量,指定production环境

3、node_modules(存放项目依赖的各种包)

4、src(存放项目代码)

5、static(静态资源目录,图片、字体等)

6、.babelrc(babel的配置文件)

(主要适用于编译es6转义为es5

一般用2个插件es2015,stage-2,transfer-runtime

"comments": false,表示不生成注释,反之就是生成注释)

{
//  .babelrc文件是babel的配置文件
//  主要适用于编译es6转义为es5'
//  "presets"表示预设,表示babel预先需要安装的一些插件。
//  stage表示ECMA的草案,后面的数字表示草案的阶段,数字越小表示包含的草案就越多
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
//  表示其他的预设插件,其他的预设插件都是通过plugins来配置的,
//  transform-runtime表示把ES6的一些语法进行一些特殊的转化例如将ES6转化成ES5
//  transform-vue-jsx:JSX是基于Javascript的语言扩展, 它允许在Javascript代码中插入XML语法风格的代码。
//  预设这个之后在babel和webpack打包的时候就会将JSX的语法编译为js(PS;浏览器默认是解析不了JSX的)
  "plugins": ["transform-vue-jsx", "transform-runtime"]
}

7、.editorconfig(编辑代码风格)

root = true
 
[*]
charset = utf-8
indent_style = space  //代码的缩进方式基于一个空格缩进
indent_size = 2    // //缩进长度 2格
end_of_line = lf   //换行符风格
insert_final_newline = true //创建一个新文件的时候会在文件末尾插入新行
trim_trailing_whitespace = true//自动移除行尾空格

8、.eslintignore(忽略ESLint语法检查的文件目录配置)

9、.eslintrc.js(eslint的配置文件)

// http://eslint.org/docs/user-guide/configuring

module.exports = {
    root: true,
    "parser": "vue-eslint-parser",
    "parserOptions": {
        "parser": "babel-eslint",
        "sourceType": "module",
        "ecmaVersion": 2017

    },
    env:
        {
            "browser": true,
            "node": true,
            "es6": true
        },
    globals: {},
    extends: ['eslint:recommended', 'plugin:vue/essential'],
    // required to lint *.vue files
    plugins: [
        'vue'
    ],
    // check if imports actually resolve
    'settings':
        {
            'import/resolver':
                {
                    'webpack':
                        {
                            'config': 'build/webpack.base.conf.js'
                        }
                }
        },
    "rules":
        {
            "comma-spacing": [2,
                {
                    "before": false,
                    "after": true
                }],
            "keyword-spacing": [2,
                {
                    "before": true,
                    "after": true
                }], // 空格
            "semi": [2, "always"], // 语句强制分号结尾
            "quotes": [2, "single"], //建议使用单引号
            "no-inner-declarations": [0, "both"], //不建议在{}代码块内部声明变量或函数
            "no-extra-boolean-cast": 2, // 多余的感叹号转布尔型
            "no-extra-semi": 2, // 多余的分号
            "no-empty": 2, // 空代码块
            "no-use-before-define": [1, "nofunc"], // 使用前未定义
            "complexity": [1, 20], // 圈复杂度大于20 警告
            "space-before-blocks": [2, "always"], // 不以新行开始的块{前面要有空格
            "space-before-function-paren": [2,
                {
                    "anonymous": "always",
                    "named": "never"
                }], // 函数定义时括号前面有2空格
            "spaced-comment": 2, // 注释风格 2空格什么的
            "space-infix-ops": 2, // 中缀操作符周围 有2空格
            "space-in-parens": [0, "never"], // 小括号里面要不要有空格
            "radix": 2, // parseInt必须指定第二个参数
            "operator-linebreak": [2, "before"], // 换行时运算符在行尾还是行首
            "one-var-declaration-per-line": 2,
            "max-len": [2, 200, 4], // 字符串最大长度
            "key-spacing": [2,
                {
                    "beforeColon": false,
                    "afterColon": true
                }], // 对象字面量中冒号的前后空格
            "indent": [2, 4,
                {
                    "SwitchCase": 1
                }], // 缩进风格, switch, case中使用缩进
            "no-multiple-empty-lines": [1,
                {
                    "max": 2
                }], // 空行最多不能超过2行
            "no-multi-str": 2, // 字符串不能用\换行
            "no-mixed-spaces-and-tabs": [2, false], // 禁止混用tab和空格
            "no-console": ["error", {allow: ["warn", "error", "log"]}],
            // 常见错误
            "comma-dangle": [1, "never"], // 定义数组或对象最后多余的逗号
            "no-debugger": 0, // debugger 调试代码未删除
            "no-constant-condition": 2, // 常量作为条件
            "no-dupe-args": 2, // 参数重复
            "no-dupe-keys": 2, // 对象属性重复
            "no-duplicate-case": 2, // case重复
            "no-empty-character-class": 2, // 正则无法匹配任何值
            "no-invalid-regexp": 2, // 无效的正则
            "no-func-assign": 1, // 函数被赋值
            "valid-typeof": 2, // 无效的类型判断
            "no-unreachable": 2, // 不可能执行到的代码
            "no-unexpected-multiline": 2, // 行尾缺少分号可能导致一些意外情况
            "no-sparse-arrays": 2, // 数组中多出逗号
            "no-shadow-restricted-names": 2, // 关键词与命名冲突
            "no-undef": 2, // 变量未定义
            "no-unused-vars": 2, // 变量定义后未使用
            "no-cond-assign": 1, // 条件语句中禁止赋值操作
            "no-native-reassign": 2, // 禁止覆盖原生对象

            // 代码风格优化
            "no-else-return": 2, // 在else代码块中return,else是多余的
            "no-multi-spaces": 2, // 不允许多个空格
            "block-scoped-var": 2, // 变量定义后未使用
            "consistent-return": 0, // 函数返回值可能是不同类型
            "accessor-pairs": 1, // object getter/setter方法需要成对出现
            "dot-location": [2, "property"], // 换行调用对象方法  点操作符应写在行首
            "no-lone-blocks": 2, // 多余的{}嵌套
            "no-labels": 2, // 无用的标记
            "no-extend-native": 1, // 禁止扩展原生对象
            "no-floating-decimal": 2, // 浮点型需要写全 禁止.2 或 2.写法
            "no-loop-func": 2, // 禁止在循环体中定义函数
            "no-new-func": 2, // 禁止new Function(...) 写法
            "no-self-compare": 2, // 不允与自己比较作为条件
            "no-sequences": 2, // 禁止可能导致结果不明确的逗号操作符
            "no-throw-literal": 2, // 禁止抛出一个直接量 应是Error对象
            "no-return-assign": [2, "always"], // 不允return时有赋值操作
            "no-redeclare": [2,
                {
                    "builtinGlobals": true
                }], // 不允许重复声明
            "no-unused-expressions": [2,
                {
                    "allowShortCircuit": true,
                    "allowTernary": true
                }], // 未使用的表达式
            "no-useless-call": 2, // 无意义的函数call或apply
            "no-useless-concat": 2, // 无意义的string concat
            "no-void": 2, // 禁用void
            "no-with": 2, // 禁用with
            "curly": [2, "all"], // if、else、while、for代码块用{}包围
            // es6部分
            "arrow-body-style": [1], //要求箭头函数体使用大括号
            "arrow-parens": [0], // 要求箭头函数的参数使用圆括号
            "arrow-spacing": [2], // 强制箭头函数的箭头前后使用一致的空格
            "constructor-super": [1], // 要求在构造函数中有 super() 的调用
            "generator-star-spacing": [2], // 强制 generator 函数中 * 号周围使用一致的空格
            "no-class-assign": [2], // 禁止修改类声明的变量
            "no-confusing-arrow": [2], // disallow arrow functions where they could be confused with comparisons
            "no-const-assign": [2], // 禁止修改 const 声明的变量
            "no-dupe-class-members": [2], // 禁止类成员中出现重复的名称
            "no-duplicate-imports": [2], // disallow duplicate module imports
            "no-new-symbol": [2], // disallow new operators with the Symbol object
            "no-restricted-imports": [0], // disallow specified modules when loaded by import
            "no-this-before-super": [2], // 禁止在构造函数中,在调用 super() 之前使用 this 或 super
            "no-useless-computed-key": [2], // disallow unnecessary computed property keys in object literals
            "no-useless-constructor": [1], // 禁用不必要的构造函数
            "no-useless-rename": [1], // disallow renaming import, export, and destructured assignments to the same name
            "no-var": [0], // 要求使用 let 或 const 而不是 var
            "object-shorthand": [0], // 要求或禁止对象字面量中方法和属性使用简写语法
            "prefer-arrow-callback": [0], // 要求使用箭头函数作为回调
            "prefer-const": [0], // 要求使用 const 声明那些声明后不再被修改的变量
            "prefer-numeric-literals": [0], // disallow parseInt() in favor of binary, octal, and hexadecimal literals
            "prefer-rest-params": [0], // require rest parameters instead of arguments
            "prefer-spread": [0], // 要求使用扩展运算符而非 .apply()
            "prefer-template": [0], // 要求使用模板字面量而非字符串连接
            "require-yield": [0], // 要求 generator 函数内有 yield
            "rest-spread-spacing": [2], // enforce spacing between rest and spread operators and their expressions
            "sort-imports": [0], // 强制模块内的 import 排序
            "symbol-description": [0], // require symbol descriptions
            "template-curly-spacing": [2], // 要求或禁止模板字符串中的嵌入表达式周围空格的使用
            "yield-star-spacing": [2], // 强制在 yield* 表达式中 * 周围使用空格
            "vue/valid-v-for": 0,
            "vue/require-v-for-key": 0
        },
    "overrides": [
        {
            "files": [
                "**/test/*.spec.js"
            ],
            "rules": {
                'no-unused-expressions': 0,
                "mocha/no-exclusive-tests": 2,
                "mocha/handle-done-callback": 2,
                "mocha/no-global-tests": 2,
                "mocha/no-identical-title": 2,
                "mocha/no-nested-tests": 2,
                "mocha/no-pending-tests": 1,
                "mocha/no-return-and-callback": 2,
                "mocha/no-setup-in-describe": 2,
                "mocha/no-sibling-hooks": 2,
                "mocha/no-skipped-tests": 1,
                "mocha/no-top-level-hooks": 2
            },
            env: {
                "browser": true,
                "es6": true,
                "mocha": true
            },
            plugins: [
                'vue',
                'mocha'
            ]
        }
    ]
}

10、gitignore(表示里面的内容再提交到git仓库时候忽略)

11、package.json(项目的启动入口,依赖包的安装指南)

12、package_lock.json(

对于npm修改node_modules树或package.json的任何操作,将自动生成package-lock.json。 它描述了生成的确切树,以便后续安装能够生成相同的树,而不管中间依赖性更新如何。

该文件旨在被提交到源存储库,并提供各种用途:描述依赖关系树的单一表示形式,以确保队友,部署和持续集成确保安装完全相同的依赖关系。

就比如说你安装了  node1.0版本,你队友安装的时候自动会安装1.0版本的,不会再装一个2.0版本的最后提交代码产生冲突


文档部分参考:vue基于webpack 模板的目录结构以及目录作用的解析

 

你可能感兴趣的:(webpack)