1.webpack配置了解

 webpack的配置文件是一個(gè)nodejs的module,使用CommonJS風(fēng)格來編寫的,比如如下:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

module.exports = {
  entry: './index',
  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js'
  }
}

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

webpack的配置文件可以隨便命名,默認(rèn)為 webpack.config.js,因此在項(xiàng)目的根目錄下,直接運(yùn)行 webpack就可以進(jìn)行打包,但是也可以對webpack命名為其他的名字,比如把它放入 build/webpack.dev.js ,代碼目錄結(jié)構(gòu)如下:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

### 目錄結(jié)構(gòu)如下:
demo                                        # 工程名|   |--- dist                               # 打包后生成的目錄文件             
|   |--- node_modules                       # 所有的依賴包|   |--- src                                # 項(xiàng)目的文件包|   |    |--- pages                         # 存放所有頁面的文件|   |    |    |--- page1|   |    |    |    |--- index.html          # 第一個(gè)頁面的html文件|   |    |    |    |--- index.styl          # 第一個(gè)頁面的css文件|   |    |    |    |--- index.js            # 第一個(gè)頁面的js文件|   |    |    |--- page2|   |    |    |    |--- index.html          # 第二個(gè)頁面的html文件|   |    |    |    |--- index.styl          # 第二個(gè)頁面的css文件|   |    |    |    |--- index.js            # 第二個(gè)頁面的js文件|   |--- build|   |    |--- webpack.base.js               # webpack 基本配置文件|   |    |--- webpack.dev.js                # 開發(fā)文件|   |    |--- webpack.build.js              # 打包線上文件                               
|   |--- .gitignore  
|   |--- README.md|   |--- package.json

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

因此我們在package.json 配置文件如下:

"scripts": {  "dev": "node build/webpack.dev.js",  "build": "node build/webpack.build.js"}

進(jìn)入項(xiàng)目的根目錄后,運(yùn)行 npm run dev 即可進(jìn)行打包。

1.1) 入口文件配置 entry參數(shù)

   entry入口文件可以是字符串的單入口文件,也可以是數(shù)組的多入口文件,但是我們最常見的是一個(gè)對象的方式來組織入口文件。因此object中的key在webpack里相當(dāng)于入口的name,可以用來生成文件的路徑,也可以使用來為此入口唯一的標(biāo)識。
比如如下:

entry: {  'page1': path.resolve(__dirname, '../src/pages/page1'),  'page2': path.resolve(__dirname, '../src/pages/page2')
}

假如頁面上有多個(gè)入口的話,這樣一個(gè)個(gè)寫比較麻煩,因此可以寫一個(gè)函數(shù)如下:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

/*
 獲取項(xiàng)目中多個(gè)入口文件*/function getEntries(paths) {  // node 中同步獲取文件列表
  var files = glob.sync(paths),
    entries = {};

  files.forEach(function(filepath) {    var toArray = filepath.split('/');    var filename = toArray[toArray.length - 2];
    entries[filename] = filepath;
  });  return entries;
}var entries = getEntries('./src/pages/*/index.js');
Object.keys(entries).forEach(function(name) {
  entry[name] = entries[name]
});

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

1.2) 輸出文件:out參數(shù)

output參數(shù)是告訴webpack以什么方式來生成/輸出文件,output有幾個(gè)常用的參數(shù)如:path, publicPath, filename, chunkFilename, 如下代碼:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

output: {
  path: path.resolve(__dirname, '../dist'),
  publicPath: '/assets/',   // 供插件在生產(chǎn)模式下更新內(nèi)嵌到css、html文件里的相對路徑url值
  filename: 'static/js/[name].js',
  chunkFilename: '[id].bundle.js',
}

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

1.3) path參數(shù)

   path參數(shù)表示生成文件的根目錄,需要傳入一個(gè)絕對路徑,如:path.resolve(__dirname, '../dist'),會(huì)解析成 /項(xiàng)目的根目錄下/dist文件, path參數(shù)和filename參數(shù)會(huì)共同組成入口文件的完整路徑。

1.4) publicPath

該參數(shù)表示的是一個(gè)URL路徑(指向生成文件的根目錄),可以用于css/js/images/font文件等資源的路徑,可以確保網(wǎng)頁正確的加載到這些資源文件。

1.5) publicPath參數(shù) 和 path參數(shù)的區(qū)別:

   path參數(shù)是針對本地文件系統(tǒng)的,但是publicPath則針對的是瀏覽器,它既可以是一個(gè)相對路徑,比如 '../../dist', 也可以是一個(gè)絕對路徑,比如:'http://www.xxx.com/', 那么什么時(shí)候使用相對路徑呢?什么時(shí)候使用絕對路徑呢?如果是引用本項(xiàng)目下的文件,最好使用相對路徑,如果是引用跨項(xiàng)目的文件,需要使用絕對路徑。

1.6) filename

filename屬性表示的是如何命名生成的入口文件,可以有如下規(guī)則:
  1. [name], 指代入口文件的name,也就是上面的entry中的key。
  2. [hash] 指代本次編譯的一個(gè)hash版本,但是請注意,只要在同一次編譯過程中生成的文件,這個(gè)[hash]值就是一樣的,每一次編譯,hash值都是一樣,也就是說不存在緩存文件,只要一編譯所有的hash
都會(huì)改變。
  3. [chunkhash] 指代當(dāng)前chunk的一個(gè)hash版本,也就是說,在每次編譯過程中,每一個(gè)chunk的hash都是不一樣的,如果某個(gè)chunk沒有發(fā)生變化,那么該chunk的hash也不會(huì)發(fā)生變化,也就是可以理解如果頁面的文件沒有發(fā)生改變,那么chunk的hash也不會(huì)發(fā)生改變,因此未改變的文件會(huì)在緩存中讀取。
1.7) chunkFilename

   chunkFilename 參數(shù) 與 filename參數(shù)類似,都是用來定義生成的命名方式的,只不過,chunkFilename參數(shù)指定的是除了入口文件外的chunk。

1.8) module參數(shù)中的 rules 配置(其實(shí)rules就相當(dāng)于之前的loaders):

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

module: {
  rules: [
    {
      test: /\.js$/,
      include: [
        path.resolve(__dirname, 'src/pages/**/*.js')
      ],
      exclude: /(node_modules)/,      // 排除node_modules 文件      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015'],
          plugins: ['transform-runtime']
        }
      }
    }
  ]
}

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

下面對一些子參數(shù)進(jìn)行說明:
test: test其實(shí)是一個(gè)使用正則表達(dá)式匹配文件的一種方式,比如上面的是,匹配以 .js結(jié)尾的文件。
include: 用來表示本rules 配置是針對那些目錄/文件,比如上面的代碼配置是針對 src/pages/ 下的所有js文件的。
exclude: 是用來排除掉那些文件的,比如上面的是 /(node_modules)/ 的意思是 排除掉 node_modules下的js文件的。
use: 使用到的loader的配置
use 下的 loader: 使用加載器名稱。
options: 該參數(shù)是為當(dāng)前l(fā)oader設(shè)置的參數(shù),對于babel也可以單獨(dú)放在 .babelrc文件中,也就是說該參數(shù)可以在項(xiàng)目的根目錄不包含.babelrc文件,把.babelrc文件移到該配置項(xiàng)來即可。

回到頂部

2.webpack CommonsChunkPlugin公共代碼剝離

    與單頁應(yīng)用相比,多頁應(yīng)用存在多個(gè)入口(每個(gè)頁面即一個(gè)入口),每個(gè)入口意味著一套完整的js代碼(包括業(yè)務(wù)邏輯和加載第三方庫、框架)。然后在每個(gè)頁面中分別加載該文件即可,

CommonsChunkPlugin: 該插件是一個(gè)可選用于建立一個(gè)獨(dú)立文件(chunk), 這個(gè)文件包括多個(gè)入口的chunk的公共模塊,通過將公共模塊拆出來,最終合成的文件能夠在最開始的時(shí)候加載一次,便存到緩存中,供后續(xù)使用,優(yōu)點(diǎn)是:會(huì)帶來速度的提升,因?yàn)闉g覽器會(huì)迅速將公共的代碼從緩存中提取出來
,而不是每次訪問一個(gè)新頁面時(shí)候,再去加載一個(gè)更大的文件。

CommonsChunkPlugin 初始化有哪些參數(shù)?
name: 給這個(gè)包含公共代碼的chunk命名。
filename: 命名打包后生成的js文件。
minChunks 公共代碼的判斷標(biāo)準(zhǔn):某個(gè)js模塊被多少個(gè)chunk(入口文件)加載了才算是公共代碼。
chunks,表示需要在哪些chunk(配置中entry的每一項(xiàng))里尋找公共代碼進(jìn)行打包,默認(rèn)不設(shè)置,那么它的提取范圍為所有的chunk。

下面是一個(gè)簡單的CommonsChunkPlugin的實(shí)列含義:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

var commonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin = ({
  name: 'vender',     // 這公共代碼的chunk命名為 'vender'
  filename: '[name].bundle.js',  // 生成的文件名為 vender.bundle.js
  minChunks: 2,     // 設(shè)定要有2個(gè)chunk(即2個(gè)頁面)加載的js模塊才會(huì)被納入公共代碼。
  chunks: ['pageA', 'pageB'],  // 只使用這些入口的 chunk})var commonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin = ({
  name: 'vender',     // 這公共代碼的chunk命名為 'vender'
  // filename: '[name].bundle.js',  // 生成的文件名為 vender.bundle.js
  minChunks: Infinity,  // 隨著入口chunk越來越多,這個(gè)配置保證沒其他的模塊會(huì)打包進(jìn) 公共的chunk})

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

下面是使用對 webpack CommonsChunkPlugin 詳解的demo:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

### 目錄結(jié)構(gòu)如下:
demo                                        # 工程名|   |--- dist                               # 打包后生成的目錄文件             
|   |--- node_modules                       # 所有的依賴包|   |--- src                                # 項(xiàng)目的文件包|   |    |--- common|   |    |     |---css                      # 公用頁面的css文件|   |    |     |---js                       # 公用頁面的js文件|   |    |--- libs|   |    |     |--- jquery.js               # 第三方庫文件   
|   |    |--- main.js                       # 入口文件|   |--- .gitignore  
|   |--- README.md|   |--- index.html                         # 首頁文件|   |--- package.json                      
|   |--- webpack.config.js                  # 配置文件 
|   |--- webpack.production.config.js       # 上線打包配置文件

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

1.1) 未使用 CommonsChunkPlugin 打包情況下
webpack.config.js 代碼如下:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

// 導(dǎo)入路徑包c(diǎn)onst path = require('path'); 
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {    //開啟sourceMap便于調(diào)試
    devtool: 'eval-source-map', 

    //入口文件,    entry: {
      main: './src/main.js'
    }, 

    output: {      // 輸出文件到當(dāng)前目錄下的 build文件夾內(nèi)
      path: path.resolve(__dirname, 'build'), 
      publicPath: '/assets/', //指定資源文件引用的目錄
      filename: 'bundle.js' // 文件名為 bundle.js
      //filename: '[name].js' // 可以打包為多個(gè)文件    },
    resolve: {
      extensions: ['*', '.js', '.json'],
    },    // 使用loader模塊    module: {        /* 
         * 在webpack2.0版本已經(jīng)將 module.loaders 改為 module.rules, 當(dāng)然module.loaders也是支持的。
         * 同時(shí)鏈?zhǔn)絣oader(用!連接)只適用于module.loader,同時(shí)-loader不可省略 
         */
        rules: [
          {
            test: /\.css$/,
            use: [              'style-loader', {
                loader: 'css-loader',
                options: {                  // modules: true // 設(shè)置css模塊化,詳情參考 https://github.com/css-modules/css-modules                }
              }, 
              {
                loader: 'postcss-loader',                // 參考 https://github.com/postcss/postcss-loader                options: {
                  plugins: function() {                    return [
                      require('autoprefixer')
                    ];
                  }
                }
              }]
          }, 
          {
            test: /\.styl(us)?$/,
            use: [                'style-loader', 'css-loader', {
                   loader: "postcss-loader",
                   options: {
                      plugins: function() {                        return [
                          require('autoprefixer')
                        ];
                      }
                    }
                }, 'stylus-loader']
          }, 
          {
            test: /\.js$/,
            loader: 'babel-loader', 
            exclude: /node_modules/ //需要排除的目錄          }
        ]
    },    // 配置devServer各種參數(shù)    devServer: {        // contentBase: "./",   // 本地服務(wù)器所加載的頁面所在的目錄
        hot: true,              // 配置HMR之后可以選擇開啟
        historyApiFallback: true, // 不跳轉(zhuǎn)
        inline: true // 實(shí)時(shí)刷新    },
    plugins: [      new HtmlWebpackPlugin({
          template: './index.html' // 模版文件      }),      new webpack.HotModuleReplacementPlugin(), // 熱加載插件    ]
}

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

main.js代碼如下:

require('./common/css/style.css');
import './common/css/stylus.styl';
require('./libs/jquery.js');

運(yùn)行命令 npm run start 可以看到打包后的文件 bundle.js 代碼內(nèi) 包含第三方j(luò)query框架的源碼。

1.2)使用CommonsChunkPlugin 
單一入口文件,分文件輸出 
webpack.config.js 代碼如下:

Android培訓(xùn),安卓培訓(xùn),手機(jī)開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn),云培訓(xùn)培訓(xùn)

// 導(dǎo)入路徑包c(diǎn)onst path = require('path'); 
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");

module.exports = {    //開啟sourceMap便于調(diào)試
    devtool: 'eval-source-map', 

    //入口文件,    entry: {
      main: './src/main.js'
    }, 

    output: {      // 輸出文件到當(dāng)前目錄下的 build文件夾內(nèi)
      path: path.resolve(__dirname, 'build'), 
      filename: '[name].js' // 可以打包為多個(gè)文件    },
    resolve: {
      extensions: ['*', '.js', '.json'],
    },    // 使用loader模塊    module: {        /* 
         * 在webpack2.0版本已經(jīng)將 module.loaders 改為 module.rules, 當(dāng)然module.loaders也是支持的。
         http://www.cnblogs.com/tugenhua0707/p/7191309.html