sw.js 3.58 KB
/* eslint-env worker */
/* global FetchEvent */

import 'whatwg-fetch';
import WorkboxSW from 'workbox-sw';
import parseQs from 'yoho-qs/parse';

/**
 * 需要缓存的路径
 */
const CACHED_PATH = [
    'boys',
    'girls',
    'kids',
    'lifestyle',
    'cate',
    'list',
    'search',
    'product',
    'shop',
    'guang'
];

const config = {
    customCacheUrl: [
        /^https:\/\/(.*)cdn\.yoho\.cn/i

        // /^https:\/\/(.*)static\.yhbimg\.com/i
    ],
    precachePage: [
        '/offline.html'
    ],
    precacheStaticFile: [
        '/index.css',
        '/common.css',
        '/libs.js',
        '/font/iconfont.woff',
        '/common.offline.js',
        '/common.offline.css'
    ],
    precacheCdnStaticFile: [
        'https://cdn.yoho.cn/pwa/404.png'
    ]
};
const qs = parseQs(self.location.search.substr(1));
const workboxSW = new WorkboxSW({
    clientsClaim: true,
    skipWaiting: true
});
const cacheFirstStrategy = workboxSW.strategies.cacheFirst({
    cacheableResponse: {
        statuses: [0, 200]
    },
    cacheExpiration: {
        maxEntries: 1000,
        maxAgeSeconds: 7 * 24 * 60 * 60 // 7 day
    }
});

// 特殊路径的预缓存文件文件
const precacheFile = [{
    url: '/sw.js?t=' + qs.t + '&staticServer=' + qs.staticServer
}].concat(config.precacheStaticFile.map(file => {
    // 根据业务自定义资源路径
    const url = self.location.protocol + qs.staticServer + file + '?t=' + qs.t;

    return {
        url: url
    };
})).concat(config.precachePage.map(page => {
    return {
        url: page + '?t=' + qs.t
    };
})).concat(config.precacheCdnStaticFile.map(file => {
    return {
        url: file
    };
}));

// 预加载文件
workboxSW.precache(precacheFile);

// 自定义缓存
config.customCacheUrl.forEach(urlRegExp => {
    workboxSW.router.registerRoute(
        urlRegExp,
        cacheFirstStrategy
    );
});

// 所有网络走 worker,异常时增加离线页面
workboxSW.router.registerRoute(args => {
    let cached = false;
    let routeRegExp = new RegExp(`^\/(${CACHED_PATH.join('|')})`);

    if (/^https:\/\/m.yohobuy.com/.test(args.url.href) &&
        (routeRegExp.test(args.url.pathname) ||
        args.url.pathname === '/')) {
        cached = true;
    }

    if (args.event.request.headers.get('x-requested-with') === 'XMLHttpRequest') {
        cached = false;
    }

    return cached;
}, args => {
    return workboxSW.strategies.networkFirst({
        cacheExpiration: {
            maxEntries: 300,
            maxAgeSeconds: 12 * 60 * 60 // 12 小时
        }
    }).handle(args).then(res => {
        if (res || args.event.request.mode !== 'navigate') {
            return res;
        }

        // navigate 请求失败后,返回网络异常页面
        return caches.match('offline.html?t=' + qs.t);
    });
});

/**
 * webp 处理
 * 匹配非 webp 的 cdn 图片资源,缓存其 webp 格式
 */
workboxSW.router.registerRoute(args => {
    let useWebp = false;
    let supportWebp = /image\/webp/i.test(args.event.request.headers.get('Accept'));

    if (!supportWebp) {
        return useWebp;
    }

    if (/^https:\/\/(.*)static\.yhbimg\.com(.*)(png|jpg|jpeg)\?(imageView|imageMogr)(.*)/.test(args.url.href) &&
    /^(?!.*format\/).*/.test(args.url.href)) {
        useWebp = true;
    }

    return useWebp;
}, args => {

    // 重新构造 fetch 请求
    args.event = new FetchEvent(args.event.type, {
        request: new Request(args.event.request.url + '/format/webp'),
        clientId: args.event.clientId,
        isReload: args.event.isReload
    });

    return workboxSW.strategies.networkOnly().handle(args);
});