官方學習文檔:https://www.webpackjs.com/guides/getting-started/
首先安裝nodejs (一搜一堆)
npm install npm -g //更新npm
簡介webpack:webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。(詳細瞭解)
最新的webpack版本是:v4.39.3
要安裝最新版本或特定版本,請運行以下命令之一:
npm install --save-dev webpack
npm install --save-dev webpack@<version>
如果你使用 webpack 4+ 版本,你還需要安裝 CLI。
npm install --save-dev webpack-cli
webpack
在全局環境下可用:
npm install --global webpack
可在安裝完成提示的路徑下查看:
用webpack 用於編譯 JavaScript 模塊:
進入要安裝編譯的目錄下:
首先我們創建一個目錄,初始化 npm,然後 在本地安裝 webpack,接着安裝 webpack-cli(此工具用於在命令行中運行 webpack):
mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev
創建好打開創建目錄文件夾:
黃色是手動添加,粉色手動修改其內容:
package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "XXXX項目前端",
+ "private": true,
- "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Author",
"license": "ISC",
"devDependencies": {
"webpack": "^4.0.1",
"webpack-cli": "^2.0.9"
},
"dependencies": {}
}
結構:
src/index.js
function component() {
var element = document.createElement('div');
// Lodash(目前通過一個 script 腳本引入)對於執行這一行是必需的
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
index.html
<!doctype html>
<html>
<head>
<title>起步</title>
<script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>
要在 index.js
中打包 lodash
依賴,我們需要在本地安裝 library:
npm install --save lodash
在安裝一個要打包到生產環境的安裝包時,你應該使用 npm install --save
,
如果你在安裝一個用於開發環境的安裝包(例如,linter, 測試庫等),你應該使用 npm install --save-dev
。
請在 npm 文檔 中查找更多信息。
src/index.js
+ import _ from 'lodash';
+
function component() {
var element = document.createElement('div');
- // Lodash, currently included via a script, is required for this line to work
+ // Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
dist/index.html
<!doctype html>
<html>
<head>
<title>起步</title>
- <script src="https://unpkg.com/[email protected]"></script>
</head>
<body>
- <script src="./src/index.js"></script>
+ <script src="main.js"></script>
</body>
</html>
在這個設置中,index.js
顯式要求引入的 lodash
必須存在,然後將它綁定爲 _
(沒有全局作用域污染)。通過聲明模塊所需的依賴,webpack 能夠利用這些信息去構建依賴圖,然後使用圖生成一個優化過的,會以正確順序執行的 bundle。
可以這樣說,執行 npx webpack
,會將我們的腳本作爲入口起點,然後 輸出 爲 main.js
。Node 8.2+ 版本提供的 npx
命令,可以運行在初始安裝的 webpack 包(package)的 webpack 二進制文件(./node_modules/.bin/webpack
):
npx webpack
Hash: dabab1bac2b940c1462b
Version: webpack 4.0.1
Time: 3003ms
Built at: 2018-2-26 22:42:11
Asset Size Chunks Chunk Names
main.js 69.6 KiB 0 [emitted] main
Entrypoint main = main.js
[1] (webpack)/buildin/module.js 519 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] ./src/index.js 256 bytes {0} [built]
+ 1 hidden module
WARNING in configuration(配置警告)
The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this
project
webpack-demo
|- package.json
+ |- webpack.config.js
|- /dist
|- index.html
|- /src
|- index.js
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
現在,讓我們通過新配置文件再次執行構建:
npx webpack --config webpack.config.js
Hash: dabab1bac2b940c1462b
Version: webpack 4.0.1
Time: 328ms
Built at: 2018-2-26 22:47:43
Asset Size Chunks Chunk Names
bundle.js 69.6 KiB 0 [emitted] main
Entrypoint main = bundle.js
[1] (webpack)/buildin/module.js 519 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] ./src/index.js 256 bytes {0} [built]
+ 1 hidden module
WARNING in configuration(配置警告)
The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this
在 package.json 添加一個 npm 腳本(npm script):
package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.0.1",
"webpack-cli": "^2.0.9",
"lodash": "^4.17.5"
}
}
現在,可以使用 npm run build
命令,來替代我們之前使用的 npx
命令。注意,使用 npm 的 scripts
,我們可以像使用 npx
那樣通過模塊名引用本地安裝的 npm 包。這是大多數基於 npm 的項目遵循的標準,因爲它允許所有貢獻者使用同一組通用腳本(如果必要,每個 flag 都帶有 --config
標誌)。
現在運行以下命令,然後看看你的腳本別名是否正常運行:
npm run build
Hash: dabab1bac2b940c1462b
Version: webpack 4.0.1
Time: 323ms
Built at: 2018-2-26 22:50:25
Asset Size Chunks Chunk Names
bundle.js 69.6 KiB 0 [emitted] main
Entrypoint main = bundle.js
[1] (webpack)/buildin/module.js 519 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] ./src/index.js 256 bytes {0} [built]
+ 1 hidden module
WARNING in configuration(配置警告)
The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this environment.('mode' 選項還未設置。將 'mode' 選項設置爲 'development' 或 'production',來啓用環境默認值。)
通過向
npm run build
命令和你的參數之間添加兩個中橫線,可以將自定義參數傳遞給 webpack,例如:npm run build -- --colors
。
安裝
在開始之前,讓我們對項目做一個小的修改:
dist/index.html
<!doctype html>
<html>
<head>
- <title>Getting Started</title>
+ <title>Asset Management</title>
</head>
<body>
<script src="./bundle.js"></script>
</body>
</html>
加載 CSS
爲了從 JavaScript 模塊中 import
一個 CSS 文件,你需要在 module
配置中 安裝並添加 style-loader 和 css-loader:
npm install --save-dev style-loader css-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
+ module: {
+ rules: [
+ {
+ test: /\.css$/,
+ use: [
+ 'style-loader',
+ 'css-loader'
+ ]
+ }
+ ]
+ }
};
webpack 根據正則表達式,來確定應該查找哪些文件,並將其提供給指定的 loader。在這種情況下,以
.css
結尾的全部文件,都將被提供給style-loader
和css-loader
。
這使你可以在依賴於此樣式的文件中 import './style.css'
。現在,當該模塊運行時,含有 CSS 字符串的 <style>
標籤,將被插入到 html 文件的 <head>
中。
我們嘗試一下,通過在項目中添加一個新的 style.css
文件,並將其導入到我們的 index.js
中:
project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- style.css
|- index.js
|- /node_modules
src/style.css
.hello {
color: red;
}
src/index.js
import _ from 'lodash';
+ import './style.css';
function component() {
var element = document.createElement('div');
// lodash 是由當前 script 腳本 import 導入進來的
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ element.classList.add('hello');
return element;
}
document.body.appendChild(component());
現在運行構建命令:
npm run build
Hash: 9a3abfc96300ef87880f
Version: webpack 2.6.1
Time: 834ms
Asset Size Chunks Chunk Names
bundle.js 560 kB 0 [emitted] [big] main
[0] ./~/lodash/lodash.js 540 kB {0} [built]
[1] ./src/style.css 1 kB {0} [built]
[2] ./~/css-loader!./src/style.css 191 bytes {0} [built]
[3] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
[4] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built]
[5] ./~/style-loader/lib/urls.js 3.01 kB {0} [built]
[6] (webpack)/buildin/global.js 509 bytes {0} [built]
[7] (webpack)/buildin/module.js 517 bytes {0} [built]
[8] ./src/index.js 351 bytes {0} [built]
再次在瀏覽器中打開 index.html
,你應該看到 Hello webpack
現在的樣式是紅色。要查看 webpack 做了什麼,請檢查頁面(不要查看頁面源代碼,因爲它不會顯示結果),並查看頁面的 head 標籤。它應該包含我們在 index.js
中導入的 style 塊元素。
此時目錄結構:
修改過配置文件:webpack.config.js
執行:npx webpack --config webpack.config.js
請注意,在多數情況下,你也可以進行 CSS 分離,以便在生產環境中節省加載時間。最重要的是,現有的 loader 可以支持任何你可以想到的 CSS 處理器風格 - postcss, sass 和 less 等。
加載圖片
假想,現在我們正在下載 CSS,但是我們的背景和圖標這些圖片,要如何處理呢?使用 file-loader,我們可以輕鬆地將這些內容混合到 CSS 中:
npm install --save-dev file-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
+ {
+ test: /\.(png|svg|jpg|gif)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
現在,當你 import MyImage from './my-image.png'
,該圖像將被處理並添加到 output
目錄,_並且_ MyImage
變量將包含該圖像在處理後的最終 url。當使用 css-loader 時,如上所示,你的 CSS 中的 url('./my-image.png')
會使用類似的過程去處理。loader 會識別這是一個本地文件,並將 './my-image.png'
路徑,替換爲輸出
目錄中圖像的最終路徑。html-loader 以相同的方式處理 <img src="./my-image.png" />
。
我們向項目添加一個圖像,然後看它是如何工作的,你可以使用任何你喜歡的圖像:
project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- icon.png
|- style.css
|- index.js
|- /node_modules
src/index.js
import _ from 'lodash';
import './style.css';
+ import Icon from './icon.png';
function component() {
var element = document.createElement('div');
// Lodash,現在由此腳本導入
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
+ // 將圖像添加到我們現有的 div。
+ var myIcon = new Image();
+ myIcon.src = Icon;
+
+ element.appendChild(myIcon);
return element;
}
document.body.appendChild(component());
src/style.css
.hello {
color: red;
+ background: url('./icon.png');
}
讓我們重新構建,並再次打開 index.html 文件:
npm run build
Hash: 854865050ea3c1c7f237
Version: webpack 2.6.1
Time: 895ms
Asset Size Chunks Chunk Names
5c999da72346a995e7e2718865d019c8.png 11.3 kB [emitted]
bundle.js 561 kB 0 [emitted] [big] main
[0] ./src/icon.png 82 bytes {0} [built]
[1] ./~/lodash/lodash.js 540 kB {0} [built]
[2] ./src/style.css 1 kB {0} [built]
[3] ./~/css-loader!./src/style.css 242 bytes {0} [built]
[4] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
[5] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built]
[6] ./~/style-loader/lib/urls.js 3.01 kB {0} [built]
[7] (webpack)/buildin/global.js 509 bytes {0} [built]
[8] (webpack)/buildin/module.js 517 bytes {0} [built]
[9] ./src/index.js 503 bytes {0} [built]
如果一切順利,和 Hello webpack
文本旁邊的 img
元素一樣,現在看到的圖標是重複的背景圖片。如果你檢查此元素,你將看到實際的文件名已更改爲像 5c999da72346a995e7e2718865d019c8.png
一樣。這意味着 webpack 在 src
文件夾中找到我們的文件,併成功處理過它!
合乎邏輯下一步是,壓縮和優化你的圖像。查看 image-webpack-loader 和 url-loader,以瞭解更多關於如果增強加載處理圖片功能。
加載字體
那麼,像字體這樣的其他資源如何處理呢?file-loader 和 url-loader 可以接收並加載任何文件,然後將其輸出到構建目錄。這就是說,我們可以將它們用於任何類型的文件,包括字體。讓我們更新 webpack.config.js
來處理字體文件:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
在項目中添加一些字體文件:
project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- my-font.woff
+ |- my-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
通過配置好 loader 並將字體文件放在合適的地方,你可以通過一個 @font-face
聲明引入。本地的 url(...)
指令會被 webpack 獲取處理,就像它處理圖片資源一樣:
src/style.css
+ @font-face {
+ font-family: 'MyFont';
+ src: url('./my-font.woff2') format('woff2'),
+ url('./my-font.woff') format('woff');
+ font-weight: 600;
+ font-style: normal;
+ }
.hello {
color: red;
+ font-family: 'MyFont';
background: url('./icon.png');
}
現在讓我們重新構建來看看 webpack 是否處理了我們的字體:
npm run build
Hash: b4aef94169088c79ed1c
Version: webpack 2.6.1
Time: 775ms
Asset Size Chunks Chunk Names
5c999da72346a995e7e2718865d019c8.png 11.3 kB [emitted]
11aebbbd407bcc3ab1e914ca0238d24d.woff 221 kB [emitted]
bundle.js 561 kB 0 [emitted] [big] main
[0] ./src/icon.png 82 bytes {0} [built]
[1] ./~/lodash/lodash.js 540 kB {0} [built]
[2] ./src/style.css 1 kB {0} [built]
[3] ./~/css-loader!./src/style.css 420 bytes {0} [built]
[4] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
[5] ./src/MyFont.woff 83 bytes {0} [built]
[6] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built]
[7] ./~/style-loader/lib/urls.js 3.01 kB {0} [built]
[8] (webpack)/buildin/global.js 509 bytes {0} [built]
[9] (webpack)/buildin/module.js 517 bytes {0} [built]
[10] ./src/index.js 503 bytes {0} [built]
重新打開 index.html
看看我們的 Hello webpack
文本顯示是否換上了新的字體。如果一切順利,你應該能看到變化。
加載數據
此外,可以加載的有用資源還有數據,如 JSON 文件,CSV、TSV 和 XML。類似於 NodeJS,JSON 支持實際上是內置的,也就是說 import Data from './data.json'
默認將正常運行。要導入 CSV、TSV 和 XML,你可以使用 csv-loader 和 xml-loader。讓我們處理這三類文件:
npm install --save-dev csv-loader xml-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
+ {
+ test: /\.(csv|tsv)$/,
+ use: [
+ 'csv-loader'
+ ]
+ },
+ {
+ test: /\.xml$/,
+ use: [
+ 'xml-loader'
+ ]
+ }
]
}
};
給你的項目添加一些數據文件:
project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- data.xml
|- my-font.woff
|- my-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules
src/data.xml
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Mary</to>
<from>John</from>
<heading>Reminder</heading>
<body>Call Cindy on Tuesday</body>
</note>
現在,你可以 import
這四種類型的數據(JSON, CSV, TSV, XML)中的任何一種,所導入的 Data
變量將包含可直接使用的已解析 JSON:
src/index.js
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
+ import Data from './data.xml';
function component() {
var element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
var myIcon = new Image();
myIcon.src = Icon;
element.appendChild(myIcon);
+ console.log(Data);
return element;
}
document.body.appendChild(component());
當你打開 index.html
並查看開發者工具中的控制檯,你應該能夠看到你導入的數據被打印在了上面!
在使用 d3 等工具來實現某些數據可視化時,預加載數據會非常有用。我們可以不用再發送 ajax 請求,然後於運行時解析數據,而是在構建過程中將其提前載入並打包到模塊中,以便瀏覽器加載模塊後,可以立即從模塊中解析數據。
全局資源
上述所有內容中最出色之處是,以這種方式加載資源,你可以以更直觀的方式將模塊和資源組合在一起。無需依賴於含有全部資源的 /assets
目錄,而是將資源與代碼組合在一起。例如,類似這樣的結構會非常有用:
- |- /assets
+ |– /components
+ | |– /my-component
+ | | |– index.jsx
+ | | |– index.css
+ | | |– icon.svg
+ | | |– img.png
這種配置方式會使你的代碼更具備可移植性,因爲現有的統一放置的方式會造成所有資源緊密耦合在一起。假如你想在另一個項目中使用 /my-component
,只需將其複製或移動到 /components
目錄下。只要你已經安裝了任何擴展依賴(external dependencies),並且你已經在配置中定義過相同的 loader,那麼項目應該能夠良好運行。
但是,假如你無法使用新的開發方式,只能被固定於舊有開發方式,或者你有一些在多個組件(視圖、模板、模塊等)之間共享的資源。你仍然可以將這些資源存儲在公共目錄(base directory)中,甚至配合使用 alias 來使它們更方便 import 導入
。
回退處理
對於接下來的指南,我們無需使用本指南中所有用到的資源,因此我們會進行一些清理工作,以便爲下一部分指南中的管理輸出章節做好準備:
project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
- |- data.xml
- |- my-font.woff
- |- my-font.woff2
- |- icon.png
- |- style.css
|- index.js
|- /node_modules
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
- module: {
- rules: [
- {
- test: /\.css$/,
- use: [
- 'style-loader',
- 'css-loader'
- ]
- },
- {
- test: /\.(png|svg|jpg|gif)$/,
- use: [
- 'file-loader'
- ]
- },
- {
- test: /\.(woff|woff2|eot|ttf|otf)$/,
- use: [
- 'file-loader'
- ]
- },
- {
- test: /\.(csv|tsv)$/,
- use: [
- 'csv-loader'
- ]
- },
- {
- test: /\.xml$/,
- use: [
- 'xml-loader'
- ]
- }
- ]
- }
};
src/index.js
import _ from 'lodash';
- import './style.css';
- import Icon from './icon.png';
- import Data from './data.xml';
-
function component() {
var element = document.createElement('div');
-
- // Lodash,現在通過 script 標籤導入
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
- element.classList.add('hello');
-
- // 將圖像添加到我們已有的 div 中。
- var myIcon = new Image();
- myIcon.src = Icon;
-
- element.appendChild(myIcon);
-
- console.log(Data);
return element;
}
document.body.appendChild(component());
修改目錄分類:
配置代碼:
const path = require('path');
module.exports = {
entry: './src/script/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module:{
rules:[
{
test:/\.css$/,
use:[
'style-loader',
'css-loader'
]
},
{
test:/\.(png|svg|jpg|gif)$/,
use:[
'file-loader'
]
}
]
},
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 9000
}
};
script/index.js
import _ from 'lodash';
// import './style.css';
// import Icon from './a1.jpg'
import '../css/style.css';
import Icon from '../pic/a1.jpg'
function component() {
var element = document.createElement('div');
// Lodash(目前通過一個 script 腳本引入)對於執行這一行是必需的
// Lodash, currently included via a script, is required for this line to work
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add("hello");
var myIcon=new Image();
myIcon.src=Icon;
elment.appendChild(myIcon);
return element;
}
document.body.appendChild(component());
css/style.css
.hello{
color:red;
background: url('../pic/a1.jpg');
}
保證路徑修改正確: