Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ pnpm-debug.log*
# macOS-specific files
.DS_Store
.vercel

# downloaded documentation
src/content/docs/
src/content/.docs-*/
4 changes: 0 additions & 4 deletions .gitmodules

This file was deleted.

10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# The Zane Website

The documentation is shallow-cloned from [`zane-lang/docs`](https://github.com/zane-lang/docs)
before starting the development server or building the site. To refresh it manually, run:

```sh
npm run sync:docs
```

Set `ZANE_DOCS_REF` to clone a branch or tag other than `main`. The clone's `.git`
directory is removed after fetching, and the downloaded documentation is ignored by Git.
6 changes: 3 additions & 3 deletions justfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
submodules:
git submodule update --remote --recursive --force
docs:
npm run sync:docs

dev:
npm run dev
Expand All @@ -8,7 +8,7 @@ ship:
#!/usr/bin/env bash
read -p "Are you sure you want to deploy to production? [y/N] " confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
just submodules && vercel --prod
vercel --prod
else
echo "Deployment cancelled."
fi
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
"type": "module",
"version": "0.0.1",
"scripts": {
"sync:docs": "node scripts/fetch-docs.mjs",
"predev": "node scripts/fetch-docs.mjs --skip-if-exists",
"dev": "astro dev",
"prestart": "node scripts/fetch-docs.mjs --skip-if-exists",
"start": "astro dev",
"prebuild": "node scripts/fetch-docs.mjs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Running npm run build currently forces a redownload of the documentation every time because prebuild does not use the --skip-if-exists flag. This prevents offline builds and slows down local production testing.

Since production environments (like Vercel or CI) always start with a clean workspace where src/content/docs does not exist, they will still fetch the docs automatically even with --skip-if-exists.

Consider adding --skip-if-exists to prebuild to allow offline builds and speed up local builds.

Suggested change
"prebuild": "node scripts/fetch-docs.mjs",
"prebuild": "node scripts/fetch-docs.mjs --skip-if-exists",

"build": "astro build",
"preview": "astro preview",
"astro": "astro"
Expand Down
43 changes: 43 additions & 0 deletions scripts/fetch-docs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { execFile } from 'node:child_process';
import { access, mkdtemp, mkdir, rename, rm } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { promisify } from 'node:util';

const execFileAsync = promisify(execFile);

const repository = 'https://github.com/zane-lang/docs.git';
const ref = process.env.ZANE_DOCS_REF || 'main';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const contentDirectory = join(root, 'src/content');
const destination = join(contentDirectory, 'docs');

if (process.argv.includes('--skip-if-exists')) {
try {
await access(destination);
console.log('Docs already exist, skipping download.');
process.exit(0);
} catch {}
}

await mkdir(contentDirectory, { recursive: true });
const workDirectory = await mkdtemp(join(contentDirectory, '.docs-'));
const checkout = join(workDirectory, 'checkout');

try {
await execFileAsync(
'git',
['clone', '--depth=1', '--branch', ref, '--single-branch', repository, checkout],
{ timeout: 30_000 },
);

await rm(join(checkout, '.git'), { recursive: true, force: true });
await rm(destination, { recursive: true, force: true });
await rename(checkout, destination);
Comment on lines +35 to +36

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If rename(checkout, destination) fails after rm(destination) has already run, the existing documentation is lost and the directory is left empty.

To make this operation more robust and prevent data loss on failure, you can rename the existing destination to a temporary backup path first, perform the rename, and then clean up the backup.

	const backup = join(contentDirectory, '.docs-old');
	try {
		await rename(destination, backup);
	} catch {}

	try {
		await rename(checkout, destination);
	} catch (error) {
		try {
			await rename(backup, destination);
		} catch {}
		throw error;
	} finally {
		await rm(backup, { recursive: true, force: true });
	}

console.log(`Cloned zane-lang/docs@${ref} to src/content/docs`);
} catch (error) {
const stderr = typeof error?.stderr === 'string' ? error.stderr.trim() : '';
throw new Error(stderr || error?.message || 'Failed to clone documentation', { cause: error });
} finally {
await rm(workDirectory, { recursive: true, force: true });
}
Comment on lines +41 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If an error occurs during rm in the finally block (for example, due to file locking issues on Windows), it will throw and suppress the original error from the try or catch block. This makes debugging the actual clone failure very difficult.

Wrapping the cleanup in a try...catch block ensures that any cleanup errors do not shadow the primary error.

} finally {
	try {
		await rm(workDirectory, { recursive: true, force: true });
	} catch {}
}

1 change: 0 additions & 1 deletion src/content/docs
Submodule docs deleted from 3074f5