到目前為止,這份說明文件已著重在預先快取方面,經常需要關注 generateSW
和 injectManifest
建構工具。雖然在服務 Worker 中加入預先快取邏輯的好理由很多,但不必透過預先快取即可使用 Workbox。
或許您的專案只需要執行階段快取,或者您想要以更簡潔的方式整合 Service Worker API,例如網路推送。您不想使用 Workbox 建構工具時,可以考慮本文的說明。
使用 Bundler 時
Bundler 在網站開發環境中相當顯眼,因此您的專案很有可能正在使用套件工具。如果是這種情況,請務必確定不需要使用 Bundler 外掛程式 (例如 workbox-webpack-plugin
)。您必須將 Service Worker 視為應用程式中的獨立進入點。
在專案的來源目錄的根目錄中,請建立 Service Worker,並使用應用程式所需的任何 Workbox 模組。以下為沒有預先快取的範例,改為在不同的 Cache
執行個體中設定導覽和圖片素材資源要求的快取策略:
// sw.js
import {NetworkFirst, CacheFirst} from 'workbox-strategies';
import {registerRoute, NavigationRoute, Route} from 'workbox-routing';
const navigationRoute = new NavigationRoute(new NetworkFirst({
cacheName: 'navigations'
}));
const imageAssetRoute = new Route(({request}) => {
return request.destination === 'image';
}, new CacheFirst({
cacheName: 'image-assets'
}));
registerRoute(navigationRoute);
registerRoute(imageAssetRoute);
接著,請將這個 Service Worker 指定為所選 Bundler 中的進入點。以下將列舉在幾種常見的整合套件中執行此操作。
Webpack
webpack 的 entry
設定接受進入點。使用這個方法時,請留意以下事項:
- 為了確保 Service Worker 可盡可能涵蓋最多的範圍,最好將該檔案輸出至輸出目錄的根目錄。
- 您不想讓 Service Worker 的版本成為版本,因為只要更新服務會產生新的雜湊值,可能會導致多個 Service Worker 部署在您的網站上。
如要符合上述條件,您可以將函式傳遞至 output.filename
,藉此檢查目前處理中的進入點是否為 Service Worker 進入點。否則,版本化檔案會寫入其正常目的地。
// webpack.config.js
import process from 'process';
const isProd = process.env.NODE_ENV === 'production';
export default {
mode: isProd ? 'production' : 'development',
context: process.cwd(),
entry: {
// Service worker entry point:
sw: './src/sw.js',
// Application entry point:
app: './src/index.js'
},
output: {
filename: ({runtime}) => {
// Check if the current filename is for the service worker:
if (runtime === 'sw') {
// Output a service worker in the root of the dist directory
// Also, ensure the output file name doesn't have a hash in it
return '[name].js';
}
// Otherwise, output files as normal
return 'js/[name].[contenthash:8].js';
},
path: './dist',
publicPath: '/',
clean: true
}
};
匯總資料
Rollup 與 webpack 類似,不同之處在於將多個進入點指定為匯出在陣列中的個別設定物件:
// rollup.config.js
import { nodeResolve } from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
// Plugins common to both entry points
const plugins = [
nodeResolve(),
];
export default [
// Application entry point
{
input: './src/index.js',
output: {
dir: './dist/js',
format: 'esm'
},
plugins
},
// Service worker entry point
{
input: './src/sw.js',
output: {
file: './dist/sw.js',
format: 'iife'
},
plugins: [
...plugins,
// This @rollup/plugin-replace instance replaces process.env.NODE_ENV
// statements in the Workbox libraries to match your current environment.
// This changes whether logging is enabled ('development') or disabled ('production').
replace({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
})
]
}
];
esbuild
esbuild 提供簡單明瞭的指令列介面:
npx esbuild ./src/sw.js --bundle --minify --outfile=./dist/sw.js
esbuild 會以預設的「development」取代 process.env.NODE_ENV,或如果啟用壓縮功能,ebuild 就會取代「production」。
沒有使用 workbox-sw
的 Bundler
您的專案甚至可能未使用 Bundler。workbox-sw
可以在服務工作站中的 CDN 中為您載入 Workbox 執行階段,而且如果您透過 importScripts
匯入這個執行階段,就不需要執行建構步驟:
// sw.js
// Imports Workbox from the CDN. Note that "6.2.0" of the URL
// is the version of the Workbox runtime.
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.2.0/workbox-sw.js');
const navigationRoute = new workbox.routing.NavigationRoute(new workbox.strategies.NetworkFirst({
cacheName: 'navigations'
}));
const imageAssetRoute = new workbox.routing.Route(({request}) => {
return request.destination === 'image';
}, new workbox.strategies.CacheFirst({
cacheName: 'image-assets'
}));
workbox.routing.registerRoute(navigationRoute);
workbox.routing.registerRoute(staticAssetRoute);
如果想從 CDN 載入 Workbox 執行階段,建議您搭配本機網址使用 workbox-sw
,
結語
現在您已學會如何在不使用快取的情況下使用 Workbox,就不用再綁定特定套件或建構工具。如此一來,您就可以靈活運用 Workbox 的執行階段快取程式碼,迅速打造服務 Worker。