透過網頁瀏覽器看到的網頁絕大部分是使用HTML進行控制編排的,由於HTML的語法結構定義較為寬鬆,網頁瀏覽器都有一定程度的容錯率,因此有可能某個100KB的HTML實際上可以等價於不到50KB的HTML,也就是說,多出來的資料量是完全不必要的,可是卻會增加更多的網路流量和時間成本。
HTML Minifier
「HTML Minifier」是筆者開發的套件,可以在產生HTML(串接字串)的同時去進行HTML的壓縮,並且支援<style>
、<script>
以及<pre>
、<code>
<textarea>
標籤的特殊處理。採用的HTML壓縮規則如下:
- 永遠移除ASCII的控制字元(字元範圍0x00-0x08, 0x11-0x1F, 0x7F)。
- 移除註解。(可選,預設會移除)
- 移除沒作用的空格(包括空白鍵空格、TAB和換行字元)。
- 連續的空格(包括空白鍵空格、TAB和換行字元)會被轉成單一的
'\x20'
或是單一的'\n'
,如果可以的話。 - 空的屬性值會被化簡。(例如
<input readonly="">
會簡化成<input readonly>
) - 除了以下幾個元素以外,所有元素內部的HTML都會被壓縮:
<pre>
<textarea>
<code>
(可選,預設會壓縮)<script>
(如果是不支援的type
屬性才不壓縮)<style>
(如果是不支援的type
屬性才不壓縮)<script>
和<style>
元素中的JS語法和CSS語法是使用minifier
這個crate來壓縮的。
在早期的的版本中,這個套件會嘗試將HTML壓縮成一行(例如<a>1</a>\n /\n <a>2</a>
=> <a>1</a> / <a>2</a>
)。不過這樣做的話,CJ字元就必須要被檢查,否則中\n文
會被壓縮成中 文
,就會是錯誤的結果。
在3.0.0版本之後,這個套件不再嘗試將HTML壓縮成一行了,如此一來變可以移除UTF-8計算,增進效能。而且這樣做的話,還可以讓這個套件除了能支援ASCII或是UTF-8編碼的輸入文字以外,也能支援其它任意自我同步(self-synchronizing)的編碼。
Crates.io
Cargo.toml
使用方法
html_minifier
這個crate底下的HTMLMinifier
結構實體擁有digest
方法,可以多次傳入要串接至HTML中的字串,最後再使用get_html
方法回傳已壓縮的HTML。也就是說,使用HTMLMinifier
時,不需要先把完整的HTML先產生好,再產生出壓縮的HTML。而是可以藉由多次呼叫HTMLMinifier
結構實體的digest
方法,來串接字串,直接產生出壓縮的HTML。如此一來可以省下許多處理時所需記憶體,又可以加快所需的時間。
use html_minifier::HTMLMinifier;
let mut html_minifier = HTMLMinifier::new();
html_minifier.digest("<!DOCTYPE html> <html ").unwrap();
html_minifier.digest("lang= en >").unwrap();
html_minifier.digest("
<head>
<meta name=viewport>
</head>
").unwrap();
html_minifier.digest("
<body class=' container bg-light '>
<input type='text' value='123 456' readonly='' />
123456
<b>big</b> 789
ab
c
中文
字
</body>
").unwrap();
html_minifier.digest("</html >").unwrap();
assert_eq!("<!DOCTYPE html> <html lang=en>
<head>
<meta name=viewport>
</head>
<body class='container bg-light'>
<input type='text' value='123 456' readonly/>
123456
<b>big</b> 789
ab
c
中文
字
</body>
</html>".as_bytes(), html_minifier.get_html());
use html_minifier::HTMLMinifier;
let mut html_minifier = HTMLMinifier::new();
html_minifier.digest("<pre > Hello world! </pre >").unwrap();
assert_eq!(b"<pre> Hello world! </pre>", html_minifier.get_html());
use html_minifier::HTMLMinifier;
let mut html_minifier = HTMLMinifier::new();
html_minifier.digest("<script type=' application/javascript '> alert('Hello!') ; </script>").unwrap();
assert_eq!("<script type='application/javascript'>alert('Hello!')</script>".as_bytes(), html_minifier.get_html());
如果希望產生出來的HTML資料是直接被送出,而不是存在記憶體中的話,可以使用HTMLMinifierHelper
這個結構體,它提供了一個比較低階的API,允許開發者在呼叫其digest
方法時,傳入一個用於輸出的實體。
use html_minifier::HTMLMinifierHelper;
use std::fs::File;
use std::io::Read;
let mut input_file = File::open("tests/data/w3schools.com_tryhow_css_example_website.htm").unwrap();
let mut output_file = File::create("tests/data/index.min.html").unwrap();
let mut buffer = [0u8; 256];
let mut html_minifier_helper = HTMLMinifierHelper::new();
loop {
let c = input_file.read(&mut buffer).unwrap();
if c == 0 {
break;
}
html_minifier_helper.digest(&buffer[..c], &mut output_file).unwrap();
}