vue-cli分析-webpack.dev.config.js

3,879 阅读6分钟

本系列文章主要讲下vue的webpack脚手架的前因后果,逐行分析其操作。如果写的有问题请务必指出!如果觉得写的还不错点个赞就是对我最大的鼓励了,谢谢!

架构说明

当使用vue-cli脚手架生成项目后,项目架构与其作用大概是这样的:

  • build负责针对不同编译环境,webpack采用哪些配置,摒弃哪些机制相关
  • config是build编译文件的另外扩展,把需要用到的配置提取出来,让配置更模块化
  • src就是写代码的地方了
  • static静态资源文件夹,注意当打包时这个文件夹下的文件都不会被打包哦
  • package.json项目所采用的类库与命令都写在这了,阅读代码首先看这个文件了

package.json

首先上面提到,阅读代码首先需要看这个文件,因为当你在命令行敲下第一句命令

npm run dev

webpack就会找到package.json文件中的script属性并依次分析命令,可见,这句命令相应的会执行

webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

这句话的意思是

webpack,在开发环境下,请你帮我运行webpack-dev-server插件,并且实时编译文件,另外,我还需有度条可见。最后,你帮我编译build文件夹下的webpack.dev.conf.js文件吧

webpack.dev.conf.js

前文说了那么多,都是为了给本文的主角(build/webpack.dev.conf.js)做铺垫,从这个文件名就不难看出,此文件是webpack在开发环境下的项目的配置文件,下面来看看这个文件到底做了什么

在文件第71-95行

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)
    }
  })
})

webpack.dev.conf.js文件对外暴露出了一个promise对象,从函数里看出,首先是引入了portfinder这个库,这是一个关于端口相关的一个库,其中指定了端口为项目启动的端口

portfinder.basePort = process.env.PORT || config.dev.port

process.env同config.dev后面会讲到

接着看代码,portfinder又执行了getPort方法,当获取到当前运行端口后,给process.env设置了port属性

process.env.PORT = port

这里这样设置是因为e2e单元测试需要用到的,在这里也不叙述了,有兴趣可以去查阅相关资料

接着往下看,promise返回了一个对象devWebpackConfig,这个对象就是webpack.dev.conf.js的核心了,往上翻代码看他定义了什么

const devWebpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  },
  // cheap-module-eval-source-map is faster for development
  devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js
  devServer: {
    clientLogLevel: 'warning',
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    hot: true,
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser,
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {
      poll: config.dev.poll,
    }
  }
})

首先说明的是,在开发环境和生产环境,webpack的配置是有很大不同的。比如在开发环境,我们需要快速的开发,所以我们可能需要一些实时加载和热更新等功能。但是在开发环境,我们不需要这些,我们需要更小的bundle,更轻量的source map,以及更轻量的资源,以改善加载时间。因此,为给个环境配置不同的webpack配置是必做的一步

虽然我们会为环境做区分,但是基于不重复原则,vue-cli为两个环境公用的配置整合到了(build/webpack.base.conf.js)文件中。然后利用webpack-merge插件将配置整合在一起

webpack.base.conf.js文件在这里不做叙述了,具体配置大家可以翻阅文件查看

在文件第17-19行

module: {
  rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
}

这里默认添加了一些匹配规则(css,postcss,less,sass,scss,stylus,styl),当webpack遇到这些文件时会采用相关的loader进行处理,但是这里没有默认配置typescript的loader,想要使用ts的可以使用ts-loader进行处理哦

接着看文件第21行

devtool: config.dev.devtool,

当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置。例如,如果将三个源文件(a.js, b.js 和 c.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会简单地指向到 bundle.js。这并通常没有太多帮助,因为你可能需要准确地知道错误来自于哪个源文件。

webpack一共提供了13中构建文件的模式,不同的值会明显影响到构建和重新构建的速度。在开发环境webpack是推荐使用cheap-module-eval-source-map模式的,而在生产环境使用cheap-source-map模式会更适合。webpack 仓库中包含一个 显示所有 devtool 变体效果的示例。这些例子或许会有助于你理解这些差异之处,在这里也不做多叙述了

当你敲下那句熟悉的npm run dev后,浏览器就会弹出一个窗口,路径赫然写着localhost:8080。这是因为vue-cli在开发模式下,采用了webpack-dev-server插件,这个插件提供了一个简单的web服务器,并且能够实时加载,大大提高了前端开发速度

看文件第24-46行

  devServer: {
    clientLogLevel: 'warning',
    historyApiFallback: {
      rewrites: [
        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
      ],
    },
    hot: true,
    contentBase: false, // since we use CopyWebpackPlugin.
    compress: true,
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser,
    overlay: config.dev.errorOverlay
      ? { warnings: false, errors: true }
      : false,
    publicPath: config.dev.assetsPublicPath,
    proxy: config.dev.proxyTable,
    quiet: true, // necessary for FriendlyErrorsPlugin
    watchOptions: {
      poll: config.dev.poll,
    }
  }

这里主要讲下devServer.proxy这个属性

devServer采用了一个非常强大的http请求中间件http-proxy-middleware。此中间件能对http请求做中间转发处理,并且能够很好的解决了开发中跨域的问题

如果你有单独的后端开发服务器 API,并且希望在同域名下发送 API 请求 ,那么代理某些 URL 会很有用

在 localhost:3000 上有后端服务的话,你可以在config/index.js文件下proxyTable属性这样设置:

proxyTable: {
  "/api": "http://localhost:3000"
}

现在请求到 /api 现在会被代理到请求 http://localhost:3000/api

接着看文件第47-69行

plugins: [
  new webpack.DefinePlugin({
    'process.env': require('../config/dev.env')
  }),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
  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: ['.*']
    }
  ])
]

webpack的插件机制能让你使用很多自带的和第三方的插件

这里使用到了:

  • DefinePlugin:允许在编译时(compile time)配置的全局常量
  • HotModuleReplacementPlugin:启用模块热替换(Enable Hot Module Replacement - HMR)
  • NamedModulesPlugin:当开启 HMR 的时候使用该插件会显示模块的相对路径,建议用于开发环境
  • HtmlWebpackPlugin:HtmlWebpackPlugin简化了HTML文件的创建,以便为你的webpack包提供服务。这对于在文件名中包含每次会随着编译而发生变化哈希的 webpack bundle 尤其有用。 你可以让插件为你生成一个HTML文件,使用lodash模板提供你自己的模板,或使用你自己的loader

以上就是webpack.dev.config.js文件所做的事情,欲知后事如何,请听下回分解。