首页 > 代码库 > 【webpack】理解配置文件

【webpack】理解配置文件

学习链接:

http://blog.csdn.net/hongchh/article/details/55113751

https://segmentfault.com/a/1190000009356434

主要分析开发(dev)和构建(build)两个过程涉及到的文件,故下面文件结构仅列出相应的内容。

├─build
│   ├─build.js
│   ├─check-versions.js
│   ├─dev-client.js
│   ├─dev-server.js
│   ├─utils.js
│   ├─vue-loader.conf.js
│   ├─webpack.base.conf.js
│   ├─webpack.dev.conf.js
│   ├─webpack.prod.conf.js
│   └─webpack.test.conf.js
├─config
│   ├─dev.env.js
│   ├─index.js
│   ├─prod.env.js
│   └─test.env.js
├─...
└─package.json

package.json

关注scripts字段的内容:

  "scripts": {
    "dev": "node build/dev-server.js",
    "build": "node build/build.js",
    "lint": "eslint --ext .js,.vue src"
  },

直接看”dev”和”build”。运行”npm run dev”的时候执行的是build/dev-server.js文件,运行”npm run build”的时候执行的是build/build.js文件,我们可以从这两个文件开始进行代码阅读分析。

build文件夹

build/dev-server.js

 

首先来看执行”npm run dev”时候最先执行的build/dev-server.js文件。该文件主要完成下面几件事情:

 

  1. 检查node和npm的版本
  2. 引入相关插件和配置
  3. 创建express服务器和webpack编译器
  4. 配置开发中间件(webpack-dev-middleware)和热重载中间件(webpack-hot-middleware)
  5. 挂载代理服务和中间件
  6. 配置静态资源
  7. 启动服务器监听特定端口(8080)
  8. 自动打开浏览器并打开特定网址(localhost:8080)

说明: express服务器提供静态文件服务,不过它还使用了http-proxy-middleware,一个http请求代理的中间件。前端开发过程中需要使用到后台的API的话,可以通过配置proxyTable来将相应的后台请求代理到专用的API服务器。

require(‘./check-versions‘)()   /*检查NodeJS和npm的版本*/
var config = require(‘../config‘)  // 获取配置
// 如果Node的环境变量中没有设置当前的环境(NODE_ENV),则使用config中的配置作为当前的环境
if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
// 一个可以调用默认软件打开网址、图片、文件等内容的插件
// 这里用它来调用默认浏览器打开dev-server监听的端口,例如:localhost:8080
var path = require(‘path‘)
var express = require(‘express‘)
var webpack = require(‘webpack‘)
var opn = require(‘opn‘)
// 一个express中间件,用于将http请求代理到其他服务器
// 例:localhost:8080/api/xxx  -->  localhost:3000/api/xxx
// 这里使用该插件可以将前端开发中涉及到的请求代理到API服务器上,方便与服务器对接
var proxyMiddleware = require(‘http-proxy-middleware‘)
// 引入相应的 webpack 配置
var webpackConfig = require(‘./webpack.dev.conf‘)
// dev-server 监听的端口,默认为config.dev.port设置的端口,即8080
// default port where dev server listens for incoming traffic
var port = process.env.PORT || config.dev.port
  // Define HTTP proxies to your custom API backend
  // https://github.com/chimurai/http-proxy-middleware
  // 定义 HTTP 代理表,代理到 API 服务器
var proxyTable = config.dev.proxyTable
// 创建1个 express 实例
var app = express()

// 数据mock
var appData = http://www.mamicode.com/require(‘../static/data.json‘)//在根目录下放置的一个data.json文件,用以模拟请求的数据
var seller = appData.seller//获取data中的数据对象
var goods = appData.goods
var ratings = appData.ratings

var apiRoutes = express.Router()//创建一个路由实例

apiRoutes.get(‘/seller‘, function(req, res) {//获取数据
  res.json({
    errno: 0,
    data: seller
  })
})

apiRoutes.get(‘/goods‘, function(req, res) {
  res.json({
    errno: 0,
    data: goods
  })
})

apiRoutes.get(‘/ratings‘, function(req, res) {
  res.json({
    errno: 0,
    data: ratings
  })
})

app.use(‘/api‘, apiRoutes)// express使用api
// 根据webpack配置文件创建Compiler对象
var compiler = webpack(webpackConfig)
// webpack-dev-middleware使用compiler对象来对相应的文件进行编译和绑定
// 编译绑定后将得到的产物存放在内存中而没有写进磁盘
// 将这个中间件交给express使用之后即可访问这些编译后的产品文件
var devMiddleware = require(‘webpack-dev-middleware‘)(compiler, {
  publicPath: webpackConfig.output.publicPath,
  stats: {
    colors: true,
    chunks: false
  }
})
// webpack-hot-middleware,用于实现热重载功能的中间件
var hotMiddleware = require(‘webpack-hot-middleware‘)(compiler)
  // force page reload when html-webpack-plugin template changes
  // 当html-webpack-plugin提交之后通过热重载中间件发布重载动作使得页面重载
compiler.plugin(‘compilation‘, function(compilation) {
  compilation.plugin(‘html-webpack-plugin-after-emit‘, function(data, cb) {
    hotMiddleware.publish({
      action: ‘reload‘
    })
    cb()
  })
})
// 将 proxyTable 中的代理请求配置挂在到express服务器上
// proxy api requests
Object.keys(proxyTable).forEach(function(context) {
  var options = proxyTable[context]
  if (typeof options === ‘string‘) {
    options = {
      target: options
    }
  }
  app.use(proxyMiddleware(context, options))
})

// handle fallback for HTML5 history API
// 重定向不存在的URL,常用于SPA
app.use(require(‘connect-history-api-fallback‘)())

// serve webpack bundle output
// 使用webpack开发中间件
// 即将webpack编译后输出到内存中的文件资源挂到express服务器上
app.use(devMiddleware)
// 将热重载中间件挂在到express服务器上
// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware)

// serve pure static assets// 静态资源的路径// 将静态资源挂到express服务器上
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static(‘./static‘))
// 启动express服务器并监听相应的端口(8080)
module.exports = app.listen(port, function(err) {
  if (err) {
    console.log(err)
    return
  }
// 应用的地址信息,例如:http://localhost:8080
var uri = ‘http://localhost:‘ + port console.log(‘Listening at ‘ + uri + ‘\n‘) // 如果符合自动打开浏览器的条件,则通过opn插件调用系统默认浏览器打开对应的地址uri // when env is testing, don‘t need open it if (process.env.NODE_ENV !== ‘testing‘) { opn(uri) } })

 build/webpack.base.conf.js

从代码中看到,dev-server使用的webpack配置来自build/webpack.dev.conf.js文件(测试环境下使用的是build/webpack.prod.conf.js,这里暂时不考虑测试环境)。而build/webpack.dev.conf.js中又引用了webpack.base.conf.js,所以先分析webpack.base.conf.js。

webpack.base.conf.js主要完成了下面这些事情:

  1. 配置webpack编译入口
  2. 配置webpack输出路径和命名规则
  3. 配置模块resolve规则
  4. 配置不同类型模块的处理规则

说明: 这个配置里面只配置了.js、.vue、图片、字体等几类文件的处理规则,如果需要处理其他文件可以在module.rules里面配置。

var path = require(‘path‘)
var config = require(‘../config‘)
var utils = require(‘./utils‘)
var projectRoot = path.resolve(__dirname, ‘../‘)// 给出正确的绝对路径

var env = process.env.NODE_ENV
  // check env & config/index.js to decide weither to enable CSS Sourcemaps for the
  // various preprocessor loaders added to vue-loader at the end of this file
var cssSourceMapDev = (env === ‘development‘ && config.dev.cssSourceMap)
var cssSourceMapProd = (env === ‘production‘ && config.build.productionSourceMap)
var useCssSourceMap = cssSourceMapDev || cssSourceMapProd

module.exports = {
  entry: {// 配置webpack编译入口
    app: ‘./src/main.js‘
  },
  output: {// 配置webpack输出路径和命名规则
    path: config.build.assetsRoot,// webpack输出的目标文件夹路径(例如:/dist)
    publicPath: process.env.NODE_ENV === ‘production‘ ? config.build.assetsPublicPath : config.dev.assetsPublicPath,// webpack编译输出的发布路径
    filename: ‘[name].js‘  // webpack输出bundle文件命名格式
  },
  resolve: {// 配置模块resolve的规则
    extensions: [‘‘, ‘.js‘, ‘.vue‘],// 自动resolve的扩展名
    fallback: [path.join(__dirname, ‘../node_modules‘)],
    alias: {// 创建路径别名,有了别名之后引用模块更方便,例如 // import Vue from ‘vue/dist/vue.common.js‘可以写成 import Vue from ‘vue‘
      ‘vue$‘: ‘vue/dist/vue.common.js‘,
      ‘src‘: path.resolve(__dirname, ‘../src‘),
      ‘assets‘: path.resolve(__dirname, ‘../src/assets‘),
      ‘components‘: path.resolve(__dirname, ‘../src/components‘),
      ‘common‘: path.resolve(__dirname, ‘../src/common‘),
      ‘img‘: path.resolve(__dirname, ‘../resource/img‘)
    }
  },
  resolveLoader: {
    fallback: [path.join(__dirname, ‘../node_modules‘)]
  },
  module: {// 配置不同类型模块的处理规则
    preLoaders: [{
      test: /\.vue$/,
      loader: ‘eslint‘,
      include: projectRoot,
      exclude: /node_modules/
    }, {
      test: /\.js$/,// 对所有.vue文件使用eslint
      loader: ‘eslint‘,
      include: projectRoot,
      exclude: /node_modules/
    }],
    loaders: [{
      test: /\.vue$/,
      loader: ‘vue‘
    }, {
      test: /\.js$/,// 对src和test文件夹下的.js文件使用babel-loader
      loader: ‘babel‘,
      include: projectRoot,
      exclude: /node_modules/
    }, {
      test: /\.json$/,
      loader: ‘json‘
    }, {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      loader: ‘url‘,
      query: {
        limit: 10000,
        name: utils.assetsPath(‘img/[name].[hash:7].[ext]‘)
      }
    }, {// 对字体资源文件使用url,query.name指明了输出的命名规则
      test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
      loader: ‘url‘,
      query: {
        limit: 10000,
        name: utils.assetsPath(‘fonts/[name].[hash:7].[ext]‘)
      }
    }]
  },
  eslint: {
    formatter: require(‘eslint-friendly-formatter‘)
  },
  vue: {
    loaders: utils.cssLoaders({
      sourceMap: useCssSourceMap
    }),
    postcss: [
      require(‘autoprefixer‘)({
        browsers: [‘last 2 versions‘]
      })
    ]
  }
}

build/webpack.dev.conf.js

接下来看webpack.dev.conf.js,这里面在webpack.base.conf的基础上增加完善了开发环境下面的配置,主要包括下面几件事情:

  1. 将hot-reload相关的代码添加到entry chunks
  2. 合并基础的webpack配置
  3. 使用styleLoaders
  4. 配置Source Maps
  5. 配置webpack插件
var config = require(‘../config‘)
var webpack = require(‘webpack‘)
var merge = require(‘webpack-merge‘)
var utils = require(‘./utils‘)
var baseWebpackConfig = require(‘./webpack.base.conf‘)
var HtmlWebpackPlugin = require(‘html-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: {
    loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // eval-source-map is faster for development
  devtool: ‘#eval-source-map‘,
  plugins: [
    new webpack.DefinePlugin({
      ‘process.env‘: config.dev.env
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: ‘index.html‘,
      template: ‘index.html‘,
      inject: true
    })
  ]
})

 

【webpack】理解配置文件