Webpack是模塊打包工具。css
Webpack已成爲現代Web開發最重要的工具之一。首先,它是一個JavaScript模板打包工具,他能轉換全部的前端資源,如HTML和CSS,甚至圖片。它可讓你更好地控制你應用程序的HTTP請求數量,並容許你使用其餘的風格資源(如Jade,Sass和ES6)。Webpack還容許你輕鬆地從npm上使用軟件包。html
本文面向剛剛接觸Webpack的初學者,主要介紹Webpack的初始設置和配置、模板、加載程序、插件、代碼拆分和熱模塊替換。若是你發現視頻教程對你更有幫助,我強烈推薦Glen Maddern’s的Webpack from First Principles做爲一個起點,瞭解是什麼使得Webpack那麼特別。前端
接下來,你須要有Node.js installed環境,你也能夠 download the demo app from our Github reponode
讓咱們用npm
新建一個項目並初始化,安裝Webpack
:webpack
mkdir webpack-demo cd webpack-demo npm init -y npm install webpack@beta --save-dev mkdir src touch index.html src/app.js webpack.config.js
編輯這些文件:git
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Hello webpack</title> </head> <body> <div id="root"></div> <script src="dist/bundle.js"></script> </body> </html>
// src/app.js const root = document.querySelector('#root') root.innerHTML = `<p>Hello webpack.</p>`
// webpack.config.js const webpack = require('webpack') const path = require('path') const config = { context: path.resolve(__dirname, 'src'), entry: './app.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, module: { rules: [{ test: /\.js$/, include: path.resolve(__dirname, 'src'), use: [{ loader: 'babel-loader', options: { presets: [ ['es2015', { modules: false }] ] } }] }] } } module.exports = config
上面的配置是一個常見的起點,它指示webpack
將咱們的入口點src/app.js
編譯輸出到/dist/bundle.js
中,全部的.js
文件將經過Babel
從ES2015
轉換到ES5
。github
爲了讓它運行,咱們須要安裝三個包:babel-core
,Webpack
模塊和資源轉換器——babel-loader
和預設的babel-preset-es2015
。{ modules: false }
啓用Tree Shaking把咱們包中不被使用的輸出刪除,從而下降文件大小。web
npm install babel-core babel-loader babel-preset-es2015 --save-dev
最後,將package.json
文件中的script
部分替換爲:npm
"scripts": { "start": "webpack --watch", "build": "webpack -p" },
在命令行中運行npm start
來監視模式啓動webpack
——每當咱們src
目錄中的.js
文件更改時,都會從新編譯輸出到bundle
中。控制檯中的輸出會告訴咱們正在建立的包,重要的是要注意包的數量和大小。
如今你應該能夠在瀏覽器中加載index.html
,並使用「Hello webpack」。json
open index.html
打開dist/bundle.js
查看webpack
作了什麼,頂部是webpack
的模板引導代碼,底部是咱們的模板。也許你對這不會有很深入的印象,但若是你跟着進度學到了這裏,你能夠運用ES6 module
和webpack
生產一個能在全部瀏覽器中運行的用於生產的包。
輸入命令行Ctrl + C
中止webpack
,並運行npm run build
用於在生產模式下編譯咱們的包。
請注意,此時包的大小已經從2.16kB降低到585字節。
再查看一下dist/bundle.js
,你會看到一個醜惡的代碼,咱們的包已經壓縮或醜化(uglify/minify),代碼運行效果是同樣的,但它並不符合最少字符須要。
開箱即用的webpack
知道如何使用各類格式的JavaScript模塊,最顯著的兩種是:
ES2015的import
語句
CommonJS的require()
語句
咱們能夠經過安裝lodash並從app.js
導入它來測試一下:
npm install lodash --save
// src/app.js import {groupBy} from 'lodash/collection' const people = [{ manager: 'Jen', name: 'Bob' }, { manager: 'Jen', name: 'Sue' }, { manager: 'Bob', name: 'Shirley' }, { manager: 'Bob', name: 'Terrence' }] const managerGroups = groupBy(people, 'manager') const root = document.querySelector('#root') root.innerHTML = `<pre>${JSON.stringify(managerGroups, null, 2)}</pre>`
運行npm start
啓動webpack
,刷新一下index.html
頁面,你能夠看到按manager
排序的人數組。
讓咱們來把people
數組移動到本身的people.js
文件中:
// src/people.js const people = [{ manager: 'Jen', name: 'Bob' }, { manager: 'Jen', name: 'Sue' }, { manager: 'Bob', name: 'Shirley' }, { manager: 'Bob', name: 'Terrence' }] export default people
咱們可使用相對路徑簡單地從app.js
導入它。
// src/app.js import {groupBy} from 'lodash/collection' import people from './people' const managerGroups = groupBy(people, 'manager') const root = document.querySelector('#root') root.innerHTML = `<pre>${JSON.stringify(managerGroups, null, 2)}</pre>`
注意:沒有相對路徑的導入,如lodash/collection
是從npm
安裝到node_modules
的模塊,本身寫的模塊是須要加一個相對路徑,如./people
來告訴webpack
區分好各個模塊。
咱們已經介紹了babel-loader
——不少loders之一,經過配置用於告訴webpack
當遇到不一樣文件類型的import
時要怎麼作。你能夠把過個loader
整合在一塊兒,咱們能夠經過從JavaScript
中導入Sass
來很好地瞭解這是如何工做的。
這種轉換涉及到三個獨立的loader
和node-sass
庫:
npm install css-loader style-loader sass-loader node-sass --save-dev
在webpack.config.js
中給咱們的.scss
文件添加新的配置規則:
// webpack.config.js rules: [{ test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] }, { // ... }]
注意:每次更改
webpack.config.js
中的任何規則時,都須要使用Ctrl+C
和npm start
命令從新啓動項目。
loader
數組會以相反的順序執行:
sass-loader
把Sass轉換成CSS
css-loader
把CSS解析到JavaScript中,並分解全部的依賴關係
style-loader
把咱們的CSS輸出到文檔中的<style>標籤中
你能夠把它當作函數調用,一個loader
的輸出會做爲input
輸入下一個。
styleLoader(cssLoader(sassLoader('source')))
讓咱們來添加一個Sass源文件:
/* src/style.scss */ $bluegrey: #2B3A42; pre { padding: 20px; background: $bluegrey; color: #dedede; text-shadow: 0 1px 1px rgba(#000, .5); }
你如今能夠從JavaScript中直接請求Sass,從app.js
的頭部引入:
// src/app.js import './style.scss' // ...
刷新一下index.html
你就會看到剛添加的樣式了。
咱們剛剛從JavaScript中導入了Sass文件,做爲一個模塊。
打開dist/bundle.js
文件並搜索「pre {
。事實上,咱們的Sass已經被編譯成一個CSS字符串,並保存爲咱們的bundle
中的一個模板。當咱們在JavaScript中導入此模板時,style-loader
會將該字符串輸出到嵌入的<style>
標籤中。
我知道你確定是在想,爲何會這樣?
我不會在這裏深刻討論這個話題,可是你能夠從如下幾個方面考慮:
你可能但願包含在項目中的JavaScript組件依賴於其餘資源(HTML、CSS、Images、SVG)來正常運行,若是這些資源能夠整合在一塊兒,那麼導入和使用就會容易不少。
消除死代碼:當JS代碼不須要導入JS組件時,將再也不導入CSS,生成的bundle
只會包含執行某些操做的代碼。
CSS模塊:CSS的全局命名空間使得開發者很難確信CSS的一個更改不會產生任何的反作用。CSS modules經過在默認狀況下使CSS local和暴露在JavaScript下使用的惟一類名來改變這一問題。
經過巧妙的方法打包/拆分代碼,來較少HTTP請求數量。
咱們可以看到的最後一個關於loader
的例子是使用url-loader
處理圖片。
在標準的HTML文檔中,當瀏覽器遇到一個<img>
標籤或background-image
屬性時會抓取圖片。使用webpack,當遇到小圖片的時候,你能夠經過將圖片源做爲字符串存儲在JavaScript中來優化小圖片,這樣,你預加載它們,瀏覽器就不用爲了提取它們而發起單獨的請求了。
npm install file-loader url-loader --save-dev
添加一個加載圖片的規則:
// webpack.config.js rules: [{ test: /\.(png|jpg)$/, use: [{ loader: 'url-loader', options: { limit: 10000 } // Convert images < 10k to base64 strings }] }, { // ... }]
從新運行項目:Ctrl + C
和npm start
使用下面命令下載test image
curl https://raw.githubusercontent.com/sitepoint-editors/webpack-demo/master/src/code.png --output src/code.png
你如今能夠在app.js
的頭部導入圖片源:
// src/app.js import codeURL from './code.png' const img = document.createElement('img') img.src = codeURL img.style.backgroundColor = "#2B3A42" img.style.padding = "20px" img.width = 32 document.body.appendChild(img) // ...
這將包括一張圖片,其中src
屬性包含圖片自己的data URL
:
<img src="data:image/png;base64,iVBO..." style="background: #2B3A42; padding: 20px" width="32">
此外,因爲使用url()
引用的css-loader
圖片也經過url-loader
運行,這就好像直接在CSS中嵌入它們。
/* src/style.scss */ pre { background: $bluegrey url('code.png') no-repeat center center / 32px 32px; }
編譯成爲:
pre { background: #2b3a42 url("data:image/png;base64,iVBO...") no-repeat scroll center center / 32px 32px; }
你如今應該能夠看到loders
是如何幫助在資源間創建一個依賴關係樹的,這是webpack首頁上的圖片展現:
儘管JavaScript是入口點,但webpack注意到你的其餘資源(如HTML、CSS和SVG)都具備各自的依賴關係——這些依賴關係是應該視爲構建過程的一部分的。
做者:Mark Brown
原文連接:A Beginner’s Guide to Webpack 2 and Module Bundling