官網給出的概念是:javascript
本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。 根據官網最直觀最出名的那個圖咱們能夠知道,webpack 能夠打包/腳本/圖片/樣式/表 從圖中咱們能夠看出左邊有依賴關係的模塊(MODULES WITH DEPENDENCIES)經過 webpack 打包成了各類靜態資源(STATIC ASSETS)css
經過上面的概念,你是否是已經大概知道了 webpack 是幹什麼的,那麼問題來了,爲何要使用 webpack 呢? 這就說來話長了,那就長話短說,emmmmhtml
爲何使用 webpack,這應該是和前端的發展有關係的,我認爲,webpack 是前端發展到必定階段的必然產物(貌似是一句廢話)。 由於計算機網絡的飛速發展,致使 web 前端也在迅猛發展。最初的實踐方案已經不能知足咱們的需求,因而,愈來愈多的新技術新思想新框架孕育而生,好比:前端
隨着前端項目的複雜度愈來愈高,相互以前的依賴愈來愈多,以及爲了更好的複用代碼,前端也須要用模塊化的思想來組織代碼。java
首先咱們要明白模塊化解決了前端的哪些痛點:node
咱們這裏說的模塊和 Java 的 package
的概念是相似的。邏輯上相關的代碼放在一個包中,每個包都是相互獨立的,不用擔憂命名衝突的問題,若是其餘人想要用這部分功能,直接 import
導入包就好react
因此前端代碼模塊化的實現,會幫咱們解決命名衝突和代碼複用的問題,那麼文件依賴要怎麼處理呢?這就用到了咱們的 webpack,稍後再作介紹。webpack
因此有了模塊,咱們就能夠方便的複用他人的代碼,那麼問題來了,無規矩不成方圓,咱們在使用他人代碼的時候確定是要遵循某種規範,因此就出現了 CommonJS、AMD 和 終極模塊化方案 —— ES6 模塊,這些都是前端模塊化的規範。web
咱們來簡單瞭解一下:正則表達式
node.js 採用的就是 CommonJS 規範,使用 require
的方法同步加載依賴,一個文件就是一個模塊,導入導出格式以下:
// 導入
const moduleA = require('./moduleA');
// 導出
module.exports = moduleA.someFunc;
複製代碼
缺點是加載的模塊是同步的,只有加載完才能執行後面的操做。由於 node.js 的模塊文件通常存在於本地硬盤,因此通常不會出現這個問題,可是在瀏覽器環境該規範就不那麼適用了。
緣由如上,由於 CommonJS 不適用於瀏覽器環境,因此出現了 AMD 規範。該規範異步加載依賴,能夠再聲明的時候指定須要加載的依賴,而且須要當作參數傳入,對於依賴的模塊提早執行,依賴前置。
寫法以下:
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });
複製代碼
ES6 直接在語言層面上實現了模塊化。咱們如今用的最多的就是 ES6 模塊化的實踐方式。
寫法以下:
// 導入
import { readFile } from 'fs';
import React from 'react';
// 導出
export function hello() {};
export default {
// ...
};
複製代碼
如今愈來愈多人也開始使用模塊化的思想寫樣式。好比如今大部分的 CSS 預編譯器都支持 @import
的寫法。將一些公用樣式放在一個文件中,在其餘文件中導入。
三大框架的出現,使咱們不須要像傳統的 JQ 同樣操做 DOM,將精力集中在對數據的處理上。
以及 ES6/7/8 和 TS 的使用越來普及,無疑使咱們的開發效率提升了不少。
可是出現的問題是:這些新興的技術並非在全部的瀏覽器上都適用,都須要將源代碼轉化爲能夠直接在瀏覽器上運行的代碼
因此,webpack 就解決了這個問題。
其實,Gulp/Gunt 和 webpack 應該是沒有可比性的,可是他們均可以稱爲前端自動化構建工具(讓咱們再也不作機械重複的事情,解放咱們的雙手)
可是 Gulp/Gunt 和 webpack 確實乾的不是一件事
Gulp 本質是 task runner,Webpack 是 module bundler
我認爲 Gulp 正如他的定義同樣:基於流的自動化構建工具,定義每個任務,而後自動將一個個任務執行。
而 webpack 是模塊化地組織,模塊化地依賴,而後模塊化地打包。相對來上,場景侷限在前端模塊化打包上。
推薦知乎 寸志 大佬的回答:gulp 有哪些功能是 webpack 不能替代的?
Rollup 是一個和 Webpack 很相似但專一於 ES6 的模塊打包工具。 Rollup 的亮點在於能針對 ES6 源碼進行 Tree Shaking 以去除那些已被定義但沒被使用的代碼,以及 Scope Hoisting 以減少輸出文件大小提高運行性能。 然而 Rollup 的這些亮點隨後就被 Webpack 模仿和實現。 因爲 Rollup 的使用和 Webpack 差很少,這裏就不詳細介紹如何使用了,而是詳細說明它們的差異:
Rollup 是在 Webpack 流行後出現的替代品; Rollup 生態鏈還不完善,體驗不如 Webpack; Rollup 功能不如 Webpack 完善,但其配置和使用更加簡單; Rollup 不支持 Code Spliting,但好處是打包出來的代碼中沒有 Webpack 那段模塊的加載、執行和緩存的代碼。 Rollup 在用於打包 JavaScript 庫時比 Webpack 更加有優點,由於其打包出來的代碼更小更快。 但功能不夠完善,不少場景都找不到現成的解決方案。
package.json
文件能夠手動的建立,也可使用命令自動建立
npm init
複製代碼
webpack 能夠直接使用 npm 安裝,能夠安裝到全局,也能夠安裝到項目
//全局安裝
npm install -g webpack
//安裝到你的項目目錄
npm install --save-dev webpack
複製代碼
推薦你們閱讀這篇文章: 入門 Webpack,看這篇就夠了
我就是跟着這篇文章作的
首先新建一個文件夾,而後在終端打開該文件夾並執行來初始化你的項目,在初始過程當中,會有一些問題幫助你建立 package.json
文件。
npm init
複製代碼
初始化以後咱們還要建立幾個文件來存放咱們的項目文件。
建立一個 app
文件夾來存放咱們打包以前的源文件
建立一個 public
文件夾來存放一個入口文件 index.html
和經過 webpack 打包以後瀏覽器可直接運行的 js
文件
好比咱們在 app
文件夾下建立一個 Greeter.js
文件,裏面有一個方法能夠再頁面顯示文字信息 Hi there and greetings!
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi there and greetings!";
return greet;
};
複製代碼
而後咱們建立一個 main.js
來引入 Greeter.js
這個文件,
瀏覽器的入口 index.html
文件內容以下(其中 bundle.js
是打包以後的文件):
<html lang="en">
<head>
<meta charset="utf-8">
<title>Webpack Sample Project</title>
</head>
<body>
<div id='root'>
</div>
<script src="bundle.js"></script>
</body>
</html>
複製代碼
此時的文件路徑以下
.
├── app
│ ├── Greeter.js
│ └── main.js
├── package.json
├── public
│ ├── bundle.js
│ └── index.html
複製代碼
初始化項目以後,要安裝 webpack
npm install --save-dev webpack
複製代碼
在安裝完 webpack 以後,能夠再 package.json
文件中看到增長了 webpack 的依賴。
安裝完 webpack 以後,咱們就要配置 webpack 了,首先建立配置文件 webpack.config.js
文件內容以下:
module.exports = {
entry: __dirname + "/app/main.js",//已屢次說起的惟一入口文件
output: {
path: __dirname + "/public",//打包後的文件存放的地方
filename: "bundle.js"//打包後輸出文件的文件名
}
}
複製代碼
而後咱們在該項目的終端輸入
webpack
複製代碼
就能夠看到以下信息:
Hash: 4e6a6b5eb88a83b29e02
Version: webpack 4.12.0
Time: 551ms
Built at: 2018-06-24 14:53:39
Asset Size Chunks Chunk Names
bundle.js 6.82 KiB 0 [emitted] main
[3] ./node_modules/css-loader!./app/main.css 190 bytes {0} [built]
[4] ./app/main.css 1.04 KiB {0} [built]
[5] ./app/Greeter.js 143 bytes {0} [built]
[6] ./app/main.js 119 bytes {0} [built]
+ 3 hidden modules
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
複製代碼
看到這樣的信息,那麼恭喜你,你的第一個 webpack 項目就完成了!
打開 public
文件夾下面的 index.html
,你就能夠再瀏覽器上看到以下的效果。
loader 用於對模塊的源代碼進行轉換。loader 可使你在 import 或"加載"模塊時預處理文件。所以,loader 相似於其餘構建工具中「任務(task)」,並提供了處理前端構建步驟的強大方法。loader 能夠將文件從不一樣的語言(如 TypeScript)轉換爲 JavaScript,或將內聯圖像轉換爲 data URL。loader 甚至容許你直接在 JavaScript 模塊中 import CSS文件!
由於 webpack 自己只能處理 JavaScript,若是要處理其餘類型的文件,就須要使用 loader
進行轉換,loader
自己就是一個函數,接受源文件爲參數,返回轉換的結果。
css-loader
例如,咱們想在剛剛的頁面增長樣式,使文字居中顯示,那麼我在 app
文件夾下面新建一個 main.css
文件。在 webpack 中,全部的文件都是模塊,因此要使用這個 css
文件,就必需要先引入。
css
文件因此我就在 app
文件夾下面的 main.js
中引入該 css 文件
const greeter = require('./Greeter.js');
require ('./main.css')
document.querySelector("#root").appendChild(greeter());
複製代碼
而後我從新打包一遍,藍後,發現竟然報錯了!
Hash: 179c18498fac6de89a96
Version: webpack 4.12.0
Time: 533ms
Built at: 2018-06-24 15:00:24
1 asset
[0] ./app/Greeter.js 143 bytes {0} [built]
[1] ./app/main.js 119 bytes {0} [built]
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
ERROR in ./app/main.js
Module not found: Error: Can't resolve 'style-loader' in '/Users/cherry/Workspace/webpack-demo' @ ./app/main.js 2:0-22 複製代碼
根據報錯信息,咱們很明顯能發現是提示咱們項目缺乏 style-loader
,這是由於 webpack 原生只支持解析 js 文件,要支持非 js 類型的文件,就須要使用 loader
因此咱們要安裝 style-loader
和 css-loader
npm i -D style-loader css-loader
複製代碼
而後修改 webpack 的配置文件 webpack.config.js
module.exports = {
entry: __dirname + "/app/main.js",//已屢次說起的惟一入口文件
output: {
path: __dirname + "/public",//打包後的文件存放的地方
filename: "bundle.js"//打包後輸出文件的文件名
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}
複製代碼
配置文件增長了 module.rules
數組,該數組是一些配置規則,告訴 webpack 符合 test
的文件須要使用 use
後面的 loader
處理。因此該規則就是對全部 .css
結尾的文件使用 style-loader
、css-loader
進行處理。
咱們來看一下 loader
有哪些特性:
webpack 中使用 loader 有三種姿式
命令行中運行
webpack --module-bind jade --module-bind 'css=style!css'
複製代碼
jade,style,css後面可省略-loader,他們分別對.jade使用jade-loader,對.css使用style-loader和css-loader
能夠直接在源碼中指定使用什麼 loader 去處理文件。
require('style-loader!css-loader?minimize!./main.css')
複製代碼
這樣就是對 ./main.css
文件先使用 css-loader
再使用 style-loader
進行轉換
webpack.config.js
最經常使用的方式就是使用本文所使用的配置文件的方式
loader name | loader des |
---|---|
babel-loader |
加載 ES2015+ 代碼,而後使用 Babel 轉譯爲 ES5 |
buble-loader |
使用 Bublé 加載 ES2015+ 代碼,而且將代碼轉譯爲 ES5 |
cache-loader |
在一些性能開銷較大的 loader 以前添加此 loader,以將結果緩存到磁盤裏。 |
coffee-loader |
將 CoffeeScript 轉化爲 JS |
css-loader |
css-loader 是將 @import 、url() 引入的 css 轉換爲 import/require() 的方式而後在解析他們 |
exports-loader |
經過添加 exports[...] = ... 語句導出文件中的變量。 |
expose-loader |
expose-loader 將模塊添加到全局對象上 |
file-loader |
file-loader 能夠解析項目中的url引入(不只限於css),根據咱們的配置, |
將圖片拷貝到相應的路徑,再根據咱們的配置,修改打包後文件引用路徑,使之指向正確的文件。 gzip-loader
| 能夠加載 gzip 壓縮以後的資源 html-loader
| 將 html 輸出爲字符串,也能夠根據配置進行壓縮 imports-loader
| imports-loader
容許使用依賴於特定全局變量的模塊,這對於依賴於像 $
這樣的全局變量的第三方模塊很是有用 jshint-loader
| 爲加載的模塊使用 jshint json-loader
| 因爲 webpack >= v2.0.0 默認支持導入 JSON 文件。若是你使用自定義文件擴展名,你可能仍然須要使用此 loader json5-loader
| 將 json5 文件解析成 js 對象 less-loader
| 將 less 轉化爲 css null-loader
| 返回一個空模塊 postcss-loader
| 將 postcss 轉化爲 css raw-loader
| 加載文件原始內容(utf-8格式) sass-loader
| 將 SASS/SCSS 轉換爲 css source-map-loader
| 從現有源文件(源代碼源URL)中提取源映射,方便調試 style-loader
| 將 CSS 放在 <style>
標籤中注入到 DOM 中 script-loader
| 在全局上下文中執行一次 JavaScript 文件(如在 script 標籤),不須要解析 svg-inline-loader
| 將 SVG 做爲模塊嵌入 url-loader
| 將文件加載爲 Base64 編碼的 URL
row 2 col 1 | row 2 col 2
插件(plugin)是 webpack 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的插件系統之上! 插件目的在於解決 loader 沒法實現的其餘事
Plugin 是用來擴展 Webpack 功能的,經過在構建流程裏注入鉤子實現,它給 Webpack 帶來了很大的靈活性。
經過plugin(插件)webpack能夠實 loader 所不能完成的複雜功能,使用 plugin 豐富的自定義 API 以及生命週期事件,能夠控制 webpack 打包流程的每一個環節,實現對 webpack 的自定義功能擴展。
webpack4 已經不支持用extract-text-webpack-plugin來優化 css, 須要改爲optimize-css-assets-webpack-plugin和mini-css-extract-plugin
在剛剛的例子中,咱們查看打包以後的 index.html
文件能夠看到咱們剛剛寫的 css 代碼放在了 head
中的 style
標籤中,這是 style-loader
幫咱們處理的
可是,若是你但願打包以後 css 在單獨的文件中,那麼你就須要 ExtractTextPlugin
這個 plugin 了。
ExtractTextPlugin
npm i -D ExtractTextPlugin
複製代碼
咱們須要修改配置文件:
const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
entry: __dirname + "/app/main.js",//已屢次說起的惟一入口文件
output: {
path: __dirname + "/public",//打包後的文件存放的地方
filename: "bundle.js",//打包後輸出文件的文件名
},
module: {
rules: [
{
test: /\.css$/,
// 轉換 .css 須要的 loader
loaders: ExtractTextPlugin.extract({
use: ['css-loader'],
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: '[name]-[contenthash:8].css'
})
]
}
複製代碼
而後咱們再從新打包,就能夠發如今 public
文件夾下面多了一個 main-493a2c3c.css
文件,下面咱們要在 index.html
中自動引入這個 css 文件
html-webpack-plugin
html-webpack-plugin
能夠根據你設置的模板,在每次運行後生成對應的模板文件,同時所依賴的 CSS/JS 也都會被引入,若是 CSS/JS 中含有 hash 值,則 html-webpack-plugin
生成的模板文件也會引入正確版本的 CSS/JS 文件。
html-webpack-plugin
安裝方式咱們已經很熟悉了
npm i -D html-webpack-plugin
複製代碼
const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: __dirname + "/app/main.js",//已屢次說起的惟一入口文件
output: {
path: __dirname + "/public",//打包後的文件存放的地方
filename: "bundle.js",//打包後輸出文件的文件名
},
module: {
rules: [
{
test: /\.css$/,
loaders: ExtractTextPlugin.extract({
use: ['css-loader'],
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: '[name]-[contenthash:8].css'
}),
new HtmlWebpackPlugin(),
]
}
複製代碼
藍後咱們刪除以前咱們在 punlic
文件夾下面 index.html
的內容,在打包一次,就會生成一個 html
模板
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
<link href="main-493a2c3c.css" rel="stylesheet"></head>
<body>
<script type="text/javascript" src="bundle.js"></script></body>
</html>
複製代碼
在 new HtmlWebpackPlugin
的時候,咱們能夠進行一系列的配置
new HtmlWebpackPlugin({
// 生成的HTML模板的title,若是模板中有設置title的名字,則會忽略這裏的設置
title: "This is the webpack config",
// 生成的模板文件的名字
filename: "/index.html",
// 模板來源文件
template: "index.html",
// 引入模塊的注入位置;取值有true/false/body/head
// true 默認值,script標籤位於html文件的 body 底部
// body script標籤位於html文件的 body 底部
// head script標籤位於html文件的 head中
// false 不插入生成的js文件,這個幾乎不會用到的
inject: "body",
// 指定頁面圖標;
favicon: "",
// 是html-webpack-plugin中集成的 html-minifier ,生成模板文件壓縮配置
minify: {
caseSensitive: false, //是否大小寫敏感
collapseBooleanAttributes: true, // 省略布爾屬性的值
collapseWhitespace: true //刪除空格
},
// 是否生成hash添加在引入文件地址的末尾,相似於咱們經常使用的時間戳,避免緩存帶來的麻煩
hash: true,
// 是否須要緩存,若是填寫true,則文件只有在改變時纔會從新生成
cache: true,
// 是否將錯誤信息寫在頁面裏,默認true,出現錯誤信息則會包裹在一個pre標籤內添加到頁面上
showErrors: true,
// 引入的模塊,這裏指定的是entry中設置多個js時,在這裏指定引入的js,若是不設置則默認所有引入
chunks: "",
// 引入模塊的排序方式
// 默認四個選項: none auto dependency {function}
// 'dependency' 文件的依賴關係
// 'auto' 默認值,插件的內置的排序方式
// 'none' 無序
// {function} 自定義
chunksSortMode: "auto",
// 排除的模塊
excludeChunks: "",
// 生成的模板文檔中標籤是否自動關閉,針對xhtml的語法,會要求標籤都關閉,默認false
xhtml: false
}),
複製代碼
摘自:http://www.css88.com/doc/webpack/plugins/
Name | Description |
---|---|
AggressiveSplittingPlugin | 將原來的 chunk 分紅更小的 chunk |
BabiliWebpackPlugin | 基於 Babel 的裁剪工具:Babili |
BannerPlugin | 在每一個生成的 chunk 頂部添加 banner |
CommonsChunkPlugin | 提取 chunks 之間共享的通用模塊 |
ComponentWebpackPlugin | 經過 webpack 使用組件 |
CompressionWebpackPlugin | 預先準備的資源壓縮版本,使用 Content-Encoding 提供訪問服務 |
ContextReplacementPlugin | 重寫 require 表達式的推斷上下文 |
DefinePlugin | 容許在編譯時(compile time)配置的全局常量 |
DllPlugin | 爲了極大減小構建時間,進行分離打包 |
EnvironmentPlugin | DefinePlugin 中 process.env 鍵的簡寫方式。 |
ExtractTextWebpackPlugin | 從 bundle 中提取文本(CSS)到單獨的文件 |
HotModuleReplacementPlugin | 啓用模塊熱替換(Enable Hot Module Replacement - HMR) |
HtmlWebpackPlugin | 簡單建立 HTML 文件,用於服務器訪問 |
I18nWebpackPlugin | 爲 bundle 增長國際化支持 |
IgnorePlugin | 從 bundle 中排除某些模塊 |
LimitChunkCountPlugin | 設置 chunk 的最小/最大限制,以微調和控制 chunk |
LoaderOptionsPlugin | 用於從 webpack 1 遷移到 webpack 2 |
MinChunkSizePlugin | 確保 chunk 大小超過指定限制 |
NoEmitOnErrorsPlugin | 在輸出階段時,遇到編譯錯誤跳過 |
NormalModuleReplacementPlugin | 替換與正則表達式匹配的資源 |
NpmInstallWebpackPlugin | 在開發時自動安裝缺乏的依賴 |
ProvidePlugin | 沒必要經過 import/require 使用模塊 |
SourceMapDevToolPlugin | 對 source map 進行更細粒度的控制 |
UglifyjsWebpackPlugin | 能夠控制項目中 UglifyJS 的版本 |
ZopfliWebpackPlugin | 經過 node-zopfli 將資源預先壓縮的版本 |
參考文章: