Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): add pwa with auto update strategy #573

Merged
merged 37 commits into from Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d1ff669
chore: fix seo and a11y
userquin Jan 18, 2022
7ec0be8
deps: add esno and pwa plugin
userquin Jan 18, 2022
7a143b5
chore: configure netlify stuff
userquin Jan 18, 2022
1d48d64
feat(docs): add pwa with auto update strategy
userquin Jan 18, 2022
8dd90a5
chore: update keywords
userquin Jan 18, 2022
2452e6f
docs: fix typo
userquin Jan 18, 2022
6f188de
chore: update netlify deployment
userquin Jan 18, 2022
f7c9316
Merge branch 'main' into userquin/docs-add-pwa
userquin Jan 19, 2022
7366ba6
fix: add favicon.ico and fix pwa 512 icon
userquin Jan 19, 2022
a78ae10
chore: add favicon.ico and move stuff to top
userquin Jan 19, 2022
b545baa
chore: add footer copyright + update some entries
userquin Jan 19, 2022
4eab2eb
chore: add favicon.ico
userquin Jan 19, 2022
4a90139
chore: update deps
userquin Jan 19, 2022
f46c8df
chore: typo
userquin Jan 19, 2022
b6803d8
Merge branch 'main' into userquin/docs-add-pwa
userquin Jan 26, 2022
96e8fef
chore: update deps
userquin Jan 26, 2022
2c38740
chore: use root `netlify.toml`
userquin Jan 26, 2022
b1b78a0
chore: collect docs data + png optimized
userquin Jan 27, 2022
2a26e23
Merge branch 'main' into userquin/docs-add-pwa
userquin Jan 27, 2022
fa3a639
chore: update deps
userquin Jan 27, 2022
64eb1d8
chore: cleanup
userquin Jan 27, 2022
d0a01c5
chore: update `Ivan Demchuk` description
userquin Jan 27, 2022
8469880
chore: simplify logic + unify sponsors
userquin Jan 28, 2022
bb03f0f
chore: disable PWA + make home images lazy
userquin Jan 28, 2022
340fbe0
chore: update h2 styles on home to have old h3 style
userquin Jan 28, 2022
c4520eb
chore: update deps
userquin Jan 28, 2022
3ac4380
Revert "chore: update deps"
userquin Jan 28, 2022
5808a7a
chore: revert sponsors images with fixed size
userquin Jan 29, 2022
ee3ac0a
Merge branch 'main' into userquin/docs-add-pwa
userquin Jan 29, 2022
3e99a07
chore: add algolia
userquin Feb 2, 2022
94f6d4b
Merge branch 'main' into userquin/docs-add-pwa
userquin Feb 18, 2022
717cb12
deps: updated deps after merge main
userquin Feb 18, 2022
a88213d
chore: restore original image behavior
userquin Feb 20, 2022
507be6a
Merge branch 'main' into userquin/docs-add-pwa
userquin Feb 20, 2022
bc83c89
chore: add again image widths and lazy loading
userquin Feb 20, 2022
18e8b23
chore: update minimal algolia styles for dark theme
userquin Feb 20, 2022
f378a55
fix: change name (aslemammad)
Aslemammad Feb 21, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 39 additions & 18 deletions docs/.vitepress/config.ts
@@ -1,20 +1,41 @@

import { defineConfig } from 'vitepress'
import { version } from '../../package.json'
import {
contributing,
discord,
font,
ogImage,
ogUrl,
releases,
twitter,
vitestDescription,
vitestName
} from "../docs-data";
// noinspection ES6PreferShortImport: IntelliJ IDE hint to avoid warning to use `~/contributors`, will fail on build if changed
import { coreTeamMembers } from '../src/contributors'

export default defineConfig({
title: 'Vitest',
description: 'A blazing fast unit test framework powered by Vite',
title: vitestName,
description: vitestDescription,
head: [
['meta', { property: 'og:title', content: 'Vitest' }],
['meta', { property: 'og:description', content: 'A blazing fast unit test framework powered by Vite' }],
['meta', { property: 'og:url', content: 'https://vitest.dev/' }],
['meta', { property: 'og:image', content: 'https://vitest.dev/og.png' }],
['meta', { name: 'twitter:title', content: 'Vitest' }],
['meta', { name: 'twitter:description', content: 'A blazing fast unit test framework powered by Vite' }],
['meta', { name: 'twitter:image', content: 'https://vitest.dev/og.png' }],
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
['meta', { name: 'theme-color', content: '#ffffff' }],
['link', { rel: 'icon', href: '/logo.svg', type: 'image/svg+xml' }],
['link', { href: 'https://fonts.googleapis.com/css2?family=Readex+Pro:wght@200;400;600&display=swap', rel: 'stylesheet' }],
['link', { rel: 'alternate icon', href: '/favicon.ico', type: 'image/png', sizes: '16x16' }],
['meta', { name: 'author', content: `${coreTeamMembers.map(c => c.name).join(', ')} and ${vitestName} contributors` }],
// TODO: review this
['meta', { name: 'keywords', content: 'vitest, vite, test, coverage, snapshot, react, vue, preact, svelte, solid, lit, ruby, cypress, puppeteer, jsdom, happy-dom, test-runner, jest, typescript, esm, tinypool, tinyspy, c8, node' }],
['meta', { property: 'og:title', content: vitestName }],
['meta', { property: 'og:description', content: vitestDescription }],
['meta', { property: 'og:url', content: ogUrl }],
['meta', { property: 'og:image', content: ogImage }],
['meta', { name: 'twitter:title', content: vitestName }],
['meta', { name: 'twitter:description', content: vitestDescription }],
['meta', { name: 'twitter:image', content: ogImage }],
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
['link', { href: font, rel: 'stylesheet' }],
['link', { rel: 'mask-icon', href: '/logo.svg', color: '#ffffff' }],
['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: "180x180" }],
],
themeConfig: {
repo: 'vitest-dev/vitest',
Expand All @@ -24,16 +45,16 @@ export default defineConfig({
editLinks: true,
editLinkText: 'Suggest changes to this page',

/* TODO

algolia: {
apiKey: '...',
apiKey: '9c3ced6fed60d2670bb36ab7e8bed8bc',
indexName: 'vitest',
searchParameters: {
facetFilters: ['tags:en']
}
},

/* TODO

carbonAds: {
carbon: '...',
placement: 'vitest'
Expand All @@ -50,22 +71,22 @@ export default defineConfig({
items: [
{
text: 'Release Notes ',
link: 'https://github.com/vitest-dev/vitest/releases',
link: releases,
},
{
text: 'Contributing ',
link: 'https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md',
link: contributing,
},
],

},
{
text: 'Discord',
link: 'https://chat.vitest.dev'
link: discord,
},
{
text: 'Twitter',
link: 'https://twitter.com/vitest_dev'
link: twitter,
},
/* TODO
{
Expand Down
4 changes: 4 additions & 0 deletions docs/.vitepress/theme/index.ts
@@ -1,5 +1,9 @@
import 'uno.css'
import { inBrowser } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import '../../main.css'

if (inBrowser)
import('./pwa')

export default DefaultTheme
3 changes: 3 additions & 0 deletions docs/.vitepress/theme/pwa.ts
@@ -0,0 +1,3 @@
import { registerSW } from 'virtual:pwa-register'

registerSW({ immediate: true })
2 changes: 1 addition & 1 deletion docs/contributors.json
Expand Up @@ -29,4 +29,4 @@
"aleclarson",
"CyriacBr",
"christianhg"
]
]
43 changes: 43 additions & 0 deletions docs/docs-data.ts
@@ -0,0 +1,43 @@
// noinspection ES6PreferShortImport: IntelliJ IDE hint to avoid warning to use `~/contributors`, will fail on build if changed
import { antfuSponsors, jsdelivr, patak, patakSponsors } from './src/contributors'
/* PWA DISABLED */
export const pwaDisabled = true

/* Texts */
export const vitestName = 'Vitest'
export const vitestShortName = 'Vitest'
export const vitestDescription = 'A blazing fast unit test framework powered by Vite'

/* CDN fonts and styles */
export const googleapis = 'https://fonts.googleapis.com'
export const gstatic = 'https://fonts.gstatic.com'
export const font = `${googleapis}/css2?family=Readex+Pro:wght@200;400;600&display=swap`

/* vitepress head */
export const ogUrl = 'https://vitest.dev/'
export const ogImage = `${ogUrl}og.png`

/* GitHub and social links */
export const releases = 'https://github.com/vitest-dev/vitest/releases'
export const contributing = 'https://github.com/vitest-dev/vitest/blob/main/CONTRIBUTING.md'
export const discord = 'https://chat.vitest.dev'
export const twitter = 'https://twitter.com/vitest_dev'

/* Avatar/Image/Sponsors servers */
export const imageServers: Record<string, string> = {
// for antfu sponsors
jsdelivr,
// for patak sponsors
patak,
// GitHub contributor avatars
github: 'github.com',
avatars: 'avatars.githubusercontent.com',
}
export const sponsors = [antfuSponsors, patakSponsors]
export const preconnectLinks = [googleapis, gstatic]
export const preconnectHomeLinks = [googleapis, gstatic, ...Object.values(imageServers).map(s => `https://${s}`)]

/* PWA runtime caching urlPattern regular expressions */
export const pwaImagesRegex = new RegExp(`^https://(${Object.values(imageServers).join('|')})/.*`, 'i')
export const pwaFontsRegex = new RegExp(`^${googleapis}/.*`, 'i')
export const pwaFontStylesRegex = new RegExp(`^${gstatic}/.*`, 'i')
2 changes: 2 additions & 0 deletions docs/index.md
Expand Up @@ -2,6 +2,8 @@
home: true
sidebar: false
title: 'Vitest - A blazing fast unit test framework powered by Vite'

footer: 'MIT Licensed | Copyright © 2021-PRESENT Anthony Fu, Matías Capeletto and Vitest contributors'
---

<Home />
51 changes: 51 additions & 0 deletions docs/main.css
Expand Up @@ -93,3 +93,54 @@ main.home {
th, td {
border: 1px solid #8885;
}

/* h3 breaks SEO => replaced with h2 with the same size */
.home-content h2 {
margin-top: 2rem;
font-size: 1.35rem;
border-bottom: none;
margin-bottom: 0;
}

.DocSearch-Modal {
--docsearch-logo-color: #ca931c;
}

@media (prefers-color-scheme: dark) {
.algolia-search-box > button {
--docsearch-searchbox-background: transparent;
--docsearch-searchbox-focus-background: var(--docsearch-searchbox-background);
--docsearch-text-color: #90a4b7;
--docsearch-key-gradient: linear-gradient(-225deg,--docsearch-searchbox-background,--docsearch-searchbox-background);
}
.algolia-search-box > button:hover {
--c-brand: #ca931c;
--docsearch-text-color: #ca931c;
--docsearch-muted-color: #ca931c;
}
.algolia-search-box > button:hover > .DocSearch-Button-Keys > .DocSearch-Button-Key {
color: #ca931c;
box-shadow: inset 0 -1px 0 0 var(--docsearch-muted-color),inset 0 0 1px 1px var(--docsearch-muted-color),0 1px 1px 1px var(--docsearch-muted-color);
}
.DocSearch-Modal {
--docsearch-modal-background: rgb(20,20,20);
--docsearch-primary-color: #ca931c;
--docsearch-highlight-color: var(--docsearch-primary-color);
--docsearch-searchbox-shadow: inset 0 0 0 2px var(--docsearch-primary-color);
--docsearch-text-color: #90a4b7;
--docsearch-muted-color: var(--c-text-lighter);
--docsearch-searchbox-background: rgb(20,20,20);
--docsearch-searchbox-focus-background: rgb(20,20,20);
--docsearch-footer-background: rgb(20,20,20);
}
.DocSearch-Commands-Key {
color: #ca931c;
--docsearch-text-color: #ca931c;
--docsearch-highlight-color: var(--docsearch-text-color);
}
.DocSearch-Footer {
--docsearch-key-gradient: linear-gradient(-225deg,--docsearch-searchbox-background,--docsearch-searchbox-background);
--docsearch-key-shadow: inset 0 -1px 0 0 #ca931c,inset 0 0 1px 1px #ca931c,0 1px 1px 1px #ca931c;
}
}

11 changes: 9 additions & 2 deletions docs/package.json
Expand Up @@ -3,8 +3,9 @@
"private": true,
"scripts": {
"dev": "vitepress --port 3333 --open",
"build": "vitepress build",
"build": "vitepress build && esno scripts/build-pwa.ts",
"serve": "vitepress serve",
"preview-https": "pnpm run build && serve .vitepress/dist",
"lint": "eslint . --ext=.ts,.vue"
},
"dependencies": {
Expand All @@ -13,10 +14,16 @@
},
"devDependencies": {
"@iconify-json/carbon": "^1.1.0",
"@types/node": "^17.0.8",
"@unocss/reset": "^0.24.4",
"@vitejs/plugin-vue": "^2.2.0",
"esno": "^0.14.0",
"fast-glob": "^3.2.10",
"https-localhost": "^4.7.0",
"unocss": "^0.24.4",
"unplugin-vue-components": "^0.17.18",
"vitepress": "^0.22.2"
"vite-plugin-pwa": "^0.11.13",
"vitepress": "^0.22.2",
"workbox-window": "^6.4.2"
}
}
28 changes: 28 additions & 0 deletions docs/public/_headers
@@ -0,0 +1,28 @@
/
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

/api/
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

/config/
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

/guide/
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

/*.html
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

/*
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer
Strict-Transport-Security: max-age=31536000; includeSubDomains

/assets/*
cache-control: max-age=31536000
cache-control: immutable
Binary file added docs/public/apple-touch-icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/bg-original.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/bg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/favicon.ico
Binary file not shown.
Binary file added docs/public/og-original.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/og.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/pwa-192x192.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/pwa-512x512.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 85 additions & 0 deletions docs/scripts/assets.ts
@@ -0,0 +1,85 @@
import { promises as fs } from 'fs'
import fg from 'fast-glob'
import { font, preconnectHomeLinks, preconnectLinks } from '../docs-data'

const preconnect = `
${preconnectLinks.map(l => `<link rel="dns-prefetch" href="${l}">`).join('\n')}
${preconnectLinks.map(l => `<link rel="preconnect" crossorigin="anonymous" href="${l}">`).join('\n')}
`

const preconnectHome = `
${preconnectHomeLinks.map(l => `<link rel="dns-prefetch" href="${l}">`).join('\n')}
${preconnectHomeLinks.map(l => `<link rel="preconnect" crossorigin="anonymous" href="${l}">`).join('\n')}
`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we automate this? I am not so confident of duplicating (It would make future changes much harder)

Copy link
Member Author

@userquin userquin Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can include some module with the site data, including all stuff there: avatars, links, contributors, fonts...

I'll be back next Tuesday, we can merge and then change it, but proceed as you wish


export const optimizePages = async(pwa: boolean) => {
const names = await fg('./.vitepress/dist/**/*.html', { onlyFiles: true })

await Promise.all(names.map(async(i) => {
let html = await fs.readFile(i, 'utf-8')

let prefetchImg = '\n\t<link rel="prefetch" href="/logo.svg">'

let usePreconnect = preconnect

if (i.endsWith('/dist/index.html')) {
usePreconnect = preconnectHome
prefetchImg = `
${prefetchImg}
\t<link rel="prefetch" href="/netlify.svg">
\t<link rel="prefetch" href="/bg.png">
`
}

// we need the font on development, so the font entry is added in vitepress head
html = html.replace(`<link href="${font.replace('&', '&amp;')}" rel="stylesheet">`, '')

html = html.replace(
/<link rel="stylesheet" href="(.*)">/g,
`
${usePreconnect}
<link rel="preload" as="style" href="$1" />
<link rel="stylesheet" href="$1" />
<link
rel="preload"
as="style"
onload="this.onload=null;this.rel='stylesheet'"
href="${font}"
/>
<noscript>
<link rel="stylesheet" crossorigin="anonymous" href="${font}" />
</noscript>`).trim()

if (pwa) {
html = html.replace(
'</head>',
`
\t<link rel="prefetch" href="/manifest.webmanifest">${prefetchImg}
\t<link rel="manifest" href="/manifest.webmanifest">\n</head>`,
)
}

// TODO: dark/light theme, don't remove yet
// html = html.replace(
// '</head>',
// '\t<link rel="manifest" href="/manifest.webmanifest">\n<script>\n'
// + ' (function() {\n'
// + ' const prefersDark = window.matchMedia && window.matchMedia(\'(prefers-color-scheme: dark)\').matches\n'
// + ' const setting = localStorage.getItem(\'color-schema\') || \'auto\'\n'
// + ' if (setting === \'dark\' || (prefersDark && setting !== \'light\'))\n'
// + ' document.documentElement.classList.toggle(\'dark\', true)\n'
// + ' })()\n'
// + ' </script></head>',
// )

html = html.replace(
/aria-hidden="true"/gi,
'tabindex="-1" aria-hidden="true"',
).replace(
/<img class="logo"/gi,
'<img class="logo" width="31" height="31"',
)

await fs.writeFile(i, html, 'utf-8')
}))
}
15 changes: 15 additions & 0 deletions docs/scripts/build-pwa.ts
@@ -0,0 +1,15 @@
import { resolveConfig } from 'vite'
import type { VitePluginPWAAPI } from 'vite-plugin-pwa'
import { optimizePages } from './assets'

const rebuildPwa = async() => {
const config = await resolveConfig({}, 'build', 'production')
// when `vite-plugin-pwa` is presented, use it to regenerate SW after rendering
const pwaPlugin: VitePluginPWAAPI = config.plugins.find(i => i.name === 'vite-plugin-pwa')?.api
const pwa = pwaPlugin && !pwaPlugin.disabled
await optimizePages(pwa)
if (pwa)
await pwaPlugin.generateSW()
}

rebuildPwa()