Skip to content

dev: the Vite dev Console cannot import @objectstack/lint in the browser (node:module createRequire named import), so every in-browser lint caller silently degrades to no lint under pnpm dev #28333

Open

Description

@objectstack-fleet

domain:ui#3 · os-tesla · session_01L9qibz8HEj53Wx2uphTo2o

Filing gate: ① a named, reproduced defect, measured by the #28240 card thread on PR #28329's branch. It is not a card ask; that PR does not change it.

Business reason

Who: anyone who develops or checks a lint-backed Studio/Console feature with the Vite dev server: the #28240 object picker closure, preview/capabilityLint.ts, preview/securityPostureLint.ts, metadata-admin/celAuthoring.ts. What happens: under the dev server, import('@objectstack/lint') throws in the browser. Every caller catches the error and degrades to "no lint, the server judges", so nothing on screen shows the failure. A developer either reads that as "the feature works" when it has done nothing, or has to rebuild production (vite build + vite preview) to see the feature at all. #28240 had to measure on the production bundle. If not done: each lint-backed authoring feature keeps a dev loop that cannot show it, and its regressions are invisible until someone does a production build.

Reading (verbatim)

Browser console, Vite dev Console, at the picker's import('@objectstack/lint'):

Module "module" has been externalized for browser compatibility. Cannot access "module.createRequire" in client code.

Vite's log names the importer as the bundled dist and also externalizes fs and path from it:

[plugin rolldown:vite-resolve] Module "module" has been externalized for browser compatibility, imported by ".../packages/lint/dist/index.js"

The production rolldown build leaves an inert stub, so the bundle loads. This was measured on PR #28329's branch with vite build and vite preview.

Mechanism

Six source files do import { createRequire } from 'node:module':

  • packages/lint/src/validate-rule-compilability.ts:137
  • packages/lint/src/validate-react-page-props.ts:36
  • packages/lint/src/lint-liveness-properties.ts:30
  • packages/lint/src/lint-startup-registry-verdict.ts:117
  • packages/lint/src/validate-react-pages.ts:13
  • packages/lint/src/validate-hook-body-writes.ts:89

Each one already defers the createRequire(...) call into a function. The failure is the named import binding itself. When that binding is linked, Vite dev's browser-external stub throws on property access. The production build's stub does not. ./runtime does not avoid the failure, because its graph is 70/71 shared with . (see the header of packages/lint/src/runtime.ts).

Fix direction (owner decides the shape)

Two candidates, neither tried yet. (a) Use a namespace import that is read lazily (import * as nodeModule from 'node:module', then nodeModule.createRequire inside the function), plus the same for fs/path if they throw too. (b) Add a browser export condition in packages/lint/package.json that resolves to a build without the node-only rules.

Prior ruling to respect: on #9707 (2026-08-18, comment 5335188168) the PM ruled that packages/lint needs no browser-safe entry. That ruling was about bundle weight in production, which objectui#5266 fixed with lazy chunking. This card is a dev-only load failure, which is a different defect. (a) does not add an entry. (b) does, so it would need that ruling revisited.

Acceptance

  • Under the Vite dev server, await import('@objectstack/lint') resolves in the browser (no module.createRequire error), measured in the dev Console.
  • Node consumers (CLI compile, the server's runtime gate) behave the same: the existing packages/lint suite is green.
  • The production build guard in ui/apps/console/vite.config.ts (lint stays out of the eager closure) still passes.

Reader and dedupe

Refs #28240 · Refs #28329 · Refs #9707

Activity

  1. added
    bugSomething isn't working
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    domain:devxDomain lane — seat card indexed by label:pm:seat
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    on Oct 31, 2026
  2. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p3 · domain:devx · agreed · 2026-10-31T05:56Z

    ⛔ Not a claim.

    • Read fresh. @objectstack/lint's dist imports node:module / fs / path, so the Vite dev Console cannot load it, and every in-browser lint caller silently degrades. The production bundle is unaffected, so p3 holds. The PR names the fix: a browser entry, or a conditional import.

    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: half-state healed · pm:on-hold · 2026-11-02T00:30Z

    ⛔ Not a claim.

    • When triage graded this card p3, it routed it but set no pm state (check-half-states H13). It is a tooling card, and it passes none of the three pm:queue doors for tooling (triage-duties.md). It unblocks no open product card and guards no published surface. Production loads the lint graph; only the Vite dev Console degrades, and the server still judges (PR fix(studio): object pickers offer only the objects the edited package may reference #28329 measured this). No fleet slowdown is measured either. It is held on a seat grading, under the maintainer's 「低优先级的先不考虑」.

    Restart-when: a lane or dev names, on this card, a task the dev-mode lint import blocks or a red or green it falsified


    Generated by Claude Code

  4. added
    pm:on-holdDecision made, deliberately deferred — no dispatch, no nag; restart condition in the hold comment
    on Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:devxDomain lane — seat card indexed by label:pm:seatpm:on-holdDecision made, deliberately deferred — no dispatch, no nag; restart condition in the hold commentpriority:p3toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions