JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2
  • Score
    100M100P100Q12043F
  • License MIT

Force update and synchronize versions for React apps using cache busting and service worker management

Package Exports

  • versynch
  • versynch/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (versynch) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

🔄 versynch

The most reliable auto-update & version sync solution for React + PWA apps

npm License

🎉 NOW LIVE ON NPM! Install with: npm install versynch

versynch is a comprehensive solution for managing version control and force-updating outdated React applications. It solves the problem of users getting stuck with stale cached versions, especially in PWA (Progressive Web App) environments.

✨ Features

  • Force Update Detection System

    • Detects legacy versions automatically on app load
    • Forces immediate cache clearing and update for severely outdated versions
    • Shows update notifications and handles the process smoothly
    • Configurable minimum build thresholds for enforcing updates
    • Safe implementation for apps without previous versioning
  • Version Management System

    • Full version tracking with semantic versioning support
    • Build numbers for precise version control
    • Automatic detection of users on old versions
    • Automated build number generation for CI/CD workflows
  • Smart Update Experience

    • Detects user activity to avoid interrupting work
    • Background updates when users are inactive
    • Configurable countdown timers and postpone options
  • Reliable Cache Busting

    • Aggressive cache clearing for legacy users
    • Service worker unregistration for clean slate
    • Timestamp-based URL parameters for cache busting

🚀 Installation

The package is now available on npm! Install it using your preferred package manager:

# Using npm
npm install versynch

# Using yarn
yarn add versynch

# Using pnpm
pnpm add versynch

📋 Requirements

  • React 16.8+ (uses hooks)
  • TypeScript (optional but recommended)
  • For full functionality, your app should use service workers

🧩 Usage

Basic Setup

import React from 'react';
import { ForceUpdateDetector, UpdateNotification } from 'versynch';

const App: React.FC = () => {
  // Your app's current version
  const appVersion = "2.1.0";
  const buildNumber = 210;

  return (
    <>
      <ForceUpdateDetector
        version={appVersion}
        build={buildNumber}
        minBuildToForceUpdate={200} // Users with builds below 200 will be forced to update
        onForceUpdate={() => console.log("Force updating...")}
      >
        <div className="app-content">
          {/* Your app content */}
        </div>
        
        <UpdateNotification 
          version={appVersion}
          build={buildNumber}
        />
      </ForceUpdateDetector>
    </>
  );
};

// For apps without previous versioning
const FirstTimeVersioningApp: React.FC = () => {
  // Initial version for an app that didn't have versioning before
  const appVersion = "1.0.0";
  const buildNumber = 100;

  return (
    <>
      <ForceUpdateDetector
        version={appVersion}
        build={buildNumber}
        minBuildToForceUpdate={0} // Set to 0 to avoid forcing updates on first implementation
        onForceUpdate={() => console.log("Processing update...")}
      >
        <div className="app-content">
          {/* Your app content */}
        </div>
        
        <UpdateNotification 
          version={appVersion}
          build={buildNumber}
        />
      </ForceUpdateDetector>
    </>
  );
};

export default App;

Automated Build Numbers

versynch includes tools to automatically generate build numbers in your CI/CD pipelines:

import React from 'react';
import { ForceUpdateDetector, UpdateNotification } from 'versynch';
import { BUILD_INFO } from './buildInfo'; // Auto-generated file

const App: React.FC = () => {
  // App version info is imported from auto-generated buildInfo.ts
  const { version, buildNumber } = BUILD_INFO;
  
  return (
    <>
      <ForceUpdateDetector
        version={version}
        build={buildNumber}
        minBuildToForceUpdate={2025060100000} // Force update for builds before June 1, 2025
        onForceUpdate={() => console.log(`Updating to ${version}...`)}
      >
        <div className="app-content">
          {/* Your app content */}
        </div>
        
        <UpdateNotification 
          version={version}
          build={buildNumber}
        />
      </ForceUpdateDetector>
    </>
  );
};

export default App;

To automatically generate build numbers in your CI/CD pipeline:

  1. Add a build step that runs the provided script:

    node scripts/generate-build-number.js
  2. Import the auto-generated build info in your app

For detailed instructions and examples, see Automated Build Documentation and GitHub Actions Examples.

Using the hooks directly

import React from 'react';
import { useVersionManager, useCacheUpdateManager } from 'versynch';

const AppVersionInfo: React.FC = () => {
  const { 
    currentVersion, 
    currentBuild,
    isUpdateAvailable,
    isForceUpdate,
    forceUpdate 
  } = useVersionManager({
    version: '2.1.0',
    build: 210
  });
  
  const {
    isUpdateInProgress,
    countdownSeconds,
    handleUpdate,
    postponeUpdate
  } = useCacheUpdateManager({
    isUpdateAvailable,
    onUpdateConfirmed: forceUpdate
  });
  
  return (
    <div>
      <h2>Current Version: {currentVersion}</h2>
      <p>Build: {currentBuild}</p>
      
      {isUpdateAvailable && (
        <div>
          <p>Update available! Installing in {countdownSeconds} seconds.</p>
          <button onClick={handleUpdate}>Update now</button>
          <button onClick={postponeUpdate}>Later</button>
        </div>
      )}
    </div>
  );
};

Service Worker Integration

For the best experience, enhance your service worker with version broadcasting:

// In your service worker (sw.js)
const APP_VERSION = '2.1.0';
const BUILD_NUMBER = 210;

// On activation, notify all clients
self.addEventListener('activate', (event) => {
  event.waitUntil(
    self.clients.matchAll().then(clients => {
      clients.forEach(client => {
        client.postMessage({
          type: 'SW_UPDATED',
          version: APP_VERSION,
          timestamp: Date.now()
        });
      });
    })
  );
});

⚙️ API Reference

Components

<ForceUpdateDetector>

Core component that detects outdated app versions and forces updates.

<ForceUpdateDetector
  version="2.1.0"              // Current app version
  build={210}                  // Current build number
  minBuildToForceUpdate={150}  // Min build number that's acceptable
  updateDelay={3000}           // Delay before forcing update (ms)
  onForceUpdate={() => {}}     // Callback when force update begins
  onUpdateAvailable={() => {}} // Callback when update detected
  onUpdateComplete={() => {}}  // Callback when update finishes
  showFallbackUI={true}        // Whether to show loading UI
  fallbackUI={<CustomLoader />} // Custom loading component
>
  {/* Your app content */}
</ForceUpdateDetector>

<UpdateNotification>

Component that shows a notification when an update is available.

<UpdateNotification
  version="2.1.0"              // Current app version
  build={210}                  // Current build number
  countdownDuration={60000}    // Countdown time before auto-update (ms)
  maxPostponeCount={3}         // Max times user can postpone update
  show={true}                  // Whether to show notification
  renderNotification={(props) => (
    // Custom notification UI
    <CustomNotification {...props} />
  )}
/>

Service Worker Integration

versynch provides tools for integrating with service workers to enhance the update process:

import { 
  registerServiceWorker,
  checkForServiceWorkerUpdate,
  activateServiceWorkerUpdate,
  BUILD_INFO 
} from 'versynch';

function App() {
  useEffect(() => {
    // Register service worker with version info
    registerServiceWorker();
    
    // Listen for updates
    window.addEventListener('serviceWorkerUpdateAvailable', () => {
      console.log('Update available!');
    });
  }, []);
  
  const handleCheckForUpdates = async () => {
    const hasUpdate = await checkForServiceWorkerUpdate();
    if (hasUpdate) {
      console.log('Update available!');
    }
  };
  
  const handleApplyUpdate = async () => {
    await activateServiceWorkerUpdate();
    // Page will reload with new version
  };
  
  return (
    <ForceUpdateDetector
      version={BUILD_INFO.version}
      build={BUILD_INFO.buildNumber}
      minBuildToForceUpdate={2025060100000}
    >
      {/* Your app content */}
    </ForceUpdateDetector>
  );
}

See Automated Build Documentation for more details.

Hooks

useVersionManager(options)

Manages version information and update processes.

const {
  currentVersion,      // Current stored version
  currentBuild,        // Current stored build
  isUpdateAvailable,   // Whether update is available
  isForceUpdate,       // Whether force update is needed
  lastChecked,         // Timestamp of last check
  forceUpdate,         // Function to force update
  checkForUpdates      // Function to check for updates
} = useVersionManager({
  version: '2.1.0',             // Current app version
  build: 210,                   // Current build number
  minBuildToForceUpdate: 200,   // Force update for users with builds below 200
  onForceUpdate: () => {},      // Callback when force update begins
  onUpdateAvailable: () => {},  // Callback when update available
  onUpdateComplete: () => {}    // Callback when update completes
});

useCacheUpdateManager(options)

Manages cache update processes with user activity detection.

const {
  isUpdateInProgress,    // Whether update is in progress
  isPostponed,           // Whether update is postponed
  postponeCount,         // Number of times update postponed
  countdownSeconds,      // Seconds left in countdown
  handleUpdate,          // Function to handle update now
  postponeUpdate,        // Function to postpone update
  startAutoUpdateProcess // Start automatic update process
} = useCacheUpdateManager({
  isUpdateAvailable,              // Whether update is available
  onUpdateConfirmed: () => {},    // Callback when update confirmed
  onUpdatePostponed: () => {},    // Callback when update postponed
  countdownDuration: 60000,       // Countdown duration (ms)
  inactivityThreshold: 30000,     // User inactivity threshold (ms)
  maxPostponeCount: 3             // Max times user can postpone
});

🛠 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

🔍 Troubleshooting

Having issues with continuous update loops or other problems? Check out our troubleshooting guide for solutions to common issues.

Key things to check:

  • Ensure minBuildToForceUpdate is configured correctly (see troubleshooting doc)
  • Verify your service worker integration
  • Check for proper error handling in update processes

📄 License

MIT

🙌 Credits

Created by Nchimunya Munyama