Webpack目前官方發(fā)布的最新版本是3.1.0,相對于2.0的怎么本,在語法上沒有變動,只是新增了功能。使用webpack,需要事先安裝node.js,并對node.js生態(tài)有一些基本的了解,比如(npm init 初始化項(xiàng)目,npm install 安裝一個包等等)。使用webpack通常有兩種方式:1. 命令行方式(CLI) , 2 script方式(推薦)。 兩種方式都需要理解webpack概念。

概念

webpack is a module bundler for modern JavaScript applications. When webpack processes your application, it recursively builds a dependency graph that includes every module your application needs, then packages all of those modules into a small number of bundles - often only one - to be loaded by the browser.

webpack是時下很火的js模塊化的打包工具。當(dāng)用webpack處理你的應(yīng)用時,它會遞歸的構(gòu)建每個模塊的依賴關(guān)系圖,然后把所有的這些依賴模塊打包到一個由數(shù)個小塊組成的文件中--通常只有一個(將被瀏覽器加載)

It is incredibly configurable, but to get started you only need to understand Four Core Concepts: entry, output, loaders, and plugins.

雖然它是高度可配置的,但是初步使用你只需要理解下面這四個核心概念:入口,輸出,加載器,插件。默認(rèn)情況下,所有這些配置項(xiàng),都保存在項(xiàng)目根目錄下一個名為webpack.config.js的文件中。

一. 入口 (entry) 

The entry point tells webpack where to start and follows the graph of dependencies to know what to bundle. You can think of your application's entry point as the contextual root or the first file to kick off your app.

所謂的入口,就是告訴webpack從哪里開始并通過依賴關(guān)系圖得知要哪些文件要打包。你可以理解為應(yīng)用程序最先讀取的文件。讀取這個文件之后,就會產(chǎn)生一個模塊依賴關(guān)系圖,那么當(dāng)前這個文件,就是依賴關(guān)系的根。

webpack.config.js

1
2
3
module.exports = {
  entry: './path/to/my/entry/file.js'
};

上例告訴webpack從./path/to/my/entry/file.js開始打包,這是最簡單的一種入口形式,實(shí)際上,它是下面這種形式的簡寫

1
2
3
4
5
module.exports = {
    entry : {
        main : './path/to/my/entry/file.js'
   
}

entry 還可以是數(shù)組的方式

1
2
3
module.exports = {
  entry: ['./path/to/my/entry/file.js']
};

這對于不想在js中引入css的情況非常有用,比如:

1
2
3
module.exports = {
  entry: ['./path/to/my/entry/file.js','./path/to/my/entry/file.css']
};

如果是多頁應(yīng)用或者想要提取公共代碼(CommonsChunkPlugin)的話,就需要使用下面這種入口方式:

1
2
3
4
5
6
7
module.exports = {
   entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
}     

 當(dāng)然,這里也可以使用數(shù)組的形式,同時引入樣式或其它文件

1
2
3
4
5
6
7
module.exports = {
  entry: {
    pageOne: ['./src/pageOne/index.js','./src/pageOne/index.css'],
    pageTwo: ['./src/pageTwo/index.js'],
    pageThree: ['./src/pageThree/index.js']
  }
}

以上就是關(guān)于入口這個概念和配置的全部內(nèi)容了,更詳細(xì)的介紹請移步官方網(wǎng)站關(guān)于入口的擴(kuò)展介紹 。 除了要告訴webpack要從哪個文件開始打包之外,還要告訴它打包生成的文件存放在哪個位置。于是就有了輸出的配置。

二. 輸出 (output)

webpack的output屬性就是告訴webpack怎么對待這些打包的代碼。

Configuring the output configuration options tell webpack how to write the compiled files to disk. Note that, while there can be multiple entry points, only one output configuration is specified.

 配置output屬性就是告訴webpack把編譯后的文件寫在磁盤的哪個地方。注意一點(diǎn),雖然入口中可以配置成多個文件的形式,但是輸出只能指定一個。

--- 打包之后資源,并不總是寫在磁盤上,也可能是在內(nèi)存中,比如使用webpack-dev-server的時候。(譯者注)

webpack.config.js

1
2
3
4
5
6
7
8
9
const path = require('path');
 
module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};

 output有兩個屬性是必須的。

 1. path 輸出路徑

  • An absolute path to your preferred output directory.  通常是絕對路徑。

 2. filename 文件名

     當(dāng)入口是多個文件的時候,可以用變量[name]代替固定的名字。這里的name變量,對應(yīng)entry中的key. ( 對于entry:配置成字符串的時候,輸出的文件名就是main,如果不明白,查看前面入口是誰的簡寫形式)

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
 entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
 
}

   在filename屬性中,除了[name]之外,還可以用[hash],[contenthash]等內(nèi)置變量, Tips ! [hash:8] 截取hash前8位

3. publicPath 虛擬路徑

  如果你有一個域名或打算用CDN,可以使用這個配置,如果你不知道,或暫時不打算用,可以先留空

1
2
3
4
5
output: {
  path: "/home/proj/cdn/assets/",
  publicPath: "http://cdn.example.com/assets/",
  filename:'[name].js'
}

 注意:如果配置了publicPath屬性,那么本地資源路徑,都會被替換成publicPath所指定的地址 (譯者注)

 三、加載器

Loaders are transformations that are applied on the source code of a module. They allow you to pre-process files as you import or “l(fā)oad” them. Thus, loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle front-end build steps. Loaders can transform files from a different language (like TypeScript) to JavaScript, or inline images as data URLs. Loaders even allow you to do things like import CSS files directly from your JavaScript modules!

加載器用于將資源代碼轉(zhuǎn)換成模塊。它允許您在導(dǎo)入或“加載”它們時預(yù)處理文件。因此,加載器就像處理各種任務(wù)的小工具,它提供一個強(qiáng)大的方法來處理前端構(gòu)建步驟。加載器可以把不同類型的文件(比如typescript)轉(zhuǎn)換成javascript 或者把圖片處理成內(nèi)聯(lián)的數(shù)據(jù)地址(如base64),加載器甚至可以像導(dǎo)入js模塊一樣直接導(dǎo)入樣式文件。

加載器聽起來很歷害的樣子,不過它不能算是webpack的功能,如果要想在項(xiàng)目中導(dǎo)入樣式模塊,需要先安裝樣式的加載器(css-loader), 同樣的,要導(dǎo)入圖片要安裝文件加載器(file-loader)

在命令行中輸入:
npm install --save-dev css-loader
即可安裝樣式加載器,后面跟的參數(shù)--save-dev 表示將保存到package.json的開發(fā)環(huán)境依賴屬性中。對應(yīng)還有一個--save表示安裝到生產(chǎn)環(huán)境。 package.json文件可以通過手工創(chuàng)建,也可用npm init(推薦)
創(chuàng)建。更多關(guān)于package.json的介紹請移步這里

 webpack.config.js

1
2
3
4
5
6
7
module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' }
    ]
  }
};

 加載器位于module屬性中(適用于webpack2.0+), rules 是一個數(shù)組,里邊可以添加多個加載器(loader).  每一個加載器用對象的方式組織,下面是一個更為復(fù)雜的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }

 每一個加載器,都有各自對應(yīng)的配置內(nèi)容,比如css-loader的詳細(xì)配置請移步這里 ,但是不管怎么說,方法都是一樣的。需要指出的事,加載器,除了在webpack.config.js中配置之外,還可以直接在js代碼中用行內(nèi)加載的方式使用,比如

import Styles from 'style-loader!css-loader?modules!./styles.css'; //多個加載器之間用!進(jìn)行分隔

不過這種方式寫起來很冗長,不推薦。還有一種方式,也一并提一下,在CLI方式中的使用

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

同樣的冗長,了解一下即可,實(shí)際項(xiàng)目中,大多是使用webpack.config.js進(jìn)行集中配置。

一般來說,一個加載器就可以完成一個任務(wù),比如file-loader 可以加載文件到j(luò)s的模塊中,可是我們常常發(fā)現(xiàn),加載css到j(luò)s模塊中,除了使用css-loader之外,常常還有一個多個附加的伴侶,比如這個style-loader。

這是為什么呢? 這其實(shí)是因?yàn)闃邮降氖褂糜袃煞N方式,一種是內(nèi)聯(lián)的方式,寫在html的style標(biāo)簽中,還有一種是外鏈,通過link的方式引用。而我們在開發(fā)環(huán)境中,css是作為js的模塊打包進(jìn)js文件中的。而且js要使用樣式,必須在html中插入style標(biāo)簽,然后把樣式以字符串的形式插入標(biāo)簽內(nèi)。所以這里需要用到兩個加載器,首先用css-loader把樣式讀取到j(luò)s的模塊中,然用style-loader寫入style標(biāo)簽中。所以也就出現(xiàn)了css-loader和style-loader成對使用的情況。對于同時使用多個加載器的情況,它們的調(diào)用順序是從右向左的。也就是說最先使用的要寫在最右邊,對于新式這個例子來說,就是style-loader!css-loader這樣寫。關(guān)于style-loader這個加載器,其實(shí)它還有一個少被人提起,卻非常有用的功能--熱替換,這部分內(nèi)容后面再細(xì)說

有人不禁要問,既然css可以直接用link的方式使用,為什么不把css打包成獨(dú)立的css文件呢?這樣我就不需要用style-loader了,而且把樣式內(nèi)聯(lián)在html中,看著不舒服。好吧,這就不得不引出webpack中的第四個概念了---插件

四、 插件 plugins

They also serve the purpose of doing anything else that a loader cannot do.

插件用于完成一些載器所不能做的事情。

其實(shí)這樣解釋不并是很嚴(yán)謹(jǐn),但是插件,確實(shí)使的webpack更加強(qiáng)大了?;氐角罢f的獨(dú)立樣式的問題,結(jié)合插件來做。

先安裝extract-text-webpack-plugin 這個插件

npm install --save-dev extract-text-webpack-plugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var node_modules_dir = path.resolve(__dirname, '../node_modules');
 
module.exports = {
    entry: {
        home:'./src/home.es6'
    },
    module: {
        rules:[{
                test:/\.css/,
                use: ExtractTextPlugin.extract({
                  fallback: "style-loader",
                  use: ["css-loader","postcss-loader"]
                })
            }
        ]
    },
    output: {
        path: path.resolve(__dirname,"../dist"),
        filename: 'js/[name][hash:7].js'
    },
    plugins: [
        new ExtractTextPlugin({
            filename: "css/[name].[contenthash].css"
        }),
        new webpack.optimize.UglifyJsPlugin()
    ],
}

 new webpack.optimize.UglifyJsPlugin() //用來壓縮代碼,這個是webpack送的,不需要單獨(dú)安裝, new ExtractTextPlugin 用來提取css到一個獨(dú)立的樣式文件,這個插件需要自己安裝,還要在loader中進(jìn)行相應(yīng)的改動,配合使用才能生效。值得注意的是,這樣一來,就牲犧了css的熱替換能力了。不過沒有關(guān)系,這個插件一般用在生產(chǎn)環(huán)境。

Hot Module Replacement  (HMR熱替換) 

這應(yīng)當(dāng)屬于webpack中比較高級的內(nèi)容了,但是在開發(fā)中,結(jié)合熱替換一起使用,會很方便。最簡單的使用方式是通過 webpack-dev-server --hot --inline 

關(guān)于這一部分的內(nèi)容,參考我以前寫的一篇文章。官方介紹移步這里這里需要指出的是,并不是加了--hot就可以實(shí)現(xiàn)熱替換,這需要對應(yīng)的加載器支持“熱替換”才行的。

比如前面說的樣式,style-loader是可以支持熱替換的。而且對于js來說,雖然webpack不需要額外的加載器就可以進(jìn)模塊化,但是并不支持“熱替換", 如果使用react.js的話,可以用react-hot-loader,如果用Vue的話,可以用vue-loader。 如果該加載器不支持熱替,會降級為自動刷新。因此,熱替換,并不是自動刷新哦。

總結(jié)

 webpack3還比較新,如果之前使用webpack2的項(xiàng)目,直接升級到webpack3的話,需要小心了,有些加載器和插件可能不支持webpack3. 比如提取css為獨(dú)立文件的插件,就不支持。webpack-dev-server也不支持 (至少在我寫這篇文章的時候還是不支持的),但是不能因噎廢食,新技術(shù)最終會取替舊技術(shù),這是行業(yè)趨勢。安于現(xiàn)狀,只會被淘汰。webpack的學(xué)習(xí)最好是自己寫一個簡單項(xiàng)目,把文章提到的和自己學(xué)到的loader,plugin都試試。把基本的概念和用法型明白之后,可以安裝別人寫的比較優(yōu)盤的項(xiàng)目拿來對照學(xué)習(xí),比如Vue-cli??纯葱袠I(yè)大牛們,是怎么配置webpack的,他們都用了哪些插件和加載器。最后,我也提供一下自己練習(xí)的項(xiàng)目,做為本篇的結(jié)尾。https://github.com/bjtqti/font-end-boilerplate.git 

http://www.cnblogs.com/afrog/p/7130561.html