Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor code #17

Merged
merged 23 commits into from
Feb 5, 2021
27 changes: 27 additions & 0 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Linter

on: [push, pull_request]

jobs:
linter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Use Node.js 12.x
uses: actions/setup-node@v2
with:
node-version: '12.x'
- name: Cache NPM dependencies
uses: actions/cache@v1
with:
path: node_modules
key: ${{ runner.OS }}-npm-cache
restore-keys: |
${{ runner.OS }}-npm-cache
- name: Install Dependencies
run: npm install
- name: Lint
run: |
npm run eslint
env:
CI: true
60 changes: 60 additions & 0 deletions .github/workflows/tester.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Tester

on: [push, pull_request]

jobs:
tester:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: ['10.x', '12.x', '14.x']
fail-fast: false
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache NPM dependencies
uses: actions/cache@v1
with:
path: node_modules
key: ${{ runner.os }}-npm-cache
restore-keys: ${{ runner.os }}-npm-cache
- name: Install Dependencies
run: npm install
- name: Test
run: npm run test
env:
CI: true
coverage:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: ['12.x']
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Cache NPM dependencies
uses: actions/cache@v1
with:
path: node_modules
key: ${{ runner.os }}-npm-cache
restore-keys: ${{ runner.os }}-npm-cache
- name: Install Dependencies
run: npm install
- name: Run test
run: npm run test
# - name: Coverage
# run: npm run test-cov
# env:
# CI: true
# - name: Coveralls
# uses: coverallsapp/github-action@master
# with:
# github-token: ${{ secrets.github_token }}
2 changes: 2 additions & 0 deletions .yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
disable-self-update-check true
registry "https://registry.npmjs.org"
47 changes: 18 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@

## Install

If you use [next](https://github.com/theme-next/hexo-theme-next) or [cake](https://github.com/jiangtj/hexo-theme-cake) theme, just install it.

```bash
yarn add @jiangtj/hexo-next-pwa
```

Others, you need to install hexo5.0 or the latest master branch
require: hexo5+ or [next](https://github.com/theme-next/hexo-theme-next)/[cake](https://github.com/jiangtj/hexo-theme-cake) theme

## Configure

I added some default configurations, see [default.yaml](default.yaml)

```yml
pwa:
# Generate manifest.json
Expand All @@ -40,44 +40,33 @@ pwa:
# type: image/png
# Generate sw.js
serviceWorker:
cdn: https://cdn.jsdelivr.net/npm/workbox-sw@5/build/workbox-sw.min.js
# See workbox-build's `generateSW()` API
# Here are some default configuration, see `./default.yaml`
precache:
# precache posts url
posts:
enable: true
sort: -date
limit: 10
# precache pages url
pages: true
options:
# sw file path
swDest: /sw.js
```

`serviceWorker.options` refer to [the workbox-build's `generateSW()` API](https://developers.google.cn/web/tools/workbox/reference-docs/latest/module-workbox-build#.generateSW). Some configurations are not supported for the time being. See the compatibility table below.
`serviceWorker.precache` define how to precache url.

| feature | status |
`serviceWorker.options` refer to [the workbox-build's `generateSW()` API](https://developers.google.cn/web/tools/workbox/reference-docs/latest/module-workbox-build#.generateSW). Some configurations are not supported, due to the precache manifest is generated in different ways.

| options | compatibility |
| :--- | :--- |
| swDest | ✔ relative to build directory |
| importScripts | ✔ |
| offlineGoogleAnalytics | ✔ |
| runtimeCaching | ✔ |
| swDest | relative to build directory |
| globDirectory | ✖ |
| additionalManifestEntries | ✖ |
| babelPresetEnvTargets | ✖ |
| cacheId | plan |
| cleanupOutdatedCaches | ✖ |
| clientsClaim | ✖ |
| directoryIndex | ✖ |
| dontCacheBustURLsMatching | ✖ |
| globFollow | ✖ |
| globIgnores | ✖ |
| globPatterns | ✖ |
| globStrict | ✖ |
| ignoreURLParametersMatching | ✖ |
| inlineWorkboxRuntime | ✖ |
| manifestTransforms | ✖ |
| maximumFileSizeToCacheInBytes | plan |
| mode | ✖ |
| maximumFileSizeToCacheInBytes | ✖ |
| modifyURLPrefix | ✖ |
| navigateFallback | ✖ |
| navigateFallbackDenylist | ✖ |
| navigateFallbackAllowlist | ✖ |
| navigationPreload | ✖ |
| skipWaiting | plan |
| sourcemap | ✖ |
| templatedURLs | ✖ |

20 changes: 12 additions & 8 deletions default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,41 @@ pwa:
# sizes: 512x512
# type: image/png
serviceWorker:
cdn: https://cdn.jsdelivr.net/npm/workbox-sw@5/build/workbox-sw.min.js
disableDevLogs: false
precache:
posts:
enable: true
sort: -date
limit: 10
pages: true
options:
swDest: /sw.js
importScripts: []
runtimeCaching:
- urlPattern: /
handler: NetworkFirst
options:
cacheName: index
- urlPattern: !!js/regexp /\.(?:js|css)$/
- urlPattern: regexp:\.(?:js|css)$
handler: StaleWhileRevalidate
options:
cacheName: js-css
- urlPattern: !!js/regexp /\.(?:png|gif|jpg|jpeg|svg)$/
- urlPattern: regexp:\.(?:png|gif|jpg|jpeg|svg)$
handler: CacheFirst
options:
cacheName: images
cacheableResponse:
statuses: [0, 200]
expiration:
maxEntries: 60
maxAgeSeconds: 2592000 # 30 * 24 * 60 * 60
- urlPattern: !!js/regexp /^https:\/\/fonts\.googleapis\.com/
- urlPattern: regexp:^https:\/\/fonts\.googleapis\.com
handler: StaleWhileRevalidate
options:
cacheName: google-fonts-stylesheets
- urlPattern: !!js/regexp /^https:\/\/fonts\.gstatic\.com/
- urlPattern: regexp:^https:\/\/fonts\.gstatic\.com
handler: CacheFirst
options:
cacheName: google-fonts-webfonts
cacheableResponse:
statuses: [0, 200]
expiration:
maxAgeSeconds: 31536000 # 365 * 24 * 60 * 60
offlineGoogleAnalytics: false
37 changes: 18 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,24 @@
'use strict';

const { generator } = hexo.extend;
const { mergeWith } = require('lodash');
const yaml = require('js-yaml');
const fs = require('fs');
const { join } = require('path');
const injector = require('hexo-extend-injector2')(hexo);
const config = require('./lib/get-default-config')(hexo);
const validate = require('./lib/validate-sw-options');

/**
* config
*/
const defaultConfig = yaml.load(fs.readFileSync(join(__dirname, 'default.yaml'), 'utf8'));
const config = mergeWith(defaultConfig.pwa, hexo.config.pwa, (objValue, srcValue) => {
if (Array.isArray(objValue)) {
return srcValue;
}
});
const { manifest, serviceWorker } = config;
serviceWorker.options = validate(serviceWorker.options);

/**
* generator manifest
*/
injector.register('head-end', `<link rel="manifest" href="${config.manifest.path}" />`);
injector.register('head-end', `<link rel="manifest" href="${manifest.path}" />`);
generator.register('pwa_manifest', () => {
const manifest = config.manifest;
return {
path: manifest.path,
data: JSON.stringify(
Object.assign({
name: config.title,
start_url: config.url
name: hexo.config.title,
start_url: hexo.config.url
}, manifest.body)
)
};
Expand All @@ -43,9 +33,18 @@ injector.register('body-end', `
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('${config.serviceWorker.options.swDest}');
navigator.serviceWorker.register('${serviceWorker.options.swDest}');
});
}
</script>
`);
generator.register('pwa_service_worker', () => require('./lib/generate-sw-string')(config.serviceWorker));

generator.register('pwa_service_worker', locals => {
return require('./lib/generate-sw-string')(locals, serviceWorker)
.then(({files}) => {
return files.map(file => ({
path: file.name,
data: file.contents
}));
});
});
19 changes: 0 additions & 19 deletions lib/define-cache.js

This file was deleted.

81 changes: 27 additions & 54 deletions lib/generate-sw-string.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,38 @@
'use strict';

const ejs = require('ejs');
const { resolve } = require('path');
const { upperFirst } = require('lodash');
const DefineCache = require('./define-cache');
const define = new DefineCache();
const getStringHash = require('./get-string-hash');
const writeServiceWorkerUsingDefaultTemplate = require('./write-sw-using-default-template');

const handeRuntimeCaching = runtimeCachingEntry => {
let capture = runtimeCachingEntry.urlPattern;
if (typeof capture === 'string') {
capture = `'${capture}'`;
}

const options = runtimeCachingEntry.options || {};

options.plugins = options.plugins || [];
['backgroundSync', 'broadcastUpdate', 'cacheableResponse', 'expiration'].forEach(item => {
if (options[item]) {
const plugin = {};
plugin.name = item;
plugin.options = options[item];
options.plugins.push(plugin);
delete options[item];
}
});
options.plugins = options.plugins.map(plugin => {
const pluginDefine = `${upperFirst(plugin.name)}Plugin`;
define.set(`workbox.${plugin.name}`, pluginDefine);
return `new ${pluginDefine}(${JSON.stringify(plugin.options)})`;
});
module.exports = async (locals, serviceWorker) => {

define.set('workbox.strategies', runtimeCachingEntry.handler);
const handler = `new ${runtimeCachingEntry.handler}(${JSON.stringify(options, (key, value) => {
if (key === 'plugins') {
return '$plugins-point';
}
return value;
})})`.replace('"$plugins-point"', `[${options.plugins.join(',')}]`);
const { precache, options } = serviceWorker;
const { pages, posts } = locals;

const method = runtimeCachingEntry.method || 'GET';
const manifestEntries = [];

define.set('workbox.routing', 'registerRoute');
return `registerRoute(${capture}, ${handler}, '${method}');`;
};

module.exports = serviceWorker => {
const options = Object.assign({
workboxCDN: serviceWorker.cdn,
disableDevLogs: serviceWorker.disableDevLogs
}, serviceWorker.options);
if (precache.posts.enable) {
posts.sort(precache.posts.sort)
.limit(precache.posts.limit)
.forEach(item => {
manifestEntries.push({
url: item.path,
revision: getStringHash(item.content)
});
});
}

if (options.runtimeCaching) {
options.runtimeCaching = options.runtimeCaching.map(handeRuntimeCaching);
if (precache.pages) {
pages.forEach(item => {
manifestEntries.push({
url: item.path,
revision: getStringHash(item.content)
});
});
}

options.importDefine = define.toString();
const files = await writeServiceWorkerUsingDefaultTemplate(Object.assign({
manifestEntries
}, options));

return {
path: options.swDest,
data: () => {
return ejs.renderFile(resolve(__dirname, '../templates/sw-template.ejs'), options);
}
};
return {files};
};
Loading