{"id":16634979,"url":"https://github.com/ruochuan12/analyse-vue-cli","last_synced_at":"2025-03-21T15:31:38.846Z","repository":{"id":44981761,"uuid":"133366592","full_name":"ruochuan12/analyse-vue-cli","owner":"ruochuan12","description":"分析vue-cli@2.9.3 搭建的webpack项目工程，欢迎star 支持^_^～ 链接是思否，阅读体验可能更佳","archived":false,"fork":false,"pushed_at":"2022-01-15T02:53:08.000Z","size":752,"stargazers_count":28,"open_issues_count":3,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-18T02:44:21.455Z","etag":null,"topics":["vue-cli","webpack"],"latest_commit_sha":null,"homepage":"https://segmentfault.com/a/1190000015252698","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ruochuan12.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-14T13:41:17.000Z","updated_at":"2023-02-02T06:52:37.000Z","dependencies_parsed_at":"2022-09-24T21:41:34.382Z","dependency_job_id":null,"html_url":"https://github.com/ruochuan12/analyse-vue-cli","commit_stats":null,"previous_names":["ruochuan12/analyse-vue-cli"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruochuan12%2Fanalyse-vue-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruochuan12%2Fanalyse-vue-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruochuan12%2Fanalyse-vue-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruochuan12%2Fanalyse-vue-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ruochuan12","download_url":"https://codeload.github.com/ruochuan12/analyse-vue-cli/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244822696,"owners_count":20516152,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["vue-cli","webpack"],"created_at":"2024-10-12T05:49:39.523Z","updated_at":"2025-03-21T15:31:38.401Z","avatar_url":"https://github.com/ruochuan12.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 分析`vue-cli@2.9.3` 搭建的`webpack`项目工程\n### 前言\n\u003e已经有很多分析`Vue-cli`搭建工程的文章，为什么自己还要写一遍呢。学习就好比是座大山，人们沿着不同的路登山，分享着自己看到的风景。你不一定能看到别人看到的风景，体会到别人的心情。只有自己去登山，才能看到不一样的风景，体会才更加深刻。\n\n**项目放在笔者的`github`上，[分析vue-cli@2.9.3 搭建的webpack项目工程](https://github.com/lxchuan12/analyse-vue-cli)。方便大家克隆下载，或者在线查看。同时也求个`star` `^_^`，也是对笔者的一种鼓励和支持。**\n\n正文从这里开始～\n\n### 使用`vue-cli`初始化`webpack`工程\n```\n// # 安装\nnpm install -g vue-cli\n// 安装完后vue命令就可以使用了。实际上是全局注册了vue、vue-init、vue-list几个命令\n\n// # ubuntu 系统下\n// [vue-cli@2.9.3] link /usr/local/bin/vue@ -\u003e /usr/local/lib/node_modules/vue-cli/bin/vue\n// [vue-cli@2.9.3] link /usr/local/bin/vue-init@ -\u003e /usr/local/lib/node_modules/vue-cli/bin/vue-init\n// [vue-cli@2.9.3] link /usr/local/bin/vue-list@ -\u003e /usr/local/lib/node_modules/vue-cli/bin/vue-list\n\nvue list\n// 可以发现有browserify、browserify-simple、pwa、simple、webpack、webpack-simple几种模板可选，这里选用webpack。\n\n// # 使用 vue init\nvue init \u003ctemplate-name\u003e \u003cproject-name\u003e\n\n// # 例子\nvue init webpack analyse-vue-cli\n```\n更多`vue-cli`如何工作的可以查看这篇文章[vue-cli是如何工作的](https://juejin.im/post/5a7b1b86f265da4e8f049081)，或者分析Vue-cli源码查看这篇[走进Vue-cli源码，自己动手搭建前端脚手架工具](https://segmentfault.com/a/1190000013975247)，再或者直接查看[vue-cli github仓库源码](https://github.com/vuejs/vue-cli/tree/master)\n\n如果对`webpack`还不是很了解，可以查看[webpack官方文档中的概念](https://webpack.docschina.org/concepts/)，虽然是最新版本的，但概念都是差不多的。\n\n### `package.json`\n分析一个项目，一般从`package.json`的命令入口`scripts`开始。\n```\n\"scripts\": {\n  // dev webpack-dev-server --inline 模式 --progress 显示进度 --config 指定配置文件（默认是webpack.config.js）\n  \"dev\": \"webpack-dev-server --inline --progress --config build/webpack.dev.conf.js\",\n  \"start\": \"npm run dev\",\n  // jest测试\n  \"unit\": \"jest --config test/unit/jest.conf.js --coverage\",\n  // e2e测试\n  \"e2e\": \"node test/e2e/runner.js\",\n  // 运行jest测试和e2e测试\n  \"test\": \"npm run unit \u0026\u0026 npm run e2e\",\n  // eslint --ext 指定扩展名和相应的文件\n  \"lint\": \"eslint --ext .js,.vue src test/unit test/e2e/specs\",\n  // node 执行build/build.js文件\n  \"build\": \"node build/build.js\"\n},\n```\n`Npm Script` 底层实现原理是通过调用 `Shell` 去运行脚本命令。`npm run start`等同于运行`npm run dev`。\n\n`Npm Script` 还有一个重要的功能是能运行安装到项目目录里的 `node_modules` 里的可执行模块。\n\n例如在通过命令`npm i -D webpack-dev-server`将`webpack-dev-server`安装到项目后，是无法直接在项目根目录下通过命令 `webpack-dev-server` 去执行 `webpack-dev-server` 构建的，而是要通过命令 `./node_modules/.bin/webpack-dev-server` 去执行。\n\n`Npm Script` 能方便的解决这个问题，只需要在 `scripts` 字段里定义一个任务，例如：\n```\n\"dev\": \"webpack-dev-server --inline --progress --config build/webpack.dev.conf.js\"\n```\n`Npm Script` 会先去项目目录下的 `node_modules` 中寻找有没有可执行的 `webpack-dev-server` 文件，如果有就使用本地的，如果没有就使用全局的。 所以现在执行 `webpack-dev-server` 启动服务时只需要通过执行 `npm run dev` 去实现。\n\u003e 再来看下 npm run dev\n `webpack-dev-server` 其实是一个`node.js`的应用程序，它是通过`JavaScript`开发的。在命令行执行`npm run dev`命令等同于执行`node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --progress --config build/webpack.dev.conf.js`。你可以试试。\n\n更多`package.json`的配置项，可以查看[阮一峰老师的文章 package.json文件](http://javascript.ruanyifeng.com/nodejs/packagejson.html)\n\n`npm run dev`指定了`build/webpack.dev.conf.js`配置去启动服务，那么我们来看下这个文件做了什么。\n\n### `build/webpack.dev.conf.js` `webpack`开发环境配置\n这个文件主要做了以下几件事情：\u003cbr\u003e\n1、引入各种依赖，同时也引入了`config`文件夹下的变量和配置，和一个工具函数`build/utils.js`，\u003cbr\u003e\n2、合并`build/webpack.base.conf.js`配置文件，\u003cbr\u003e\n3、配置开发环境一些`devServer`，`plugin`等配置，\u003cbr\u003e\n4、最后导出了一个`Promise`，根据配置的端口，寻找可用的端口来启动服务。\n\n具体可以看`build/webpack.dev.conf.js`这个文件注释：\n\n```\n'use strict'\n// 引入工具函数\nconst utils = require('./utils')\n// 引入webpack\nconst webpack = require('webpack')\n// 引入config/index.js配置\nconst config = require('../config')\n// 合并webpack配置\nconst merge = require('webpack-merge')\nconst path = require('path')\n// 基本配置\nconst baseWebpackConfig = require('./webpack.base.conf')\n// 拷贝插件\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\n// 生成html的插件\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\n// 友好提示的插件 https://github.com/geowarin/friendly-errors-webpack-plugin\nconst FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')\n// 查找可用端口 // github仓库 https://github.com/indexzero/node-portfinder\nconst portfinder = require('portfinder')\n\n\n// process模块用来与当前进程互动，可以通过全局变量process访问，不必使用require命令加载。它是一个EventEmitter对象的实例。\n\n// 后面有些process模块用到的，所以这里统一列举下。\n// 更多查看这篇阮一峰的这篇文章 http://javascript.ruanyifeng.com/nodejs/process.html\n\n// process对象提供一系列属性，用于返回系统信息。\n// process.pid：当前进程的进程号。\n// process.version：Node的版本，比如v0.10.18。\n// process.platform：当前系统平台，比如Linux。\n// process.title：默认值为“node”，可以自定义该值。\n// process.argv：当前进程的命令行参数数组。\n// process.env：指向当前shell的环境变量，比如process.env.HOME。\n// process.execPath：运行当前进程的可执行文件的绝对路径。\n// process.stdout：指向标准输出。\n// process.stdin：指向标准输入。\n// process.stderr：指向标准错误。\n\n// process对象提供以下方法：\n// process.exit()：退出当前进程。\n// process.cwd()：返回运行当前脚本的工作目录的路径。_\n// process.chdir()：改变工作目录。\n// process.nextTick()：将一个回调函数放在下次事件循环的顶部。\n\n// host\nconst HOST = process.env.HOST\n// 端口\nconst PORT = process.env.PORT \u0026\u0026 Number(process.env.PORT)\n\n// 合并基本的webpack配置\nconst devWebpackConfig = merge(baseWebpackConfig, {\n  module: {\n    // cssSourceMap这里配置的是true\n    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })\n  },\n  // cheap-module-eval-source-map is faster for development\n  // 在开发环境是cheap-module-eval-source-map选项更快\n  // 这里配置的是cheap-module-eval-source-map\n  // 更多可以查看中文文档：https://webpack.docschina.org/configuration/devtool/#devtool\n  // 英文 https://webpack.js.org/configuration/devtool/#development\n  devtool: config.dev.devtool,\n\n  // these devServer options should be customized in /config/index.js\n  devServer: {\n    // 配置在客户端的日志等级，这会影响到你在浏览器开发者工具控制台里看到的日志内容。\n    // clientLogLevel 是枚举类型，可取如下之一的值 none | error | warning | info。\n    // 默认为 info 级别，即输出所有类型的日志，设置成 none 可以不输出任何日志。\n    clientLogLevel: 'warning',\n    // historyApiFallback boolean object 用于方便的开发使用了 HTML5 History API 的单页应用。\n    // 可以简单true 或者 任意的 404 响应可以提供为 index.html 页面。\n    historyApiFallback: {\n      rewrites: [\n        // config.dev.assetsPublicPath 这里是 /\n        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },\n      ],\n    },\n    // 开启热更新\n    hot: true,\n    // contentBase 配置 DevServer HTTP 服务器的文件根目录。\n    // 默认情况下为当前执行目录，通常是项目根目录，所有一般情况下你不必设置它，除非你有额外的文件需要被 DevServer 服务。\n    contentBase: false, // since we use CopyWebpackPlugin.\n    // compress 配置是否启用 gzip 压缩。boolean 为类型，默认为 false。\n    compress: true,\n    // host\n    // 例如你想要局域网中的其它设备访问你本地的服务，可以在启动 DevServer 时带上 --host 0.0.0.0\n    // 或者直接设置为 0.0.0.0\n    // 这里配置的是localhost\n    host: HOST || config.dev.host,\n    // 端口号 这里配置的是8080\n    port: PORT || config.dev.port,\n    // 打开浏览器，这里配置是不打开false\n    open: config.dev.autoOpenBrowser,\n    // 是否在浏览器以遮罩形式显示报错信息 这里配置的是true\n    overlay: config.dev.errorOverlay\n      ? { warnings: false, errors: true }\n      : false,\n      // 这里配置的是 /\n    publicPath: config.dev.assetsPublicPath,\n    // 代理 这里配置的是空{},有需要可以自行配置\n    proxy: config.dev.proxyTable,\n    // 启用 quiet 后，除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。\n    // 开启后一般非常干净只有类似的提示 Your application is running here: http://localhost:8080\n    quiet: true, // necessary for FriendlyErrorsPlugin\n    // webpack-dev-middleware\n    // watch: false,\n    // 启用 Watch 模式。这意味着在初始构建之后，webpack 将继续监听任何已解析文件的更改。Watch 模式默认关闭。\n    // webpack-dev-server 和 webpack-dev-middleware 里 Watch 模式默认开启。\n    // Watch 模式的选项\n    watchOptions: {\n      // 或者指定毫秒为单位进行轮询。\n      // 这里配置为false\n      poll: config.dev.poll,\n    }\n    // 更多查看中文文档：https://webpack.docschina.org/configuration/watch/#src/components/Sidebar/Sidebar.jsx\n  },\n  plugins: [\n    // 定义为开发环境\n    new webpack.DefinePlugin({\n      // 这里是 { NODE_ENV: '\"development\"' }\n      'process.env': require('../config/dev.env')\n    }),\n    // 热更新插件\n    new webpack.HotModuleReplacementPlugin(),\n    // 热更新时显示具体的模块路径\n    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.\n    // 在编译出现错误时，使用 NoEmitOnErrorsPlugin 来跳过输出阶段。\n    new webpack.NoEmitOnErrorsPlugin(),\n    // github仓库 https://github.com/ampedandwired/html-webpack-plugin\n    new HtmlWebpackPlugin({\n      filename: 'index.html',\n      template: 'index.html',\n      // inject 默认值 true，script标签位于html文件的 body 底部\n      // body 通true, header, script 标签位于 head 标签内\n      // false 不插入生成的 js 文件，只是单纯的生成一个 html 文件\n      inject: true\n    }),\n    // copy custom static assets\n    // 把static资源复制到相应目录。\n    new CopyWebpackPlugin([\n      {\n        // 这里是 static\n        from: path.resolve(__dirname, '../static'),\n        // 这里是 static\n        to: config.dev.assetsSubDirectory,\n        // 忽略.开头的文件。比如这里的.gitkeep，这个文件是指空文件夹也提交到git\n        ignore: ['.*']\n      }\n    ])\n  ]\n})\n// 导出一个promise\nmodule.exports = new Promise((resolve, reject) =\u003e {\n  // process.env.PORT 可以在命令行指定端口号，比如PORT=2000 npm run dev，那访问就是http://localhost:2000\n  // config.dev.port 这里配置是 8080\n  portfinder.basePort = process.env.PORT || config.dev.port\n  // 以配置的端口为基准，寻找可用的端口，比如：如果8080占用，那就8081,以此类推\n  // github仓库 https://github.com/indexzero/node-portfinder\n  portfinder.getPort((err, port) =\u003e {\n    if (err) {\n      reject(err)\n    } else {\n      // publish the new Port, necessary for e2e tests\n      process.env.PORT = port\n      // add port to devServer config\n      devWebpackConfig.devServer.port = port\n\n      // Add FriendlyErrorsPlugin\n      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({\n        compilationSuccessInfo: {\n          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],\n        },\n        // notifyOnErrors 这里配置是 true\n        // onErrors 是一个函数，出错输出错误信息，系统原生的通知\n        onErrors: config.dev.notifyOnErrors\n        ? utils.createNotifierCallback()\n        : undefined\n      }))\n\n      resolve(devWebpackConfig)\n    }\n  })\n})\n```\n\n### `build/utils.js` 工具函数\n\n上文`build/webpack.dev.conf.js`提到引入了`build/utils.js`工具函数。\u003cbr\u003e\n该文件主要写了以下几个工具函数：\u003cbr\u003e\n1、`assetsPath`返回输出路径，\u003cbr\u003e\n2、`cssLoaders`返回相应的`css-loader`配置，\u003cbr\u003e\n3、`styleLoaders`返回相应的处理样式的配置，\u003cbr\u003e\n4、`createNotifierCallback`创建启动服务时出错时提示信息回调。\n\n具体配置可以看该文件注释：\n\n```\n'use strict'\nconst path = require('path')\n// 引入配置文件config/index.js\nconst config = require('../config')\n// 提取css的插件\nconst ExtractTextPlugin = require('extract-text-webpack-plugin')\n// 引入package.json配置\nconst packageConfig = require('../package.json')\n// 返回路径\nexports.assetsPath = function (_path) {\n  const assetsSubDirectory = process.env.NODE_ENV === 'production'\n    // 二级目录 这里是 static\n    ? config.build.assetsSubDirectory\n    // 二级目录 这里是 static\n    : config.dev.assetsSubDirectory\n\n  // 生成跨平台兼容的路径\n  // 更多查看Node API链接：https://nodejs.org/api/path.html#path_path_posix\n  return path.posix.join(assetsSubDirectory, _path)\n}\n\nexports.cssLoaders = function (options) {\n  // 作为参数传递进来的options对象\n  // {\n  //   // sourceMap这里是true\n  //   sourceMap: true,\n  //   // 是否提取css到单独的css文件\n  //   extract: true,\n  //   // 是否使用postcss\n  //   usePostCSS: true\n  // }\n  options = options || {}\n\n  const cssLoader = {\n    loader: 'css-loader',\n    options: {\n      sourceMap: options.sourceMap\n    }\n  }\n\n  const postcssLoader = {\n    loader: 'postcss-loader',\n    options: {\n      sourceMap: options.sourceMap\n    }\n  }\n\n  // generate loader string to be used with extract text plugin\n  // 创建对应的loader配置\n  function generateLoaders (loader, loaderOptions) {\n    // 是否使用usePostCSS，来决定是否采用postcssLoader\n    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]\n\n    if (loader) {\n      loaders.push({\n        loader: loader + '-loader',\n        // 合并 loaderOptions 生成options\n        options: Object.assign({}, loaderOptions, {\n          sourceMap: options.sourceMap\n        })\n      })\n    }\n\n    // Extract CSS when that option is specified\n    // (which is the case during production build)\n    if (options.extract) {\n      // 如果提取使用ExtractTextPlugin插件提取\n      // 更多配置 看插件中文文档：https://webpack.docschina.org/plugins/extract-text-webpack-plugin/\n      return ExtractTextPlugin.extract({\n        // 指需要什么样的loader去编译文件\n        // loader 被用于将资源转换成一个 CSS 导出模块 (必填)\n        use: loaders,\n        // loader（例如 'style-loader'）应用于当 CSS 没有被提取(也就是一个额外的 chunk，当 allChunks: false)\n        fallback: 'vue-style-loader'\n      })\n    } else {\n      return ['vue-style-loader'].concat(loaders)\n    }\n  }\n\n  // https://vue-loader.vuejs.org/en/configurations/extract-css.html\n  return {\n    css: generateLoaders(),\n    postcss: generateLoaders(),\n    less: generateLoaders('less'),\n    // sass indentedSyntax 语法缩进，类似下方格式\n    // #main\n    //   color: blue\n    //   font-size: 0.3em\n    sass: generateLoaders('sass', { indentedSyntax: true }),\n    scss: generateLoaders('sass'),\n    stylus: generateLoaders('stylus'),\n    styl: generateLoaders('stylus')\n  }\n}\n\n// Generate loaders for standalone style files (outside of .vue)\n// 最终会返回webpack css相关的配置\nexports.styleLoaders = function (options) {\n  // {\n  //   // sourceMap这里是true\n  //   sourceMap: true,\n  //   // 是否提取css到单独的css文件\n  //   extract: true,\n  //   // 是否使用postcss\n  //   usePostCSS: true\n  // }\n  const output = []\n  const loaders = exports.cssLoaders(options)\n\n  for (const extension in loaders) {\n    const loader = loaders[extension]\n    output.push({\n      test: new RegExp('\\\\.' + extension + '$'),\n      use: loader\n    })\n  }\n\n  return output\n}\n\n// npm run dev 出错时， FriendlyErrorsPlugin插件 配置 onErrors输出错误信息\nexports.createNotifierCallback = () =\u003e {\n  // 'node-notifier'是一个跨平台系统通知的页面，当遇到错误时，它能用系统原生的推送方式给你推送信息\n  const notifier = require('node-notifier')\n\n  return (severity, errors) =\u003e {\n    if (severity !== 'error') return\n\n    const error = errors[0]\n    const filename = error.file \u0026\u0026 error.file.split('!').pop()\n\n    notifier.notify({\n      title: packageConfig.name,\n      message: severity + ': ' + error.name,\n      subtitle: filename || '',\n      icon: path.join(__dirname, 'logo.png')\n    })\n  }\n}\n\n```\n\n### `build/webpack.base.conf.js` `webpack`基本配置文件\n\n上文`build/webpack.dev.conf.js`提到引入了`build/webpack.base.conf.js`这个`webpack`基本配置文件。\u003cbr\u003e\n这个文件主要做了以下几件事情：\u003cbr\u003e\n1、引入各种插件、配置等，其中引入了`build/vue-loader.conf.js`相关配置，\u003cbr\u003e\n2、创建`eslint`规则配置，默认启用，\u003cbr\u003e\n3、导出`webpack`配置对象，其中包含`context`，入口`entry`，输出`output`，`resolve`，`module`下的`rules`（处理对应文件的规则），和`node`相关的配置等。\n\n具体可以看这个文件注释：\n\n```\n// 使用严格模式，更多严格模式可以查看\n// [阮一峰老师的es标准入门](http://es6.ruanyifeng.com/?search=%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F\u0026x=0\u0026y=0#docs/function#%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F)\n'use strict'\nconst path = require('path')\n// 引入工具函数\nconst utils = require('./utils')\n// 引入配置文件，也就是config/index.js文件\nconst config = require('../config')\n// 引入vue-loader的配置文件\nconst vueLoaderConfig = require('./vue-loader.conf')\n// 定义获取绝对路径函数\nfunction resolve (dir) {\n  return path.join(__dirname, '..', dir)\n}\n// 创建eslint配置\nconst createLintingRule = () =\u003e ({\n  test: /\\.(js|vue)$/,\n  loader: 'eslint-loader',\n  // 执行顺序，前置，还有一个选项是post是后置\n  // 把 eslint-loader 的执行顺序放到最前面，防止其它 Loader 把处理后的代码交给 eslint-loader 去检查\n  enforce: 'pre',\n  // 包含文件夹\n  include: [resolve('src'), resolve('test')],\n  options: {\n    // 使用友好的eslint提示插件\n    formatter: require('eslint-friendly-formatter'),\n    // eslint报错提示是否显示以遮罩形式显示在浏览器中\n    // 这里showEslintErrorsInOverlay配置是false\n    emitWarning: !config.dev.showEslintErrorsInOverlay\n  }\n})\n\nmodule.exports = {\n  // 运行环境的上下文，就是实际的目录，也就是项目根目录\n  context: path.resolve(__dirname, '../'),\n  // 入口\n  entry: {\n    app: './src/main.js'\n  },\n  // 输出\n  output: {\n    // 路径 这里是根目录下的dist\n    path: config.build.assetsRoot,\n    // 文件名\n    filename: '[name].js',\n    publicPath: process.env.NODE_ENV === 'production'\n      // 这里是 /，但要上传到github pages等会路径不对，需要修改为./\n      ? config.build.assetsPublicPath\n      // 这里配置是 /\n      : config.dev.assetsPublicPath\n  },\n  // Webpack 在启动后会从配置的入口模块出发找出所有依赖的模块，Resolve 配置 Webpack 如何寻找模块所对应的文件。\n  resolve: {\n    // 配置了这个，对应的扩展名可以省略\n    extensions: ['.js', '.vue', '.json'],\n    alias: {\n      // 给定对象的键后的末尾添加 $，以表示精准匹配 node_modules/vue/dist/vue.esm.js\n      // 引用 import Vue from 'vue'就是引入的这个文件最后export default Vue 导出的Vue;\n      // 所以这句可以以任意大写字母命名 比如：import V from 'vue'\n      'vue$': 'vue/dist/vue.esm.js',\n      // src别名 比如 ：引入import HelloWorld from '@/components/HelloWorld'\n      '@': resolve('src'),\n    }\n  },\n  // 定义一些文件的转换规则\n  module: {\n    rules: [\n      // 是否使用eslint 这里配置是true\n      ...(config.dev.useEslint ? [createLintingRule()] : []),\n      {\n        test: /\\.vue$/,\n        // vue-loader中文文档：https://vue-loader-v14.vuejs.org/zh-cn/\n        loader: 'vue-loader',\n        options: vueLoaderConfig\n      },\n      {\n        // js文件使用babel-loader转换\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]\n      },\n      {\n        // 图片文件使用url-loader转换\n        test: /\\.(png|jpe?g|gif|svg)(\\?.*)?$/,\n        loader: 'url-loader',\n        options: {\n          // 限制大小10000B(bytes)以内，转成base64编码的dataURL字符串\n          limit: 10000,\n          // 输出路径 img/名称.7位hash.扩展名\n          name: utils.assetsPath('img/[name].[hash:7].[ext]')\n        }\n      },\n      {\n        // 视频文件使用url-loader转换\n        test: /\\.(mp4|webm|ogg|mp3|wav|flac|aac)(\\?.*)?$/,\n        loader: 'url-loader',\n        options: {\n          limit: 10000,\n          name: utils.assetsPath('media/[name].[hash:7].[ext]')\n        }\n      },\n      {\n        test: /\\.(woff2?|eot|ttf|otf)(\\?.*)?$/,\n        loader: 'url-loader',\n        options: {\n          limit: 10000,\n          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')\n        }\n      }\n    ]\n  },\n  // 这里的node是一个对象，其中每个属性都是 Node.js 全局变量或模块的名称，每个 value 是以下其中之一\n  // empty 提供空对象。\n  // false 什么都不提供。\n  // 更多查看 中文文档：https://webpack.docschina.org/configuration/node/\n  node: {\n    // prevent webpack from injecting useless setImmediate polyfill because Vue\n    // source contains it (although only uses it if it's native).\n    // 防止webpack注入一些polyfill 因为Vue已经包含了这些。\n    setImmediate: false,\n    // prevent webpack from injecting mocks to Node native modules\n    // that does not make sense for the client\n    dgram: 'empty',\n    fs: 'empty',\n    net: 'empty',\n    tls: 'empty',\n    child_process: 'empty'\n  }\n}\n```\n\n### `build/vue-loader.conf.js` `vue-loader`配置文件\n\n上文`build/webpack.dev.conf.js`提到引入了`build/vue-loader.conf.js`。\n\n这个文件主要导出了一份`Vue-loader`的配置，\n主要有：`loaders`，`cssSourceMap`，`cacheBusting`，`transformToRequire`。\n\n具体看该文件注释：\n```\n'use strict'\nconst utils = require('./utils')\nconst config = require('../config')\nconst isProduction = process.env.NODE_ENV === 'production'\nconst sourceMapEnabled = isProduction\n  // 这里是true\n  ? config.build.productionSourceMap\n  // 这里是true\n  : config.dev.cssSourceMap\n// 更多配置 可以查看vue-loader中文文档：https://vue-loader-v14.vuejs.org/zh-cn/\nmodule.exports = {\n  // cssLoaders 生成相应loader配置，具体看utils文件中的cssLoader\n  loaders: utils.cssLoaders({\n    // 是否开启sourceMap，便于调试\n    sourceMap: sourceMapEnabled,\n    // 是否提取vue单文件的css\n    extract: isProduction\n  }),\n  // 是否开启cssSourceMap，便于调试\n  cssSourceMap: sourceMapEnabled,\n  // 这里是true\n  // 缓存破坏，进行sourceMap debug时，设置成false很有帮助。\n  cacheBusting: config.dev.cacheBusting,\n  // vue单文件中，在模板中的图片等资源引用转成require的形式。以便目标资源可以由 webpack 处理。\n  transformToRequire: {\n    video: ['src', 'poster'],\n    source: 'src',\n    img: 'src',\n    // 默认配置会转换 \u003cimg\u003e 标签上的 src 属性和 SVG 的 \u003cimage\u003e 标签上的 xlink：href 属性。\n    image: 'xlink:href'\n  }\n}\n\n```\n\n看完了这些文件相应配置，开发环境的相关配置就串起来了。其中`config/`文件夹下的配置，笔者都已经注释在`build/`文件夹下的对应的文件中，所以就不单独说明了。\n\n那回过头来看，`package.json`的`scripts`中的`npm run build`配置，`node build/build.js`，其实就是用`node`去执行`build/build.js`文件。\n\n### `build/build.js` `npm run build` 指定执行的文件\n\n这个文件主要做了以下几件事情：\u003cbr\u003e\n1、引入`build/check-versions`文件，检查`node`和`npm`的版本，\u003cbr\u003e\n2、引入相关插件和配置，其中引入了`webpack`生产环境的配置`build/webpack.prod.conf.js`，\u003cbr\u003e\n3、先控制台输出`loading`，删除`dist`目录下的文件，开始构建，构建失败和构建成功都给出相应的提示信息。\n\n具体可以查看相应的注释：\n\n```\n'use strict'\n// 检查node npm的版本\nrequire('./check-versions')()\n\nprocess.env.NODE_ENV = 'production'\n// 命令行中的loading\nconst ora = require('ora')\n// 删除文件或文件夹\nconst rm = require('rimraf')\n// 路径相关\nconst path = require('path')\n// 控制台输入样式 chalk 更多查看：https://github.com/chalk/chalk\nconst chalk = require('chalk')\n// 引入webpack\nconst webpack = require('webpack')\n// 引入config/index.js\nconst config = require('../config')\n// 引入 生产环境webpack配置\nconst webpackConfig = require('./webpack.prod.conf')\n\n// 控制台输入开始构建loading\nconst spinner = ora('building for production...')\nspinner.start()\n\n// 删除原有构建输出的目录文件 这里是dist 和 static\nrm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err =\u003e {\n  // 如果出错，抛出错误\n  if (err) throw err\n  webpack(webpackConfig, (err, stats) =\u003e {\n    // 关闭 控制台输入开始构建loading\n    spinner.stop()\n    // 如果出错，抛出错误\n    if (err) throw err\n    process.stdout.write(stats.toString({\n      colors: true,\n      modules: false,\n      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.\n      chunks: false,\n      chunkModules: false\n    }) + '\\n\\n')\n\n    // 如果有错，控制台输出构建失败\n    if (stats.hasErrors()) {\n      console.log(chalk.red('  Build failed with errors.\\n'))\n      process.exit(1)\n    }\n\n    // 控制台输出构建成功相关信息\n    console.log(chalk.cyan('  Build complete.\\n'))\n    console.log(chalk.yellow(\n      '  Tip: built files are meant to be served over an HTTP server.\\n' +\n      '  Opening index.html over file:// won\\'t work.\\n'\n    ))\n  })\n})\n\n```\n\n### `build/check-versions` 检查`node`和`npm`版本\n\n上文提到`build/check-versions` 检查`node`和`npm`版本，这个文件主要引入了一些插件和配置，最后导出一个函数，版本不符合预期就输出警告。\n\n具体查看这个配置文件注释：\n\n```\n'use strict'\n// 控制台输入样式 chalk 更多查看：https://github.com/chalk/chalk\nconst chalk = require('chalk')\n// 语义化控制版本的插件 更多查看：https://github.com/npm/node-semver\nconst semver = require('semver')\n// package.json配置\nconst packageConfig = require('../package.json')\n// shell 脚本 Unix shell commands for Node.js 更多查看：https://github.com/shelljs/shelljs\nconst shell = require('shelljs')\n\nfunction exec (cmd) {\n  return require('child_process').execSync(cmd).toString().trim()\n}\n\nconst versionRequirements = [\n  {\n    name: 'node',\n    currentVersion: semver.clean(process.version),\n    // 这里配置是\"node\": \"\u003e= 6.0.0\",\n    versionRequirement: packageConfig.engines.node\n  }\n]\n// 需要使用npm\nif (shell.which('npm')) {\n  versionRequirements.push({\n    name: 'npm',\n    currentVersion: exec('npm --version'),\n    // 这里配置是\"npm\": \"\u003e= 3.0.0\"\n    versionRequirement: packageConfig.engines.npm\n  })\n}\n// 导出一个检查版本的函数\nmodule.exports = function () {\n  const warnings = []\n\n  for (let i = 0; i \u003c versionRequirements.length; i++) {\n    const mod = versionRequirements[i]\n\n    // 当前版本不大于所需版本\n    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {\n      warnings.push(mod.name + ': ' +\n        chalk.red(mod.currentVersion) + ' should be ' +\n        chalk.green(mod.versionRequirement)\n      )\n    }\n  }\n\n  // 如果有警告，全部输出到控制台\n  if (warnings.length) {\n    console.log('')\n    console.log(chalk.yellow('To use this template, you must update following to modules:'))\n    console.log()\n\n    for (let i = 0; i \u003c warnings.length; i++) {\n      const warning = warnings[i]\n      console.log('  ' + warning)\n    }\n\n    console.log()\n    process.exit(1)\n  }\n}\n\n```\n\n### `build/webpack.prod.conf.js` `webpack`生产环境配置\n\n上文`build/build.js`提到，引入了这个配置文件。\u003cbr\u003e\n这个文件主要做了以下几件事情：\u003cbr\u003e\n1、引入一些插件和配置，其中引入了`build/webpack.base.conf.js` `webpack`基本配置文件，\u003cbr\u003e\n2、用`DefinePlugin`定义环境，\u003cbr\u003e\n3、合并基本配置，定义自己的配置`webpackConfig`，配置了一些`modules`下的`rules`，`devtools`配置，`output`输出配置，一些处理`js`、提取`css`、压缩`css`、输出`html`插件、提取公共代码等的\n`plugins`，\u003cbr\u003e\n4、如果启用`gzip`，再使用相应的插件处理，\u003cbr\u003e\n5、如果启用了分析打包后的插件，则用`webpack-bundle-analyzer`，\u003cbr\u003e\n6、最后导出这份配置。\n\n具体可以查看这个文件配置注释：\n\n```\n'use strict'\n// 引入node路径相关\nconst path = require('path')\n// 引入utils工具函数\nconst utils = require('./utils')\n// 引入webpack\nconst webpack = require('webpack')\n// 引入config/index.js配置文件\nconst config = require('../config')\n// 合并webpack配置的插件\nconst merge = require('webpack-merge')\n// 基本的webpack配置\nconst baseWebpackConfig = require('./webpack.base.conf')\n// 拷贝文件和文件夹的插件\nconst CopyWebpackPlugin = require('copy-webpack-plugin')\n// 压缩处理HTML的插件\nconst HtmlWebpackPlugin = require('html-webpack-plugin')\nconst ExtractTextPlugin = require('extract-text-webpack-plugin')\n// 压缩处理css的插件\nconst OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')\n// 压缩处理js的插件\nconst UglifyJsPlugin = require('uglifyjs-webpack-plugin')\n\n// 用DefinePlugin定义环境\nconst env = process.env.NODE_ENV === 'testing'\n  // 这里是 { NODE_ENV: '\"testing\"' }\n  ? require('../config/test.env')\n  // 这里是 { NODE_ENV: '\"production\"' }\n  : require('../config/prod.env')\n// 合并基本webpack配置\nconst webpackConfig = merge(baseWebpackConfig, {\n  module: {\n    // 通过styleLoaders函数生成样式的一些规则\n    rules: utils.styleLoaders({\n      // sourceMap这里是true\n      sourceMap: config.build.productionSourceMap,\n      // 是否提取css到单独的css文件\n      extract: true,\n      // 是否使用postcss\n      usePostCSS: true\n    })\n  },\n  // 配置使用sourceMap true 这里是 #source-map\n  devtool: config.build.productionSourceMap ? config.build.devtool : false,\n  output: {\n    // 这里是根目录下的dist\n    path: config.build.assetsRoot,\n    // 文件名称 chunkhash\n    filename: utils.assetsPath('js/[name].[chunkhash].js'),\n    // chunks名称 chunkhash\n    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')\n  },\n  plugins: [\n    // http://vuejs.github.io/vue-loader/en/workflow/production.html\n    // 定义具体是什么环境\n    new webpack.DefinePlugin({\n      'process.env': env\n    }),\n    // 压缩js插件\n    new UglifyJsPlugin({\n      uglifyOptions: {\n        compress: {\n          // 警告\n          warnings: false\n          // 构建后的文件 常用的配置还有这些\n          // 去除console.log 默认为false。  传入true会丢弃对console函数的调用。\n          // drop_console: true,\n          // 去除debugger\n          // drop_debugger: true,\n          // 默认为null. 你可以传入一个名称的数组，而UglifyJs将会假定那些函数不会产生副作用。\n          // pure_funcs: [ 'console.log', 'console.log.apply' ],\n        }\n      },\n      // 是否开启sourceMap 这里是true\n      sourceMap: config.build.productionSourceMap,\n      // 平行处理（同时处理）加快速度\n      parallel: true\n    }),\n    // extract css into its own file\n    // 提取css到单独的css文件\n    new ExtractTextPlugin({\n      // 提取到相应的文件名 使用内容hash contenthash\n      filename: utils.assetsPath('css/[name].[contenthash].css'),\n      // Setting the following option to `false` will not extract CSS from codesplit chunks.\n      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.\n      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,\n      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110\n      // allChunks 默认是false,true指提取所有chunks包括动态引入的组件。\n      allChunks: true,\n    }),\n    // Compress extracted CSS. We are using this plugin so that possible\n    // duplicated CSS from different components can be deduped.\n    new OptimizeCSSPlugin({\n      // 这里配置是true\n      cssProcessorOptions: config.build.productionSourceMap\n        ? { safe: true, map: { inline: false } }\n        : { safe: true }\n    }),\n    // generate dist index.html with correct asset hash for caching.\n    // you can customize output by editing /index.html\n    // see https://github.com/ampedandwired/html-webpack-plugin\n    new HtmlWebpackPlugin({\n      // 输出html名称\n      filename: process.env.NODE_ENV === 'testing'\n        ? 'index.html'\n        // 这里是 根目录下的dist/index.html\n        : config.build.index,\n      // 使用哪个模板\n      template: 'index.html',\n      // inject 默认值 true，script标签位于html文件的 body 底部\n      // body 通true, header, script 标签位于 head 标签内\n      // false 不插入生成的 js 文件，只是单纯的生成一个 html 文件\n      inject: true,\n      // 压缩\n      minify: {\n        // 删除注释\n        removeComments: true,\n        // 删除空格和换行\n        collapseWhitespace: true,\n        // 删除html标签中属性的双引号\n        removeAttributeQuotes: true\n        // 更多配置查看html-minifier插件\n        // more options:\n        // https://github.com/kangax/html-minifier#options-quick-reference\n      },\n      // necessary to consistently work with multiple chunks via CommonsChunkPlugin\n      // 在chunk被插入到html之前，你可以控制它们的排序。允许的值 ‘none’ | ‘auto’ | ‘dependency’ | {function} 默认为‘auto’.\n      // dependency 依赖（从属）\n      chunksSortMode: 'dependency'\n    }),\n    // keep module.id stable when vendor modules does not change\n    // 根据代码内容生成普通模块的id，确保源码不变，moduleID不变。\n    new webpack.HashedModuleIdsPlugin(),\n    // enable scope hoisting\n    // 开启作用域提升 webpack3新的特性，作用是让代码文件更小、运行的更快\n    new webpack.optimize.ModuleConcatenationPlugin(),\n    // split vendor js into its own file\n    // 提取公共代码\n    new webpack.optimize.CommonsChunkPlugin({\n      name: 'vendor',\n      minChunks (module) {\n        // any required modules inside node_modules are extracted to vendor\n        return (\n          module.resource \u0026\u0026\n          /\\.js$/.test(module.resource) \u0026\u0026\n          module.resource.indexOf(\n            path.join(__dirname, '../node_modules')\n          ) === 0\n        )\n      }\n    }),\n    // extract webpack runtime and module manifest to its own file in order to\n    // prevent vendor hash from being updated whenever app bundle is updated\n    // 提取公共代码\n    new webpack.optimize.CommonsChunkPlugin({\n      // 把公共的部分放到 manifest 中\n      name: 'manifest',\n      // 传入 `Infinity` 会马上生成 公共chunk，但里面没有模块。\n      minChunks: Infinity\n    }),\n    // This instance extracts shared chunks from code splitted chunks and bundles them\n    // in a separate chunk, similar to the vendor chunk\n    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk\n    // 提取动态组件\n    new webpack.optimize.CommonsChunkPlugin({\n      name: 'app',\n      // 如果设置为 `true`，一个异步的  公共chunk 会作为 `options.name` 的子模块，和 `options.chunks` 的兄弟模块被创建。\n      // 它会与 `options.chunks` 并行被加载。可以通过提供想要的字符串，而不是 `true` 来对输出的文件进行更换名称。\n      async: 'vendor-async',\n      // 如果设置为 `true`，所有  公共chunk 的子模块都会被选择\n      children: true,\n      // 最小3个，包含3，chunk的时候提取\n      minChunks: 3\n    }),\n\n    // copy custom static assets\n    // 把static资源复制到相应目录。\n    new CopyWebpackPlugin([\n      {\n        from: path.resolve(__dirname, '../static'),\n        // 这里配置是static\n        to: config.build.assetsSubDirectory,\n        // 忽略.开头的文件。比如这里的.gitkeep，这个文件是指空文件夹也提交到git\n        ignore: ['.*']\n      }\n    ])\n  ]\n})\n// 如果开始gzip压缩，使用compression-webpack-plugin插件处理。这里配置是false\n// 需要使用是需要安装 npm i compression-webpack-plugin -D\nif (config.build.productionGzip) {\n  const CompressionWebpackPlugin = require('compression-webpack-plugin')\n\n  webpackConfig.plugins.push(\n    new CompressionWebpackPlugin({\n      // asset： 目标资源名称。 [file] 会被替换成原始资源。\n      // [path] 会被替换成原始资源的路径， [query] 会被替换成查询字符串。默认值是 \"[path].gz[query]\"。\n      asset: '[path].gz[query]',\n      // algorithm： 可以是 function(buf, callback) 或者字符串。对于字符串来说依照 zlib 的算法(或者 zopfli 的算法)。默认值是 \"gzip\"。\n      algorithm: 'gzip',\n      // test： 所有匹配该正则的资源都会被处理。默认值是全部资源。\n      // config.build.productionGzipExtensions 这里是['js', 'css']\n      test: new RegExp(\n        '\\\\.(' +\n        config.build.productionGzipExtensions.join('|') +\n        ')$'\n      ),\n      // threshold： 只有大小大于该值的资源会被处理。单位是 bytes。默认值是 0。\n      threshold: 10240,\n      // minRatio： 只有压缩率小于这个值的资源才会被处理。默认值是 0.8。\n      minRatio: 0.8\n    })\n  )\n}\n\n// 输出分析的插件 运行npm run build --report\n// config.build.bundleAnalyzerReport这里是 process.env.npm_config_report\n// build结束后会自定打开 http://127.0.0.1:8888 链接\nif (config.build.bundleAnalyzerReport) {\n  // 更多查看链接地址：https://www.npmjs.com/package/webpack-bundle-analyzer\n  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin\n  webpackConfig.plugins.push(new BundleAnalyzerPlugin())\n}\n// 当然也可以用官方提供的网站 http://webpack.github.io/analyse/#home\n// 运行类似 webpack --profile --json \u003e stats.json 命令\n// 把生成的构建信息stats.json上传即可\n\n\n// 最终导出 webpackConfig\nmodule.exports = webpackConfig\n\n```\n至此，我们就分析完了`package.json`中的`npm run dev`和`npm run build`两个命令。测试相关的类似就略过吧。\n\n`npm run lint`，`.eslintrc.js`中的配置不多，更多可以查看[eslint英文文档](https://eslint.org/)或[`eslint`中文官网](http://eslint.cn/)，所以也略过吧。不过提一下，把`eslint`整合到`git`工作流。可以安装`husky`，`npm i husky -S`。安装后，配置`package.json`的`scripts`中，配置`precommit`，具体如下：\n```\n\"scripts\": {\n  \"lint\": \"eslint --ext .js,.vue src test/unit test/e2e/specs\",\n  \"precommit\": \"npm run lint\",\n},\n```\n配置好后，每次`git commit -m`提交会检查代码是否通过`eslint`校验，如果没有校验通过则提交失败。还可以配置`prepush`。`husky`不断在更新，现在可能与原先的配置不太相同了，具体查看[husky github仓库](https://github.com/typicode/husky)。原理就是`git-hooks`,`pre-commit`的钩子。对`shell`脚本熟悉的同学也可以自己写一份`pre-commit`。复制到项目的`.git/hooks/pre-commit`中。不需要依赖`husky`包。我司就是用的`shell`脚本。\n\n\n最后提一下`.babelrc`文件中的配置。\n\n### `.babelrc` `babel`相关配置\n配置了一些转码规则。这里附上两个链接：[`babel`英文官网](https://babeljs.io/)和[`babel`的中文官网](https://babel.bootcss.com/)。\n\n具体看文件中的配置注释：\n```\n{\n  // presets指明转码的规则\n  \"presets\": [\n    // env项是借助插件babel-preset-env，下面这个配置说的是babel对es6,es7,es8进行转码，并且设置amd,commonjs这样的模块化文件，不进行转码\n    [\"env\", {\n      \"modules\": false,\n      \"targets\": {\n        \"browsers\": [\"\u003e 1%\", \"last 2 versions\", \"not ie \u003c= 8\"]\n      }\n    }],\n    \"stage-2\"\n  ],\n  // plugins 属性告诉 Babel 要使用哪些插件，插件可以控制如何转换代码。\n  // transform-vue-jsx 表明可以在项目中使用jsx语法，会使用这个插件转换\n  \"plugins\": [\"transform-vue-jsx\", \"transform-runtime\"],\n  // 在特定的环境中所执行的转码规则，当环境变量是下面的test就会覆盖上面的设置\n  \"env\": {\n    // test 是提前设置的环境变量，如果没有设置BABEL_ENV则使用NODE_ENV，如果都没有设置默认就是development\n    \"test\": {\n      \"presets\": [\"env\", \"stage-2\"],\n      \"plugins\": [\"transform-vue-jsx\", \"transform-es2015-modules-commonjs\", \"dynamic-import-node\"]\n    }\n  }\n}\n```\n\n文件中`presets`中有配置`env`和`stage-2`，可能不知道是什么。这里引用[深入浅出webpack](http://webpack.wuhaolin.cn/3%E5%AE%9E%E6%88%98/3-1%E4%BD%BF%E7%94%A8ES6%E8%AF%AD%E8%A8%80.html)书中，第三章，`3-1`使用`ES6`语言 小节的一段，解释一下。\u003cbr\u003e\n\u003e`presets` 属性告诉 `Babel` 要转换的源码使用了哪些新的语法特性，一个 Presets 对一组新语法特性提供支持，多个 `Presets` 可以叠加。 `Presets` 其实是一组 `Plugins` 的集合，每一个 `Plugin` 完成一个新语法的转换工作。`Presets` 是按照 `ECMAScript` 草案来组织的，通常可以分为以下三大类（书中就是说三大类，我发现就两点~~~）：\u003cbr\u003e\n\u003e1、已经被写入 ECMAScript 标准里的特性，由于之前每年都有新特性被加入到标准里，所以又可细分为：\u003cbr\u003e\nes2015 包含在2015里加入的新特性；\u003cbr\u003e\nes2016 包含在2016里加入的新特性；\u003cbr\u003e\nes2017 包含在2017里加入的新特性；\u003cbr\u003e\nes2017 包含在2017里加入的新特性；\u003cbr\u003e\nenv 包含当前所有 ECMAScript 标准里的最新特性。\u003cbr\u003e\n\u003e2、被社区提出来的但还未被写入 `ECMAScript` 标准里特性，这其中又分为以下四种：\u003cbr\u003e\n`stage0` 只是一个美好激进的想法，有 `Babel` 插件实现了对这些特性的支持，但是不确定是否会被定为标准；\u003cbr\u003e\n`stage1` 值得被纳入标准的特性；\u003cbr\u003e\n`stage2` 该特性规范已经被起草，将会被纳入标准里；\u003cbr\u003e\n`stage3` 该特性规范已经定稿，各大浏览器厂商和 `` 社区开始着手实现；\u003cbr\u003e\n`stage4` 在接下来的一年将会加入到标准里去。\u003cbr\u003e\n\n至此，就算相对完整的分析完了`Vue-cli`(版本`v2.9.3`)搭建的`webpack`项目工程。希望对大家有所帮助。\u003cbr\u003e\n**项目放在笔者的`github`上，[分析vue-cli@2.9.3 搭建的webpack项目工程](https://github.com/lxchuan12/analyse-vue-cli)。方便大家克隆下载，或者在线查看。同时也求个`star` `^_^`，也是对笔者的一种鼓励和支持。**\u003cbr\u003e\n笔者知识能力有限，文章有什么不妥之处，欢迎指出~\n\n### 关于\n作者：常以**若川**为名混迹于江湖。前端路上 | PPT爱好者 | 所知甚少，唯善学\u003cbr\u003e\n[个人博客](https://lxchuan12.github.io/)\u003cbr\u003e\n[segmentfault个人主页](https://segmentfault.com/u/lxchuan12)\u003cbr\u003e\n[掘金个人主页](https://juejin.im/user/57974dc55bbb500063f522fd/posts)\u003cbr\u003e\n[知乎](https://www.zhihu.com/people/lxchuan12/activities)\u003cbr\u003e\n[github](https://github.com/lxchuan12)\u003cbr\u003e\n\n### 小结\n1、分析这些，逐行注释，还是需要一些时间的。其中有些不是很明白的地方，及时查阅相应的官方文档和插件文档（建议看英文文档和最新的文档），不过文档没写明白的地方，可以多搜索一些别人的博客文章，相对比较清晰明了。\u003cbr\u003e\n2、前端发展太快，这个`Vue-cli@2.9.3` `webpack`版本还是`v3.x`，webpack现在官方版本已经是`v4.12.0`，相信不久后，`Vue-cli`也将发布支持`webpack v4.x`的版本，`v3.0.0`已经是`beta.16`了。\u003cbr\u003e\n3、后续有余力，可能会继续分析新版的`vue-cli`构建的`webpack`项目工程。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruochuan12%2Fanalyse-vue-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruochuan12%2Fanalyse-vue-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruochuan12%2Fanalyse-vue-cli/lists"}