How to Achieve Real‑Time Version Updates in Micro‑Frontend Apps with Pure Frontend Polling

This article details a zero‑intrusion solution for synchronizing version numbers across multiple micro‑frontend environments using a lightweight frontend poller, static version files, Nginx cache control, and Ant Design Vue modals, enabling testers to see updates within 30 seconds without backend changes.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
How to Achieve Real‑Time Version Updates in Micro‑Frontend Apps with Pure Frontend Polling

Background and Problem

In a micro‑frontend ecosystem each sub‑application is deployed to dev, test, release and production environments. Frequent releases cause testers to keep working on stale pages because the displayed version does not change, leading to repeated “old version” complaints.

Requirements

Detect a newer version within 30 seconds of release.

Show a modal that displays the current version, the latest version and the environment.

Provide “Refresh now” and “Later” actions without forcing an immediate interruption.

Implement the solution without any backend changes and keep it compatible with the existing CI/CD pipeline.

Chosen Approach

Four alternatives were evaluated (pure frontend polling of version.json, Service‑Worker/PWA, WebSocket push, backend unified API). Considering implementation speed and team resources, the team selected the pure frontend polling + static version file method.

Key Principles

Unique, traceable version number : baseVersion‑env‑timestamp.

Zero‑intrusion release : Jenkins continues to run the existing npm run build‑xxx commands; the only addition is the generated version.json file.

Technical Overview

1. Build‑time Generation of version.json

The version is computed once in vue.config.js, injected into process.env.APP_VERSION, and written to a static version.json placed under the sub‑app’s public path.

const buildEnvName = getEnvName();
const buildVersion = getAppVersion();
module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.DefinePlugin({
        "process.env.APP_VERSION": JSON.stringify(buildVersion),
        "process.env.APP_ENV": JSON.stringify(buildEnvName),
      })
    ]
  },
  chainWebpack(config) {
    config.plugin("generate-version-json").use({
      apply(compiler) {
        compiler.hooks.done.tap("GenerateVersionJsonPlugin", () => {
          fs.writeFileSync(
            path.resolve(__dirname, "edu/version.json"),
            JSON.stringify({
              version: buildVersion,
              env: buildEnvName,
              timestamp: new Date().toISOString(),
              publicPath: "/child/edu"
            }, null, 2)
          );
        });
      }
    });
  }
};

2. Frontend Polling and Comparison

After the app mounts, a poller requests version.json every 30 seconds with cache: "no-store" and a timestamp query parameter to bypass any CDN or browser cache. If the fetched version differs from the bundled version, a modal is shown.

class VersionChecker {
  currentVersion = process.env.APP_VERSION;
  publicPath = "/child/edu";
  checkInterval = 30 * 1000;

  init() {
    console.log(`📌 Current frontend version: ${this.currentVersion} (${process.env.APP_ENV})`);
    this.startChecking();
    document.addEventListener("visibilitychange", () => {
      if (document.visibilityState === "visible" && !this.hasNotified) {
        this.checkForUpdate();
      }
    });
  }

  async checkForUpdate() {
    const url = `${this.publicPath}/version.json?t=${Date.now()}`;
    const response = await fetch(url, { cache: "no-store" });
    if (!response.ok) return;
    const latestInfo = await response.json();
    if (latestInfo.version !== this.currentVersion && !this.hasNotified) {
      this.hasNotified = true;
      this.stopChecking();
      this.showUpdateModal(latestInfo.version, latestInfo.env);
    }
  }
}

3. Interaction Prompt

The modal is implemented with Ant Design Vue’s Modal.confirm. It displays the current version, the latest version and the environment, and offers two actions:

Refresh now – forces a full page reload.

Later – dismisses the modal and resumes polling.

4. Nginx Cache Strategy

HTML pages and version.json are served with Cache‑Control: no-store (and related headers) to guarantee fresh retrieval. Static assets (JS/CSS/images) keep long‑term caching.

location / {
  if ($request_filename ~* .html$) {
    add_header Cache-Control "no-store, no-cache, must-revalidate";
  }
}
location /child/edu {
  if ($request_filename ~* .html$) {
    add_header Cache-Control "no-store, no-cache, must-revalidate";
  }
}
location ~* /child/edu/version.json$ {
  add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
  add_header Pragma "no-cache";
  add_header Expires "0";
  add_header Surrogate-Control "no-store";
}

5. CI/CD Integration

The existing Jenkins scripts are unchanged; the only addition is the generated version.json placed under /child/edu. All build commands include the OpenSSL compatibility flag.

develop : npm run build-develop/child/edu testing : npm run build-testing/child/edu release : npm run build-release/child/edu production : npm run build-production/child/edu Each command is prefixed with cross-env NODE_OPTIONS=--openssl-legacy-provider to handle OpenSSL version differences.

Testing and Validation

First‑visit: open a dev page, verify the console logs the bundled version and that version.json is fetched without caching.

Trigger new version: modify any source, rebuild, keep the old page open – it should not auto‑refresh.

Polling verification: within 30 seconds a modal appears showing the new version.

Interaction paths: “Refresh now” forces a reload; “Later” records the choice and resumes polling.

Edge cases: switching browser tabs, clearing cache, accessing from a new device, or rapid successive releases all correctly detect the latest version.

Common Issues and Remedies

No modal – version.json missing or unchanged. Check deployment path and ensure the file is generated.

Modal shows old version after refresh – static assets cached. Verify Nginx cache headers and browser cache settings.

Build failure – missing cross-env or permission issue. Install the dependency and ensure the Jenkins workspace is writable.

False update alerts – version generated multiple times during build. Cache buildVersion at the top of vue.config.js and reuse it globally.

Impact

Testers receive version‑update prompts within 30 seconds, dramatically improving testing efficiency.

“Ghost” modals disappear; version comparison logic stabilizes.

No backend changes are required; the release pipeline remains untouched.

Documentation enables other sub‑applications to adopt the solution without reinventing it.

Future Work

Package the logic as a reusable SDK supporting Vue CLI and Vite.

Build a visual version panel in the host app to aggregate versions across environments.

Introduce differentiated refresh strategies: forced refresh for high‑priority releases, optional for regular updates.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CI/CDmicro-frontendVueNginxversioningAnt Design Vuefrontend polling
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.