webpack脱坑之旅

目录结构:

  • build
    • webpack.base.conf.js
    • webpack.dev.conf.js
    • webpack.prod.conf.js

webpack.base.conf.js

// webpack基本配置
const path = require('path')  // 引入path模块处理不同系统之间的路径问题
const projectRoot =  path.resolve(__dirname, '../')  // 项目根目录
const utils = require('./uitls')
const config = require('../config')

const env = process.env.NODE_ENV       // js的全局变量process 通过改变NODE_ENV的值,控制项目的生产与开发环境

// 其实就是判断是否启用css源映射
const cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
const cssSourceMapProd =  (env === 'production' && config.build.productionSourceMap)
const useCssSourceMap = cssSourceMapDev || cssSourceMapProd

module.exports = {
  entry: {     // 需要打包的入口文件
    app: './src/main.js'
  },

  output: {    // 输出文件配置,常用的三个参数:
    path: config.build.assetsRoot,   // 告诉webpack结果文件放到哪里,是一个绝对路径
    // publicPath: 表示的是一个url路径(指向生成文件的根目录),用于生成css/js/图片/字体文件等资源的路径以保证网也能够正确加载到资源
    publicpath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,  // 判断环境,配置公共路径
    // filename 参数表示的是如何命名出来的入口文件,规则如下:
    // [name]  指代入口文件(entry参数)的key 也就是上面的app 
    // [hash]  指代本次编译的hash版本,每次编译的每个文件的hash值相同;从缓存层面来说,就是一次全量替换
    filename: '[name].js'
  },

  // 用来配置依赖文件的匹配,如依赖文件的别名配置、模块的查找目录、默认查找的文件后缀名
  // resolve.root 用来制定模块查找的根路径,必须为-!绝对路径!-,值可以是路径字符串或者是字符串数组,依次查找
  resolve: {
    extensions: ['', '.vue', '.js', '.json'],
    fallback: [path.join(__dirname, '../node_modules')],  // 配置依赖项路径
    alias: {  // 配置依赖文件的别名,键名就是别名,值是路径
      'vue$': 'vue/dist/vue.common.js',
      'src': path.resolve(__dirname, '../src'),
      'assets': path.resolve(__dirname, '../src/assets'),
      'components': path.resolve(__dirname, '../src/components')
    }
  },

  resolveLoader: {
    fallback: [path.join(__dirname, '../node_modules')]
  },

  // 用来进行模块加载相关配置
  modules: {
    preLoaders: [  // 调用loader之前需要调用的loader,用来检查代码
      {
        test: /\.vue$/,
        loader: 'eslint',
        include: projectRoot,
        exclude: /node_modules/
      },
      {
        test: /\.js$/,            // 匹配名称规则
        loader: 'eslint',         // 需要用到的loader
        include: projectRoot,     // 包括哪些文件
        exclude: /node_modules/   // 除了哪些文件
      }
    ],
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue'
      },
      {
        test: /\.js$/,
        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]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      // expose-loader,这个loader的作用是,将指定js模块export的变量声明为全局变量
      {
        test: require.resolve('jquery'),   // 这里配置项的目标是jquery
        laoder: 'expose?$!expose?jQuery'   // 先把jQuery对象声明为全局对象jQuery,再通过管道进一步声明为全局变量$
      }
    ]
  },

  eslint: {
    formatter: require('eslint-friendly-formatter')
  },

  vue: {
    loaders: utils.cssLoaders({sourceMap: useCssSourceMap}),
    postcss: [         // 解决vue文件中的一些样式解析,比如scoped
      require('autoprefixer')({
        browers: ['last 2 versions']
      })
    ]
  }

}

webpack.dev.conf.js

const webpack = require('webpack')
const utils = require('./utils')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webapck.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')

// add hot-reload related code to entry trunks  // 将热重载相关代码添加到条目中
Object.keys(baseWebpackConfig.entry).forEach(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: [
    // DefinePluign 是webpack的内置插件,该插件可以在打包的时候替换制定的变量
    new webpack.DefinePlugin({      // 开发环境,将环境变量改变成开发环境的值
      'process.env': config.dev.env
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }),

    // 将jQuery引入项目中,但是jQuery是通过jQuery.extend(object)以及jQuery.fn.extend(object)方法来将方法挂载到jQuery($)对象上的 
    // 传统的script引入,$是全局变量,所以可以直接使用,但是webpack限制了模块的作用域,所以$不在全局中,因此获取不到

    // A: ProvidePlugin的机制是:当webpack加载到某个js模块里,出现了未定义且名称符合
    // (字符串完全匹配)配置中key的变量时,会自动require配置中value所指定的js模块
    // expose-loader,这个loader的作用是,将指定js模块export的变量声明为全局变量。
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery",
      'window.$': 'jquery',
    })
  ]
})

webpack.prod.conf.js

const utils = require('./utils')
const path = require('path')
const config = require('../config')
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const env = config.build.env

let webpackConfig = merge(baseWebpackConfig, {
  module: {
    loaders: utils.styleLoaders({sourceMap: config.build.productionSourceMap, extract: true})  
  },

  devtool: config.build.productionSourceMap ? '#source-map' : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js')
  },
  vue: {
    loaders: utils.cssLoaders({
      sourceMap: config.build.sourceMap,
      extract: true
    })
  },

  // webpack 插件有固定的用法
  // 1 利用Plugin 的初始方法并传入Plugin预设的参数进行初始化,生成一个实例
  // 2 将此实例插入到webpack配置文件中的plugins参数(数组类型)里面即可
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePluign({
      'process.env': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warning: false
      }
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    // extract css into its own file
    new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
    // 使用正确的缓存资源哈希生成dist index.html
    // 通过改变index.html可以定制output
    // see https://github.com/ampedandwired/html-webpack-plugin

    new HtmlWebpackPlugin({
      // filename 生成网页的HTML名字,可以使用 '/' 来控制文件的目录结构,最终生成的路径是基于webpack配置的output.path的
      filename: config.build.index,
      template: 'index.html',
      inject: true,
      // inject 是指将加载的js文件插入到哪里,默认是插入到body的末尾,如果设置'head' 则插入到head中
      minify: {
        removeComments: true,
        collapseWhitespace: true, 
        // more options:  https://github.com/kangax/html-minifier#options-quick-reference
      },
      chunksSortMode: 'dependency'
    }),

    // 如果文件是多入口的文件,可能存在重复代码,将公共代码取出来,就不会重复下载公共代码了(多个页面间会共享此文件的缓存)
    // CommonsChunkPlugin的初始化常用参数有解析?
    // name: 这个给公共代码的chunk唯一的标识
    // filename,如何命名打包后生产的js文件,也是可以用上[name]、[hash]、[chunkhash]
    // minChunks,公共代码的判断标准:某个js模块被多少个chunk加载了才算是公共代码
    new webpack.ptimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extract to verdon 任何node_modules中必须的模块都将提供给verdon
        return (
          module.resource && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0
        )
      }
    }),
    // 将webpack运行时和模块清单提取到提取到自己的文件,防止在更新项目时更新verdon hash
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['verdon']
    })
  ]
})

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

module.exports = webpackConfig
posted @ 2017-11-01 10:11  翩然雪海间  阅读(428)  评论(1编辑  收藏  举报