
Product
Socket MCP Adds Org Alerts, Threat Feed Review, and Package Inspection
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.
@julien-lin/universal-pwa-cli
Advanced tools
Command-line interface for UniversalPWA - Transform any web project into a Progressive Web App (PWA) with one click.
npx @julien-lin/universal-pwa-cli init
This command will:
No global installation needed — npx is the recommended way to run the CLI.
UniversalPWA peut être configuré via un fichier de configuration pour éviter de passer toutes les options en ligne de commande.
npx @julien-lin/universal-pwa-cli generate-config
Cette commande génère un fichier universal-pwa.config.ts (ou .js, .json, .yaml) basé sur votre projet.
universal-pwa.config.ts (TypeScript - recommandé)universal-pwa.config.js (JavaScript)universal-pwa.config.json (JSON)universal-pwa.config.yaml (YAML)Voir CONFIGURATION.md pour la documentation complète avec tous les exemples.
init CommandInitialize a PWA in your project.
For projects using build tools (React, Vite, Vue, etc.), always build first, then initialize the PWA:
# 1. Build your project first (generates assets with hashes)
npm run build
# or
pnpm build
# or
yarn build
# 2. Then initialize PWA
# In interactive mode, select "Production" when prompted
# The CLI will auto-detect dist/ directory and suggest it
npx @julien-lin/universal-pwa-cli init
# Or explicitly specify output directory
npx @julien-lin/universal-pwa-cli init --output-dir dist
Why? The service worker needs to precache all your built assets (JS/CSS with hashes). If you initialize before building, the service worker won't know about the hashed filenames.
Environment Detection:
dist/ or build/ exists with recent files (< 24h)public/Simply run without arguments to launch interactive prompts:
npx @julien-lin/universal-pwa-cli init
The CLI will guide you through a 2-phase workflow:
Phase 1: Environment Selection
dist/ or build/ directoriesPhase 2: Application Configuration
package.json)All prompts include smart defaults, validation, and contextual suggestions!
npx @julien-lin/universal-pwa-cli init [options]
Options:
-p, --project-path <path> : Project path (default: current directory)-n, --name <name> : Application name-s, --short-name <shortName> : Short name (max 12 characters)-i, --icon-source <path> : Source image for icons-t, --theme-color <color> : Theme color (hex, e.g., #2c3e50)-b, --background-color <color> : Background color (hex)--skip-icons : Skip icon generation--skip-service-worker : Skip service worker generation--skip-injection : Skip meta-tags injection-o, --output-dir <dir> : Output directory (auto-detects dist/ for React/Vite, otherwise public/)--base-path <path> : Base path for deployment (e.g., /app/, /api/pwa/)Examples:
# For production build (React/Vite)
npm run build
npx @julien-lin/universal-pwa-cli init --output-dir dist --icon-source ./logo.png
# For development or static sites
npx @julien-lin/universal-pwa-cli init \
--name "My Application" \
--short-name "MyApp" \
--icon-source ./logo.png \
--theme-color "#2c3e50"
# For deployment under a subpath
npx @julien-lin/universal-pwa-cli init \
--name "CreativeHub" \
--output-dir public \
--base-path "/creativehub/"
# For API-based PWA
npx @julien-lin/universal-pwa-cli init \
--name "PWA API" \
--output-dir dist \
--base-path "/api/pwa/"
If your PWA is deployed under a subpath (e.g., behind a reverse proxy or on a shared domain), use the --base-path option to ensure all resources are properly scoped.
--base-path/app/ instead of //pwa/ or /myapp//api/v1/pwa/When you specify --base-path /app/:
<link rel="manifest" href="/app/manifest.json">/app/sw.js/app/ pathThis ensures:
Symfony Project - Deployed under /creative-hub/ path:
npm run build
npx @julien-lin/universal-pwa-cli init \
--name "Creative Hub" \
--output-dir public \
--base-path "/creative-hub/"
Next.js with Custom Base Path:
pnpm build
npx @julien-lin/universal-pwa-cli init \
--output-dir .next \
--base-path "/dashboard/"
Static Site on Shared Hosting - Deployed at example.com/apps/myapp/:
npx @julien-lin/universal-pwa-cli init \
--name "My App" \
--output-dir dist \
--base-path "/apps/myapp/"
Important Notes:
/ and ideally end with /https://yourdomain/basePath/manifest.json is accessibleThe CLI automatically injects a PWA install handler into your HTML. To display an install button in your application, use the exposed global functions:
window.installPWA() : Triggers the install promptwindow.isPWAInstalled() : Checks if the app is already installedwindow.isPWAInstallable() : Checks if the app is installable// Check if installable and show a button
if (window.isPWAInstallable && window.isPWAInstallable()) {
const installButton = document.createElement("button");
installButton.textContent = "Install App";
installButton.onclick = () => {
window.installPWA().catch(console.error);
};
document.body.appendChild(installButton);
}
import { useState, useEffect } from "react";
function InstallButton() {
const [isInstallable, setIsInstallable] = useState(false);
const [isInstalled, setIsInstalled] = useState(false);
useEffect(() => {
// Check initial state
if (window.isPWAInstalled) {
setIsInstalled(window.isPWAInstalled());
}
if (window.isPWAInstallable) {
setIsInstallable(window.isPWAInstallable());
}
// Listen to custom events
const handleInstallable = () => setIsInstallable(true);
const handleInstalled = () => {
setIsInstalled(true);
setIsInstallable(false);
};
window.addEventListener("pwa-installable", handleInstallable);
window.addEventListener("pwa-installed", handleInstalled);
return () => {
window.removeEventListener("pwa-installable", handleInstallable);
window.removeEventListener("pwa-installed", handleInstalled);
};
}, []);
if (isInstalled || !isInstallable) {
return null;
}
return <button onClick={() => window.installPWA?.()}>Install App</button>;
}
The injected script emits custom events you can listen to:
pwa-installable : Emitted when the app becomes installablepwa-installed : Emitted after successful installationpwa-install-choice : Emitted with user's choice ({ detail: { outcome: 'accepted' | 'dismissed' } })scan CommandScan a project and detect framework, architecture, and assets.
npx @julien-lin/universal-pwa-cli scan [options]
Options:
-p, --project-path <path> : Project path (default: current directory)Example:
npx @julien-lin/universal-pwa-cli scan
Output:
preview CommandPreview the PWA configuration of a project.
npx @julien-lin/universal-pwa-cli preview [options]
Options:
-p, --project-path <path> : Project path (default: current directory)--port <port> : Server port (default: 3000)--open : Open in browserExample:
npx @julien-lin/universal-pwa-cli preview --port 8080
After running npx @julien-lin/universal-pwa-cli init, the following files are generated:
manifest.json - PWA manifest filesw.js - Service Worker (Workbox)sw-src.js - Service Worker source (for customization)icon-*.png - PWA icons in multiple sizes (72x72 to 512x512)apple-touch-icon.png - Apple Touch Icon (180x180)splash-*.png - Splash screens for iOSMeta tags are automatically injected into your HTML files.
You can also use the CLI as a module:
import { initCommand } from "@julien-lin/universal-pwa-cli";
const result = await initCommand({
projectPath: "./my-project",
name: "My App",
iconSource: "./icon.png",
});
If UniversalPWA is useful to you, please consider sponsoring the project to help maintain and improve it.
# Install dependencies
pnpm install
# Build
pnpm build
# Tests
pnpm test
# Lint
pnpm lint
FAQs
CLI to transform any web project into a PWA
We found that @julien-lin/universal-pwa-cli demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.

Product
Socket Firewall blocks malicious VS Code and Open VSX extensions before install, protecting developers from compromised editor marketplaces.

Research
More than 140 Mastra npm packages were compromised in a supply chain attack that used a typosquatted dependency to deliver a cross-platform infostealer during installation.