Webpack-基礎(chǔ)概念

深入淺出Webpack學(xué)習(xí)筆記

基本概念

常用的構(gòu)建工具

所有的構(gòu)建工具所做的工做大致一樣抬探,都是把源代碼翻譯轉(zhuǎn)換成可執(zhí)行的代碼院领,包括如下內(nèi)容:

  • 代碼轉(zhuǎn)換:TypeScript轉(zhuǎn)換成JavaScript附鸽,SCSS轉(zhuǎn)換成CSS;
  • 文件優(yōu)化:壓縮JavaScript恬总、CSS盆犁、圖片等資源,利用一些優(yōu)化手段诈铛,如搖樹優(yōu)化乙各,移除無關(guān)代碼;
  • 代碼分割:提取多個頁面的公共代碼幢竹、提取首屏不需加載的代碼讓其異步加載耳峦,防止首次進入應(yīng)用等待時間過長;
  • 模塊合并:在一些模塊化的項目中會有很多個模塊和文件妨退,需要構(gòu)建工具把這些模塊文件分類合并成一個文件妇萄;
  • 自動刷新:監(jiān)聽本地代碼蜕企,自動構(gòu)建加載,方便開發(fā)冠句;
  • 代碼校驗:提交代碼前進行代碼規(guī)范檢查轻掩;
  • 自動發(fā)布:更新完代碼后,自動構(gòu)建出線上代碼懦底,推送到線上或其他環(huán)境上唇牧;

Npm Script

Grunt

Gulp

Fis3

Webpack

https://www.webpackjs.com/
Webpack是一個模塊化打包工具,專注于構(gòu)建模塊化項目聚唐,在Webpack眼里一切文件都是模塊丐重,通過Loader轉(zhuǎn)換翻譯文件,通過Plugin注入鉤子杆查,最后輸出由多個模塊組合成的文件扮惦。

之所以一切文件皆模塊,如:JavaScript亲桦、CSS崖蜜、SCSS以及圖片等資源,在Webpack眼中都是模塊客峭,因為這樣可以更好的理清描述各個模塊之間的依賴關(guān)系豫领,方便Webpack對模塊進行打包組合,輸出瀏覽器使用的靜態(tài)資源舔琅。

簡單使用:

module.exports = {
    // 定義入口文件
    entry: './index.js',
    // 定義打包輸出文件
    output: {
        // 最終會把依賴的所有模塊打包成一個bundle.js文件
        filename: './bundle.js'
    }
}

Webpack的優(yōu)點

  • 專注于處理模塊化項目等恐,可以做到開箱即用,一步到位备蚓;
  • 通過Plugin進行擴展课蔬,完整好用又不失靈活;
  • 使用場景豐富星著,除了web端购笆,其他場景也可以;
  • 社區(qū)活躍虚循;
  • 開發(fā)體驗好;

缺點是只能采用模塊化開發(fā)項目样傍。

Rollup

安裝與使用

安裝只需要一行命令横缔,當然可以全局安裝,但是不推薦衫哥。

npm install -D webpack

或者指定版本號:

npm install -D webpack@2.xxx

或者直接安裝最新版:

npm install -D webpack@beta

注意:如果你使用的webpack版本較新茎刚,在webpack4.x測試下,你需要額外安裝一依賴: npm i webpack-cli @webpack-cli/init撤逢。 可以參考webpack-cli

運行Webpack命令:

node_modules/.bin/webpack

或者通過配置npm script來運行:

"script": {
    "start": "webpack --config webpack.config.js"
}

具體如何使用膛锭?

前面有了基本使用方法粮坞,但是具體落實到代碼上該怎么寫?我們可以通過構(gòu)建一個采用CommonJs模塊化的簡單Demo來理解初狰。

建立如下文件:
|-- index.html // 入口文件
|-- show.js // js文件莫杈,里面我們隨便寫一個函數(shù)
|-- main.js // 入口文件
|-- package.json // npm 配置文件
|-- webpack.config.js // webpack 配置文件

index.html

index.html文件內(nèi)容包含了一個script和一個id等于app的div。

<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <div id="app"></div>
        <!-- 導(dǎo)入 Webpack 輸出的 JavaScript 文件 -->
        <script src="./dist/bundle.js"></script>
    </body>
</html>

show.js

show.js文件定義了一個show函數(shù)奢入,該方法將給頁面中的div插入一段文本筝闹;同時,我們利用CommonJs規(guī)范腥光,將該函數(shù)導(dǎo)出关顷。

function show() {
    document.getElementById('app').innerText = 'hello world';
}
module.exports = show;

main.js

main.js文件將show.js引入,并執(zhí)行show函數(shù)武福。

const show = require('./show.js');
show();

webpack.config.js

執(zhí)行webpack構(gòu)建執(zhí)行命令的時候议双,會自動讀取項目根目錄下的webpack.config.js文件,所以我們新建該文件捉片,并指明入口文件和打包輸出文件聋伦。

const path = require('path');
module.exports = {
    entry: './main.js',
    output: {
        filename: './bundle.js',
        path: path.resolve(__dirnam, './dist') // 輸出路徑
    }
}

之所以使用CommonJs規(guī)范來導(dǎo)出webpack配置界睁,是因為webpack運行在Node下觉增,所以我們要使用CommonJs規(guī)范來描述一個如何構(gòu)建的Object對象。

執(zhí)行webpack構(gòu)建命令后翻斟,在項目根目錄下會多出一個dist文件夾逾礁,以及一個bundle.js文件。bundle.js依賴main.jsshow.js兩個文件以及內(nèi)置的webpackBootstrap啟動函數(shù)访惜,從入口文件main.js出發(fā)嘹履,識別出源碼中模塊化導(dǎo)入的語句,把入口文件所依賴的模塊或文件遞歸的打包到一個文件中:bundle.js文件债热。

此時砾嫉,直接打開index.html文件可以正常顯示一段文案。

使用Loader

繼續(xù)前面的內(nèi)容窒篱,這次我們創(chuàng)建一個CSS文件: main.css焕刮。
建立如下文件:
|-- index.html // 入口文件
|-- show.js // js文件,里面我們隨便寫一個函數(shù)
|-- main.js // 入口文件
|-- package.json // npm 配置文件
|-- webpack.config.js // webpack 配置文件
|-- main.css

文件中我們添加一段文本居中的樣式:

#app {
    text-align: center;
}

然后墙杯,我們在main.js引入這個CSS文件:

// 引入css
require('./main.css');

const show = require('./show.js');
show();

編寫工作做完后配并,我們自然的想到直接執(zhí)行webpack構(gòu)建命令,但是此時還不可以高镐,因為Webpack原生僅支持解析JavaScript文件溉旋,如果需要
解析其他類型的文件,需要引入相應(yīng)的Loader嫉髓,這里观腊,我們因為需要解析CSS邑闲,所以需要引入CSS Loader。

手動的去配置webpack.config.js文件:

const path = require('path');
module.exports = {
    entry: './main.js',
    output: {
        filename: './bundle.js',
        path: path.resolve(__dirname, './dist'),
    },
    module: {
        rules: [
            {
                // 用正則匹配css文件
                test: '/\.css$/',
                use: ['style-loader', 'css-loader?minimize'], // minimize:需要進行壓縮
            }
        ]
    }
}

上面我們簡單的配置了一個Loader規(guī)則梧油。

Loader相當于一個翻譯員苫耸,將某個文件源碼翻譯成可執(zhí)行的代碼。配置規(guī)則要求我們在rules數(shù)組中配置一個對象婶溯,指定test屬性值來匹配那些文件需要翻譯鲸阔,通過use來指定需要使用哪些Loader,這里我們使用了style-loadercss-loader迄委。

需要注意的是褐筛,在配置use屬性的時候:

  • use屬性值是一個數(shù)組,數(shù)組中的每個元素為loader的名字叙身,尤其要注意的是渔扎,Loader的執(zhí)行順序是由后到前;
  • 可以給Loader以URL querystring的形式傳遞參數(shù)寨典,比如前面的css-loader?minimize破喻,具體參可以參考所使用的Loader文檔;

理解了Loader后阴孟,我們需要進行安裝相應(yīng)的Loader依賴:

npm install -D style-loader css-loader

所有準備工作做完后瓣赂,我們執(zhí)行構(gòu)建命令:

npm start 或者 node_modules/.bin/webpack

然后再觀察bundle.js文件,會發(fā)現(xiàn)代碼更新了丑掺,并且CSS代碼也被打包了進來谷浅,打開index.html秘血,可以看到居中效果即彪。

這里我們提一下紧唱,CSS之所可以寫在JavaScript中,歸功于剛才引入的style-lader隶校,大概遠離就是將CSS樣式以字符串的形式存儲到JavaScript對象中漏益,然后在網(wǎng)頁執(zhí)行的時候,通過DOM操作動態(tài)的加入到頁面中的<style>標簽中深胳。

當然绰疤,這樣會導(dǎo)致頁面加載時間變長,一定程度上需要我們再去優(yōu)化處理舞终,比如將CSS單獨打包成一個文件轻庆,單獨的輸出,這種操作权埠,我們可以通過Plugin來實現(xiàn)榨了。Plugin也是Webpack的一個重要概念。

Tips:

use的配置中攘蔽,給Loader傳遞參數(shù)除了剛才的寫法,我們還可以傳遞一個對象來實現(xiàn):

module.exports = {
    rules: [
        {
            test: '/\.css$/',
            use: ['style-loader', { loader: 'css-loader', options: { minimize: true } }],
        }
    ]
}

除了在webpack.config.js中配置Loader外呐粘,還可以在代碼文件中直接引入相關(guān)Loader满俗,比如剛才的場景就可以這么處理:

// main.js
requrie('style-loader!css-loader?minimize!.main.css');

這樣就能指定對引入的main.css文件先進行css-loader在采用style-loder轉(zhuǎn)換转捕。

另外,前面我們提到了Loader的記載順序是從后到前的唆垃,所以這里我們必須把css-loader放在后面五芝,也就是先執(zhí)行。因為css-loder是將css代碼編譯辕万,而style-loader是將編譯好的css加到頁面中枢步。

使用Plugin

Plugin是用來擴展Webpack功能的,給Webpack帶來了很大的靈活性渐尿,通過在構(gòu)建流程中注入鉤子來實現(xiàn)醉途。

繼續(xù)前面的操作,我們這次需要優(yōu)化一下砖茸,把main.css代碼打包到單獨的一個文件中隘擎。

我們需要在配置文件webpack.config.js文件中添加plugins屬性,來配置Plugin凉夯。

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: 'main.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist'),
    },
    module: {
        rules: [
            {
                test: '/\.css$/',
                use: ExtractTextPlugin({
                    use: ['css-loader']
                })
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin({
            // 從.js中提取.css文件
            filename: `[name]_[contenthash:8].css`
        })
    ]
}

前面我們引入了新的插件货葬,需要先安裝:

npm install -D extract-text-webpack-plugin

然后我們執(zhí)行構(gòu)建命令,會發(fā)現(xiàn)dist目錄下多出來一個.css結(jié)尾的CSS文件劲够,bundle.js中也沒有CSS代碼了震桶,然后我們手動將該CSS文件引入index.html就可以了。

通過上面的代碼我們可以看到征绎,我們可以通過配置plugins屬性來配置蹲姐,其值是一個數(shù)組,數(shù)組中的每一項是一個實例炒瘸,并且在實例化一個對象的時候淤堵,我們可以通過構(gòu)造函數(shù)傳入這個組件支持的屬性配置。

上面用到的extract-text-webpack-plugin就是一個插件顷扩,用來提取JavaScript中的CSS代碼到一個單獨的文件拐邪,filename屬性指定了輸出的文件名,[name]_[contenthash:8].cssname代表文件名隘截,contenthash:8意思是根據(jù)文件內(nèi)容算出8位hash值扎阶。

該插件的其他配置可以在官網(wǎng)上找到。

使用DevServer

到目前為止婶芭,我們也只是做了打包構(gòu)建的工作东臀,在正常的開發(fā)過程中,還需要實現(xiàn)下面的功能:

  • 代碼自動構(gòu)建犀农,自動刷新惰赋,實現(xiàn)文件變化監(jiān)聽;
  • 提供HTTP服務(wù);
  • 支持Source Map赁濒,方便調(diào)試轨奄。

上面提到的,Webpack原生支持1拒炎、3兩點挪拟,對于提供HTTP服務(wù),我們可以借助DevServe击你,是官方提供的一個開發(fā)工具玉组。

DevServer會自動開啟一個本地HTTP服務(wù),同時會自動啟動Webpack構(gòu)建丁侄,并通過WebSocket協(xié)議接受Webpack的文件的實時變更惯雳,做到可以實時預(yù)覽,方便我們開發(fā)绒障。

安裝與啟動

安裝DevServer:

npm install webpack-dev-server

啟動DevServer

webpack-dev-server

啟動成功后吨凑,我們可以在控制臺看到一串輸出:

Project is running at http://localhost:8080

此時,我們訪問http://localhost:8080就會自動執(zhí)行根目錄下的index.html文件户辱。

如果此時訪問鸵钝,我們會發(fā)現(xiàn)引入的bundle.js報404錯誤,是因為DevServer會把Webpack構(gòu)建的文件保存在內(nèi)存中庐镐,在要訪問輸出的文件時候恩商,必須通過HTTP服務(wù)來訪問,并且DevServer不會理會webpack.config.js配置里的output.path屬性必逆,所以我們需要訪問http://localhost/bundle.js才可以怠堪。

修改index.html文件js引用路徑:

<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <div id="app"></div>
        <!-- 修改路徑如下 -->
        <script src="./bundle.js"></script>
    </body>
</html>

實時預(yù)覽

我們現(xiàn)在修改main.jsmain.css名眉、show.js文件中的任一一處粟矿,保存后,瀏覽器便會自動刷新损拢,加載修改后的代碼陌粹。

不過我們需要注意的是,通過DevServer啟動的Webpack會自動開啟文件監(jiān)聽福压,也就是這里的修改代碼自動觸發(fā)刷新頁面的功能掏秩;而如果我們通過webpack來啟動默認是不會開啟監(jiān)聽模式的,只有我們顯示的指明需要開啟監(jiān)聽模式才可以荆姆。

開啟監(jiān)聽模式: webpack --watch

DevServer會讓W(xué)ebpack在構(gòu)建的過程中在JavaScript代碼中注入一個代理客戶端用于控制網(wǎng)頁蒙幻,并通過WebSocket協(xié)議進行通知,如果文件發(fā)生變化胆筒,會立刻告知剛才注入的代理客戶端邮破,代理客戶端收到信息后,執(zhí)行刷新網(wǎng)頁操作。

但是如果我們修改index.html文件不會觸發(fā)網(wǎng)頁刷新操作决乎,這是因為Webpack在啟動時候會以配置中心的entry為口入去遞歸解析entry所以來的文件队询,只有entry本身和其所依賴的文件才會被添加到監(jiān)聽對象中派桩;另外构诚,index.html文件脫離了JavaScript模塊化系統(tǒng),所以Webpack監(jiān)聽不到铆惑。

模塊熱替換

模塊熱替換不同于前面的頁面刷新范嘱,這里的模塊熱替換,可以在不刷新頁面的情況下實現(xiàn)重新加載新的模塊代碼的效果员魏,當有新的模塊代碼時候丑蛤,會將新的替換掉老的,并重新執(zhí)行一遍代碼撕阎,從而做到不刷新頁面受裹,卻可以實時預(yù)覽的效果。

相比較來說虏束,模塊熱更新在開發(fā)體驗和效率上會略勝一籌棉饶。

模塊熱替換默認是關(guān)閉的,我們可以在啟動DevServer的時候帶上--hot參數(shù)來開啟镇匀。

Source Map

通過指定devtool source-map參數(shù)來開啟Source Map功能照藻。

所謂的Source Map就是一份代碼映射。在開過過程中汗侵,我們在瀏覽器看到的代碼都是編譯過的幸缕,所以沒辦法看到未編譯的代碼,很難去調(diào)試晰韵,代碼可讀性很差发乔。

而Source Map可以將編譯前的代碼給映射出來,讓我們可以在源碼上調(diào)試雪猪。Webpack支持生成Source Map栏尚,只需要在啟動的時候帶上--devtool source-map參數(shù)。然后啟動后浪蹂,我們便可以在Chrome開發(fā)者工具下調(diào)試抵栈。

核心概念

  • Entry: 入口配置,Webpack構(gòu)建的第一步將從Entry開始坤次,可以抽象成輸入古劲;
  • Module:在Webpack里一切皆模塊,一個模塊對應(yīng)一個文件缰猴。Webpack會從Entry入手产艾,遞歸的找到所有的依賴模塊;
  • Chunk:代碼塊,一個Chunk由多個模塊組合而成闷堡,用于代碼分割片段隘膘;
  • Loader:模塊轉(zhuǎn)換器,用于把模塊中的內(nèi)容按需求轉(zhuǎn)換成新的內(nèi)容杠览,如ES6轉(zhuǎn)換成ES5弯菊;
  • Plugin:擴展插件,在Webpack構(gòu)建流程中特定時機注入擴展來改變邏輯和結(jié)果踱阿;
  • Output:輸出結(jié)果管钳,在Webpack經(jīng)過前面一系列處理后返回的最終結(jié)果。

Webpack啟動后會從Entry配置的Module開始软舌,遞歸的解析其依賴的所有Module才漆,每找到一個Module,會調(diào)用相應(yīng)的Loader對其進行轉(zhuǎn)換佛点,對Module轉(zhuǎn)換后醇滥,在解析當前Module所依賴的Module,同樣會調(diào)用相應(yīng)的Loader超营。這些Module會以Entry為單位分組鸳玩,一個Entry和其依賴的所有Module都會打包成一個Chunk。最終Webpack會把Chunk轉(zhuǎn)換成文件輸出糟描,整個構(gòu)建流程中怀喉,Webpack會在特定時機執(zhí)行Plugin定義的邏輯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末船响,一起剝皮案震驚了整個濱河市躬拢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌见间,老刑警劉巖聊闯,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異米诉,居然都是意外死亡菱蔬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門史侣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拴泌,“玉大人,你說我怎么就攤上這事惊橱◎礁” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵税朴,是天一觀的道長回季。 經(jīng)常有香客問我家制,道長,這世上最難降的妖魔是什么泡一? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任颤殴,我火速辦了婚禮,結(jié)果婚禮上鼻忠,老公的妹妹穿的比我還像新娘涵但。我一直安慰自己,他們只是感情好粥烁,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布贤笆。 她就那樣靜靜地躺著,像睡著了一般讨阻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上篡殷,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天钝吮,我揣著相機與錄音,去河邊找鬼板辽。 笑死奇瘦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的劲弦。 我是一名探鬼主播耳标,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼邑跪!你這毒婦竟也來了次坡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤画畅,失蹤者是張志新(化名)和其女友劉穎砸琅,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轴踱,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡症脂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了淫僻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诱篷。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖雳灵,靈堂內(nèi)的尸體忽然破棺而出棕所,到底是詐尸還是另有隱情,我是刑警寧澤细办,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布橙凳,位于F島的核電站蕾殴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏岛啸。R本人自食惡果不足惜钓觉,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坚踩。 院中可真熱鬧荡灾,春花似錦、人聲如沸瞬铸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗓节。三九已至荧缘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拦宣,已是汗流浹背截粗。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸵隧,地道東北人绸罗。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像豆瘫,于是被迫代替她去往敵國和親珊蟀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

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