Skip to content

Fixed layer issue for search in docs#2

Closed
MukundLadani wants to merge 1 commit into
webjsdev:mainfrom
MukundLadani:fix/webjs-doc
Closed

Fixed layer issue for search in docs#2
MukundLadani wants to merge 1 commit into
webjsdev:mainfrom
MukundLadani:fix/webjs-doc

Conversation

@MukundLadani
Copy link
Copy Markdown
Contributor

Fixed using gemini CLI
It resolved the issue, not sure about the changes. Please review

@vivek7405
Copy link
Copy Markdown
Collaborator

This is probably not needed anymore.

@vivek7405 vivek7405 closed this May 17, 2026
vivek7405 added a commit that referenced this pull request May 22, 2026
…quirement

The post was too Tailwind-centric. Easy to read it as "you need
Tailwind to use webjs," which is wrong: the framework is agnostic
about the styling story. Tailwind is the scaffold default because
it pairs well with the rest of the stack, but vanilla CSS, CSS
modules, BEM, hand-written stylesheets, or another utility framework
all work the same way.

Changes:

  - Added an explicit note after benefit #1: webjs does NOT require
    Tailwind, the benefit (external CSS cascades into light-DOM
    components) is general, Tailwind is just the concrete example
    in the post.
  - Benefit #2 ("CSS cache-friendly"): broadened from "tailwind.css"
    to "an external stylesheet (the scaffold's tailwind.css, or your
    own app.css, or whatever you write)."
  - Scoping section: added a mention of BEM / class-prefix
    discipline as a non-Tailwind way to avoid leakage. Linked to
    the framework's `light-dom-css-prefix` lint rule that catches
    unprefixed selectors in vanilla CSS for light-DOM components.
  - Summary bullets: "Tailwind utility classes apply" -> "External
    CSS applies without escape hatches: Tailwind, vanilla, CSS
    modules, BEM, whatever you bring."
  - Closing paragraph: "light DOM with Tailwind by default" ->
    "light DOM by default, with Tailwind as the scaffold default
    but no framework-level requirement to use it."

The argument is now framed as light-DOM-vs-shadow, not as
Tailwind-evangelism. Tailwind users still see Tailwind-flavored
examples throughout, but non-Tailwind users see the framework
working for them too.
vivek7405 added a commit that referenced this pull request May 22, 2026
* feat(website): launch the /blog with 11 grounded long-form posts

Infrastructure:
- `blog/<slug>.md` with frontmatter at the repo root, mirroring the
  changelog/ shape. Hand-rolled frontmatter parse + markdown renderer
  in the page handlers (no markdown library, no client runtime).
- `website/app/blog/page.ts`: index page listing all posts sorted by
  date DESC. Layout boundary matches /changelog (max-w-[840px]).
- `website/app/blog/[slug]/page.ts`: per-post page with full SEO
  metadata (title, description, og:title, og:description, og:type,
  og:url, twitter:card, publishedTime, author, tags). canonical URL
  per post. Custom-positioned bullets that stay inside the layout
  via `before:` pseudo-elements. Code blocks with internal padding so
  long lines do not stick to the left border when they overflow-x.
- Nav: `/blog` link added to both desktop and mobile header.
- Railway watch path: `/blog/**` added to the website service via
  the railway agent, so future blog edits trigger redeploys.

Posts, each anchored in actual git history / PR descriptions /
source-file docstrings (not invented details):

- `why-webjs` (origin/thesis, derived from the author's existing
  post at heyvivek.com; tagline "tiny in size, not in power")
- `betting-on-lits-mental-model` (the API parity rationale; 127
  lit-ported tests from PR #31's title)
- `strip-types-not-esbuild` (the Node 24 stripper migration in
  PR #9; cache details from packages/server/src/dev.js)
- `signals-replaced-setstate` (PR #43, breaking change; TC39
  Stage 1 shape; algorithm description from signal.js docstring)
- `light-dom-slots-with-full-parity` (PR #8 / #44; polyfill
  design from slot.js docstring)
- `the-naming-saga` (the wjs/webjscli/webjsdev/create-webjs arc
  from this PR's own development)
- `ai-first-is-plumbing` (AGENTS.md + the multi-tool config files
  + hooks + lint rules, all verifiable in scaffold templates)
- `file-based-routing` (router.js JSDoc lists the conventions;
  same Next.js shape, with the divergences spelled out)
- `client-router-turbo-drive-style` (router-client.js docstring
  + ssr.js's X-Webjs-Have handling)
- `why-not-lit-as-a-dependency` (SSR + decorators + the
  AI-reads-node_modules angle the user surfaced)
- `built-ins-auth-session-cookies-cache` (the four-method cache
  store interface from cache.js's CacheStore typedef, the Remix-
  shaped Session class, the NextAuth-shaped createAuth())

Typography:
- 17px paragraph at 1.8 leading, my-7 spacing.
- Title at clamp(36px, 6vw, 56px), more presence on the page.
- Description in serif italic at 19px.
- Headings at clamp 21-34px with strong vertical rhythm.
- Code blocks at 13px monospace with px-6 py-5 padding inside
  the code element (not the pre) so overflow-x scrolls cleanly.
- Footer pad-top + mt-28 so the "All posts" link does not collide
  with the last paragraph.

Markdown supported by the renderer:
- # / ## / ### headings (h2 / h3 / h4 in output)
- Paragraphs
- Bulleted lists with custom-positioned markers
- `> ` blockquotes with accent border
- ```fenced``` code blocks
- Inline: **bold**, *italic*, `code`, [link](url)

* fix(blog): switch [slug] page spacing to arbitrary-value classes

Three concrete formatting fixes that all stemmed from one root cause:
Tailwind named-scale utilities (mt-20, my-8, mt-14, my-7) were NOT
landing in the compiled tailwind.css. The dev-server's watcher had
not picked them up from the new blog/[slug]/page.ts. So the page
rendered with classes that resolved to no CSS at all, which is why
the user saw:

  - Headings sticking to the previous paragraph (no mt-20).
  - "All posts" footer link colliding with last paragraph.
  - Code blocks with no vertical breathing room.

Fix: switch every spacing utility to its arbitrary-value form
(`mt-[80px]` instead of `mt-20`, `my-[28px]` instead of `my-7`,
etc.). Arbitrary-value classes get JIT-emitted from the literal
token in source, so they compile regardless of whether the named
scale has been brought into the build.

Also brings the [slug] page's max-width from 760px back up to
840px to match /changelog and /blog index, restoring the layout
boundary parity the user pointed out twice.

The compiled tailwind.css is gitignored (regenerated at deploy
time), so this commit ships only the source change. The classes
JIT correctly on the next `tailwindcss` invocation.

Bundle of post-grade improvements:
  - Code block padding moved inside the <code> with px-[24px]
    py-[20px], so overflow-x preserves padding on both sides.
  - List items use `before:content-['•']` absolute-positioned
    markers so bullets stay inside the layout column.
  - Title at clamp(36px, 6vw, 56px), description in serif italic.
  - Footer with mt-[128px] pt-[40px] for the "All posts" link.

* refactor(website): move blog + changelog logic into modules/, follow webjs's own convention

The website was stuffing file-reading, frontmatter parsing, and markdown
rendering directly inside `app/blog/page.ts`, `app/blog/[slug]/page.ts`,
and `app/changelog/page.ts`. That violates the layout we tell every
scaffolded webjs app to follow in AGENTS.md:

  app/                      ROUTING ONLY. Thin route adapters.
  modules/<feature>/        Feature-scoped queries + utils + types.
  lib/                      App-wide helpers.

Dogfooding fix. New layout:

  website/lib/frontmatter.ts                    Shared parser (browser-safe).
  website/modules/blog/queries/
    list-posts.server.ts                        Read all posts, return metadata.
    get-post.server.ts                          Read one post by slug, return body.
  website/modules/blog/utils/render-post.ts     Long-form markdown renderer.
  website/modules/blog/types.ts                 Post / PostWithBody.
  website/modules/changelog/queries/
    list-entries.server.ts                      Read all changelog entries.
  website/modules/changelog/utils/
    render-entry.ts                             Compact-card markdown renderer.
    pkg-badge.ts                                Color-coded package pill.
  website/modules/changelog/types.ts            Entry.

The route files at `website/app/blog/page.ts`,
`website/app/blog/[slug]/page.ts`, and `website/app/changelog/page.ts`
are now thin adapters that import from the modules and render the
result. None of them do file IO or string-parsing directly.

Same routes, same output. Logic moved to where AGENTS.md says it
should live.

The `'use server'` directive on each query file makes the file
source-protected (browser imports get a throw-at-load stub) and
RPC-callable (so a client component could in principle import
`listPosts` if it needed to, and the dev server would rewrite the
import into an RPC stub). For the current pages, both query files
are only called server-side from the page's default export.

Sharing across the two features: `parseFrontmatter()` is identical
for both, so it lives in `website/lib/frontmatter.ts` (lib/ scope
because it's cross-feature). The inline-markdown regexes diverge
between the two renderers (different code-block sizes, different
heading typography), so each module has its own renderer rather
than parameterizing a shared one. Two callers, two short
implementations, no premature abstraction.

* blog(why-webjs): replace 'started' with 'built' in opening

* blog(why-webjs): retitle to avoid duplicating the personal-blog title

* blog(why-webjs): drop 'small' from the title

* blog(why-webjs): reframe around 'wanted this framework, built it for myself'

The post leaned hard on critiquing other frameworks (stack traces in
minified bundles, convention drift between engineers, etc.). Reframed
per the user's direction: the story is "I wanted a framework close
to web standards with the Next.js-style DX I enjoy. Could not find
one I personally liked. Built one for myself. AI-first followed
naturally from building it from scratch in 2025."

New shape:

  - Open with what I wanted (web standards + Next.js DX), the search,
    the not-finding, the decision to build my own.
  - "Close to web standards" section explains the platform-first
    architecture (native web components, lit-shaped public API on
    top), without comparing other frameworks unfavorably.
  - "How small that lets the framework be" surfaces the concrete
    5-10% of Next.js size claim, with the feature parity list and
    the explanation: the platform does the heavy lifting (web
    components, Node 24 strip-types, HTTP/2 multiplex, CSS vars).
  - "Why AI-first followed naturally" reframes the AI-first content
    as the consequence of building from scratch in 2025, not the
    starting motivation. Same content, different positioning.

Removed:

  - "watching AI agents try to write code in those frameworks ..."
    paragraph that read as a critique of competitors.
  - "stack traces that pointed at minified bundle positions the
    agent could not read" line.
  - "conventions that two engineers would interpret differently"
    line, which read as a dig.
  - The "why web components, not React/Vue/Svelte/Solid?" framing.
    Replaced with "what close-to-standards means" which states the
    positive case without the comparison.

Title and intro keep the AI-era angle for SEO and for the inaugural-
post role of why-webjs.md.

* blog(lit): consolidate the two lit posts into one

The two posts (`betting-on-lits-mental-model.md` and
`why-not-lit-as-a-dependency.md`) argued the same point from two
angles, with substantial content overlap. Merged the strongest
material from both into one post and deleted the redundant file.

Kept the `betting-on-lits-mental-model` slug (better SEO surface,
nuanced title). Retitled to "Lit-shaped, without depending on lit"
to flag the dual angle directly.

The merged post is now structured as:

  1. The "minimal version: just re-export lit" code, and why I
     considered it for a week before writing my own runtime.
  2. What I wanted to KEEP from lit (the API surface the corpus
     already knows, with the four-agents experiment as evidence).
  3. Why I did NOT depend on lit, broken into four reasons in load-
     bearing order:
     a. SSR (the killer, with the four lit-ssr structural limits)
     b. The decorator + erasable-TypeScript conflict
     c. The AI-agent-reads-node_modules readability argument
     d. Fine-grained control over edge cases
  4. What an LLM sees when it reads webjs (the code-diff comparison)
  5. What the runtime ownership cost (lost lit bug fixes,
     lost cleverness, ~10 KB size delta)
  6. The "what if lit ships SSR + slots tomorrow" hypothetical
  7. Not a dig at lit
  8. Reading the actual implementation

* blog(light-dom-default): add post on why webjs picks light DOM as default

Most web-components frameworks default to shadow DOM (lit, Stencil,
FAST). webjs flips the default: every component renders in light DOM
unless it sets `static shadow = true`. The post walks through six
concrete benefits in load-bearing order:

  1. Tailwind utility classes apply (the load-bearing one for webjs).
  2. CSS stays cache-friendly: external stylesheet hit once by the
     browser, instead of inline `static styles` shipped per page.
  3. document.getElementById, querySelector, closest just work
     without shadow-piercing.
  4. Accessibility behaves the way ARIA + form association specs
     assume (aria-labelledby across roots, form data carrying
     light-DOM input names, no formAssociated/ElementInternals
     ceremony).
  5. Playwright / Puppeteer / Web Test Runner selectors work
     without `>>>` pierce syntax. Agents writing tests reuse the
     same selectors they write in components.
  6. SEO + crawler reach is more reliable in initial HTML. Modern
     Googlebot handles DSD correctly, but the long tail of
     crawlers, social-card scrapers, RSS readers, and archival
     bots is more variable. Light DOM is the lower-variance answer.

Counters the "but scoping!" argument by pointing at the two real
shadow-DOM use cases (third-party embeds, design-system primitives
meant to drop into hostile pages) and notes that Tailwind utilities
sidestep the leakage thought experiment for app code.

Links to the existing light-dom-slots-with-full-parity post for
the slot-projection story, which is what unblocks light DOM as a
serious default (most frameworks treat <slot> as a shadow-only
feature, webjs ships full parity in both modes).

Dated 2025-12-22, slotted between why-webjs (2025-12-15) and
light-dom-slots-with-full-parity (2025-12-30) so the
foundational decision lands before the slot deep-dive.

* blog(light-dom-default): correct the 'shadow DOM is the default' framing

Native web components default to LIGHT DOM. If a custom element does
not call attachShadow(...), there is no shadow root. Lit picked a
different default for its LitElement class (it attaches a shadow root
in the constructor unless you override createRenderRoot to return
this), and because lit is what most developers and most AI training
data treat as canonical web-components style, the perception has
shifted toward "shadow DOM is the default."

The opening of the post implied the latter. Rewritten to state the
platform-level fact accurately:

  - Native web components default to light DOM.
  - lit defaults to shadow DOM by attaching a shadow root in
    LitElement's constructor.
  - webjs aligns with the platform default, not lit's default.

This is also a sharper framing for the rest of the post: the
"benefits of light DOM" become "benefits the platform already gives
you that lit's default opts out of."

Description in the frontmatter updated to match.

* blog(light-dom-default): restore Stencil + FAST alongside lit in the framing

Web-verified the original claim: lit, Stencil, and FAST all default
to shadow DOM. With three independent data points, the framing is
sharper than "lit picked a different default" alone:

  - lit: LitElement attaches a shadow root in its constructor
    unless you override createRenderRoot to return this.
  - Stencil: components default to shadow DOM. The stencil generate
    CLI emits shadow-enabled components and the @component
    decorator's shadow field defaults to true.
  - FAST: FASTElement automatically attaches a ShadowRoot and
    renders the template into it.

All three are cited inline with links to their official docs.

The reframing is "the three libraries developers actually learn
web components from all default to shadow, and that's where the
'shadow is the default' perception comes from. The platform itself
does not share that default."

That is a stronger argument for webjs's choice than the
single-library version.

* blog(light-dom-default): correct Stencil's actual default

Stencil's @component decorator defaults shadow: false (light DOM).
You opt INTO shadow with @component({ shadow: true }). The earlier
claim that Stencil "defaults to shadow DOM" conflated the CLI
scaffolder default (the `stencil generate` template enables shadow)
with the framework's actual decorator default (which does not).

Verified by fetching both stencil.io/docs/styling and
stencil.io/docs/component:

  - styling: "To use the Shadow DOM in a Stencil component, you can
    set the shadow option to true in the component decorator."
  - component: "If shadow is set to false, the component will not
    use native shadow DOM encapsulation." Default is false.

The post now states the accurate picture:

  - lit defaults to shadow at the framework level
  - FAST defaults to shadow at the framework level
  - Stencil defaults to light at the framework level; the CLI
    scaffolder is what produces shadow-enabled components

The "popular libraries pick shadow" framing is now scoped to lit
and FAST. Stencil is called out as the precedent that backs webjs's
choice: same underlying default (light), shadow as opt-in.

This is actually a stronger argument for webjs than the previous
"everyone defaults to shadow" framing, because it shows there is
existing precedent in the ecosystem for light-DOM-by-default at the
framework level.

* blog(light-dom-default): clarify Tailwind is scaffold default, not requirement

The post was too Tailwind-centric. Easy to read it as "you need
Tailwind to use webjs," which is wrong: the framework is agnostic
about the styling story. Tailwind is the scaffold default because
it pairs well with the rest of the stack, but vanilla CSS, CSS
modules, BEM, hand-written stylesheets, or another utility framework
all work the same way.

Changes:

  - Added an explicit note after benefit #1: webjs does NOT require
    Tailwind, the benefit (external CSS cascades into light-DOM
    components) is general, Tailwind is just the concrete example
    in the post.
  - Benefit #2 ("CSS cache-friendly"): broadened from "tailwind.css"
    to "an external stylesheet (the scaffold's tailwind.css, or your
    own app.css, or whatever you write)."
  - Scoping section: added a mention of BEM / class-prefix
    discipline as a non-Tailwind way to avoid leakage. Linked to
    the framework's `light-dom-css-prefix` lint rule that catches
    unprefixed selectors in vanilla CSS for light-DOM components.
  - Summary bullets: "Tailwind utility classes apply" -> "External
    CSS applies without escape hatches: Tailwind, vanilla, CSS
    modules, BEM, whatever you bring."
  - Closing paragraph: "light DOM with Tailwind by default" ->
    "light DOM by default, with Tailwind as the scaffold default
    but no framework-level requirement to use it."

The argument is now framed as light-DOM-vs-shadow, not as
Tailwind-evangelism. Tailwind users still see Tailwind-flavored
examples throughout, but non-Tailwind users see the framework
working for them too.

* blog(file-based-routing): strip opening to two options, frame around personal DX

The opening listed three options (invent, Rails-shaped, Next.js).
Rails was never seriously in the running and the inclusion read as
filler. Stripped to two: custom or Next.js. The decision is now
framed primarily around the Next.js DX I personally enjoy, with
the corpus-priors argument as a secondary reason rather than the
load-bearing one.

* blog(naming-saga): rewrite 'the user pointed out' to first person

The post is bylined by Vivek and written in first-person voice. The
'the user pointed out' phrasing slipped through, treating someone
else as the source of the insight. Now reads 'I realized,' matching
the rest of the post's voice.

Audited the other blog posts for similar third-person 'user'
references. The remaining mentions are about end-users of the
framework (package.json size, function-wrapping callers, store
config etc.) which is the correct use of the word.

* blog(index): remove 'written as the project evolves' tagline

* blog([slug]): tighten footer spacing before 'All posts' link

Reduced mt from 128px to 72px and pt from 40px to 32px, halving
the gap between the last paragraph and the bottom 'All posts' link.
Earlier value was overcompensating after the user pointed out the
link sticking to the paragraph; this lands in the comfortable
middle.

* blog([slug]): walk back the footer spacing reduction

Previous change went from 168px to 104px which the user said was
too aggressive. Dialed to 140px (mt-[104px] pt-[36px]), a modest
~17% reduction from the original 168px rather than the 38% cut.
vivek7405 added a commit that referenced this pull request May 26, 2026
Chokidar fires rebuild on every relevant file change with an 80ms
debounce. If two file edits arrive within ~80ms but each rebuild
takes >80ms (jspm.io fetch easily takes 100-500ms), both rebuilds
run concurrently and whichever finishes LAST wins.

Failure mode: rebuild #1 starts with the file state before edit B.
Rebuild #2 starts (debounced) with the post-B state. If #1's
jspm.io fetch is slow and #2 is fast, #2 calls setVendorEntries
first with fresh data, then #1 calls it with stale data, leaving
the dev server serving a permanently-stale importmap until the
next rebuild.

Fix: chain rebuilds onto a sequential promise so the next rebuild
waits for the previous to finish. Also adds a monotonic token: a
rebuild's setVendorEntries call is no-op if a newer rebuild has
already been queued. The token is defensive belt-and-suspenders;
serialization alone would suffice.

No new tests (the race is a timing window that needs real chokidar
events to exercise; serialization is provable from the code shape).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants