From “Version Conflicts” to Refresh Prompts in 30 Seconds: A Micro-Frontend Team’s Practice

1. Background & Pain Points

Our team maintains a micro‑frontend sub‑application cluster, where each sub‑application must serve multiple environments simultaneously (dev / test / release / online).

We use a branch strategy (master / release / test / dev / hotfix / feature_x.x.x) and Jenkins automation — enabling multiple releases per day.

But the real bottleneck isn't release frequency; it's one persistent issue:

> Testers often stay on outdated pages for extended periods.

---

1.1 Real-World Scenario

  • Morning: Testers open the dev page.
  • Afternoon: We release new component styles.
  • Testers continue regression testing on the old page.
  • Shouting “please refresh” in group chat → unreliable → leads to invalid defects and repetitive communication.

Incident highlight:

We used webpack DefinePlugin and a custom plugin, each calling `getAppVersion()` separately.

Result:

  • Frontend console: `0.8.3-release-202511210828`
  • `version.json`: `0.8.3-release-202511210829`
  • One‑second mismatch → users got constant refresh prompts → dubbed “version number conflict” internally.

---

1.2 Requirements

  • Detect version updates within 30 seconds.
  • Update pop‑up showing Current Version / Latest Version / Environment.
  • Refresh Now” / “Remind Me Later” options.
  • Fully frontend + Nginx implementationno backend modifications.
  • Remain compatible with existing micro‑frontend architecture & CI/CD workflow.

---

2. Solution Exploration & Trade-offs

| Solution | Complexity | Real‑Time | Dependencies | Suitable For | Pros / Cons |

|-------------------------------------------|------------|-----------|----------------------|--------------------------------|----------------------------------------------------------------------|

| Pure Frontend Polling (`version.json`) | Low | Medium | Frontend + Nginx | Multi‑env micro‑frontend | Low cost, minor network overhead |

| Service Worker / PWA | Medium | High | Modern browsers | PWA apps | Good cache control; heavier refactor |

| WebSocket Push | High | Highest | Backend service | Strong realtime needs | Requires backend work |

| Backend API for Unified Version Mgmt | Medium | Medium | Frontend + Backend | Centralized control | Higher cross‑team coupling |

---

> 💡 Note: In broader CI/CD + AI workflows, multi‑platform content sync faces similar challenges. Platforms like AiToEarn官网 offer open‑source tools for AI‑assisted content creation and publishing across multiple platforms — connecting creation, publishing, analytics, and AI模型排名.

---

Decision: Pure Frontend Polling + Static version.json

Principles:

  • Unique, Traceable Version Numbers: Format = base version – environment – timestamp.
  • Zero-Intervention Release: Jenkins continues `npm run build-xxx` — no added steps.

---

3. Technical Overview

  • Generate `version.json` at build time:
  • In `vue.config.js`, pre‑compute version number.
  • Inject into frontend (`process.env.APP_VERSION`).
  • Write to `version.json` in output.
  • Frontend polling every 30s (no cache).
  • Pop-up Prompt using Ant Design Vue `Modal.confirm`.
  • Cache Strategy:
  • No cache for HTML & version.json in Nginx.
  • Long-term cache for JS/CSS/images.
  • CI/CD: Add `version.json` as part of build artifacts — no extra steps.

---

4. Key Implementation Details

4.1 Build-time Deterministic Versioning

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)
          );
        });
      },
    });
  },
};

Locks version number once per build, ensuring consistency between frontend code and static files.

---

4.2 Runtime Version Polling & Cache Busting

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

  init() {
    console.log(`📌 Current: ${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);
    }
  }
}

Key Details:

  • `cache: "no-store"` + timestamp ⇒ bypass CDN/browser cache.
  • `visibilitychange` ⇒ immediate check on tab focus.

---

4.3 Nginx Cache Policy

No-cache for HTML & version.json:

location ~* \.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";
}

Cache others long-term.

---

4.4 CI/CD Zero-touch Setup

| Env | Command | Path | Notes |

|------------|---------------------------|--------------|-------------------|

| develop | `npm run build-develop` | `/child/edu` | Development test |

| testing | `npm run build-testing` | `/child/edu` | Integration test |

| release | `npm run build-release` | `/child/edu` | Pre-release |

| production | `npm run build-production`| `/child/edu` | Live deployment |

No change to existing Jenkins flow — `version.json` ships automatically.

---

5. Testing Workflow

  • Initial Load → Verify console version number + uncached `version.json`.
  • Deploy New Build with old page open → Detect update within 30s.
  • Interaction:
  • Refresh Now: Reloads with new assets.
  • Remind Later: Continues polling.
  • Edge Cases: Tab switch, cache clear, quick successive releases.

---

6. Common Issues & Fixes

| Symptom | Cause | Fix |

|-------------------------------------------|----------------------------------------|-------------------------------------------------------|

| No pop-up | `version.json` missing/unchanged | Check build output & deployment path |

| Pop-up but still old version after refresh| Static resource caching | Review Nginx & browser cache policies |

| Build failure | `cross-env` missing | Install deps, check Jenkins directory permissions |

| Continuous false alerts | Multiple version generation per build | Cache `buildVersion` globally in build config |

---

7. Results

  • 30s outdated page detection.
  • No more ghost pop-ups; stable comparison logic.
  • Pure frontend + Nginx change — no release process modification.
  • Reusable approach for other sub‑apps.

---

8. Future Plans

  • Universal SDK for Vue CLI / Vite.
  • Visual Version Panel in main app.
  • Custom Refresh Strategies: force for critical versions.

---

> 🌟 Lesson learned: Trivial-seeming version control details can hide major delivery risks. Document once, reuse many times.

---

If you’re tackling micro‑frontend version sync, this approach is ready to use.

For multi‑platform publishing alongside, AiToEarn官网 integrates AI content generation, publishing, analytics, and ranking — deploy across platforms like Douyin, Kwai, WeChat, Bilibili, Facebook, Instagram, LinkedIn, YouTube, Pinterest, X — with one workflow.

See AiToEarn文档 and GitHub开源 for details.

Read more

Translate the following blog post title into English, concise and natural. Return plain text only without quotes. 哈佛大学 R 编程课程介绍

Harvard CS50: Introduction to Programming with R Harvard University offers exceptional beginner-friendly computer science courses. We’re excited to announce the release of Harvard CS50’s Introduction to Programming in R, a powerful language widely used for statistical computing, data science, and graphics. This course was developed by Carter Zenke.