上一篇筆記整理了整合JS資源的過程,現(xiàn)在我們嘗試整合一些其他資源
在 webpack 出現(xiàn)之前,前端開發(fā)人員會(huì)使用 grunt 和 gulp 等工具來處理資源,并將它們從 /src 文件夾移動(dòng)到 /dist 或 /build 目錄中。
同樣的方式也被用于 JS 模塊,但是像 webpack 這樣的工具,將動(dòng)態(tài)打包(dynamically bundle)所有依賴項(xiàng)(創(chuàng)建所謂的依賴圖(dependency graph))。這是極好的創(chuàng)舉,因?yàn)楝F(xiàn)在每個(gè)模塊都可以明確表述它自身的依賴,我們將避免打包未使用的模塊。
webpack 最出色的功能之一就是,除了 JavaScript,還可以通過 loader 引入任何其他類型的文件。也就是說,以上列出的那些 JavaScript 的優(yōu)點(diǎn)(例如顯式依賴),同樣可以用來構(gòu)建網(wǎng)站或 web 應(yīng)用程序中的所有非 JavaScript 內(nèi)容。讓我們從 CSS 開始起步,或許你可能已經(jīng)熟悉了這個(gè)設(shè)置過程。
安裝以及加載 CSS
為了從 JS 模塊中 import 一個(gè) CSS 文件,需要在 module 配置中安裝并添加 style-loader 和 css-loader
npm install --save-dev style-loader css-loader
并在 webpack.config.fs 文件中添加一個(gè)模塊規(guī)則
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
// 文件中添加下面的代碼
module: {
rules: [
{
// 每次遇到 require 或 import 時(shí)進(jìn)行檢測
test: /\.css$/,
// 如果是 .css 后綴的文件,則用下面兩個(gè) loader 去處理
use: [
'style-loader',
'css-loader'
]
}
]
}
};
webpack 根據(jù)正則表達(dá)式,來確定應(yīng)該查找哪些文件,并將其提供給指定的 loader。上面的這種情況,以 .css 結(jié)尾的全部文件,都將被提供給 style-loader 和 css-loader。
這樣就可以在依賴于此樣式的文件中 import './style.css'。然后,當(dāng)該模塊運(yùn)行時(shí),含有 CSS 字符串的 <style> 標(biāo)簽,將被插入到 html 文件中的 <head> 中。
我想如果理解了上篇 JS 整合的方法,這里應(yīng)該也不難,如果你覺得應(yīng)該看看詳細(xì)的過程,請?jiān)L問管理資源 | webpack
需要注意的是,多數(shù)情況下,也可以進(jìn)行 CSS 分離,以便在生產(chǎn)環(huán)境中節(jié)省加載時(shí)間。最重要的是,現(xiàn)有的 loader 可以支持任何你可以想到的 css 處理器風(fēng)格 - postcss , sass 和 less 等。
加載圖片
上述的過程做到了 CSS 的加載,但是我們的背景和圖標(biāo)這些圖片要怎么去處理呢?這就要用到另一個(gè) loader 了(file-loader),可以通過它輕松地將這些內(nèi)容混合到 CSS 中:
npm install --save-dev file-loader
當(dāng)然我們同樣要修改我們的 webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
};
當(dāng)在 JS 文件中 import img from './img.png',該圖像將被處理并添加到 output 目錄,并且 img 變量將包含該圖像在處理后的最終 url。當(dāng)使用 css-loader 時(shí),如上所示,你的 CSS 中的 url('./img.png') 會(huì)使用類似的過程去處理。loader 會(huì)識(shí)別這是一個(gè)本地文件,并將 './img.png' 路徑替換為 輸出 目錄中圖像的最終路徑。html-loader 以相同的方式處理 <img src="./img.png" />。
詳細(xì)的過程,請?jiān)L問 管理資源 | webpack
合乎邏輯的下一步是:壓縮和優(yōu)化你的圖像。查閱
image-webpack-loader和url-loader,以了解更多關(guān)于增強(qiáng)加載處理圖片功能。
加載字體
處理完了圖像,那么像字體這樣的其他資源如何處理呢?file-loader 和 url-loader 可以接受并加載任何文件,然后將其輸出到構(gòu)建目錄。
更新 webpack.config.js ,在 rules 里加入
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
然后再項(xiàng)目中添加一些字體文件 ./src/my-font.woff 或者 ./src/my-font.woff2
通過配置好 loader 并將字體文件放在合適的地方,可以通過一個(gè) @font-face 聲明引入。本地的 url(...) 指令會(huì)被 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;
}
body {
font-family: 'MyFont';
}
加載數(shù)據(jù)
數(shù)據(jù)也是可以加載的有用資源,如:JSON 文件、CSV、TSV 和 XML。類似于 NodeJS,JSON 支持實(shí)際上是內(nèi)置的,也就是說 import Data from './data.json' 默認(rèn)將正常運(yùn)行。要導(dǎo)入 CSV、TSV 和 XML,你可以使用 csv-loader 和 xml-loader。
npm install --save-dev csv-loader xml-loader
同樣需要更新 webpack.config.js ,在 rules 里加入
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader'
]
},
{
test: /\.xml$/,
use: [
'xml-loader'
]
}
可以 import 這四種類型的數(shù)據(jù)(JSON, CSV, TSV, XML)中的任何一種,所導(dǎo)入的 Data 變量將包含可直接使用的已解析 JSON
import Data from './data.xml'
全局資源
|——/components
|——/my-component
|——index.js
|——index.css
|——icon.svg
|——img.png
這種配置方式會(huì)使你的代碼更具備可移植性,因?yàn)楝F(xiàn)有的統(tǒng)一放置的方式會(huì)造成所有資源緊密耦合在一起。假如你想在另一個(gè)項(xiàng)目中使用 /my-component,只需將其復(fù)制或移動(dòng)到 /components 目錄下。只要你已經(jīng)安裝了任何擴(kuò)展依賴(external dependencies),并且你已經(jīng)在配置中定義過相同的 loader,那么項(xiàng)目應(yīng)該能夠良好運(yùn)行
管理輸出
目前為止,我們在 index.html 文件中手動(dòng)引入所有資源,然而隨著應(yīng)用程序增長,并且一旦開始對文件名使用哈希并輸出多個(gè)bundle/main,手動(dòng)對 index.html 文件進(jìn)行處理,一切就會(huì)變得困難起來。
這個(gè)時(shí)候,我們可以通過一些插件,使這個(gè)過程更容易操控。
準(zhǔn)備
首先,讓我們重新調(diào)整一下我們的項(xiàng)目
webpack-demo
|——package.json
|——webpack.config.fs
|——/dist
|——/src
|——index.js
|——print.js // 新增
|——/node_modules
我們在 src/print.js 文件中添加一些測試邏輯
src/print.js
export.default function printMe() {
console.log('I get called from print.js')
}
并且在 src/index.js 文件中使用這個(gè)函數(shù)
src/index.js
import $ from 'jquery'
import printMe from './print.js'
$('body').on('click', printMe)
$('body').append('<h1>Kofe Chen</h1>')
同時(shí),我們還要更新 dist/index.html 文件,來為 webpack 分離入口做好準(zhǔn)備
dist/index.html
<!doctype html>
<html>
<head>
<title>Output Management</title>
<script src="./print.bundle.js"></script>
</head>
<body>
<script src="./app.bundle.js"></script>
</body>
</html>
最后調(diào)整配置,在 entry 添加 src/print.js 作為新的入口起點(diǎn)( print ),然后修改 output,一遍根據(jù)入口名稱動(dòng)態(tài)生成 bundle 名稱:
webpack.config.js
const path = require('path');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
執(zhí)行的時(shí)候,如果存在 webpack.config.js 配置文件,webpack 命令將會(huì)默認(rèn)選擇使用它。
webpack 生成了 print.bundle.js 和 app.bundle.js 文件,這也和我們在 index.html 文件中指定的文件名稱相對應(yīng)。
但是,如果我們更改了一個(gè)入口起點(diǎn)的名稱,甚至添加了一個(gè)新的名稱,生成的包將被重命名在一個(gè)構(gòu)建中,可原本的 index.html 文件仍然會(huì)引用舊的名字。那么我們就需要用 HtmlWebpackPlugin 來解決這個(gè)問題。
設(shè)定 HtmlWebpackPlugin
首先安裝插件,并且調(diào)整 webpack.config.js 文件
npm install --save-dev html-webpack-plugin
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
output: {
filename: '[name].main.js',
path: path.resolve(__dirname, 'dist')
}
};
在構(gòu)建之前,我們應(yīng)該了解的是:雖然在 dist/ 文件夾中已經(jīng)有了 index.html 這個(gè)文件,然后 HtmlWebpackPlugin 還是會(huì)默認(rèn)生成 index.html 文件。也就是說,HtmlWebpackPlugin 會(huì)用新生成的 index.html 文件把我們原來創(chuàng)建的替換掉。
如果想要了解更多 HtmlWebpackPlugin 插件提供的全部功能和選項(xiàng),可以訪問 HtmlWebpackPlugin
你還可以看一下 html-webpack-template,除了默認(rèn)模板之外,還提供了一些額外的功能。
清理 /dist 文件夾
webpack 會(huì)生成文件,然后將這些文件放置在 /dist 文件夾中,但是 webpack 無法追蹤到哪些文件是實(shí)際在項(xiàng)目中用到的。
通常,在每次構(gòu)建前清理 /dist 文件夾,是比較推薦的做法,因此只會(huì)生成用到的文件。
clean-webpack-plugin 是一個(gè)比較普及的管理插件
npm install clean-webpack-plugin --save-dev
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
現(xiàn)在執(zhí)行 npm run build,再檢查 /dist 文件夾,如果順利,應(yīng)該不會(huì)再看到舊的文件,只有構(gòu)建后生成的文件。
Manifest
通過 manifest ,webpack 能夠?qū)?你的模塊映射到輸出 bundle 的過程 保持追蹤。
通俗點(diǎn)講,就是生成一個(gè) 源碼到輸出文件的映射
詳細(xì)請?jiān)L問 Manifest 管理輸出 | webpack