webpack開發和生產兩個環境的配置詳解


目錄

一開始在接觸webpack 的時候,簡直痛不欲生,現在回頭看,做個注釋,
當然參考了很多文章。這是一個關於vue 開發的webpack 架構會列舉出來

webpack 系列教程
Webpack——令人困惑的地方
Express結合Webpack的全棧自動刷新
Webpack傻瓜式指南(一)
Webpack資源總結

啟動指令

1 "scripts": {
2     "dev": "node build/dev-server.js", // 
3     "build": "node build/build.js",// 打包
4     "lint": "eslint --ext .js,.vue src"
5   },

webpack.base.conf.js

webpack基本配置

  1 var path = require('path')
  2 var config = require('../config')
  3 var utils = require('./utils')
  4 var projectRoot = path.resolve(__dirname, '../')
  5  
  6 var env = process.env.NODE_ENV
  7 // check env & config/index.js to decide whether to enable CSS source maps for the
  8 // various preprocessor loaders added to vue-loader at the end of this file
  9 var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
 10 var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
 11 var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
 12  
 13 // 配置文件的內容需要通過module.exports暴露
 14 module.exports = {
 15  
 16   // 配置需要打包的入口文件,值可以是字符串、數組、對象。
 17   // 1. 字符串: entry: './entry'
 18   // 2. 字符串: entry:[ './entry1','entry2'] (多入口)
 19   // 3. 對象:   entry: {alert/index': path.resolve(pagesDir, `./alert/index/page`)}
 20   // 多入口書寫的形式應為object,因為object,的key在webpack里相當於此入口的name,
 21   entry: {
 22     app: './src/main.js'
 23   },
 24   output: {
 25  
 26     // 輸出文件配置,output 輸出有自己的一套規則,常用的參數基本就是這三個
 27     // path: 表示生成文件的根目錄 需要一個**絕對路徑** path僅僅告訴Webpack結果存儲在哪里
 28     path: config.build.assetsRoot,
 29  
 30     // publicPath 參數表示的是一個URL 路徑(指向生成文件的跟目錄),用於生成css/js/圖片/字體文件
 31     // 等資源的路徑以確保網頁能正確地加載到這些資源.
 32     // “publicPath”項則被許多Webpack的插件用於在生產模式下更新內嵌到css、html文件里的url值.
 33     // 例如,在localhost(即本地開發模式)里的css文件中邊你可能用“./test.png”這樣的url來加載圖片,
 34     // 但是在生產模式下“test.png”文件可能會定位到CDN上並且你的Node.js服務器可能是運行在HeroKu上邊的。
 35     // 這就意味着在生產環境你必須手動更新所有文件里的url為CDN的路徑。
 36       //開發環境:Server和圖片都是在localhost(域名)下
 37       //.image { 
 38       // background-image: url('./test.png');
 39       //}
 40       // 生產環境:Server部署下HeroKu但是圖片在CDN上
 41       //.image { 
 42       //  background-image: url('https://someCDN/test.png');
 43       //}
 44 ![](http://images2015.cnblogs.com/blog/1108527/201703/1108527-20170304195944626-432609161.png)
 45  
 46  
 47     publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
 48     
 49     // filename 屬性表示的是如何命名出來的入口文件,規則是一下三種: 
 50     // [name] 指代入口文件的name,也就是上面提到的entry參數的key,因此,我們可以在name里利用/,即可達到控制文件目錄結構的效果。
 51     // [hash],指代本次編譯的一個hash版本,值得注意的是,只要是在同一次編譯過程中生成的文件,這個[hash].js 
 52     //的值就是一樣的;在緩存的層面來說,相當於一次全量的替換。
 53     filename: '[name].js'
 54   },
 55  
 56   // 用來配置依賴文件的匹配,如依賴文件的別名配置、模塊的查找目錄、默認查找的
 57   // 文件后綴名
 58   // resolve.root 該選型用來制定模塊查找的根路徑,必須為**絕對路徑**,值可以
 59   // 是路徑字符串或者路徑數組若是數組,則會依次查找
 60   resolve: {
 61     extensions: ['', '.js', '.vue', '.json'],
 62     fallback: [path.join(__dirname, '../node_modules')],
 63  
 64     // 用來配置依賴文件的別名,值是一個對,該對象的鍵是別名,值是實際路徑
 65     alias: {
 66       'vue$': 'vue/dist/vue.common.js',
 67       'src': path.resolve(__dirname, '../src'),
 68       'assets': path.resolve(__dirname, '../src/assets'),
 69       'components': path.resolve(__dirname, '../src/components')
 70     }
 71   },
 72   resolveLoader: {
 73     fallback: [path.join(__dirname, '../node_modules')]
 74   },
 75  
 76   // 用來進行模塊加載相關的配置
 77   module: {
 78     preLoaders: [
 79       {
 80         test: /\.vue$/,
 81         loader: 'eslint',
 82         include: projectRoot,
 83         exclude: /node_modules/
 84       },
 85       {
 86         test: /\.js$/,
 87         loader: 'eslint',
 88         include: projectRoot,
 89         exclude: /node_modules/
 90       }
 91     ],
 92     loaders: [
 93       // webpack擁有一個類似於插件的機制,名為Loader,通過Loader,webpack能夠針對每一種特定的資源做出相應的處理
 94       // 1.test參數用來指示當前配置項針對哪些資源,該值應是一個條件值(condition)。
 95       // 2.exclude參數用來剔除掉需要忽略的資源,該值應是一個條件值(condition)。
 96       // 3.include參數用來表示本loader配置僅針對哪些目錄/文件,該值應是一個條件值(condition)。
 97       // 而include參數則用來指示目錄;注意同時使用這兩者的時候,實際上是and的關系。
 98       // 4.loader/loaders參數,用來指示用哪個或哪些loader來處理目標資源,這倆貨
 99       // 表達的其實是一個意思,只是寫法不一樣,我個人推薦用loader寫成一行,多個
100       // loader間使用!分割,這種形式類似於管道的概念,又或者說是函數式編程。形
101       // 如loader: 'css?!postcss!less',可以很明顯地看出,目標資源先經less-loader
102       // 處理過后將結果交給postcss-loader作進一步處理,然后最后再交給css-loader。
103       {
104         test: /\.vue$/,
105         loader: 'vue'
106       },
107       {
108         test: /\.js$/,
109         loader: 'babel',
110         include: projectRoot,
111         exclude: /node_modules/
112       },
113       {
114         test: /\.json$/,
115         loader: 'json'
116       },
117       {
118         test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
119         loader: 'url',
120         query: {
121           limit: 10000,
122           name: utils.assetsPath('img/[name].[hash:7].[ext]')
123         }
124       },
125       {
126         test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
127         loader: 'url',
128         query: {
129           limit: 10000,
130           name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
131         }
132       },
133       // expose-loader,這個loader的作用是,將指定js模塊export的變量聲明為全局變量
134       {
135         test: require.resolve('jquery'),  // 此loader配置項的目標是NPM中的jquery
136         loader: 'expose?$!expose?jQuery', // 先把jQuery對象聲明成為全局變量`jQuery`,再通過管道進一步又聲明成為全局變量`$`
137       },
138     ]
139   },
140   eslint: {
141     formatter: require('eslint-friendly-formatter')
142   },
143   vue: {
144     loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
145  
146     // 解決.vue中文件style的部分一些特性解析,比如scoped
147     postcss: [
148  
149       require('autoprefixer')({
150         browsers: ['last 2 versions']
151       })
152     ]
153   }
154 }

webpack.dev.conf.js

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: [
    // DefinePlugin 是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
    }),
    // 可以自動加載當前模塊依賴的其他模塊並已制定別名注入到當前的模塊中,引入jq
    // 在網上看到的文章,救了我的命 ProvidePlugin + expose-loader 引入jq 
    // 
    // 如果你把jQuery看做是一個普通的js模塊來加載(要用到jQuery的模塊統統先require
    // 后再使用),那么,當你加載老式jQuery插件時,往往會提示找不到jQuery實例
    // 有時候是提示找不到$),這是為啥呢?
    // 要解釋這個問題,就必須先稍微解釋一下jQuery插件的機制:jQuery插件是通過
    // jQuery提供的jQuery.fn.extend(object)和jQuery.extend(object)這倆方法,來
    // 把插件本身實現的方法掛載到jQuery(也即$)這個對象上的。傳統引用jQuery及
    // 其插件的方式是先用<script>加載jQuery本身,然后再用同樣的方法來加載其插件;
    // jQuery會把jQuery對象設置為全局變量(當然也包括了$),既然是全局變量,那么
    // 插件們很容易就能找到jQuery對象並掛載自身的方法了。
    // 
    // 而webpack作為一個遵從模塊化原則的構建工具,自然是要把各模塊的上下文環境給
    // 分隔開以減少相互間的影響;而jQuery也早已適配了AMD/CMD等加載方式,換句話說,
    // 我們在require jQuery的時候,實際上並不會把jQuery對象設置為全局變量。說到
    // 這里,問題也很明顯了,jQuery插件們找不到jQuery對象了,因為在它們各自的上下
    // 文環境里,既沒有局部變量jQuery(因為沒有適配AMD/CMD,所以就沒有相應的requi
    // re語句了),也沒有全局變量jQuery。
    // 
    // A: ProvidePlugin的機制是:當webpack加載到某個js模塊里,出現了未定義且名稱符合
    // (字符串完全匹配)配置中key的變量時,會自動require配置中value所指定的js模塊
    // expose-loader,這個loader的作用是,將指定js模塊export的變量聲明為全局變量。
    // 
    // B:externals 調用jq 
    // externals是webpack配置中的一項,用來將某個全局變量“偽裝”成某個js模塊的exports,
    // 如下面這個配置:
    // externals: {'jquery': 'window.jQuery',},
    // 那么,當某個js模塊顯式地調用var $ = require('jquery')的時候,就會把window,
    // jQuery返回給它,與上述ProvidePlugin + expose-loader的方案相反,此方案是先用
    // <script>加載的jQuery滿足老式jQuery插件的需要,再通過externals將其轉換成符合
    // 模塊化要求的exports。
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery",
      'window.$': 'jquery',
    })
  ]
})

webpack.prod.conf.js

var path = require('path')
var config = require('../config')
var utils = require('./utils')
var webpack = require('webpack')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var env = config.build.env
 
var 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'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  vue: {
    loaders: utils.cssLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
 
  // webpack插件位置,有固定的用法
  // 1. 利用Plugin的初始方法並傳入Plugin預設的參數進行初始化,生成一個實例。
  // 2. 將此實例插入到webpack配置文件中的plugins參數(數組類型)里即可。
  // 
  // 1. 
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    // extract css into its own file
    new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')),
    // 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
    new HtmlWebpackPlugin({
 
      // filename 生成網頁的HTML名字,可以使用/來控制文件文件的目錄結構,最
      // 終生成的路徑是基於webpac配置的output.path的
      filename: config.build.index,
      template: 'index.html',
      inject: true,
      // inject,指示把加載js文件用的<script>插入到哪里,默認是插到<body>
      // 的末端,如果設置為'head',則把<script>插入到<head>里。
      minify: {
        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
      chunksSortMode: 'dependency'
    }),
 
    // 如果文件是多入口的文件,可能存在,重復代碼,把公共代碼提取出來,又不會重復下載公共代碼了
    // (多個頁面間會共享此文件的緩存)
    // CommonsChunkPlugin的初始化常用參數有解析?
    // name: 這個給公共代碼的chunk唯一的標識
    // filename,如何命名打包后生產的js文件,也是可以用上[name]、[hash]、[chunkhash]
    // minChunks,公共代碼的判斷標准:某個js模塊被多少個chunk加載了才算是公共代碼
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to 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
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      chunks: ['vendor']
    })
  ]
})
 
if (config.build.productionGzip) {
  var 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

 

 

 

  • 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 whether to enable CSS source maps 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暴露
  • module.exports = {
  •  
  • // 配置需要打包的入口文件,值可以是字符串、數組、對象。
  • // 1. 字符串: entry: './entry'
  • // 2. 字符串: entry:[ './entry1','entry2'] (多入口)
  • // 3. 對象: entry: {alert/index': path.resolve(pagesDir, `./alert/index/page`)}
  • // 多入口書寫的形式應為object,因為object,的key在webpack里相當於此入口的name,
  • entry: {
  • app: './src/main.js'
  • },
  • output: {
  •  
  • // 輸出文件配置,output 輸出有自己的一套規則,常用的參數基本就是這三個
  • // path: 表示生成文件的根目錄 需要一個**絕對路徑** path僅僅告訴Webpack結果存儲在哪里
  • path: config.build.assetsRoot,
  •  
  • // publicPath 參數表示的是一個URL 路徑(指向生成文件的跟目錄),用於生成css/js/圖片/字體文件
  • // 等資源的路徑以確保網頁能正確地加載到這些資源.
  • // “publicPath”項則被許多Webpack的插件用於在生產模式下更新內嵌到css、html文件里的url值.
  • // 例如,在localhost(即本地開發模式)里的css文件中邊你可能用“./test.png”這樣的url來加載圖片,
  • // 但是在生產模式下“test.png”文件可能會定位到CDN上並且你的Node.js服務器可能是運行在HeroKu上邊的。
  • // 這就意味着在生產環境你必須手動更新所有文件里的url為CDN的路徑。
  • //開發環境:Server和圖片都是在localhost(域名)下
  • //.image {
  • // background-image: url('./test.png');
  • //}
  • // 生產環境:Server部署下HeroKu但是圖片在CDN上
  • //.image {
  • // background-image: url('https://someCDN/test.png');
  • //}
  • ![](http: //images2015.cnblogs.com/blog/1108527/201703/1108527-20170304195944626-432609161.png)
  •  
  •  
  • publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
  •  
  • // filename 屬性表示的是如何命名出來的入口文件,規則是一下三種:
  • // [name] 指代入口文件的name,也就是上面提到的entry參數的key,因此,我們可以在name里利用/,即可達到控制文件目錄結構的效果。
  • // [hash],指代本次編譯的一個hash版本,值得注意的是,只要是在同一次編譯過程中生成的文件,這個[hash].js
  • //的值就是一樣的;在緩存的層面來說,相當於一次全量的替換。
  • filename: '[name].js'
  • },
  •  
  • // 用來配置依賴文件的匹配,如依賴文件的別名配置、模塊的查找目錄、默認查找的
  • // 文件后綴名
  • // resolve.root 該選型用來制定模塊查找的根路徑,必須為**絕對路徑**,值可以
  • // 是路徑字符串或者路徑數組若是數組,則會依次查找
  • resolve: {
  • extensions: [ '', '.js', '.vue', '.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')]
  • },
  •  
  • // 用來進行模塊加載相關的配置
  • module: {
  • preLoaders: [
  • {
  • test: /\.vue$/,
  • loader: 'eslint',
  • include: projectRoot,
  • exclude: /node_modules/
  • },
  • {
  • test: /\.js$/,
  • loader: 'eslint',
  • include: projectRoot,
  • exclude: /node_modules/
  • }
  • ],
  • loaders: [
  • // webpack擁有一個類似於插件的機制,名為Loader,通過Loader,webpack能夠針對每一種特定的資源做出相應的處理
  • // 1.test參數用來指示當前配置項針對哪些資源,該值應是一個條件值(condition)。
  • // 2.exclude參數用來剔除掉需要忽略的資源,該值應是一個條件值(condition)。
  • // 3.include參數用來表示本loader配置僅針對哪些目錄/文件,該值應是一個條件值(condition)。
  • // 而include參數則用來指示目錄;注意同時使用這兩者的時候,實際上是and的關系。
  • // 4.loader/loaders參數,用來指示用哪個或哪些loader來處理目標資源,這倆貨
  • // 表達的其實是一個意思,只是寫法不一樣,我個人推薦用loader寫成一行,多個
  • // loader間使用!分割,這種形式類似於管道的概念,又或者說是函數式編程。形
  • // 如loader: 'css?!postcss!less',可以很明顯地看出,目標資源先經less-loader
  • // 處理過后將結果交給postcss-loader作進一步處理,然后最后再交給css-loader。
  • {
  • 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'), // 此loader配置項的目標是NPM中的jquery
  • loader: 'expose?$!expose?jQuery', // 先把jQuery對象聲明成為全局變量`jQuery`,再通過管道進一步又聲明成為全局變量`$`
  • },
  • ]
  • },
  • eslint: {
  • formatter: require( 'eslint-friendly-formatter')
  • },
  • vue: {
  • loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }),
  •  
  • // 解決.vue中文件style的部分一些特性解析,比如scoped
  • postcss: [
  •  
  • require( 'autoprefixer')({
  • browsers: [ 'last 2 versions']
  • })
  • ]
  • }
  • }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM