{"id":16347061,"url":"https://github.com/ospoon/spa-build-version","last_synced_at":"2025-11-09T02:30:26.657Z","repository":{"id":105557419,"uuid":"389250087","full_name":"OSpoon/spa-build-version","owner":"OSpoon","description":"在SPA模式网页版本检测方案","archived":false,"fork":false,"pushed_at":"2021-07-25T03:22:22.000Z","size":119,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-28T06:09:37.498Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://juejin.cn/post/6988527907404513288","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OSpoon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-25T03:20:09.000Z","updated_at":"2021-07-25T03:23:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"e9c57285-a50c-49e0-b341-7e71ce79511b","html_url":"https://github.com/OSpoon/spa-build-version","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OSpoon%2Fspa-build-version","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OSpoon%2Fspa-build-version/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OSpoon%2Fspa-build-version/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OSpoon%2Fspa-build-version/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OSpoon","download_url":"https://codeload.github.com/OSpoon/spa-build-version/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239565664,"owners_count":19660158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T00:39:28.229Z","updated_at":"2025-11-09T02:30:26.604Z","avatar_url":"https://github.com/OSpoon.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"### ![默认文件1627142651331.png](https://cdn.nlark.com/yuque/0/2021/png/2373519/1627142667290-b803397c-58ac-42b8-8c38-166d66a546c1.png#clientId=u2ef91b7e-108d-4\u0026from=drop\u0026id=u27fc37c3\u0026margin=%5Bobject%20Object%5D\u0026name=%E9%BB%98%E8%AE%A4%E6%96%87%E4%BB%B61627142651331.png\u0026originHeight=383\u0026originWidth=900\u0026originalType=binary\u0026ratio=1\u0026size=125100\u0026status=done\u0026style=none\u0026taskId=u47e55081-ebe0-4e59-8389-bf1579b8ec1)\n\u003e 方案来源于团队分享后的总结实现,文中代码并未在实际产品中是使用,仅供参考。\n\n### 背景\n\u003e 由于在spa模式的应用中页面的内容变化不再引起整个页面的重新加载,故需要解决在spa模式的应用中网页在使用的过程中服务器已更新的资源不能被及时的获取的问题。\n\n### 解决思路\n\n1. 标记版本: \n   1. 在`vue.config.js`中每次编译生成一个版本号\n   1. 使用`html-webpack-plugin`插件将版本号插入到`index.html`的`mate`标签\n   1. 在`webpack`编译结束生成附带版本号的`version.json`文件放置到服务器\n2. 检测版本\n   1. 通过`document.getElementsByTagName(\"meta\").buildVersion.content`获取浏览器已打开网页的版本号\n   1. 通过不带缓存的`get`请求获取服务器存放的新版本号的`version.json` \n3. 刷新页面: 通过检测版本来提示或自动刷新页面获取最新的服务器资源\n### 标记版本\n\n1. 配置`html-webpack-plugin`为`index.html`插入编译版本号\n```javascript\nconst BuildVersionWebpackPlugin = require(\"./build-version.js\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\n\nconst buildVersion = Date.now();\nconsole.log(\"当前编译版本: \u003e\u003e\", buildVersion);\nmodule.exports = {\n  configureWebpack: (config) =\u003e {\n    config.plugins.forEach((plugin) =\u003e {\n      if (plugin instanceof HtmlWebpackPlugin) {\n        plugin.options.version = buildVersion;\n      }\n    });\n  },\n};\n\n```\n\n2. 在`index.html`插入`mate`标签\n```html\n\u003cmeta name=\"buildVersion\" content=\"\u003c%= htmlWebpackPlugin.options.version %\u003e\"\u003e\n```\n\n3. 创建用于生成`version.json`的`webpack`插件`build-version.js`\n```javascript\nconst pluginName = \"BuildVersionWebpackPlugin\";\nconst fs = require(\"fs\");\nconst path = require(\"path\");\n\n/**\n * 编译后生成版本文件\n */\nclass BuildVersionWebpackPlugin {\n  constructor({ output = \"./\", version = Date.now() }) {\n    this.output = output;\n    this.version = version;\n  }\n  apply(compiler) {\n    compiler.hooks.done.tap(pluginName, () =\u003e {\n      console.log(\"webpack 编译完成,正在生成版本文件！\");\n      const outputPath = path.resolve(this.output, \"./version.json\");\n      const versionJson = JSON.stringify({\n        version: this.version,\n      });\n      fs.writeFileSync(outputPath, versionJson, {\n        encoding: \"utf-8\",\n      });\n    });\n  }\n}\n\nmodule.exports = BuildVersionWebpackPlugin;\n```\n\n4. 配置新建的webpack插件\n```javascript\nconst BuildVersionWebpackPlugin = require(\"./build-version.js\");\n\nconst buildVersion = Date.now();\nconsole.log(\"当前编译版本: \u003e\u003e\", buildVersion);\nmodule.exports = {\n  configureWebpack: (config) =\u003e {\n    ...\n    config.plugins.push(\n      new BuildVersionWebpackPlugin({\n        output: \"./dist\",\n        version: buildVersion,\n      })\n    );\n  },\n};\n```\n### 检测版本\n\n1. 获取服务器存放的版本号\n```javascript\nasync function _serverVersion() {\n  return await new Promise((resolve) =\u003e {\n    fetch(\"/version.json\", {\n      headers: {\n        \"cache-control\": \"no-cache\",\n      },\n    })\n      .then((response) =\u003e {\n        try {\n          response.json().then((json) =\u003e {\n            resolve(json.version);\n          });\n        } catch (error) {\n          resolve(0);\n        }\n      })\n      .catch(() =\u003e {\n        resolve(0);\n      });\n  });\n}\n```\n\n2. 获取浏览器本地页面的版本号\n```javascript\nfunction _currentVersion() {\n  return Number(document.getElementsByTagName(\"meta\").buildVersion.content);\n}\n```\n\n3. 版本号比较\n```javascript\nasync function _inspector() {\n  let isConsistent = true;\n  const sv = await _serverVersion();\n  const cv = _currentVersion();\n  console.log(`检测到本地版本${cv}和服务器版本${sv}`);\n  console.log(\"本地\u0026服务器版本是否一致:\u003e\u003e\", (isConsistent = sv === cv));\n  return isConsistent;\n}\n\nexport default async function() {\n  return await _inspector();\n}\n```\n### 刷新页面\n\n1. 检测更新时机: 推荐在路由切换之后检测,或主要模块进入时检测\n1. 检测函数,具体的刷新逻辑按实际场景考虑\n```javascript\nversionCheck() {\n  inspector().then((isConsistent) =\u003e {\n    if (!isConsistent) {\n      const isReload = window.confirm(\n        \"检测到本地版本和服务器版本不一致,点击确定更新页面 \"\n      );\n      if (isReload) {\n        window.location.reload();\n      }\n    }\n  });\n}\n```\n### 效果图\n![image.png](https://cdn.nlark.com/yuque/0/2021/png/2373519/1627140859277-13976e5a-6a75-44a7-801f-ab9a73c08ebf.png#clientId=uefe95f85-8f1c-4\u0026from=paste\u0026height=544\u0026id=u64881ce4\u0026margin=%5Bobject%20Object%5D\u0026name=image.png\u0026originHeight=544\u0026originWidth=1116\u0026originalType=binary\u0026ratio=1\u0026size=39563\u0026status=done\u0026style=none\u0026taskId=udc22d3ce-2f26-4698-adef-ac6710e78e7\u0026width=1116)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fospoon%2Fspa-build-version","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fospoon%2Fspa-build-version","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fospoon%2Fspa-build-version/lists"}