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

Offline support #1888

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2677ccf
Upgrade to astro 1.4.7
zadeviggers Oct 10, 2022
a45cbeb
Merge pull request #2 from zadeviggers/upgrade-to-astro-1.4
zadeviggers Oct 10, 2022
1b4d8d5
First steps
zadeviggers Oct 22, 2022
575660b
First steps
zadeviggers Oct 22, 2022
3d9c7cb
Merge
zadeviggers Oct 22, 2022
7c845ef
Basic offline works
zadeviggers Oct 22, 2022
1635ec9
Remove vite-plugin-pwa
zadeviggers Oct 22, 2022
1726097
Cache assets & priority caching system
zadeviggers Oct 23, 2022
a97b925
Make service worker typescript, and add headers
zadeviggers Oct 23, 2022
d839cb9
Add sidebar to offline page
zadeviggers Oct 23, 2022
c216cd6
Disable fully in dev
zadeviggers Oct 23, 2022
4bb8c19
Remove old debugging code
zadeviggers Oct 24, 2022
da3d150
Add warning to pages when served from cache
zadeviggers Oct 24, 2022
e8f22c4
Fix formatting
zadeviggers Oct 24, 2022
1ec4db9
Fix linter errors
zadeviggers Oct 24, 2022
bd65067
Clean up worker code,, and get offline working properly
zadeviggers Oct 24, 2022
2a63268
Comment service worker code better
zadeviggers Oct 24, 2022
06027ee
Add `skipWaiting`
zadeviggers Oct 24, 2022
289ea04
Only download pages in the user's selected language
zadeviggers Oct 24, 2022
3b6502d
Download translated pages without refresh
zadeviggers Oct 24, 2022
1f36aea
Fix offline page breaking when switching languages
zadeviggers Oct 25, 2022
c610abe
Improve status indicator
zadeviggers Oct 25, 2022
3b16f63
Remove simple-vanilla-notfications
zadeviggers Oct 25, 2022
0e61249
Make all strings in ui translatable
zadeviggers Oct 25, 2022
799949e
Revert making ui translatable since it breaks stuff
zadeviggers Oct 25, 2022
daf7c76
Revert "Revert making ui translatable since it breaks stuff"
zadeviggers Oct 25, 2022
4d00df8
Fixed making ui translatable
zadeviggers Oct 25, 2022
0c16806
Merge branch 'main' into offline-support
zadeviggers Oct 25, 2022
ae83a9c
Remove duplicated key
zadeviggers Oct 25, 2022
4ab8070
Merge branch 'offline-support' of https://github.com/zadeviggers/docs…
zadeviggers Oct 25, 2022
6126811
Remove link from offline page
zadeviggers Oct 25, 2022
4858601
Remove unused rtlLanguages import
zadeviggers Oct 25, 2022
df12b4d
Merge branch 'main' into offline-support
zadeviggers Oct 25, 2022
0e522b4
Add article wrapper to offline page
zadeviggers Oct 25, 2022
8402fc0
Remove offline page from sitemap
zadeviggers Oct 25, 2022
c2ed726
Rename integration to `offlineMode`
zadeviggers Oct 25, 2022
69909e9
Merge branch 'offline-support' of https://github.com/zadeviggers/docs…
zadeviggers Oct 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { tokens, foregroundPrimary, backgroundPrimary } from './syntax-highlight
import { astroAsides } from './integrations/astro-asides';
import { astroSpoilers } from './integrations/astro-spoilers';
import { astroCodeSnippets } from './integrations/astro-code-snippets';
import { offlineMode } from './integrations/offline-mode';

import { remarkFallbackLang } from './plugins/remark-fallback-lang';
import { rehypeTasklistEnhancer } from './plugins/rehype-tasklist-enhancer';

Expand Down Expand Up @@ -46,6 +48,7 @@ export default defineConfig({
astroFlavoredMarkdown: true,
},
integrations: [
offlineMode(),
preact({ compat: true }),
sitemap({
i18n: {
Expand All @@ -54,6 +57,10 @@ export default defineConfig({
Object.keys(languages).map((lang) => [lang, normalizeLangTag(lang)])
),
},
filter: (page) => {
if (page.endsWith('offline/')) return false;
return true;
},
}),
astroAsides(),
astroSpoilers(),
Expand Down
120 changes: 120 additions & 0 deletions integrations/offline-mode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { RouteData } from 'astro';
import { AstroIntegration } from 'astro';
import { transpileModule } from 'typescript';

import { readFile, writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { join } from 'node:path';

import tsConfig from '../../tsconfig.json';
import languages from '../../src/i18n/languages';

export function offlineMode(): AstroIntegration {
return {
name: 'astro-docs-offline-mode',
hooks: {
'astro:config:setup': async ({ updateConfig }) => {
updateConfig({
vite: {
plugins: [rollupPlugin()],
},
});
},
'astro:build:done': async ({ routes, dir }) => {
const generatedWorker = await generateSw(routes, Date.now().toString());

const outFile = fileURLToPath(new URL('./service-worker.js', dir));
await writeFile(outFile, generatedWorker);
},
},
};
}

// Important routes to cache
const importantRoutes: string[] = Object.keys(languages).map((key) => `/${key}/offline/`);

// Exclude all the *.mjs files - one shows up in the list for each page
const excludeAssetRegEx = /\.mjs$/;

// Things like css files, js files, etc
const importantAssets: string[] = [
'index.css',
'theme.css',
'favicon.ico',
'favicon.svg',
'manifest.webmanifest',
];

// Things like fonts
const unimportantAssets: string[] = [];

function formatFilePathStrings(strings: string[]): string[] {
const newStrings: string[] = [];
for (const str of strings) {
let newStr = str;
if (!newStr.startsWith('/')) newStr = '/' + newStr;
newStr = `'${newStr}'`;
newStrings.push(newStr);
}
return newStrings;
}

// Rollup plugin for getting the paths for all the assets
function rollupPlugin() {
return {
name: 'astro-docs-service-worker-rollup-plugin',
writeBundle: {
async handler(_, bundle: { [fileName: string]: unknown }) {
Object.keys(bundle)
.filter((fileName) => !fileName.match(excludeAssetRegEx))
.forEach((fileName) => {
// Don't double-cache thing
if (importantAssets.includes(fileName)) return;

// Don't cache videos, since they take up loads of space.
if (fileName.endsWith('.mp4')) return;

unimportantAssets.push(fileName);
});
},
},
};
}

// Function to generate the service worker file
async function generateSw(routes: RouteData[], hash: string): Promise<string> {
// Load the template file
const swTemplate = await readFile(join(__dirname, 'service-worker-template.ts'), 'utf-8');

const routePaths = routes
.filter((route) => !!route.pathname)
.map((route) => route.pathname!)
.map((pathName) => {
// Don't add a slash to the end of paths that already have one
if (pathName.endsWith('/')) return pathName;
// Don't add a slash to the end of paths that have an extension
if (/\.[a-zA-Z]+$/.test(pathName)) return pathName;

// Add a slash to the end of all other paths
return pathName + '/';
});

const importantFiles = formatFilePathStrings([...importantRoutes, ...importantAssets]);
const otherFiles = formatFilePathStrings([
...routePaths.filter((route) => !importantRoutes.includes(route)),
...unimportantAssets,
]);

const generatedTemplate = swTemplate
.replace('/* $%_priority_files_%$ */', importantFiles.join(','))
.replace('/* $%_other_files_%$ */', otherFiles.join(','))
.replace('/* $%_hash_%$ */', hash);

// Compile from typescript
const compiledTemplate = transpileModule(generatedTemplate, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
compilerOptions: tsConfig.compilerOptions as any,
}).outputText.replace('export {};', ''); // Get rid of this artifact from typescript

return compiledTemplate;
}
Loading