Skip to content

About

Website, Blogs and Documentation for OLake

Topics

Resources

Accessibility

Stars

16 stars

Watchers

2 watching

Forks

Repository files navigation

OLake Website – Contributor Handbook

(The site is built with Docusaurus)


1. Prerequisites & Local Setup

Stack: Docusaurus 3.10, React 19, Tailwind CSS 4, strict MDX 3.

  1. Node. Use the version in .nvmrc (currently 24; package.json requires 22 or newer).

    nvm use
  2. Clone and install

    git clone https://github.com/datazip-inc/olake-docs.git
    cd olake-docs
    npm install
  3. Clear the cache after every git pull, after npm install, and after editing any plugin file in src/plugins (the compile cache does not notice plugin changes). A "Module not found" or ReactContextError on every page usually means a stale cache.

    npm run clear
  4. Start the development server

    npm start

    Your default browser opens the local site. Some effects are production-only (for example the generated image sizes), so check final results in a build.

  5. Build (this is what CI runs; broken links and anchors only produce warnings in the build output)

    CI=true npm run build

    npm run build runs docusaurus build and then the image sitemap script. It does not touch the repo: the Open Graph images in static/img/og/ are generated by hand with npm run og-images and committed (see 1.2). To preview the output: npm run serve.

  6. Optional checks (not run in CI)

    Command What it checks
    npm run typecheck tsc --noEmit over the TypeScript sources
    npm run lint:content MDX and front matter rules for docs, blog and customer-stories files; details in 1.2. Errors fail the command only when you run it yourself.
    npm run og-images -- --check Fails if a blog cover has no 1200x630 social card in static/img/og/, or the cover changed since the card was rendered. Writes nothing. Run it after adding a post or changing a cover.

1.1 Design system pointers

  • Tokens: src/css/tokens.css holds the --olake-* colors, type scale and spacing for light and dark. Use the Tailwind olake-* utilities (defined in src/css/custom.css) or var(--olake-*); do not hard-code hex values in components.
  • UI primitives: src/components/landing/ui/ (Button, Section, SectionHeading, Card, CtaBanner, LakesidePage). Build marketing pages from these.
  • Page titles (h1): defined once in src/css/typography.css; do not set h1 size or weight in a component.
  • Swizzling: wrap the original (@theme-original/<Component>) instead of copying it, so the swizzle survives Docusaurus upgrades.

1.2 Content checks (run locally, not enforced in CI)

CI (test-deploy.yml on pull requests, deploy.yml on master) only builds the site; none of the checks below block a merge, and the legacy MDX syntax (<!-- --> comments, {#id} heading ids, :::note Title) still compiles. They are there so you can catch problems before opening a PR.

Run it locally

npm run lint:content                                  # errors fail (exit 1), warnings are listed
npm run lint:content -- blog/2026-10-01-my-post.mdx   # limit to a file or folder
npm run lint:content -- --strict                      # warnings fail too (optional, not used in CI)
npm run build                                         # broken links and anchors are printed as warnings

Errors (fail lint:content when you run it). The preferred form for each:

Rule Correct form
html-comment {/* comment */}, never <!-- comment --> (only <!-- truncate --> is allowed)
heading-id ## Install {/* #install */}, never ## Install {#install}
admonition-title :::tip[Before you start], never :::tip Before you start
second-h1 (posts) The title comes from front matter; start body headings at ## and do not use # ... or <h1>
old-blog-url [Post](/blog/my-post-slug/), never /blog/2024/05/01/...
title-length (posts) title: at most 70 characters (put longer SEO wording in seo_title:)
title-missing, title-entity (posts) title: "Postgres to Iceberg", with no &amp; or &#38;
description-missing Every post and doc has a description:
authors-missing, author-unknown authors: [anshika], where the id exists in the folder's authors.yml
tags-missing, tags-count, tag-undefined tags: [olake, iceberg]: at least one, at most 8, each defined in the folder's tags.yml
image-missing, image-path, image-not-found image: /img/blog/cover/my-cover.webp starts with / and the file exists under static/
slug-space, slug-duplicate Slugs are unique per folder and contain no spaces
filename-space No spaces in file names
frontmatter-yaml Front matter parses as YAML (quote values that contain :)
unclosed-fence Every opening code fence has a closing one

Warnings (listed only; fix them in files you touch). A summary written as :::tip[TL;DR] or ## TL;DR instead of the component, a description outside 120-160 characters, <br> outside a table, bold lines used as headings, code fences without a language, heading level jumps, absolute https://olake.io/... links, a post that does not end with <BlogCTA/>, docs/shared partials that have front matter, and a file name date that differs from the date: field.

TLDR component. Write the post summary once, right after the opening paragraph, as a component with a blank line after the opening tag and before the closing tag:

<TLDR>

- Point one
- Point two

</TLDR>

Internal links. Link to /docs/, not /docs/intro/. lint:content does not check this. The build prints a warning for a link to a route that does not exist, so read the build output. A plain <section id="x"> is not collected as an anchor, so a <Link to="#x"> to it is reported as broken even though the id exists; use <a href="#x"> for in-page links on custom pages.

Common fixes

  • heading-id or html-comment on old content: rewrite the syntax by hand as shown above. Do not use npm run write-heading-ids, it writes the old {#id} form.
  • title-length: shorten title: and move the full phrase to seo_title:. It feeds the page title, og:title and twitter:title, while the visible H1 stays short.
  • tag-undefined or author-unknown: add the entry to that folder's tags.yml or authors.yml, or pick an existing one.
  • image-not-found: check the case and extension of the file name under static/img/.
  • Broken link or anchor warning in the build output: it names the page and the target; fix the target or the heading id it points to.

Open Graph images. Every post cover needs a 1200x630 card in static/img/og/ (the post page points og:image and twitter:image at it). They are generated by hand and committed, not on every build:

npm run og-images             # render only missing or stale cards, update scripts/og-images.manifest.json
npm run og-images -- --force  # re-render every card
npm run og-images -- --check  # write nothing, exit 1 if a card is missing or stale

A card is stale when the SHA-256 of its source cover no longer matches scripts/og-images.manifest.json. File times are not used. After adding a post or changing a cover, run npm run og-images and commit the new card and the manifest.


2. Adding a Blog Post

Directory When to use
/blog OLake and Iceberg topics
  1. Navigate to the correct directory.

  2. Create an MDX file: YYYY-MM-DD-blog-slug.mdx. The date reflects the publish date, not the commit date.

  3. Copy the front-matter (metadata) from an existing post and update it.

  4. Manage authors

    • Each directory has its own authors.yml.
    • Add new authors here before referencing them in a post.
  5. Append <BlogCTA/> as the final line of every blog post.


3. Blog Image Structure

  1. Root folder: static/img/blog/
  2. Cover images: static/img/blog/cover/<slug>-cover.png
  3. Inline images: static/img/blog/YYYY/MM/<slug>-N.png

Example – slug flatten-array, published May 2025:

static/img/blog/cover/flatten-array-cover.webp
static/img/blog/2025/05/flatten-array-1.webp
static/img/blog/2025/05/flatten-array-2.webp

4. Component Structure

  1. Create reusable React (.tsx) components in src/components.

    • Keep them text-agnostic and modular.
  2. Before creating, scan existing components for reuse.

  3. To expose a component globally in MDX, import it once in src/theme/MDXComponents/Index.js.

    • Afterwards, you can use <MyComponent/> in any file under /blog or /docs.
    • HTML pages in src/pages still require manual imports.

5. Adding Documentation

  1. Create the MDX file under /docs.
  2. Register the file (and its order) in sidebars.js. Order-of-appearance in the sidebar is defined here.

5.1 Shared Text Components

  • Place reusable snippets in docs/shared/.
  • Import them in src/theme/MDXComponents/Index.js.
  • Use them anywhere with the usual <SharedComponent/> syntax.
  • docs/shared/ is excluded from the docs build (exclude in docusaurus.config.js), so snippets are not published as pages or listed in the sitemap. They only render where they are imported. Do not link to /docs/shared/... URLs.

6. Other Key Information

Topic Details
Redirects Configure in the @docusaurus/plugin-client-redirects list in docusaurus.config.js. Never leave a "moved" stub .mdx behind (see 6.5).
CNAME Do not delete static/CNAME; GitHub Pages needs it for olake.io.
Public files Any asset in static is publicly accessible (e.g. /reddit.json).
Next.js We may switch to the Next.js plug-in later for Lighthouse gains.
Embedding media Images: Markdown ![Alt](/img/...); use raw HTML for size control.
Videos: embed via HTML.
MDX & HTML MDX accepts all HTML except tables (use Markdown tables).
Docusaurus features Components like <Tabs>, <TabItem>, :::info, etc. are native—see their docs.

6.1 Code Block Guidelines

    ```py title="docker-compose.yml"
    # code here
    ````

Supported lexers: py, bash, sh, js, jsx, go, yaml, yml, text, …

6.2 Heading Style (Do not bold the text)


## Heading   ✅

### Heading  ✅

## **Heading**   ❌

6.3 Swizzling (Advanced)

Use Docusaurus swizzle to override core components and UI of how . Swizzled files live in src/theme/.
We have already swizzled: blog pages, doc pages, navbar, and footer.

6.4 Drafts

Add work-in-progress content to the root /drafts folder; it will not be published. A draft that must live inside docs/, blog/ etc. needs draft: true in its frontmatter. A folder called docs/drafts/ is not hidden automatically: a page there is published and goes into the sitemap unless it has draft: true.

6.5 SEO rules

Breaking these has cost search traffic before. Run npm run build and npm run lint:content and look at the output before opening a PR.

  • Canonical URLs keep the trailing slash, and Docusaurus writes them. The site is trailingSlash: true; GitHub Pages 301s the no-slash URL to the slash URL, and the sitemap and hreflang use the slash URL. Never add your own <link rel="canonical"> and never strip the slash from a permalink. og:url and JSON-LD url/@id must match the canonical. Before the fix Google indexed both versions of 172 pages.
  • Hardcoded internal links end in a slash (/slack/, /contact/, /blog/, also absolute https://olake.io/... links in MDX, which Docusaurus does not normalise). Use SLACK_URL instead of retyping the Slack link. A link without the slash costs a 301 hop on every click and crawl.
  • Changing or removing a URL needs a redirect. If you change a post's slug, rename a doc or delete a page, add { from, to } to the client-redirects list in docusaurus.config.js in the same PR. In 2026-04 a top post changed slug without one and kept 404ing in search with about 500 clicks of history. Do not keep a "(Moved)" stub .mdx page. Put a slash before any # or ? in a redirect to; src/plugins/client-redirects-slash restores it in the generated stubs because Docusaurus drops it.
  • Titles. The site title is OLake, so every <title> ends in | OLake (docs too). Keep the rendered title at 60 characters or fewer, so the frontmatter title at about 52. If the visible H1 needs to be longer, add seo_title: "..." (about 52 characters) to the frontmatter: it replaces only <title>, og:title and twitter:title, and the H1 keeps title. Docs titles under 25 characters get their sidebar section appended automatically. Code: src/theme/seo/helpers.ts, src/theme/DocItem/Metadata, src/theme/BlogPostPage.
  • Descriptions. Every page needs its own description of 120 to 155 characters (max 160, min 100), unique across the site. Do not copy one post's description into another, and do not leave it truncated with "...". Files in docs/shared are snippets and have no frontmatter.
  • Pages that must not be indexed get noindex, follow: confirmation pages, archive pages, tag and author pagination, zero-post authors, /search/. The theme does this for the generated pages; add it yourself to any new thank-you or utility page. Keep them crawlable (no robots.txt block), otherwise Google never sees the tag.
  • Taxonomy pages (blog and customer-stories archive, authors, tags) get their title, description and H1 from the swizzled components in src/theme (Blog/useBlogInstance.js). Titles carry no post count (the count made SEO audits report "title changed" on every new post). A new blog instance must be added there, or its pages fall back to the "Blog" wording.
  • Sitemap exclusions live in the sitemap options of docusaurus.config.js (tags, authors, archive, search, docs/shared, confirmation pages, pagination). docs/shared is not built as pages at all.
  • One og:type, one H1, one JSON-LD per schema. Pages under src/pages get og:type=website from src/theme/Layout; posts emit article. Emit JSON-LD with src/components/JsonLd, not <Head><script dangerouslySetInnerHTML> (Helmet drops it).
  • Images. Keep every image under about 300 KB (WebP; no GIFs, use short muted looping video).

7. Git Basics You’ll Need

git add .                       # stage all changes
git commit -m "Message"         # commit
git commit -am "Message"        # add + commit tracked files
git pull                        # fetch & merge
git push                        # push current branch
git branch                      # list branches
git status                      # show working tree status
git checkout -b <new-branch>    # create and switch
git switch <branch>             # switch existing branch

7.1 Push a New Branch

git push --set-upstream origin <branch-name>

8. Recommended Git Workflow

# 1. Make sure local master is current
git switch master
git pull origin master

# 2. Create a feature branch
git checkout -b blog/your-slug         # or docs/your-topic, etc.

# 3. Work on your changes
#    (add blog MDX, images, authors.yml, sidebar entry, etc.)

# 4. Stage & commit
git add .
git commit -m "Add <your-slug> blog to OLake docs"

# 5. Push and open a PR
git push --set-upstream origin blog/your-slug

8.1 Working on Multiple Branches

  1. Finish work on the first branch and push.

  2. Ensure master is up to date:

    git switch master
    git pull origin master
  3. Create your next branch:

    git checkout -b blog/second-slug
  4. Repeat the add → commit → push cycle.

Tips • Git can feel tricky—refer to official docs, blog posts, or ask in Slack. • Always branch from master unless directed otherwise.


9. Need Assistance?

  • Check the official Docusaurus docs.
  • For Git issues, consult documentation or ChatGPT.

Happy writing and shipping content!

About

Website, Blogs and Documentation for OLake

Topics

Resources

Accessibility

Stars

16 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages