資源管理
如果你從一開始就跟著教程做, 你現(xiàn)在已經(jīng)有一個(gè)叫做"Hello webpack"的小項(xiàng)目了, 現(xiàn)在讓我們嘗試處理其他的資源,像是 images,看看他們是如何被處理的。
在webpack之前, 前端開發(fā)者會(huì)使用grunt 、gulp之類的工具去處理這些資源文件, 并且把他們從/src 目錄移動(dòng)到 /dist 甚至是 /build 目錄。 當(dāng)然這個(gè)想法也同樣用于處理Javascript模塊, 但是像是webpack這類工具會(huì)動(dòng)態(tài)構(gòu)建所有依賴項(xiàng)目(創(chuàng)建之前說過的 依賴圖像),這簡(jiǎn)直棒極了,因?yàn)樗心K現(xiàn)在顯式地聲明它地依賴項(xiàng),這樣我們就可以避免把不必要地依賴項(xiàng)構(gòu)建到當(dāng)前項(xiàng)目中去。
webpack最棒的一個(gè)特性是, 只要有l(wèi)oader,你可以包含任何類型的文件到當(dāng)前模塊,而不僅僅Javascript 。 這就意味著對(duì)于任何用于JavaScript的好東西(像是顯式聲明依賴項(xiàng))可以同樣接受所有東西,去構(gòu)建你的網(wǎng)站或者app, 讓我們先從css開始吧, 你可以已經(jīng)對(duì)此步驟非常熟悉了。
構(gòu)建
首先對(duì)我們之前使用的項(xiàng)目做一些微小的更改:
<!doctype html>
<html>
<head>
- <title>Getting Started</title>
+ <title>Asset Management</title>
</head>
<body>
- <script src="./main.js"></script>
+ <script src="./bundle.js"></script>
</body>
</html>
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
- filename: 'main.js',
+ filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
加載 CSS
為了將一個(gè)css 引入到JavaScript模塊中, 你需要將 style-loader 以及 css-loader 安裝并且添加到你的 module configuration 中:
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 使用常規(guī)的表達(dá)式去檢測(cè)那個(gè)文件應(yīng)該被查找,并且將它推送給指定的loader去處理。這樣的話任何以.css 結(jié)尾的文件都會(huì)被分配給 style-loader 和 css-loader 。
這可以讓你成功引入 style.css( import './style.css') 文件到需要該樣式的模塊中?,F(xiàn)在一旦模塊運(yùn)行,一個(gè)包含字符化css的<style>會(huì)插入到html文件的 <header> 標(biāo)簽中。
讓我們添加一個(gè) style.css 文件到項(xiàng)目中并把它引入到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, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ element.classList.add('hello');
return element;
}
document.body.appendChild(component());
然后使用你的構(gòu)建命令:
npm run build
...
Asset Size Chunks Chunk Names
bundle.js 76.4 KiB 0 [emitted] main
Entrypoint main = bundle.js
...
在瀏覽器中再次打開 index.html, 你應(yīng)該會(huì)看到 Hello webpack 已經(jīng)被格式化為紅色。 想看webpack究竟對(duì)我們的項(xiàng)目做了什么, 檢查頁(yè)面(不要看頁(yè)面源文件,因?yàn)樗粫?huì)給你看的(????)),只需要看頁(yè)面的head標(biāo)簽。 它一般會(huì)包含我們之前給index.js 引入的style塊。
記住你可以,并且大多數(shù)情況下需要,最小化css , 為了更短時(shí)間加載完畢。在最上面, 有許多不同風(fēng)格的CSS loader 供你挑選。例如 postcss, sass, less ,這里僅僅舉幾個(gè)例子。
加載圖片
現(xiàn)在我們可以在項(xiàng)目里引入css ,但是如果我們的圖片,像是背景圖片或者是圖標(biāo)也想搞進(jìn)去該怎么辦呢? ——使用file-loader 我們可以同樣很輕松地將他們插入到項(xiàng)目中:
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'
+ ]
+ }
]
}
};
現(xiàn)在,當(dāng)你引入圖片(import MyImage from './my-image.png'), 這個(gè)圖片會(huì)被處理,并添加到你的輸出目錄中, 處理完畢的圖片最終會(huì)生成一個(gè)url。 當(dāng)像上面那樣使用css-loader 的時(shí)候, 類似的處理過程會(huì)把url('./my-image.png')添加入你的CSS中。loader會(huì)把圖片識(shí)別問本地文件,并且將'./my-image.png'路勁替換為最終在你輸出目錄下的圖片路徑。 html-loader 以同樣的方式處理<img src="./my-image.png" />。
現(xiàn)在添加一個(gè)圖片到我們項(xiàng)目中,然后看看它是怎么工作的,你可以引用任何你喜歡的圖片(意味著教程不提供圖片...):
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, 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);
return element;
}
document.body.appendChild(component());
src/style.css
.hello {
color: red;
+ background: url('./icon.png');
}
生成一個(gè)新的構(gòu)建并再次打開index.html
npm run build
...
Asset Size Chunks Chunk Names
da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big]
bundle.js 76.7 KiB 0 [emitted] main
Entrypoint main = bundle.js
...
如果一切順利,你應(yīng)該會(huì)看到你的你的icon變成了一個(gè)疊加的背景圖片, 就像是要給img 標(biāo)簽在我們的Hello webpack 下面一樣(笑). 如果你觀察這個(gè)元素, 你會(huì)看到它真正的面目(文件名) 已經(jīng)變成像下面這個(gè)樣子:
5c999da72346a995e7e2718865d019c8.png。這意味著webpack在我們的src文件夾找到了圖片并且成功的處理掉了它。
一個(gè)合理的不走是最小化并且優(yōu)化你的圖片。 瀏覽 image-webpack-loader以及url-loader以查看更多關(guān)于如何加強(qiáng)圖片加載處理的技能!
加載字體
如果要加載其他資源,像是字體呢? 文件、url loader 會(huì)處理任何你載入的文件并且輸出到你的build 目錄。 這就意味著我們使用它去處理任何類型的文件,包括fonts。 首先,更改一下 webpack.config.js 使得webpack具有加載字體的能力。
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'
+ ]
+ }
]
}
};
添加一些字體文件到你的項(xiàng)目中:
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
設(shè)置完加載器,并且把字體放入項(xiàng)目后,你可以通過 @font-face 聲明去寫作處理。本地的 url(...) 指令會(huì)被webpack處理,就像處理image那樣:
+ @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');
}
現(xiàn)在運(yùn)行build命令,看看wbepack是否處理了字體文件:
npm run build
...
Asset Size Chunks Chunk Names
5439466351d432b73fdb518c6ae9654a.woff2 19.5 KiB [emitted]
387c65cc923ad19790469cfb5b7cb583.woff 23.4 KiB [emitted]
da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big]
bundle.js 77 KiB 0 [emitted] main
Entrypoint main = bundle.js
打開index.html ,看看我們的Hello Webpack 文本是否已經(jīng)被改變?yōu)樾碌淖煮w。 如果一切順利, 應(yīng)該是會(huì)看到這些變化的。
加載數(shù)據(jù)
另外一個(gè)很有用的可被加載資源是data,像是JSON files , CSVs, TSVS ,以及XML。 對(duì)于JSON的支持實(shí)際上已經(jīng)被內(nèi)部支持,像是NodeJS一樣,意味著 import Data from './data.json' 可以直接被運(yùn)行。 但是如果要加載CSV , TSV,或者是XML 你可以分別使用csv-loader 以及 xml-loader,現(xiàn)在讓我們著手處理這些吧:
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'
+ ]
+ }
]
}
};
添加一些數(shù)據(jù)文件到你的項(xiàng)目中:
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>
現(xiàn)在你可以加載任何JSON, CSV,TSV,XML。 你引入的Data變量會(huì)被解析為JSON。
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;
}
再次運(yùn)行npm run build 命令,并且打開Index.html。 如果你看了控制臺(tái)(瀏覽器或者NODE) ,你應(yīng)該可以看到你載入的data 被打印到控制臺(tái)上。
這個(gè)在實(shí)現(xiàn)一些數(shù)據(jù)可視化工具,例如D3 會(huì)變得非常有用。 比起在運(yùn)行時(shí)請(qǐng)求ajax請(qǐng)求并且轉(zhuǎn)換data, 你可以在構(gòu)建的時(shí)候就將它載入你的模塊, 而轉(zhuǎn)換過后的數(shù)據(jù)可以在模塊載入到瀏覽器的時(shí)候馬上被使用。
全局資源
上面提到的最酷的一部分是, 使用這個(gè)方式加載模塊允許你給模塊和資源分組到一起,使其變得更加直觀。比起依賴于包含所有資源的全局的/assets 目錄, 你可以將對(duì)應(yīng)的資源文件于代碼分到同一個(gè)目錄下。 例如,下面這個(gè)目錄結(jié)構(gòu)會(huì)變得非常有用:
- |- /assets
+ |– /components
+ | |– /my-component
+ | | |– index.jsx
+ | | |– index.css
+ | | |– icon.svg
+ | | |– img.png
這個(gè)步驟讓你的代碼變得更“便攜“ 當(dāng)所有組件即將對(duì)接的時(shí)候。 加入你想把 /my-component 用于其他項(xiàng)目, 直接簡(jiǎn)單的復(fù)制或者移動(dòng)這個(gè)目錄到目標(biāo)項(xiàng)目的/components 下。 一旦你安裝了所需要的外部依賴項(xiàng),以及你的配置文件中對(duì)應(yīng)的loaders被定義, 你的組件應(yīng)該能跑起來。
然而, 加入你已經(jīng)被你那根深蒂固的觀念束縛,或者你有一些資源是多個(gè)組件共享的(views, templates, modules, 等到)。 webpack依然可以將這些資源保存在根目錄下, 你甚至可以使用 aliasing 讓項(xiàng)目變得更加容易加載。
包裝
下一節(jié)教程,我們不需要使用本章用到的,這些亂七八糟的資源文件。所以我們需要對(duì)其做一些清理以便我們進(jìn)入下一章節(jié)。
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, 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;
}