mirror of
https://github.com/jcreek/SelectionWheel.git
synced 2026-07-12 18:53:45 +00:00
feat(#6): Add PWA functionality and service worker
This commit is contained in:
Generated
+4700
-718
File diff suppressed because it is too large
Load Diff
+14
-6
@@ -4,8 +4,8 @@
|
||||
"description": "A fun and simple selection wheel.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"dev": "webpack serve",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"dev": "webpack serve --hot --config webpack.dev.js",
|
||||
"lint": "eslint --ignore-path .eslintignore --ext .js,.ts ."
|
||||
},
|
||||
"repository": {
|
||||
@@ -27,8 +27,6 @@
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"react-dev-utils": "^12.0.1",
|
||||
"sass": "^1.52.3",
|
||||
"sass-loader": "^13.0.0",
|
||||
"style-loader": "^3.3.1",
|
||||
@@ -36,10 +34,20 @@
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.9.2",
|
||||
"webpack-webmanifest-loader": "^2.0.2"
|
||||
"webpack-webmanifest-loader": "^2.0.2",
|
||||
"workbox-cli": "^6.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/d3": "^7.4.0",
|
||||
"d3": "^7.6.1"
|
||||
"d3": "^7.6.1",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"react-dev-utils": "^12.0.1",
|
||||
"webpack-manifest-plugin": "^5.0.0",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"workbox-navigation-preload": "^6.5.4",
|
||||
"workbox-precaching": "^6.5.4",
|
||||
"workbox-routing": "^6.5.4",
|
||||
"workbox-strategies": "^6.5.4",
|
||||
"workbox-webpack-plugin": "^6.5.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
"description": "A fun and simple selection wheel.",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./android-chrome-192x192.png",
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./android-chrome-512x512.png",
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as d3 from 'd3';
|
||||
import loadServiceWorker from './loadServiceWorker';
|
||||
|
||||
require('./assets/favicon.ico');
|
||||
require('./assets/android-chrome-192x192.png');
|
||||
@@ -208,3 +209,7 @@ function startSpinning() {
|
||||
|
||||
const button = document.getElementById('startSpinning');
|
||||
button.onclick = startSpinning;
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
loadServiceWorker();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
export default function loadServiceWorker() {
|
||||
let deferredPrompt;
|
||||
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
const installApp = document.getElementById('install-offline-app');
|
||||
|
||||
installApp.addEventListener('click', async () => {
|
||||
if (deferredPrompt !== null) {
|
||||
deferredPrompt.prompt();
|
||||
const { outcome } = await deferredPrompt.userChoice;
|
||||
if (outcome === 'accepted') {
|
||||
deferredPrompt = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('install-app-btn-container').style.display = 'block';
|
||||
deferredPrompt = e;
|
||||
});
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/service-worker.js');
|
||||
});
|
||||
|
||||
if (window.matchMedia('(display-mode: standalone)').matches) {
|
||||
document.getElementById('install-app-btn-container').style.display = 'none';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { precacheAndRoute } from 'workbox-precaching';
|
||||
import * as navigationPreload from 'workbox-navigation-preload';
|
||||
import { NetworkFirst, CacheFirst } from 'workbox-strategies';
|
||||
import { registerRoute, NavigationRoute, Route } from 'workbox-routing';
|
||||
|
||||
// Precache the manifest
|
||||
// eslint-disable-next-line no-underscore-dangle, no-restricted-globals
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
// Enable navigation preload - this should reduce navigation latency
|
||||
navigationPreload.enable();
|
||||
|
||||
const navigationRoute = new NavigationRoute(new NetworkFirst({
|
||||
cacheName: 'navigations',
|
||||
}));
|
||||
|
||||
const imageAssetRoute = new Route(({ request }) => request.destination === 'image', new CacheFirst({
|
||||
cacheName: 'image-assets',
|
||||
}));
|
||||
|
||||
registerRoute(navigationRoute);
|
||||
registerRoute(imageAssetRoute);
|
||||
@@ -26,5 +26,11 @@
|
||||
<textarea id="input-lines" rows="15" cols="60" name="text"
|
||||
placeholder="Enter names to be shuffled, one per line. Leave this area empty in order to use a default set of generated names."></textarea>
|
||||
<button id="startSpinning">Start spinning</button>
|
||||
|
||||
<p id="install-app-btn-container">
|
||||
<button id="install-offline-app" class="btn btn-secondary btn-xs">
|
||||
<span>Install the app (you can even use it offline!)</span>
|
||||
</button>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +1,12 @@
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
|
||||
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
|
||||
|
||||
const options = {};
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
target: 'web',
|
||||
entry: {
|
||||
bundle: path.resolve(__dirname, 'src/index.ts'),
|
||||
},
|
||||
@@ -12,23 +15,7 @@ module.exports = {
|
||||
filename: '[name].[contenthash].js',
|
||||
clean: true,
|
||||
assetModuleFilename: '[name].[contenthash][ext]',
|
||||
publicPath: './',
|
||||
},
|
||||
devtool: 'source-map',
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
port: 3000,
|
||||
open: true,
|
||||
hot: true,
|
||||
compress: true,
|
||||
historyApiFallback: true,
|
||||
devMiddleware: {
|
||||
index: true,
|
||||
mimeTypes: { phtml: 'text/html' },
|
||||
writeToDisk: true,
|
||||
},
|
||||
publicPath: '',
|
||||
},
|
||||
watchOptions: { poll: true },
|
||||
module: {
|
||||
@@ -100,5 +87,6 @@ module.exports = {
|
||||
template: 'src/template.html',
|
||||
}),
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/.*/]),
|
||||
new WebpackManifestPlugin(options),
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
const path = require('path');
|
||||
const { merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
port: 3000,
|
||||
open: true,
|
||||
hot: true,
|
||||
compress: true,
|
||||
historyApiFallback: true,
|
||||
devMiddleware: {
|
||||
index: true,
|
||||
mimeTypes: { phtml: 'text/html' },
|
||||
writeToDisk: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
const merge = require('webpack-merge');
|
||||
const { InjectManifest } = require('workbox-webpack-plugin');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
common.plugins.push(new InjectManifest({
|
||||
swSrc: './src/serviceWorker.js',
|
||||
swDest: 'service-worker.js',
|
||||
maximumFileSizeToCacheInBytes: 50000000,
|
||||
}));
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
performance: {
|
||||
hints: false,
|
||||
maxEntrypointSize: 512000,
|
||||
maxAssetSize: 512000,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user