diff --git a/CHANGELOG.md b/CHANGELOG.md index ce9f2fcc..9fc16d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## [0.22.2](https://github.com/vuejs/vitepress/compare/v0.22.1...v0.22.2) (2022-02-14) + +### Features + +- improve default chunk strategy + page hash stability ([1ef69e2](https://github.com/vuejs/vitepress/commit/1ef69e212f91e43431b4fe4bdba17ca4f29a7b49)) + +## [0.22.1](https://github.com/vuejs/vitepress/compare/v0.22.0...v0.22.1) (2022-02-14) + +### Features + +- automatically update hash map + retry on failed page fetch ([2324948](https://github.com/vuejs/vitepress/commit/23249483d60da1952c64a1f764873652b587c2dc)) +- use git-based lastUpdated data ([d32d8d4](https://github.com/vuejs/vitepress/commit/d32d8d441917dcb480a6735da78c2d6fc3e589c0)) + + Note: lastUpdated data is now disabled by default due to the performance overhead of retrieving the git information. This also means each page's metadata object no longer contains the `lastUpdated` property by default - it will only be present if the new `lastUpdated: true` config option is enabled. + +# [0.22.0](https://github.com/vuejs/vitepress/compare/v0.21.6...v0.22.0) (2022-02-11) + +- Upgrade to Vite 2.8 + ## [0.21.6](https://github.com/vuejs/vitepress/compare/v0.21.5...v0.21.6) (2022-01-19) ### Perf diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 0c326ba5..cfb87e63 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -4,6 +4,7 @@ export default defineConfig({ lang: 'en-US', title: 'VitePress', description: 'Vite & Vue powered static site generator.', + lastUpdated: true, themeConfig: { repo: 'vuejs/vitepress', diff --git a/package.json b/package.json index 7a848579..6c6e963a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vitepress", - "version": "0.21.6", + "version": "0.22.2", "description": "Vite & Vue powered static site generator", "main": "dist/node/index.js", "typings": "types/index.d.ts", @@ -38,6 +38,7 @@ "docs-dev": "node ./bin/vitepress dev docs", "docs-debug": "node --inspect-brk ./bin/vitepress dev docs", "docs-build": "npm run build && node ./bin/vitepress build docs", + "docs-build-only": "node ./bin/vitepress build docs", "docs-serve": "node ./bin/vitepress serve docs", "ci-docs": "run-s build docs-build" }, @@ -73,10 +74,10 @@ "dependencies": { "@docsearch/css": "^3.0.0-alpha.41", "@docsearch/js": "^3.0.0-alpha.41", - "@vitejs/plugin-vue": "^2.0.0", + "@vitejs/plugin-vue": "^2.2.0", "prismjs": "^1.25.0", - "vite": "^2.7.12", - "vue": "^3.2.27" + "vite": "^2.8.1", + "vue": "^3.2.31" }, "devDependencies": { "@microsoft/api-extractor": "^7.18.9", @@ -85,6 +86,7 @@ "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.0.4", "@types/compression": "^1.7.0", + "@types/cross-spawn": "^6.0.2", "@types/debug": "^4.1.7", "@types/fs-extra": "^9.0.11", "@types/koa": "^2.13.1", @@ -98,6 +100,7 @@ "chokidar": "^3.5.1", "compression": "^1.7.4", "conventional-changelog-cli": "^2.1.1", + "cross-spawn": "^7.0.3", "debug": "^4.3.2", "diacritics": "^1.3.0", "enquirer": "^2.3.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39615105..bfdad189 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,7 @@ importers: '@rollup/plugin-json': ^4.1.0 '@rollup/plugin-node-resolve': ^13.0.4 '@types/compression': ^1.7.0 + '@types/cross-spawn': ^6.0.2 '@types/debug': ^4.1.7 '@types/fs-extra': ^9.0.11 '@types/koa': ^2.13.1 @@ -21,11 +22,12 @@ importers: '@types/micromatch': ^4.0.2 '@types/node': ^15.6.1 '@types/polka': ^0.5.3 - '@vitejs/plugin-vue': ^2.0.0 + '@vitejs/plugin-vue': ^2.2.0 chalk: ^4.1.1 chokidar: ^3.5.1 compression: ^1.7.4 conventional-changelog-cli: ^2.1.1 + cross-spawn: ^7.0.3 debug: ^4.3.2 diacritics: ^1.3.0 enquirer: ^2.3.6 @@ -57,17 +59,17 @@ importers: semver: ^7.3.5 sirv: ^1.0.12 typescript: ^4.3.2 - vite: ^2.7.12 + vite: ^2.8.1 vitest: ^0.1.19 - vue: ^3.2.27 + vue: ^3.2.31 yorkie: ^2.0.0 dependencies: '@docsearch/css': 3.0.0-alpha.41 '@docsearch/js': 3.0.0-alpha.41 - '@vitejs/plugin-vue': 2.0.0_vite@2.7.12+vue@3.2.27 + '@vitejs/plugin-vue': 2.2.0_vite@2.8.1+vue@3.2.31 prismjs: 1.25.0 - vite: 2.7.12 - vue: 3.2.27 + vite: 2.8.1 + vue: 3.2.31 devDependencies: '@microsoft/api-extractor': 7.18.11 '@rollup/plugin-alias': 3.1.5_rollup@2.57.0 @@ -75,6 +77,7 @@ importers: '@rollup/plugin-json': 4.1.0_rollup@2.57.0 '@rollup/plugin-node-resolve': 13.0.5_rollup@2.57.0 '@types/compression': 1.7.2 + '@types/cross-spawn': 6.0.2 '@types/debug': 4.1.7 '@types/fs-extra': 9.0.13 '@types/koa': 2.13.4 @@ -88,6 +91,7 @@ importers: chokidar: 3.5.2 compression: 1.7.4 conventional-changelog-cli: 2.1.1 + cross-spawn: 7.0.3 debug: 4.3.2 diacritics: 1.3.0 enquirer: 2.3.6 @@ -544,6 +548,12 @@ packages: '@types/node': 15.14.9 dev: true + /@types/cross-spawn/6.0.2: + resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} + dependencies: + '@types/node': 15.14.9 + dev: true + /@types/debug/4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: @@ -713,98 +723,98 @@ packages: resolution: {integrity: sha512-4LPNrqSJknLzILMVXn2P/mh0djNgFvom4T9Y1hmhaB8OBm1cY71bMMSrGRu1q5qF4JZzY6iaGT11BHmCMY/NZg==} dev: true - /@vitejs/plugin-vue/2.0.0_vite@2.7.12+vue@3.2.27: - resolution: {integrity: sha512-4Xn1h9OcaAf7KYrvz2oEi52fCCCLcCzyr3pDOrzYTWrs0DrzNOXt9fT5IiGb1f/uoNTdX3aAkXVGNXrGkzF/zw==} + /@vitejs/plugin-vue/2.2.0_vite@2.8.1+vue@3.2.31: + resolution: {integrity: sha512-wXigM1EwN2G7rZcwG6kLk9ivvIMhx2363tCEvMBiXcTu5nePM/12hUPVzPb83Uugt6U+zom1gTpJopi/Ow/jwg==} engines: {node: '>=12.0.0'} peerDependencies: vite: ^2.5.10 vue: ^3.2.25 dependencies: - vite: 2.7.12 - vue: 3.2.27 + vite: 2.8.1 + vue: 3.2.31 dev: false - /@vue/compiler-core/3.2.27: - resolution: {integrity: sha512-JyxAglSM/pb9paG5ZNuKrf5IUpzLzQA3khjWGF9oESELCLQlt6O3YyPMR2A69wIpYWrf5mScZ8YY8TJKOI/1kQ==} + /@vue/compiler-core/3.2.31: + resolution: {integrity: sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==} dependencies: '@babel/parser': 7.16.4 - '@vue/shared': 3.2.27 + '@vue/shared': 3.2.31 estree-walker: 2.0.2 source-map: 0.6.1 dev: false - /@vue/compiler-dom/3.2.27: - resolution: {integrity: sha512-NyQ7nEbopUBPUMHM4c3FPCbFbnQwptoPjW5Y5qfJ7hfiCNhOuhQsDNqi5JYKBxfpxiFNwjcN9F8t1AsnLrDloQ==} + /@vue/compiler-dom/3.2.31: + resolution: {integrity: sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==} dependencies: - '@vue/compiler-core': 3.2.27 - '@vue/shared': 3.2.27 + '@vue/compiler-core': 3.2.31 + '@vue/shared': 3.2.31 dev: false - /@vue/compiler-sfc/3.2.27: - resolution: {integrity: sha512-WyecUhLN5UAQAr2QlmG2nA56OEnhZJaBnSw0G1tazb9rwDuK0V9tnbIXbQgmQlx+x4sJxgg61yWGcIXfilTl3A==} + /@vue/compiler-sfc/3.2.31: + resolution: {integrity: sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==} dependencies: '@babel/parser': 7.16.4 - '@vue/compiler-core': 3.2.27 - '@vue/compiler-dom': 3.2.27 - '@vue/compiler-ssr': 3.2.27 - '@vue/reactivity-transform': 3.2.27 - '@vue/shared': 3.2.27 + '@vue/compiler-core': 3.2.31 + '@vue/compiler-dom': 3.2.31 + '@vue/compiler-ssr': 3.2.31 + '@vue/reactivity-transform': 3.2.31 + '@vue/shared': 3.2.31 estree-walker: 2.0.2 magic-string: 0.25.7 - postcss: 8.4.5 + postcss: 8.4.6 source-map: 0.6.1 dev: false - /@vue/compiler-ssr/3.2.27: - resolution: {integrity: sha512-+l09t319iV7HVSrXfBw9OLwMZIPOFTXmHjZ61Bc5ZcwKqOYAR4uTurKpoXAfcSc5qs/q6WdE9jY3nrP0LUEMQQ==} + /@vue/compiler-ssr/3.2.31: + resolution: {integrity: sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==} dependencies: - '@vue/compiler-dom': 3.2.27 - '@vue/shared': 3.2.27 + '@vue/compiler-dom': 3.2.31 + '@vue/shared': 3.2.31 dev: false - /@vue/reactivity-transform/3.2.27: - resolution: {integrity: sha512-67//61ObGxGnVrPhjygocb24eYUh+TFMhkm7szm8v5XdKXjkNl7qgIOflwGvUnwuIRJmr9nZ7+PvY0fL+H2upA==} + /@vue/reactivity-transform/3.2.31: + resolution: {integrity: sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==} dependencies: '@babel/parser': 7.16.4 - '@vue/compiler-core': 3.2.27 - '@vue/shared': 3.2.27 + '@vue/compiler-core': 3.2.31 + '@vue/shared': 3.2.31 estree-walker: 2.0.2 magic-string: 0.25.7 dev: false - /@vue/reactivity/3.2.27: - resolution: {integrity: sha512-QPfIQEJidRGIu/mPexhcB4csp1LEg2Nr+/QE72MnXs/OYDtFErhC9FxIyymkxp/xvAgL5wsnSOuDD6zWF42vRQ==} + /@vue/reactivity/3.2.31: + resolution: {integrity: sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==} dependencies: - '@vue/shared': 3.2.27 + '@vue/shared': 3.2.31 dev: false - /@vue/runtime-core/3.2.27: - resolution: {integrity: sha512-NJrjuViHJyrT4bwIocbE4XDaDlA1Pj61pQlneZZdFEvgdMLlhzCCiJ4WZnWcohYQeisUAZjEFKK8GjQieDPFbw==} + /@vue/runtime-core/3.2.31: + resolution: {integrity: sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==} dependencies: - '@vue/reactivity': 3.2.27 - '@vue/shared': 3.2.27 + '@vue/reactivity': 3.2.31 + '@vue/shared': 3.2.31 dev: false - /@vue/runtime-dom/3.2.27: - resolution: {integrity: sha512-tlnKkvBSkV7MPUp/wRFsYcv67U1rUeZTPfpPzq5Kpmw5NNGkY6J075fFBH2k0MNxDucXS+qfStNrxAyGTUMkSA==} + /@vue/runtime-dom/3.2.31: + resolution: {integrity: sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==} dependencies: - '@vue/runtime-core': 3.2.27 - '@vue/shared': 3.2.27 + '@vue/runtime-core': 3.2.31 + '@vue/shared': 3.2.31 csstype: 2.6.18 dev: false - /@vue/server-renderer/3.2.27_vue@3.2.27: - resolution: {integrity: sha512-dZnzkFCDe6A/GIe/F1LcG6lWpprHVh62DjTv8wubtkHwfJWOmOeHp+KvPDRrswL/L3ghsm+E31xY+pvkgM3pbQ==} + /@vue/server-renderer/3.2.31_vue@3.2.31: + resolution: {integrity: sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==} peerDependencies: - vue: 3.2.27 + vue: 3.2.31 dependencies: - '@vue/compiler-ssr': 3.2.27 - '@vue/shared': 3.2.27 - vue: 3.2.27 + '@vue/compiler-ssr': 3.2.31 + '@vue/shared': 3.2.31 + vue: 3.2.31 dev: false - /@vue/shared/3.2.27: - resolution: {integrity: sha512-rpAn9k6O08Lvo7ekBIAnkOukX/4EsEQLPrRJBKhIEasMsOI5eX0f6mq1sDUSY7cgAqWw2d7QtP74CWxdXoyKxA==} + /@vue/shared/3.2.31: + resolution: {integrity: sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ==} dev: false /JSONStream/1.3.5: @@ -1537,8 +1547,9 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild-android-arm64/0.13.15: - resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==} + /esbuild-android-arm64/0.14.21: + resolution: {integrity: sha512-Bqgld1TY0wZv8TqiQmVxQFgYzz8ZmyzT7clXBDZFkOOdRybzsnj8AZuK1pwcLVA7Ya6XncHgJqIao7NFd3s0RQ==} + engines: {node: '>=12'} cpu: [arm64] os: [android] requiresBuild: true @@ -1552,8 +1563,9 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.13.15: - resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==} + /esbuild-darwin-64/0.14.21: + resolution: {integrity: sha512-j+Eg+e13djzyYINVvAbOo2/zvZ2DivuJJTaBrJnJHSD7kUNuGHRkHoSfFjbI80KHkn091w350wdmXDNSgRjfYQ==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] requiresBuild: true @@ -1567,8 +1579,9 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.13.15: - resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==} + /esbuild-darwin-arm64/0.14.21: + resolution: {integrity: sha512-nDNTKWDPI0RuoPj5BhcSB2z5EmZJJAyRtZLIjyXSqSpAyoB8eyAKXl4lB8U2P78Fnh4Lh1le/fmpewXE04JhBQ==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] requiresBuild: true @@ -1582,8 +1595,9 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.13.15: - resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==} + /esbuild-freebsd-64/0.14.21: + resolution: {integrity: sha512-zIurkCHXhxELiDZtLGiexi8t8onQc2LtuE+S7457H/pP0g0MLRKMrsn/IN4LDkNe6lvBjuoZZi2OfelOHn831g==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] requiresBuild: true @@ -1597,8 +1611,9 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.13.15: - resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==} + /esbuild-freebsd-arm64/0.14.21: + resolution: {integrity: sha512-wdxMmkJfbwcN+q85MpeUEamVZ40FNsBa9mPq8tAszDn8TRT2HoJvVRADPIIBa9SWWwlDChIMjkDKAnS3KS/sPA==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] requiresBuild: true @@ -1612,8 +1627,9 @@ packages: dev: true optional: true - /esbuild-linux-32/0.13.15: - resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==} + /esbuild-linux-32/0.14.21: + resolution: {integrity: sha512-fmxvyzOPPh2xiEHojpCeIQP6pXcoKsWbz3ryDDIKLOsk4xp3GbpHIEAWP0xTeuhEbendmvBDVKbAVv3PnODXLg==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] requiresBuild: true @@ -1627,8 +1643,9 @@ packages: dev: true optional: true - /esbuild-linux-64/0.13.15: - resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==} + /esbuild-linux-64/0.14.21: + resolution: {integrity: sha512-edZyNOv1ql+kpmlzdqzzDjRQYls+tSyi4QFi+PdBhATJFUqHsnNELWA9vMSzAaInPOEaVUTA5Ml28XFChcy4DA==} + engines: {node: '>=12'} cpu: [x64] os: [linux] requiresBuild: true @@ -1642,8 +1659,9 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.13.15: - resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==} + /esbuild-linux-arm/0.14.21: + resolution: {integrity: sha512-aSU5pUueK6afqmLQsbU+QcFBT62L+4G9hHMJDHWfxgid6hzhSmfRH9U/f+ymvxsSTr/HFRU4y7ox8ZyhlVl98w==} + engines: {node: '>=12'} cpu: [arm] os: [linux] requiresBuild: true @@ -1657,8 +1675,9 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.13.15: - resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==} + /esbuild-linux-arm64/0.14.21: + resolution: {integrity: sha512-t5qxRkq4zdQC0zXpzSB2bTtfLgOvR0C6BXYaRE/6/k8/4SrkZcTZBeNu+xGvwCU4b5dU9ST9pwIWkK6T1grS8g==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] requiresBuild: true @@ -1672,8 +1691,9 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.13.15: - resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==} + /esbuild-linux-mips64le/0.14.21: + resolution: {integrity: sha512-jLZLQGCNlUsmIHtGqNvBs3zN+7a4D9ckf0JZ+jQTwHdZJ1SgV9mAjbB980OFo66LoY+WeM7t3WEnq3FjI1zw4A==} + engines: {node: '>=12'} cpu: [mips64el] os: [linux] requiresBuild: true @@ -1687,8 +1707,9 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.13.15: - resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==} + /esbuild-linux-ppc64le/0.14.21: + resolution: {integrity: sha512-4TWxpK391en2UBUw6GSrukToTDu6lL9vkm3Ll40HrI08WG3qcnJu7bl8e1+GzelDsiw1QmfAY/nNvJ6iaHRpCQ==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] requiresBuild: true @@ -1702,8 +1723,25 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.13.15: - resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==} + /esbuild-linux-riscv64/0.14.21: + resolution: {integrity: sha512-fElngqOaOfTsF+u+oetDLHsPG74vB2ZaGZUqmGefAJn3a5z9Z2pNa4WpVbbKgHpaAAy5tWM1m1sbGohj6Ki6+Q==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-linux-s390x/0.14.21: + resolution: {integrity: sha512-brleZ6R5fYv0qQ7ZBwenQmP6i9TdvJCB092c/3D3pTLQHBGHJb5zWgKxOeS7bdHzmLy6a6W7GbFk6QKpjyD6QA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /esbuild-netbsd-64/0.14.21: + resolution: {integrity: sha512-nCEgsLCQ8RoFWVV8pVI+kX66ICwbPP/M9vEa0NJGIEB/Vs5sVGMqkf67oln90XNSkbc0bPBDuo4G6FxlF7PN8g==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] requiresBuild: true @@ -1717,8 +1755,9 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.13.15: - resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==} + /esbuild-openbsd-64/0.14.21: + resolution: {integrity: sha512-h9zLMyVD0T73MDTVYIb/qUTokwI6EJH9O6wESuTNq6+XpMSr6C5aYZ4fvFKdNELW+Xsod+yDS2hV2JTUAbFrLA==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] requiresBuild: true @@ -1732,8 +1771,9 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.13.15: - resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==} + /esbuild-sunos-64/0.14.21: + resolution: {integrity: sha512-Kl+7Cot32qd9oqpLdB1tEGXEkjBlijrIxMJ0+vlDFaqsODutif25on0IZlFxEBtL2Gosd4p5WCV1U7UskNQfXA==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] requiresBuild: true @@ -1747,8 +1787,9 @@ packages: dev: true optional: true - /esbuild-windows-32/0.13.15: - resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==} + /esbuild-windows-32/0.14.21: + resolution: {integrity: sha512-V7vnTq67xPBUCk/9UtlolmQ798Ecjdr1ZoI1vcSgw7M82aSSt0eZdP6bh5KAFZU8pxDcx3qoHyWQfHYr11f22A==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] requiresBuild: true @@ -1762,8 +1803,9 @@ packages: dev: true optional: true - /esbuild-windows-64/0.13.15: - resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==} + /esbuild-windows-64/0.14.21: + resolution: {integrity: sha512-kDgHjKOHwjfJDCyRGELzVxiP/RBJBTA+wyspf78MTTJQkyPuxH2vChReNdWc+dU2S4gIZFHMdP1Qrl/k22ZmaA==} + engines: {node: '>=12'} cpu: [x64] os: [win32] requiresBuild: true @@ -1777,8 +1819,9 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.13.15: - resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==} + /esbuild-windows-arm64/0.14.21: + resolution: {integrity: sha512-8Sbo0zpzgwWrwjQYLmHF78f7E2xg5Ve63bjB2ng3V2aManilnnTGaliq2snYg+NOX60+hEvJHRdVnuIAHW0lVw==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] requiresBuild: true @@ -1792,28 +1835,31 @@ packages: dev: true optional: true - /esbuild/0.13.15: - resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==} + /esbuild/0.14.21: + resolution: {integrity: sha512-7WEoNMBJdLN993dr9h0CpFHPRc3yFZD+EAVY9lg6syJJ12gc5fHq8d75QRExuhnMkT2DaRiIKFThRvDWP+fO+A==} + engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-arm64: 0.13.15 - esbuild-darwin-64: 0.13.15 - esbuild-darwin-arm64: 0.13.15 - esbuild-freebsd-64: 0.13.15 - esbuild-freebsd-arm64: 0.13.15 - esbuild-linux-32: 0.13.15 - esbuild-linux-64: 0.13.15 - esbuild-linux-arm: 0.13.15 - esbuild-linux-arm64: 0.13.15 - esbuild-linux-mips64le: 0.13.15 - esbuild-linux-ppc64le: 0.13.15 - esbuild-netbsd-64: 0.13.15 - esbuild-openbsd-64: 0.13.15 - esbuild-sunos-64: 0.13.15 - esbuild-windows-32: 0.13.15 - esbuild-windows-64: 0.13.15 - esbuild-windows-arm64: 0.13.15 + esbuild-android-arm64: 0.14.21 + esbuild-darwin-64: 0.14.21 + esbuild-darwin-arm64: 0.14.21 + esbuild-freebsd-64: 0.14.21 + esbuild-freebsd-arm64: 0.14.21 + esbuild-linux-32: 0.14.21 + esbuild-linux-64: 0.14.21 + esbuild-linux-arm: 0.14.21 + esbuild-linux-arm64: 0.14.21 + esbuild-linux-mips64le: 0.14.21 + esbuild-linux-ppc64le: 0.14.21 + esbuild-linux-riscv64: 0.14.21 + esbuild-linux-s390x: 0.14.21 + esbuild-netbsd-64: 0.14.21 + esbuild-openbsd-64: 0.14.21 + esbuild-sunos-64: 0.14.21 + esbuild-windows-32: 0.14.21 + esbuild-windows-64: 0.14.21 + esbuild-windows-arm64: 0.14.21 /esbuild/0.14.3: resolution: {integrity: sha512-zyEC5hkguW2oieXRXp8VJzQdcO/1FxCS5GjzqOHItRlojXnx/cTavsrkxdWvBH9li2lUq0bN+LeeVEmyCwiR/Q==} @@ -2271,6 +2317,12 @@ packages: resolution: {integrity: sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==} dependencies: has: 1.0.3 + dev: true + + /is-core-module/2.8.1: + resolution: {integrity: sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==} + dependencies: + has: 1.0.3 /is-date-object/1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} @@ -2769,8 +2821,8 @@ packages: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /nanoid/3.1.30: - resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==} + /nanoid/3.2.0: + resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2791,7 +2843,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.20.0 + resolve: 1.22.0 semver: 5.7.1 validate-npm-package-license: 3.0.4 dev: true @@ -2801,7 +2853,7 @@ packages: engines: {node: '>=10'} dependencies: hosted-git-info: 4.0.2 - is-core-module: 2.6.0 + is-core-module: 2.8.1 semver: 7.3.5 validate-npm-package-license: 3.0.4 dev: true @@ -3054,13 +3106,13 @@ packages: trouter: 2.0.1 dev: true - /postcss/8.4.5: - resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==} + /postcss/8.4.6: + resolution: {integrity: sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.1.30 + nanoid: 3.2.0 picocolors: 1.0.0 - source-map-js: 1.0.1 + source-map-js: 1.0.2 /preact/10.5.15: resolution: {integrity: sha512-5chK29n6QcJc3m1lVrKQSQ+V7K1Gb8HeQY6FViQ5AxCAEGu3DaHffWNDkC9+miZgsLvbvU9rxbV1qinGHMHzqA==} @@ -3194,7 +3246,7 @@ packages: /resolve/1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: - is-core-module: 2.6.0 + is-core-module: 2.8.1 path-parse: 1.0.7 dev: true @@ -3203,6 +3255,15 @@ packages: dependencies: is-core-module: 2.6.0 path-parse: 1.0.7 + dev: true + + /resolve/1.22.0: + resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==} + hasBin: true + dependencies: + is-core-module: 2.8.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 /restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} @@ -3380,8 +3441,8 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true - /source-map-js/1.0.1: - resolution: {integrity: sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==} + /source-map-js/1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} /source-map/0.6.1: @@ -3545,6 +3606,10 @@ packages: has-flag: 4.0.0 dev: true + /supports-preserve-symlinks-flag/1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + /temp-dir/2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} @@ -3717,8 +3782,8 @@ packages: engines: {node: '>= 0.8'} dev: true - /vite/2.7.12: - resolution: {integrity: sha512-KvPYToRQWhRfBeVkyhkZ5hASuHQkqZUUdUcE3xyYtq5oYEPIJ0h9LWiWTO6v990glmSac2cEPeYeXzpX5Z6qKQ==} + /vite/2.8.1: + resolution: {integrity: sha512-Typ8qjUnW0p53gBsJpisrKcZlEbUPZATja9BG6Z09QZjg9YrnEn/htkr/VH4WhnH7eNUQeSD+wKI1lHzQRWskw==} engines: {node: '>=12.2.0'} hasBin: true peerDependencies: @@ -3733,9 +3798,9 @@ packages: stylus: optional: true dependencies: - esbuild: 0.13.15 - postcss: 8.4.5 - resolve: 1.20.0 + esbuild: 0.14.21 + postcss: 8.4.6 + resolve: 1.22.0 rollup: 2.60.1 optionalDependencies: fsevents: 2.3.2 @@ -3765,21 +3830,21 @@ packages: local-pkg: 0.4.1 tinypool: 0.1.1 tinyspy: 0.2.8 - vite: 2.7.12 + vite: 2.8.1 transitivePeerDependencies: - less - sass - stylus dev: true - /vue/3.2.27: - resolution: {integrity: sha512-p1cH8Q6eaPwvANCjFQj497a914cxXKKwOG3Lg9USddTOrn4/zFMKjn9dnovkx+L8VtFaNgbVqW8mLJS/eTA6xw==} + /vue/3.2.31: + resolution: {integrity: sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==} dependencies: - '@vue/compiler-dom': 3.2.27 - '@vue/compiler-sfc': 3.2.27 - '@vue/runtime-dom': 3.2.27 - '@vue/server-renderer': 3.2.27_vue@3.2.27 - '@vue/shared': 3.2.27 + '@vue/compiler-dom': 3.2.31 + '@vue/compiler-sfc': 3.2.31 + '@vue/runtime-dom': 3.2.31 + '@vue/server-renderer': 3.2.31_vue@3.2.31 + '@vue/shared': 3.2.31 dev: false /wcwidth/1.0.1: diff --git a/scripts/release.js b/scripts/release.js index ba93a43e..8e5cef88 100644 --- a/scripts/release.js +++ b/scripts/release.js @@ -9,7 +9,6 @@ const currentVersion = require('../package.json').version const versionIncrements = ['patch', 'minor', 'major'] const inc = (i) => semver.inc(currentVersion, i) -const bin = (name) => path.resolve(__dirname, `../node_modules/.bin/${name}`) const run = (bin, args, opts = {}) => execa(bin, args, { stdio: 'inherit', ...opts }) const step = (msg) => console.log(chalk.cyan(msg)) diff --git a/src/client/app/router.ts b/src/client/app/router.ts index 0b3d523f..f7c2a397 100644 --- a/src/client/app/router.ts +++ b/src/client/app/router.ts @@ -58,7 +58,7 @@ export function createRouter( let latestPendingPath: string | null = null - async function loadPage(href: string, scrollPosition = 0) { + async function loadPage(href: string, scrollPosition = 0, isRetry = false) { const targetLoc = new URL(href, fakeHost) const pendingPath = (latestPendingPath = targetLoc.pathname) try { @@ -106,6 +106,19 @@ export function createRouter( if (!err.message.match(/fetch/)) { console.error(err) } + + // retry on fetch fail: the page to hash map may have been invalidated + // because a new deploy happened while the page is open. Try to fetch + // the updated pageToHash map and fetch again. + if (!isRetry) { + try { + const res = await fetch(siteDataRef.value.base + 'hashmap.json') + ;(window as any).__VP_HASH_MAP__ = await res.json() + await loadPage(href, scrollPosition, true) + return + } catch (e) {} + } + if (latestPendingPath === pendingPath) { latestPendingPath = null route.path = pendingPath @@ -185,7 +198,7 @@ function scrollTo(el: HTMLElement, hash: string, smooth = false) { let target: Element | null = null try { - target = el.classList.contains('.header-anchor') + target = el.classList.contains('header-anchor') ? el : document.querySelector(decodeURIComponent(hash)) } catch (e) { diff --git a/src/client/theme-default/Layout.vue b/src/client/theme-default/Layout.vue index f14ed8ee..26ba9b4c 100644 --- a/src/client/theme-default/Layout.vue +++ b/src/client/theme-default/Layout.vue @@ -4,12 +4,11 @@ import { useRoute, useData } from 'vitepress' import { isSideBarEmpty, getSideBarConfig } from './support/sideBar' // components +import Home from './components/Home.vue' import NavBar from './components/NavBar.vue' import SideBar from './components/SideBar.vue' import Page from './components/Page.vue' -const Home = defineAsyncComponent(() => import('./components/Home.vue')) - const NoopComponent = () => null const CarbonAds = __CARBON__ diff --git a/src/client/theme-default/components/LastUpdated.vue b/src/client/theme-default/components/LastUpdated.vue index ab888fbc..f495a083 100644 --- a/src/client/theme-default/components/LastUpdated.vue +++ b/src/client/theme-default/components/LastUpdated.vue @@ -1,5 +1,5 @@ diff --git a/src/client/theme-default/components/PageFooter.vue b/src/client/theme-default/components/PageFooter.vue index 41e1dded..93c7ce60 100644 --- a/src/client/theme-default/components/PageFooter.vue +++ b/src/client/theme-default/components/PageFooter.vue @@ -1,6 +1,9 @@ diff --git a/src/node/build/build.ts b/src/node/build/build.ts index 7ed05aea..6dd1d2b2 100644 --- a/src/node/build/build.ts +++ b/src/node/build/build.ts @@ -5,6 +5,7 @@ import { resolveConfig } from '../config' import { renderPage } from './render' import { OutputChunk, OutputAsset } from 'rollup' import ora from 'ora' +import path from 'path' export async function build( root: string, @@ -68,6 +69,13 @@ export async function build( spinner.stopAndPersist({ symbol: okMark }) + + // emit page hash map for the case where a user session is open + // when the site got redeployed (which invalidates current hash map) + fs.writeJSONSync( + path.join(siteConfig.outDir, 'hashmap.json'), + pageToHashMap + ) } finally { await fs.remove(siteConfig.tempDir) } diff --git a/src/node/build/bundle.ts b/src/node/build/bundle.ts index bb736847..7a5a46f1 100644 --- a/src/node/build/bundle.ts +++ b/src/node/build/bundle.ts @@ -73,13 +73,25 @@ export async function bundle( ...(ssr ? {} : { - chunkFileNames(chunk): string { - if (!chunk.isEntry && /runtime/.test(chunk.name)) { - return `assets/framework.[hash].js` + chunkFileNames(chunk) { + // avoid ads chunk being intercepted by adblock + return /(?:Carbon|BuySell)Ads/.test(chunk.name) + ? `assets/chunks/ui-custom.[hash].js` + : `assets/chunks/[name].[hash].js` + }, + manualChunks(id, ctx) { + // move known framework code into a stable chunk so that + // custom theme changes do not invalidate hash for all pages + if (id.includes('plugin-vue:export-helper')) { + return 'framework' + } + if ( + isEagerChunk(id, ctx) && + (/@vue\/(runtime|shared|reactivity)/.test(id) || + /vitepress\/dist\/client/.test(id)) + ) { + return 'framework' } - return adComponentRE.test(chunk.name) - ? `assets/ui-custom.[hash].js` - : `assets/[name].[hash].js` } }) } @@ -133,4 +145,53 @@ export async function bundle( return { clientResult, serverResult, pageToHashMap } } -const adComponentRE = /(?:Carbon|BuySell)Ads/ +const cache = new Map() + +/** + * Check if a module is statically imported by at least one entry. + */ +function isEagerChunk(id: string, { getModuleInfo }: any) { + if ( + id.includes('node_modules') && + !/\.css($|\\?)/.test(id) && + staticImportedByEntry(id, getModuleInfo, cache) + ) { + return 'vendor' + } +} + +function staticImportedByEntry( + id: string, + getModuleInfo: any, + cache: Map, + importStack: string[] = [] +): boolean { + if (cache.has(id)) { + return cache.get(id) as boolean + } + if (importStack.includes(id)) { + // circular deps! + cache.set(id, false) + return false + } + const mod = getModuleInfo(id) + if (!mod) { + cache.set(id, false) + return false + } + + if (mod.isEntry) { + cache.set(id, true) + return true + } + const someImporterIs = mod.importers.some((importer: string) => + staticImportedByEntry( + importer, + getModuleInfo, + cache, + importStack.concat(id) + ) + ) + cache.set(id, someImporterIs) + return someImporterIs +} diff --git a/src/node/config.ts b/src/node/config.ts index f2453951..a9277b85 100644 --- a/src/node/config.ts +++ b/src/node/config.ts @@ -37,6 +37,7 @@ export interface UserConfig { themeConfig?: ThemeConfig locales?: Record markdown?: MarkdownOptions + lastUpdated?: boolean /** * Options to pass on to `@vitejs/plugin-vue` */ @@ -72,7 +73,7 @@ export type RawConfigExports = export interface SiteConfig extends Pick< UserConfig, - 'markdown' | 'vue' | 'vite' | 'shouldPreload' | 'mpa' + 'markdown' | 'vue' | 'vite' | 'shouldPreload' | 'mpa' | 'lastUpdated' > { root: string srcDir: string @@ -145,6 +146,7 @@ export async function resolveConfig( outDir, tempDir: resolve(root, '.temp'), markdown: userConfig.markdown, + lastUpdated: userConfig.lastUpdated, alias: resolveAliases(root, themeDir), vue: userConfig.vue, vite: userConfig.vite, diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index 4f3e0b7e..46cbff35 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -50,7 +50,8 @@ export type { Header } export const createMarkdownRenderer = ( srcDir: string, - options: MarkdownOptions = {} + options: MarkdownOptions = {}, + base: string ): MarkdownRenderer => { const md = MarkdownIt({ html: true, @@ -68,11 +69,15 @@ export const createMarkdownRenderer = ( .use(containerPlugin) .use(headingPlugin) .use(imagePlugin) - .use(linkPlugin, { - target: '_blank', - rel: 'noopener noreferrer', - ...options.externalLinks - }) + .use( + linkPlugin, + { + target: '_blank', + rel: 'noopener noreferrer', + ...options.externalLinks + }, + base + ) // 3rd party plugins .use(attrs, options.attrs) .use(anchor, { diff --git a/src/node/markdown/plugins/link.ts b/src/node/markdown/plugins/link.ts index e44c043a..d1448bc8 100644 --- a/src/node/markdown/plugins/link.ts +++ b/src/node/markdown/plugins/link.ts @@ -11,7 +11,8 @@ const indexRE = /(^|.*\/)index.md(#?.*)$/i export const linkPlugin = ( md: MarkdownIt, - externalAttrs: Record + externalAttrs: Record, + base: string ) => { md.renderer.rules.link_open = (tokens, idx, options, env, self) => { const token = tokens[idx] @@ -76,6 +77,11 @@ export const linkPlugin = ( // export it for existence check pushLink(url.replace(/\.html$/, '')) + // append base to internal (non-relative) urls + if (url.startsWith('/')) { + url = `${base}${url}`.replace(/\/+/g, '/') + } + // markdown-it encodes the uri hrefAttr[1] = decodeURI(url) } diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts index a596e22b..29db7461 100644 --- a/src/node/markdownToVue.ts +++ b/src/node/markdownToVue.ts @@ -8,6 +8,7 @@ import { PageData, HeadConfig, EXTERNAL_URL_RE } from './shared' import { slash } from './utils/slash' import chalk from 'chalk' import _debug from 'debug' +import { getGitTimestamp } from './utils/getGitTimestamp' const debug = _debug('vitepress:md') const cache = new LRUCache({ max: 1024 }) @@ -25,9 +26,11 @@ export function createMarkdownToVueRenderFn( options: MarkdownOptions = {}, pages: string[], userDefines: Record | undefined, - isBuild = false + isBuild = false, + base: string, + includeLastUpdatedData = false ) { - const md = createMarkdownRenderer(srcDir, options) + const md = createMarkdownRenderer(srcDir, options, base) pages = pages.map((p) => slash(p.replace(/\.md$/, ''))) const userDefineRegex = userDefines @@ -39,11 +42,11 @@ export function createMarkdownToVueRenderFn( ) : null - return ( + return async ( src: string, file: string, publicDir: string - ): MarkdownCompileResult => { + ): Promise => { const relativePath = slash(path.relative(srcDir, file)) const dir = path.dirname(file) @@ -132,9 +135,11 @@ export function createMarkdownToVueRenderFn( description: inferDescription(frontmatter), frontmatter, headers: data.headers || [], - relativePath, - // TODO use git timestamp? - lastUpdated: Math.round(fs.statSync(file).mtimeMs) + relativePath + } + + if (includeLastUpdatedData) { + pageData.lastUpdated = await getGitTimestamp(file) } const vueSrc = diff --git a/src/node/plugin.ts b/src/node/plugin.ts index fc6d8e6f..7f6e6f33 100644 --- a/src/node/plugin.ts +++ b/src/node/plugin.ts @@ -1,10 +1,7 @@ import path from 'path' import { defineConfig, mergeConfig, Plugin, ResolvedConfig } from 'vite' import { SiteConfig, resolveSiteData } from './config' -import { - createMarkdownToVueRenderFn, - MarkdownCompileResult -} from './markdownToVue' +import { createMarkdownToVueRenderFn } from './markdownToVue' import { DIST_CLIENT_PATH, APP_PATH, SITE_DATA_REQUEST_PATH } from './alias' import { slash } from './utils/slash' import { OutputAsset, OutputChunk } from 'rollup' @@ -49,11 +46,7 @@ export function createVitePressPlugin( pages } = siteConfig - let markdownToVue: ( - src: string, - file: string, - publicDir: string - ) => MarkdownCompileResult + let markdownToVue: ReturnType // lazy require plugin-vue to respect NODE_ENV in @vue/compiler-x const vuePlugin = require('@vitejs/plugin-vue')({ @@ -84,7 +77,9 @@ export function createVitePressPlugin( markdown, pages, config.define, - config.command === 'build' + config.command === 'build', + config.base, + siteConfig.lastUpdated ) }, @@ -131,12 +126,12 @@ export function createVitePressPlugin( } }, - transform(code, id) { + async transform(code, id) { if (id.endsWith('.vue')) { return processClientJS(code, id) } else if (id.endsWith('.md')) { // transform .md files into vueSrc so plugin-vue can handle it - const { vueSrc, deadLinks, includes } = markdownToVue( + const { vueSrc, deadLinks, includes } = await markdownToVue( code, id, config.publicDir @@ -257,7 +252,7 @@ export function createVitePressPlugin( // hot reload .md files as .vue files if (file.endsWith('.md')) { const content = await read() - const { pageData, vueSrc } = markdownToVue( + const { pageData, vueSrc } = await markdownToVue( content, file, config.publicDir diff --git a/src/node/utils/getGitTimestamp.ts b/src/node/utils/getGitTimestamp.ts new file mode 100644 index 00000000..07c4d820 --- /dev/null +++ b/src/node/utils/getGitTimestamp.ts @@ -0,0 +1,13 @@ +import { spawn } from 'cross-spawn' + +export function getGitTimestamp(file: string) { + return new Promise((resolve, reject) => { + const child = spawn('git', ['log', '-1', '--pretty="%ci"', file]) + let output = '' + child.stdout.on('data', (d) => (output += String(d))) + child.on('close', () => { + resolve(+new Date(output)) + }) + child.on('error', reject) + }) +} diff --git a/types/shared.d.ts b/types/shared.d.ts index 8f41bc5e..645c0114 100644 --- a/types/shared.d.ts +++ b/types/shared.d.ts @@ -8,7 +8,7 @@ export interface PageData { description: string headers: Header[] frontmatter: Record - lastUpdated: number + lastUpdated?: number } export interface SiteData {