本專案原始碼均可在 這裡 找到。
之前公司的官網專案靜態檔案都是放在公司自己的靜態伺服器中,這其中的弊端就不贅述了。簡單說一下 CDN 的好處:
CDN 可以解決因分佈、頻寬、伺服器效能帶來的訪問延遲問題,適用於站點加速、點播、直播等場景。使使用者可就近取得所需內容,解決 Internet 網路擁擠的狀況,提高使用者訪問網站的響應速度和成功率。控制時延無疑是現代資訊科技的重要指標,CDN 的意圖就是儘可能的減少資源在轉發、傳輸、鏈路抖動等情況下順利保障資訊的連貫性。CDN 就是扮演者護航者和加速者的角色,更快準狠的觸發資訊和觸達每一個使用者,帶來更為極致的使用體驗。
上傳指令碼檔案
這裡為了最小化演示路徑,我們只上傳專案所用的 js 檔案。且 CDN 基於七牛雲。
// webpack.config.js
module.exports = {
// 入口檔案
entry: `./src/app.js`,
// 打包出口
output: {
path: path.resolve(__dirname, `dist`),
filename: `app.js`,
publicPath: `http://example.clouddn.com/example/` // CDN 地址
}
}
複製程式碼
在 output.publicPath
中可以配置我們的 CDN 地址(這裡你要有一個七牛雲的 賬戶 )。之後我們引入 qn-webpack。
plugin 配置見該 plugin 原始碼即可。這裡有一份示例配置:
// webpack.config.js
const qiniuWebpackPlugin = new QiniuWebpackPlugin({
accessKey: `七牛雲個人皮膚 > 金鑰管理 > AK`,
secretKey: `七牛雲個人皮膚 > 金鑰管理 > SK`,
bucket: `物件儲存空間名`,
path: `空間內儲存路徑`,
exclude: /index.html$/ // 需要排除上傳的檔案
});
module.exports = {
// 載入外掛
plugins: [ qiniuWebpackPlugin ]
};
複製程式碼
現在執行:
npm run build # webpack --mode=production
複製程式碼
在終端中我們已經可以看到我們的 js 檔案被上傳至自己的 CDN 服務中。通過 html-webpack-plugin 我們引入 js 的路徑也相應的替換成了 CDN 地址。
上傳圖片
很多時候,在我們的專案中,需要去:
import url from `./your/img/path`;
<img src={url}>
複製程式碼
圖片掛上 CDN 也是很有必要的,圖片視訊檔案之類的東西本身就比較大而且可以算是靜態的內容,從動態伺服器上分離出去,可以極大的減小服務的負載。特別像是七牛雲這樣擁有圖片處理引擎的服務商,我們還可以通過 imageView2 來處理上傳至 CDN 的圖片。
說回圖片上傳,首先我們引入 file-loader ,Webpack 配置如下:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /.(gif|png|jpe?g|svg|webp)$/i,
use: [
{
loader: `file-loader`,
options: {
// publicPath: 預設 `__webpack_public_path__` 為 `output.publicPath`
}
}
]
}
]
}
}
複製程式碼
file-loader 會指示 Webpack 將所需的物件作為檔案引入並返回其公共 URL 。
再次執行:
npm run build # webpack --mode=production
複製程式碼
兩個檔案已經被上傳至 CDN ,且路徑被替換。但是, 2.74 MiB
與後面的 [big]
很是鮮豔,下一步我們需要壓縮圖片以減少檔案體積。
處理圖片
之前我們可以看看 Chrome 控制檯:
2.7 MiB
的圖片就算放在 CDN ,請求時間也超過了 100ms
,那麼我們開始處理圖片。
引入 image-webpack-loader 並開始配置 Webpack :
//webpack.config.js
module.exports = {
module: {
rules: [{
test: /.(gif|png|jpe?g|svg|webp)$/i,
use: [
{
loader: `file-loader`,
options: {
// publicPath: 預設 `__webpack_public_path__` 為 `output.publicPath`
}
}, {
loader: `image-webpack-loader`,
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false,
},
pngquant: {
quality: `65-90`,
speed: 4
},
gifsicle: {
interlaced: false,
},
WebP: {
quality: 75
}
}
},
],
}]
}
}
複製程式碼
詳細配置參見 文件 。
再次打包:
發現圖片大小從 2.74 MiB -> 1.16 MiB
雖然還是有點大,但是已經有很明顯的大小變化。再來看看 Chrome 控制檯:
效果很明顯 140 ms -> 43 ms
。
WebP
在進行這一步之前,需要簡單瞭解一下什麼是 WebP 格式圖片。
目前移動端 Android 4.0 以上、PC 端 Chorme 10+(14 ~ 16 有渲染bug)、Opera 11+ 、Safri 均支援 WebP 格式圖片。 WebP 與 jpg 相比較,編碼速度慢 10 倍,解碼速度慢 1.5 倍,而絕大部分的網路應用中,圖片都是靜態檔案,所以對於使用者使用只需要關心解碼速度即可。但實際上,webp 雖然會增加額外的解碼時間,但是由於減少了檔案體積,縮短了載入的時間,實際上檔案的渲染速度反而變快了。
搬運知乎上的一張圖片:
所以我們可以得出結論:WebP 體積大幅減少,圖片質量也有保障,除了相容性不太好。
對於相容性,我們可以看這張圖:
考慮到相容性的問題,我們之後會進行專門處理。現在第一步則是轉化 png & jpg -> Webp
。
這裡選用 gulp 作為轉化圖片為 WebP 的自動化構建工具。Webpack 社群外掛看 這裡,我這裡選用 gulp 作為構建工具也是希望自己能夠控制 WebP 圖片的製作,在本地生成而不是 CI 打包時(時間有點長… 。
//gulpfile.js
const gulp = require(`gulp`);
const webp = require(`gulp-webp`); // 基於 cwebp 的 gulp 外掛
// 基於 cwebp 轉化圖片
gulp.task(`webp`, () =>
gulp.src(`src/img/*.{png,jpg,jpeg}`)
.pipe(webp({ quality: 75 })) // 詳情配置見:https://github.com/imagemin/imagemin-webp#api
.pipe(gulp.dest(`src/img`))
);
// 監聽資料夾變化
gulp.task(`watch`, () =>
gulp.watch(`src/img/*.{png,jpg,jpeg}`, [`webp`])
);
gulp.task(`default`, () =>
gulp.start(`watch`)
);
複製程式碼
配置之後我們執行打包可以比較一下:
-
使用 WebP 格式前
-
使用 WebP 格式後
最後我們在專案中使用 WebP 時候,需要判斷一下瀏覽器是否支援 WebP 格式圖片:
const canUseWebp = (() => {
return document.createElement(`canvas`).toDataURL(`image/webp`).indexOf(`data:image/webp`) > -1;
})()
// 如果可以使用 WebP ,則給頂部元素加上一個 class
if (canUseWebp) {
document.getElementsByTagName(`body`)[0].className += ` webp`;
}
複製程式碼
將這段 js 內聯在 head 標籤中後,我們可以利用 CSS 前處理器來判斷是否需要使用 WebP 格式圖片。
// stylus
bg($url, $type)
background-image url($url + $type)
.webp & // 如果擁有 .webp 類名,則使用 WebP 格式圖片
background-image url($url + `.webp`)
複製程式碼
// less
.mixin(@url, @type) {
background-image: url(@{url}.@{type});
.webps & {
background-image: url(`@{url}.webp`);
}
}
複製程式碼
// scss
@mixin bg($url, $type) {
background-image: url($url + $type);
@at-root(with: all) .webps & {
background-image: url($url + `.webp`);
}
}
複製程式碼
Amigooo 部落格 地址