PWA Helpers
pwa-helpers is a collection of small, focused helper methods and mixins designed to reduce boilerplate when building Progressive Web Apps. It offers utilities for common PWA features such as client-side routing, network connectivity detection, dynamic metadata updates for SEO and social sharing, and media query monitoring. The current stable version is 0.9.1, with recent updates including TypeScript support introduced in v0.9.0. This library is designed to be framework-agnostic, providing vanilla JavaScript functions that can integrate with any web application stack, differentiating itself by its minimalist approach rather than being a comprehensive framework.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'call') at installRouter
cause Attempting to call `installRouter` (or other helpers) as a function when it was imported incorrectly, often due to a CommonJS `require()` in an ESM-only context or an incorrect named import.fixEnsure you are using named ES module imports: `import { installRouter } from 'pwa-helpers/router.js';`. Verify that your build setup correctly handles ES modules. -
Error: Cannot find module 'pwa-helpers/router.js' or 'pwa-helpers/network.js'
cause Module resolution failure, often due to missing the `.js` extension in the import path, or incorrect pathing in a non-bundled environment.fixAlways include the `.js` file extension in your `import` paths for `pwa-helpers` modules, e.g., `import { installRouter } from 'pwa-helpers/router.js';`. This is crucial for browser-native ESM and some Node.js module resolvers.
Warnings
- gotcha pwa-helpers is designed as an ES Module (ESM) library. Attempting to use `require()` for imports in a CommonJS environment without proper transpilation or bundler configuration will lead to module resolution errors.
- gotcha When programmatically changing the URL (e.g., in a single-page application), `installRouter`'s callback is not automatically triggered by `window.history.pushState` or `replaceState`. You must manually call the callback with `window.location` after modifying the history.
- gotcha The `metadata.js` helper will only update fields for which values are explicitly provided. If a property like `image` or `description` is omitted from the object passed to `updateMetadata`, the corresponding Open Graph or Twitter card tag will not be set or updated, rather than cleared.
- gotcha The TypeScript support introduced in `v0.9.0` adds type definitions. While this doesn't break JavaScript usage, projects with strict TypeScript configurations or specific build setups might need to ensure their `tsconfig.json` correctly includes or excludes declaration files if unexpected build issues arise.
Install
-
npm install pwa-helpers -
yarn add pwa-helpers -
pnpm add pwa-helpers
Imports
- installRouter
const { installRouter } = require('pwa-helpers/router');import { installRouter } from 'pwa-helpers/router.js'; - updateMetadata
import updateMetadata from 'pwa-helpers/metadata';
import { updateMetadata } from 'pwa-helpers/metadata.js'; - installOfflineWatcher
import { installOfflineWatcher } from 'pwa-helpers/network';import { installOfflineWatcher } from 'pwa-helpers/network.js';
Quickstart
import { installRouter } from 'pwa-helpers/router.js';
import { updateMetadata } from 'pwa-helpers/metadata.js';
import { installOfflineWatcher } from 'pwa-helpers/network.js';
// A dummy store and navigate action for the example
const store = {
dispatch: (action) => console.log('Dispatching action:', action)
};
const navigate = (location) => ({ type: 'NAVIGATE', payload: location.pathname });
function handleNavigation(location, event = null) {
console.log('Navigated to:', location.pathname);
// Example of integrating with a Redux-like store
store.dispatch(navigate(location));
// Update metadata based on the current route
updateMetadata({
title: `My PWA - ${location.pathname.substring(1) || 'Home'}`,
description: `Content for ${location.pathname}`,
url: window.location.href
});
if (event && event.type === 'click') {
window.scrollTo(0, 0);
console.log('Scrolled to top after click.');
}
}
// Install the router
installRouter(handleNavigation);
// Install the offline watcher
installOfflineWatcher((offline) => {
const message = offline ? 'You are currently OFFLINE' : 'You are currently ONLINE';
console.log(message);
// Optionally update UI based on connectivity
const statusElement = document.getElementById('network-status');
if (statusElement) statusElement.textContent = message;
});
// Simulate a programmatic navigation
setTimeout(() => {
window.history.pushState({}, '', '/about');
handleNavigation(window.location);
}, 2000);
// Create a simple div for network status (if running in a browser environment)
if (typeof document !== 'undefined') {
const statusDiv = document.createElement('div');
statusDiv.id = 'network-status';
statusDiv.textContent = 'Checking network status...';
document.body.appendChild(statusDiv);
}