Webpack 5 走起! - Asset Modules(8) - asset/source

前言

接下來講講另一種特別的狀況,有些時候我們會需要取得讀取的檔案內容,那麼就會使用 asset/source。

asset/source

前面講了外部連結與內部注入的檔案處理方式,那麼有些時候的開發狀況則是我們要去讀取特定的檔案內容,在原本的做法是使用 raw-loader,但在 webpack 5 則是使用 asset/source

因此這邊先在 src/assets/json 底下建立一個 json 檔案內容如下

1
2
3
4
{
"name": "Ray",
"url": "https://hsiangfeng.github.io/"
}

接下來一樣針對 webpack.config.js 增加 asset/source 打包規則

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rules:[
{
test: /\.png/,
type: 'asset/resource'
},
{
test: /\.jpg/,
type: 'asset/inline'
},
{
test: /\.json/,
type: 'asset/source'
}
],

注意,這邊不管要打包什麼你都必須要在 main.js 匯入哦~

1
2
import jsonTest from './assets/JSON/data.json';
console.log(jsonTest); // { "name": "Ray", "url": "https://hsiangfeng.github.io/" }

這邊可以注意到一件事情使用 asset/source 也是與 asset/inline 類似,它是直接注入於打包後的 main.js 中,因此若你打開檔案來看是一樣可以看到類似的狀況的

1
{t.exports='{\n  "name": "Ray",\n  "url": "https://hsiangfeng.github.io/"\n}'},511

assets

最後也一起補充 type: 'assets' 的部分,假使如果你的 rules 是沒有特別設置要走 assets/inline or assets/resource 的話,並且正規表達式又是設置成相關副檔名,那麼依照 webpack 內建設置來講,當如果你的檔案小於 8kb 時,它會自動辨識為與 assets/inline 相同的方式,也就是採用注入的方式,如果是大於 8kb 則是採用 assets/resource,說起來算是格外的方便。

當然你也可以針對這個檔案大小的規則做一些設置,以官方的範例說明就是使用 dataUrlCondition 來告知 webpack 多少檔案大小的檔案要採用 assets/inline or assets/resource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
rules:[
{
test: /\.png/,
type: 'asset/resource'
},
{
test: /\.jpg/,
type: 'asset/inline'
},
{
test: /\.json/,
type: 'asset/source'
},
{
test: /\.txt/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 1 * 1024 // 1kb
},
},
},
],

以我剛剛建立的檔案來講 hello.txt 就有 3kb,因此 webpack 就會採用 assets/resource 的方式,但另一個則小於 1kb。

1
2
3
4
import txt from './assets/other/hello.txt'; // 大於 1kb
console.log(txt); // http://localhost:3000/images/93599c4febd4a8137603.txt
import txt from './assets/other/hello.txt'; // 大於 1kb
console.log(txt); // data:text/plain;base64,V2VsY29tZS5XZWIuV29ybGQKV2VsY29tZS5XZWIuV29ybGQKV2VsY29tZS5XZWIuV29ybGQ=

那麼一樣為了注入在檔案內,一樣會是採用 base64 處理過唷~

補充

這邊如果你依照前面文章走一次之後,應該會發現 .txt 的檔案會被注入到 images 資料夾底下,因為我目前的 Assets Modules 都是統一輸出路徑是 assetModuleFilename: 'images/[hash][ext]',,因此為了確保每個檔案輸出的路徑,那麼每一個 assets/xxx 就必須加上一個屬性為 generator 並統一改成以下會較好,以下是完整內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
mode: 'development',
entry: path.resolve(__dirname, './src/main.js'),
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].[contenthash:6].bundle.js',
},
devServer: {
contentBase: path.resolve(__dirname, './dist'),
port: 3000,
compress: true,
open: true,
hot: true,
},
module: {
rules:[
{
test: /\.(png|jpe?g|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'assets/images/[hash][ext]',
},
},
{
test: /\.svg/,
type: 'asset/inline',
generator: {
filename: 'assets/icon/[hash][ext]',
},
},
{
test: /\.json/,
type: 'asset/source',
generator: {
filename: 'assets/json/[hash][ext]',
},
},
{
test: /\.txt/,
type: 'asset',
generator: {
filename: 'assets/txt/[hash][ext]',
},
parser: {
dataUrlCondition: {
maxSize: 1 * 1024 // 1kb
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack 5',
template: path.resolve(__dirname, './src/template/index.html'),
filename: 'index.html',
inject: 'body',
}),
new CleanWebpackPlugin(),
]
};

因此這邊設置完畢之後 assetModuleFilename: 'assets/[hash][ext]', 就可以移除了,該參數的概念類似預設輸出路徑,如果你沒有告知 Asset Module 的 generator,它就會統一走 assetModuleFilename

build

參考文獻

Liker 讚賞 (拍手)

如果這一篇筆記文章對你有幫助,希望可以求點支持或 牡蠣 鼓勵 (ノД`)・゜・。

Liker 是一個按讚(拍手)的讚賞機制,每一篇文章最多可以按五下拍手,過程你只需要登入,如果你願意按個讚,對於創作者來講是一個莫大的鼓勵與支持。

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ