還學(xué)不會(huì)webpack秩冈?看這篇本缠!

摘要: webpack入門教程。

  • 原文:[還學(xué)不會(huì)webpack漩仙?看這篇搓茬!]
  • 作者:Fundebug

版權(quán)歸原作者所有。

Webpack已經(jīng)流行好久了队他,但很多同學(xué)使用webpack時(shí)還是一頭霧水,一下看到那么多文檔峻村、各種配置麸折、各種loader、plugin立馬就暈頭轉(zhuǎn)向了粘昨。我也不例外垢啼,以至于很長一段時(shí)間對(duì)webpack都是一知半解的狀態(tài)。但是想要繼續(xù)做好前端张肾,webpack是必須得跨過的一道坎,其實(shí)掌握webpack并不難,只是我們沒有找到正確的方法担忧。本文就是我自己在學(xué)習(xí)webpack時(shí)的一點(diǎn)心得體會(huì)岗喉,供大家參考

什么是webpack?

一句話概括:webpack是一個(gè)模塊打包工具(module bundler)芍秆。重點(diǎn)在于兩個(gè)關(guān)鍵詞“模塊”和“打包”惯疙。什么是模塊呢?我們回顧一下曾經(jīng)的前端開發(fā)方式妖啥,js文件通過script標(biāo)簽靜態(tài)引入霉颠,js文件之間由于沒有強(qiáng)依賴關(guān)系,如果文件1要用到文件2的某些方法或變量荆虱,則必須將文件1放到文件2后面加載蒿偎。隨著項(xiàng)目的增大,js文件之間的依賴關(guān)系越發(fā)錯(cuò)綜復(fù)雜怀读,維護(hù)難度也越來越高诉位。這樣的困境驅(qū)使著前端工程師們不斷探索新的開發(fā)模式,從后端愿吹、app的開發(fā)模式中我們獲得靈感不从,為什么不能引入“模塊”的概念讓js文件之間可以相互引用呢?模塊1要使用模塊2的功能犁跪,只需要在該模塊1中明確引用模塊2就行了椿息,而不用擔(dān)心它們的排列順序歹袁。基于這種理念寝优,CommonJSAMD規(guī)范被創(chuàng)造了出來条舔,然后有了require.js、system.js這樣的前端模塊加載工具和node的模塊系統(tǒng)乏矾,直到現(xiàn)在流行的es6 module孟抗。

模塊的引入解決了文件之間依賴引用的問題,而打包則解決了文件過多的問題钻心。當(dāng)項(xiàng)目規(guī)模增大凄硼,模塊的數(shù)量數(shù)以千計(jì),瀏覽器如果要加載如此多的文件捷沸,頁面加載的速度勢(shì)必會(huì)受影響摊沉,而bundler可以把多個(gè)關(guān)聯(lián)的文件打包到一起從而大量減少文件的數(shù)量提高網(wǎng)頁加載性能。提供模塊化的開發(fā)方式和編譯打包功能就是webpack的核心痒给,其他很多功能都圍繞它們展開说墨。

核心概念

Module(模塊)

對(duì)于webpack,模塊不僅僅是javascript模塊苍柏,它包括了任何類型的源文件尼斧,不管是圖片、字體试吁、json文件都是一個(gè)個(gè)模塊棺棵。Webpack支持以下的方式引用模塊:

Dependency Graph(依賴關(guān)系圖)

所謂的依賴關(guān)系圖是webpack根據(jù)每個(gè)模塊之間的依賴關(guān)系遞歸生成的一張內(nèi)部邏輯圖,有了這張依賴關(guān)系圖潘悼,webpack就能按圖索驥把所有需要模塊打包成一個(gè)bundle文件了律秃。

Entry(入口)

繪制依賴關(guān)系圖的起始文件被稱為entry。默認(rèn)的entry為 ./src/index.js治唤,或者我們可以在配置文件中配置棒动。entry可以為一個(gè)也可以為多個(gè)。

module.exports = {
  entry: './src/index.js'
}

或者

module.exports = {
  entry: {
    main: './src/index.js'
  }
};

多個(gè)entry宾添,一個(gè)chunk
我們也可以指定多個(gè)獨(dú)立的文件為entry船惨,但將它們打包到一個(gè)chunk中,此種方法被稱為 multi-main entry缕陕,我們需要傳入文件路徑的數(shù)組:

module.exports = {
  entry: ['./src/index.js', './src/index2.js', './src/index3.js']
}

但是改種方法的靈活性和擴(kuò)展性有限粱锐,因此并不推薦使用。

多個(gè)entry扛邑,多個(gè)chunk

如果有多個(gè)entry怜浅,并且每個(gè)entry生成對(duì)應(yīng)的chunk,我們需要傳入object:

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js'
  }
};

這種寫法有最好的靈活性和擴(kuò)展性,支持和其他的局部配置(partial configuration)進(jìn)行合并恶座。比如將開發(fā)環(huán)境和生產(chǎn)的配置分離搀暑,并抽離出公共的配置,在不同的環(huán)境下運(yùn)行時(shí)再將環(huán)境配置和公共配置進(jìn)行合并跨琳。

Output(出口)

有了入口自点,對(duì)應(yīng)的就有出口。顧名思義脉让,出口就是webpack打包完成的輸出桂敛,output定義了輸出的路徑和文件名稱。Webpack的默認(rèn)的輸出路徑為 ./dist/main.js溅潜。同樣术唬,我們可以在配置文件中配置output:

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

多個(gè)entry的情況
當(dāng)有多個(gè)entry的時(shí)候,一個(gè)entry應(yīng)該對(duì)應(yīng)一個(gè)output滚澜,此時(shí)輸出的文件名需要使用替換符(substitutions)聲明以確保文件名的唯一性碴开,例如使用入口模塊的名稱:

module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}

最終在 ./dist 路徑下面會(huì)生成 app.js和search.js兩個(gè)bundle文件。

Loader

Webpack自身只支持加載js和json模塊博秫,而webpack的理念是讓所有的文件都能被引用和加載并生成依賴關(guān)系圖,所以loader出場了眶掌。Loader能讓webpack能夠去處理其他類型的文件(比如圖片挡育、字體文件、xml)朴爬。我們可以在配置文件中這樣定義一個(gè)loader:
webpack.config.js

module.exports = {
  module: {
    rules: [
      { 
        test: /\.txt$/, 
        use: 'raw-loader' 
      }
    ]
  }
};

其中test定義了需要被轉(zhuǎn)化的文件或者文件類型即寒,use定義了對(duì)該文件進(jìn)行轉(zhuǎn)化的loader的類型。該條配置相當(dāng)于告訴webpack當(dāng)遇到一個(gè)txt文件的引用時(shí)(使用require或者import進(jìn)行引用)召噩,先用raw-loader轉(zhuǎn)換一下該文件再把它打包進(jìn)bundle母赵。

還有其他各種類型的loader,比如加載css文件的css-loader具滴,加載圖片和字體文件的file-loader凹嘲,加載html文件的html-loader,將最新JS語法轉(zhuǎn)換成ES5的babel-loader等等构韵。完整列表請(qǐng)參考 webpack loaders周蹭。

Plugin(插件)

Plugin和loader是兩個(gè)比較混淆和模糊的概念。Loader是用來轉(zhuǎn)換和加載特定類型的文件疲恢,所以loader的執(zhí)行層面是單個(gè)的源文件凶朗。而plugin可以實(shí)現(xiàn)的功能更強(qiáng)大,plugin可以監(jiān)聽webpack處理過程中的關(guān)鍵事件显拳,深度集成進(jìn)webpack的編譯器棚愤,可以說plugin的執(zhí)行層面是整個(gè)構(gòu)建過程。Plugin系統(tǒng)是構(gòu)成webpack的主干杂数,webpack自身也基于plugin系統(tǒng)搭建宛畦,webpack有豐富的內(nèi)置插件和外部插件瘸洛,并且允許用戶自定義插件。官方列出的插件有 這些刃永。

與loader不同货矮,使用plugin我們必須先引用該插件,例如:

const webpack = require('webpack'); // 用于引用webpack內(nèi)置插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 外部插件

module.exports = {
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

實(shí)踐

了解webpack的基本概念之后斯够,我們通過實(shí)踐來加深理解囚玫。接下來,我們使用webpack搭建一個(gè)簡易的react腳手架读规。

創(chuàng)建項(xiàng)目

首先創(chuàng)建react-webpack-starter項(xiàng)目并使用 npm init 初始化抓督。

安裝依賴

安裝react

npm i react react-dom

安裝webpack相關(guān)

npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader

安裝webpack-cli后可以在命令行中執(zhí)行webpack命令;webpack-dev-server提供了簡易的web服務(wù)器束亏,并且在修改文件之后自動(dòng)執(zhí)行webpack的編譯操作并自動(dòng)刷新瀏覽器铃在,省去了重復(fù)的手動(dòng)操作;html-webpack-plugin用于自動(dòng)生成index.html文件碍遍,并且在index.html中自動(dòng)添加對(duì)bundle文件的引用定铜;style-loader和css-loader用于加載css文件。

安裝babel相關(guān)
由于react中使用了class, import這樣的es6的語法怕敬,為了提高網(wǎng)站的瀏覽器兼容性揣炕,我們需要用babel轉(zhuǎn)換一下。

npm i -D @babel/core @babel/preset-env @babel/preset-react babel-loader

其中@babel/core是babel的核心模塊东跪,包含了babel的核心功能畸陡;@babel/preset-env支持轉(zhuǎn)換ES6以及更新的js語法,并且可根據(jù)需要兼容的瀏覽器類型選擇加載的plugin從而精簡生成的代碼虽填;@babel/preset-react包含了babel轉(zhuǎn)換react所需要的plugin丁恭;babel-loader是webpack的babel加載器。

配置webpack

在項(xiàng)目根目錄下面新建webpack.config.js斋日,內(nèi)容如下:
webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_module/,
        use: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'] // 注意排列順序牲览,執(zhí)行順序與排列順序相反
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
}

其中HtmlWebpackPlugin使用自定義的模版來生成html 文件,模版的內(nèi)容如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>My React App</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>
配置babel

在項(xiàng)目根目錄下面新建.babelrc文件桑驱,配置我們安裝的兩個(gè)babel preset:
.babelrc

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}
生成react應(yīng)用根節(jié)點(diǎn)

./src/index

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(<App />, document.getElementById('app'));

./src/component/App.js

import './App.css';

export default class App extends Component {
  render() {
    return (
      <div>
        my react webpack starter
      </div>
    )
  }
}

./src/components/App.css

body{
  font-size: 60px;
  font-weight: bolder;
  color: red;
  text-transform: uppercase;
}

配置 package.json

最后竭恬,在package.json文件里面加上兩個(gè)scripts,用來運(yùn)行開發(fā)服務(wù)器和打包:
package.json

"scripts": {
  "start": "webpack-dev-server --mode development --open --hot",
  "build": "webpack --mode production"
}

注意熬的,我們啟用了webpack-dev-server的模塊熱更新功能(HMR)痊硕,進(jìn)一步提高我們的開發(fā)效率。
到此一個(gè)最簡版本的react腳手架就搭建完成了押框,我們運(yùn)行一下看看效果:

image.png

是不是沒有想象中的那么難呢岔绸?當(dāng)然webpack還有很多其他的功能和特性需要掌握,希望在參考本文之后大家進(jìn)一步的學(xué)習(xí)更加順利 ??。
本文demo地址:https://github.com/MudOnTire/webpack-tutorial

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盒揉,一起剝皮案震驚了整個(gè)濱河市晋被,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刚盈,老刑警劉巖羡洛,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異藕漱,居然都是意外死亡欲侮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門肋联,熙熙樓的掌柜王于貴愁眉苦臉地迎上來威蕉,“玉大人,你說我怎么就攤上這事橄仍∪驼牵” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵侮繁,是天一觀的道長虑粥。 經(jīng)常有香客問我,道長宪哩,這世上最難降的妖魔是什么舀奶? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮斋射,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘但荤。我一直安慰自己罗岖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布腹躁。 她就那樣靜靜地躺著桑包,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纺非。 梳的紋絲不亂的頭發(fā)上哑了,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音烧颖,去河邊找鬼弱左。 笑死,一個(gè)胖子當(dāng)著我的面吹牛炕淮,可吹牛的內(nèi)容都是我干的拆火。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼们镜!你這毒婦竟也來了币叹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤模狭,失蹤者是張志新(化名)和其女友劉穎颈抚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嚼鹉,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贩汉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了反砌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雾鬼。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宴树,靈堂內(nèi)的尸體忽然破棺而出策菜,到底是詐尸還是另有隱情,我是刑警寧澤酒贬,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布又憨,位于F島的核電站,受9級(jí)特大地震影響锭吨,放射性物質(zhì)發(fā)生泄漏蠢莺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一零如、第九天 我趴在偏房一處隱蔽的房頂上張望躏将。 院中可真熱鬧,春花似錦考蕾、人聲如沸祸憋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚯窥。三九已至,卻和暖如春塞帐,著一層夾襖步出監(jiān)牢的瞬間拦赠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工葵姥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荷鼠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓榔幸,卻偏偏與公主長得像颊咬,于是被迫代替她去往敵國和親务甥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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

  • 目錄第1章 webpack簡介 11.1 webpack是什么喳篇? 11.2 官網(wǎng)地址 21.3 為什么使用 web...
    lemonzoey閱讀 1,731評(píng)論 0 1
  • 作者:小 boy (滬江前端開發(fā)工程師)本文原創(chuàng)麸澜,轉(zhuǎn)載請(qǐng)注明作者及出處挺尿。原文地址:https://www.smas...
    iKcamp閱讀 2,747評(píng)論 0 18
  • 寫在開頭 先說說為什么要寫這篇文章, 最初的原因是組里的小朋友們看了webpack文檔后, 表情都是這樣的: (摘...
    Lefter閱讀 5,279評(píng)論 4 31
  • 4月份在異常忙碌的節(jié)奏中結(jié)束了馁害,不過拿到了兩個(gè)重要的結(jié)果窄俏,一是成都演說生產(chǎn)力課程,帶領(lǐng)小組拿到冠軍碘菜,二是...
    演講教練兵哥閱讀 894評(píng)論 0 0
  • 感恩父母健在 感恩老公每月還房貸 感恩老公跟我甜蜜有愛 感恩老公對(duì)我不離不棄 感恩老公主動(dòng)給我發(fā)信息語音聊天 感恩...
    rong2018閱讀 293評(píng)論 0 0