簡單-webpack學(xué)習(xí)筆記

什么是Webpack只怎?

按照官方文檔的解釋,Webpack就是個模塊打包工具怜俐,將模塊及其依賴打包生成靜態(tài)資源身堡。在Webpack的機(jī)制里,所有的資源都是模塊(js,css,圖片等)拍鲤,而且可以通過代碼分隔(Code Splitting)的方法異步加載贴谎,實現(xiàn)性能上的優(yōu)化。

為什么要使用Webpack

1 與react一類模塊化開發(fā)的框架搭配著用比較好季稳。
2 屬于配置型的構(gòu)建工具擅这,比較用容易上手,160行代碼可大致實現(xiàn)gulp400行才能實現(xiàn)的功能景鼠。
3 webpack使用內(nèi)存來對構(gòu)建內(nèi)容進(jìn)行緩存蕾哟,構(gòu)建過程中會比較快。

Webpack的配置


Webpack的配置主要為了這幾大項目:

  • entry:js入口源文件
  • output:生成文件
  • module:進(jìn)行字符串的處理
  • resolve:文件路徑的指向
  • plugins:插件莲蜘,比loader更強(qiáng)大谭确,能使用更多webpack的api

配置中常用的loader:

  • 處理樣式,轉(zhuǎn)成css票渠,如:less-loader, sass-loader
  • 圖片處理逐哈,如: url-loader, file-loader。兩個都必須用上问顷。否則超過大小限制的圖片無法生成到目標(biāo)文件夾中
  • 處理js昂秃,將es6或更高級的代碼轉(zhuǎn)成es5的代碼。如: babel-loader杜窄,babel-preset-es2015肠骆,babel-preset-react
  • 將js模塊暴露到全局,使用expose-loader

常用Plugins介紹

  • 代碼熱替換, HotModuleReplacementPlugin
  • 生成html文件塞耕,HtmlWebpackPlugin
  • 將css成生文件蚀腿,而非內(nèi)聯(lián),ExtractTextPlugin
  • 報錯但不退出webpack進(jìn)程,NoErrorsPlugin
  • 代碼丑化莉钙,UglifyJsPlugin廓脆,開發(fā)過程中不建議打開
  • 多個 html共用一個js文件(chunk),可用CommonsChunkPlugin
  • 清理文件夾磁玉,Clean
  • 調(diào)用模塊的別名ProvidePlugin停忿,例如想在js中用$,如果通過webpack加載蚊伞,需要將$與jQuery對應(yīng)起來

CommonJS 與 AMD 支持

Webpack 對 CommonJS 的 AMD 的語法做了兼容, 方便遷移代碼 不過實際上, 引用模塊的規(guī)則是依據(jù) CommonJS 來的

require('lodash') // 從模塊目錄查找
require('./file') // 按相對路徑查找

AMD 語法中, 也要注意, 是按 CommonJS 的方案查找的

define (require, exports. module) ->
require('lodash') # commonjs 當(dāng)中這樣是查找模塊的 
require('./file')

重點解釋

Chunk的概念

chunk是使用Webpack過程中最重要的幾個概念之一席赂。在Webpack打包機(jī)制中,編譯的文件包括entry(入口时迫,可以是一個或者多個資源合并而成氧枣,由html通過script標(biāo)簽引入)和chunk(被entry所依賴的額外的代碼塊,同樣可以包含一個或者多個文件)别垮。從頁面加速的角度來講便监,我們應(yīng)該盡可能將所有的js打包到一個bundle.js之中,但是總會有一些功能是使用過程中才會用到的碳想。出于性能優(yōu)化的需要烧董,對于這部分資源我們可以做成按需加載,通過require.ensure方法實現(xiàn)

require.ensure([], function(require) { 
var dialog = require('./components/dialog'); 
// todo ...
 });

而固定的公用代碼則獨立打包到trunk之中胧奔。在Webpack的配置中逊移,我們可以通過CommonsChunkPlugin插件對指定的chunks進(jìn)行公共模塊的提取。我們指定好生成文件的名字龙填,以及想抽取哪些入口js文件的公共代碼胳泉,webpack就會自動幫我們合并好

var chunks = Object.keys(entries); 
plugins: [ 
 new webpack.optimize.CommonsChunkPlugin({
 name: 'vendors', // 將公共模塊提取,生成名為`vendors`的chunk
 chunks: chunks,
 minChunks: chunks.length // 提取所有entry共同依賴的模塊
 })
 ],

Loader

Loader就是資源轉(zhuǎn)換器岩遗。由于在webpack里扇商,所有的資源都是模塊,不同資源都最終轉(zhuǎn)化成js去處理宿礁。針對不同形式的資源采用不同的Loader去編譯案铺,這就是Loader的意義。Loader在使用之前必須先通過npm安裝梆靖,然后在config里面通過module配置才能使用控汉。舉個例子:

module: {
 loaders: [{
 test: /\.(png|jpg|jpeg|gif)$/,
 loader: 'url?limit=10000&name=images/[name].[ext]' 
}]}

上述配置中,test的作用是正則匹配返吻,匹配到png或jpg或gif結(jié)尾的文件就采用url-loader來做對應(yīng)的編譯姑子。由于loader都是默認(rèn)以-loader后綴結(jié)尾的,所以可以省略后綴"-loader"测僵,直接寫成url街佑。問號后面是參數(shù),表示10000B以下的圖片直接壓縮成base64編碼,超過10000B的圖片輸出到"images/文件名.拓展名"舆乔。上面的配置也可以這樣寫:

loaders: [{
 test: /\.(png|jpg|jpeg|gif)$/, 
loader: 'url-loader',
 query:{ 
        limit:'10000', 
        name:'images/[name].[ext]'
       }
}]

Plugin

插件的引入和loader差不多岳服,只是插件是以對象的形式引入剂公。像靜態(tài)資源路徑的替換這種功能就能通過插件來處理希俩。比如公用模塊打包到chunk的插件:

var chunks = Object.keys(entries);
plugins: [ 
     new webpack.optimize.CommonsChunkPlugin({
         name: 'vendors', // 將公共模塊提取,生成名為`vendors`的chunk 
         chunks: chunks,
         minChunks: chunks.length // 提取所有entry共同依賴的模塊
 })],

搭建自己的構(gòu)建集成環(huán)境

介紹完上面幾個概念纲辽,我們就可以進(jìn)入動手搭建腳手架的階段了颜武。

項目目錄
假設(shè)我們要搭建的demo項目的目錄結(jié)構(gòu)是這樣的:

- webapp/      # webapp根目錄 
    + node_modules # node_modules 
    - src/ # 開發(fā)目錄 
        - index # index模塊
        + images/ # webapp圖片資源目錄 
        index.html # 模板
        index.js # 模塊entry
        style.less # 樣式表 
webpack.config.js # webpack配置文件 
package.json # 項目依賴文件
config.js # 項目配置文件 
README.md # 項目說明

配置過程
項目目錄確定之后,下面開始來著手配置webpack拖吼。

安裝webpack
首先鳞上,全局安裝webpack,至于怎么裝...額吊档,就不侮辱大家智商了篙议。

安裝依賴
這一步也非常簡單,根據(jù)項目需要用到的依賴 npm i xxx--save-dev怠硼,也可以在配置webpack.config.js的過程中根據(jù)需要安裝鬼贱。

配置webpack
這一步基本是webpack配置的全部內(nèi)容。由于webpack默認(rèn)讀取根目錄下的webpack.config.js文件香璃,所以我們需要在根目錄手動創(chuàng)建这难。看看我們的webpack.config.js配置文件:
1葡秒、首先姻乓,引入我們需要用到的npm模塊

var path = require('path'); //node 原生path模塊 
var webpack = require('webpack'); // webpack 
var glob = require('glob'); // glob模塊,用于讀取webpack入口目錄文件 
var ExtractTextPlugin = require('extract-text-webpack-plugin'); //webpack插件 
var HtmlWebpackPlugin = require('html-webpack-plugin'); //webpack插件 
var OpenBrowserPlugin = require('open-browser-webpack-plugin');//webpack插件 
var CleanPlugin = require('clean-webpack-plugin')//webpack插件眯牧,用于清除目錄文件
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;//處理trunk

2蹋岩、讀取入口文件
按照之前約定的項目目錄,我們的webpack入口文件所在目錄為src/index/index.js学少。所以星澳,先要用glob讀取模塊入口。在這里旱易,我們把讀取目錄定義為一個函數(shù):

var getEntry = function(){
       var entry = {};
       glob.sync('./src/**/*.js')
              .forEach(function(name){
                var start = name.indexOf('/src')+4,
                      end = name.length - 3;
                var n = name.slice(start,end);
                n = n.slice(0,n.lastIndexOf(/'));
      });
      return entry;
}

然后將配置封裝在module.exports禁偎,定義入口entry字段,entry可以為字符串阀坏、對象或者數(shù)組如暖,對應(yīng)單頁面和多頁面應(yīng)用

... 
module.exports = {
         entry: getEntry(), 
          ...
 }

3、定義資源輸出
資源打包輸出的配置在output內(nèi)忌堂,主要包括path盒至、filename、chunkFilename以及publicPath。path是資源輸出路徑枷遂,filename是資源命名規(guī)則樱衷,chunkFilename是公共js打包后輸出的命名,publicPath是靜態(tài)資源的公共路徑酒唉,比如線上CDN地址等矩桂,開發(fā)環(huán)境可以不設(shè)置,這樣CSS中的相對路徑就不會包括publicPath痪伦。在output輸出的時候可以根據(jù)開發(fā)環(huán)境或者生產(chǎn)環(huán)境選擇不同的文件命名方法侄榴,因為一般來說,線上的資源都是要經(jīng)過壓縮的网沾。比如我們定義一個"prod"變量判斷當(dāng)前編譯環(huán)境:

... 
output: { 
path: path.resolve(__dirname, prod ? "./dist" : "./build"), 
filename: prod ? "js/[name].min.js" : "js/[name].js", 
chunkFilename: 'js/[name].chunk.js', 
publicPath: prod ? "http:cdn.mydomain.com" : ""
 },
 ...

[name]的值是根據(jù)入口entry顯示的文件名癞蚕。比如index.js這個入口文件,對應(yīng)的output的[name]值就應(yīng)該是“index”辉哥,當(dāng)然桦山,我們還可以根據(jù)需要使用[hash]、[id]這樣的值醋旦。

4. 定義resolve

為了方便開發(fā)恒水,我們可以定義自己的別名,以便很快捷地引用不同的模塊浑度,別名(alias)的定義是在resolve對象之中寇窑。比如,

resolve: 
{ 
alias:{
 xyz: "/absolute/path/to/file.js"
 }
}

那么箩张,當(dāng)我們在代碼中require('xyz')的時候甩骏,實際上我們是引入'/absolute/path/to/file.js'這個文件。還可以配置extensions對象先慷,使得開發(fā)過程中文件資源的處理可以忽略后綴饮笛。在我們的demo中,是這樣配置的:

       ...
 resolve: { 
        //配置項,設(shè)置忽略js后綴 
        extensions: ['', '.js', '.less', '.css', '.png', '.jpg'],
         root: './src',
       // 模塊別名
       alias: {} 
        },
       ...

5论熙、配置loaders
loader的配置是在module中定義福青。根據(jù)文章開頭部分的介紹,loaders就是定義一個個資源處理器脓诡,demo項目主要用到下面幾個loader:

... 
module: { 
loaders: [{ 
test: /\.(png|jpg|jpeg|gif)$/,
 loader: 'url?limit=10000&name=images/[name].[ext]'
 }, { 
test: /\.less$/, 
loader: ExtractTextPlugin.extract('style', 'css!less')
 }, { 
test: /\.js[x]?$/, exclude: /node_modules/, 
loader: 'babel?presets[]=es2015&presets[]=react'
 }, {
test: /\.html$/, 
loader: 'html?attrs=img:src img:srcset' 
}] }, 
...

ExtractTextPlugin.extract是用來提取出單獨的CSS文件的插件无午,如果不使用這個插件處理樣式文件,CSS會內(nèi)聯(lián)在頁面中祝谚,不利于做樣式表維護(hù);而babel則是用來做es6轉(zhuǎn)換宪迟。

6、定義Plugins

... 
plugins: [ 
    new HtmlWebpackPlugin({ 
          filename: 'index.html',
          template: './src/index/index.html'
      }), 
    new CleanPlugin(['dist', 'build']), // 啟動熱替換 
    new webpack.HotModuleReplacementPlugin(), 
    new ExtractTextPlugin('[name].css', {
       allChunks: true 
    }), 
    new webpack.NoErrorsPlugin(),
    new OpenBrowserPlugin({
         url: 'http://localhost:8080'
     }),
     /* 公共*/
    new CommonsChunkPlugin({ 
      name: 'vendors',
      minChunks: Infinity 
    }),
   ]
 ...

HtmlWebpackPlugin插件用來自動在頁面中注入chunk交惯;HotModuleReplacementPlugin插件是用來做熱替換的次泽,每次開發(fā)環(huán)境下的資源發(fā)生變更之后都會自動重新打包輸出穿仪,不需要重新構(gòu)建;配置OpenBrowserPlugin插件可以在構(gòu)建完成之后自動打開瀏覽器的"localhost:8080"這個路徑意荤;CommonsChunkPlugin插件定義chunk名字啊片,文章開始部分已做詳細(xì)介紹。

8玖像、編譯環(huán)境判斷
在“步驟3”我們需要根據(jù)當(dāng)前的編譯環(huán)境來選擇不同的資源輸出方式紫谷。編譯環(huán)境的判斷可以通過定義node的script來設(shè)置環(huán)境變量。在我們項目根目錄的package.json文件中御铃,定義:

"scripts": 
{
 "dev": "webpack-dev-server", 
"build": "webpack", 
"deploy": "set NODE_ENV=production&&webpack -p --progress --colors" },

這樣的話碴里,終端執(zhí)行"npm run dev" 就相當(dāng)于執(zhí)行 "webpack-dev-server"沈矿。如果執(zhí)行"npm run deploy"上真,那就是編譯生產(chǎn)環(huán)境,node就會設(shè)置環(huán)境變量"NODE_ENV"為"production"羹膳。然后在webpack的配置文件中睡互,通過"process.env.NODE_ENV"就可以讀取到"production"這個值。所以在配置的開頭陵像,我們這樣定義一個局部變量:

var prod = process.env.NODE_ENV === 'production' ? true : false;

之后在配置文件的最后就珠,根據(jù)當(dāng)前的編譯環(huán)境,如果是生產(chǎn)環(huán)境就配置引用壓縮丑化插件"UglifyJsPlugin"醒颖,如果是開發(fā)環(huán)境就配置webpack-dev-server

/ 判斷開發(fā)環(huán)境還是生產(chǎn)環(huán)境,添加uglify等插件 if (process.env.NODE_ENV === 'production') {
 module.exports.plugins = (module.exports.plugins || [])
 .concat([ 
new webpack.DefinePlugin({
 __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
 }), 
new webpack.optimize.UglifyJsPlugin({
 compress: {
 warnings: false
 } }), 
new webpack.optimize.OccurenceOrderPlugin(),
 ]);
 } else { 
module.exports.devtool = 'source-map';
 module.exports.devServer = {
 port: 8080, 
contentBase: './build', 
hot: true, 
historyApiFallback: true, 
publicPath: "", 
stats: { colors: true }, 
plugins: [ new webpack.HotModuleReplacementPlugin() ] 
}; 
}

模塊代碼
至此妻怎,我們已經(jīng)完成了一個基本的webpack配置,接下來就是使用webpack構(gòu)建代碼了泞歉。我們定義的index模塊的代碼入口是index.js逼侦,在Index.js內(nèi)通過require()方式引入不同的資源用于打包:

require('./style.less'); //引入.less預(yù)處理文件
require('./index.html'); //引入同級目錄的index.html文件

然后,執(zhí)行"npm run dev"即可查看本地環(huán)境的靜態(tài)資源效果腰耙。
demo項目的完整代碼可以查看github
參考鏈接
Webpack 入門指迷
webpack使用優(yōu)化(基本篇)
阮一峰16個demo
Webpack 中文指南

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榛丢,一起剝皮案震驚了整個濱河市画机,隨后出現(xiàn)的幾起案子呛谜,更是在濱河造成了極大的恐慌嗦明,老刑警劉巖蚣抗,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侯繁,死亡現(xiàn)場離奇詭異鱼鼓,居然都是意外死亡帮寻,警方通過查閱死者的電腦和手機(jī)悍赢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門援制,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戏挡,“玉大人,你說我怎么就攤上這事隘谣≡鲇担” “怎么了啄巧?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掌栅。 經(jīng)常有香客問我秩仆,道長,這世上最難降的妖魔是什么猾封? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任澄耍,我火速辦了婚禮,結(jié)果婚禮上晌缘,老公的妹妹穿的比我還像新娘齐莲。我一直安慰自己,他們只是感情好磷箕,可當(dāng)我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布选酗。 她就那樣靜靜地躺著,像睡著了一般岳枷。 火紅的嫁衣襯著肌膚如雪芒填。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天空繁,我揣著相機(jī)與錄音殿衰,去河邊找鬼。 笑死盛泡,一個胖子當(dāng)著我的面吹牛闷祥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播傲诵,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼凯砍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掰吕?” 一聲冷哼從身側(cè)響起果覆,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎殖熟,沒想到半個月后局待,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡菱属,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年钳榨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纽门。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡薛耻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赏陵,到底是詐尸還是另有隱情饼齿,我是刑警寧澤饲漾,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站缕溉,受9級特大地震影響考传,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜证鸥,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一僚楞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枉层,春花似錦泉褐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矩欠,卻和暖如春财剖,著一層夾襖步出監(jiān)牢的瞬間悠夯,已是汗流浹背癌淮。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留沦补,地道東北人乳蓄。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像夕膀,于是被迫代替她去往敵國和親虚倒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容

  • GitChat技術(shù)雜談 前言 本文較長产舞,為了節(jié)省你的閱讀時間魂奥,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,698評論 7 110
  • 版權(quán)聲明:本文為博主原創(chuàng)文章哈蝇,未經(jīng)博主允許不得轉(zhuǎn)載。 webpack介紹和使用 一攘已、webpack介紹 1炮赦、由來 ...
    it筱竹閱讀 11,159評論 0 21
  • webpack 介紹 webpack 是什么 為什么引入新的打包工具 webpack 核心思想 webpack 安...
    yxsGert閱讀 6,480評論 2 71
  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看样勃,也希望更多的人看到...
    小小字符閱讀 8,178評論 7 35
  • 前段時間熱播的電視劇《我的前半生》里的老金吠勘,表面看起來是個忠厚本分的老實人性芬,但內(nèi)心卻不像表現(xiàn)出來的那么無害。他敏感...
    十里紅塵閱讀 4,516評論 1 3