feat: add no-empty-screen-component rule (blank mobile preview / orphan return-null root route)#72
Open
mrpopo573 wants to merge 1 commit into
Open
feat: add no-empty-screen-component rule (blank mobile preview / orphan return-null root route)#72mrpopo573 wants to merge 1 commit into
mrpopo573 wants to merge 1 commit into
Conversation
Flags a default-exported screen/route component whose body renders nothing
(return null / return undefined / empty return / empty fragment). This is the
orphan-stub signature behind a recurring class of blank mobile previews: the
generation agent moves real UI into a route group (e.g. (tabs)/index.tsx) but
leaves the top-level index.tsx as 'export default function Index(){ return null; }',
so the '/' route renders nothing and the app boots to a white screen in both the
web preview and Expo Go.
Scoped to be single-file decidable and low false-positive: only fires on a
default-exported PascalCase (or anonymous) component whose entire body is a single
empty return, resolving identifier default exports to their in-scope declaration.
Conditional early returns, loading/auth gates, real JSX (including childless
elements like <View />), and non-default helpers are left alone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a new laint rule,
no-empty-screen-component, that flags a default-exported screen/route component whose body renders nothing:return null,return undefined, an emptyreturn;, or an empty fragment (<></>). A concise-body arrow (() => null) and an identifier default export resolving to such a function are covered too.Why
Recurring class of blank mobile previews at first boot. The generation agent restructures a mobile app's routes into a route group (for example moving the home UI into
(tabs)/index.tsx) but leaves the top-level entrysrc/app/index.tsxas a stub:Route
/resolves to that top-levelindex.tsx, rendersnull, and the app boots to a white screen in both the web preview and Expo Go. The user then burns several retry prompts before it self-resolves.Evidence (CloudWatch worker logs, us-east-2, 7 day window): the co-occurring Metro
metro-virtual/unresolved/throw-*.jsbundle error fired 497 times across 97 distinct sandboxes, trending up day over day, with a shared virtual-module signature. This rule catches the static, single-file half of that failure (thereturn nullroot route) before it ships.The rule is intentionally single-file decidable (laint rules receive AST plus source, no filename) and scoped to keep false positives near zero: it only fires on a default-exported PascalCase or anonymous component whose entire body is one empty return. Anything with a conditional early return (loading gate, auth guard,
+not-found), any real JSX (including childless elements like<View />), or a non-default helper that returns null is left alone.Scope
src/rules/no-empty-screen-component.ts: the rule +meta(severity error, platformsexpo+web, category React / JSX).tests/no-empty-screen-component.test.ts: 14 cases, both fire and no-fire, including the loading-gate and childless-element non-fire guards.src/rules/index.tsandREADME.md: regenerated bynpm run sync(registry entry, README rule table row, rule count 55 to 56). Generated files, not hand-edited.Testing
npm test: full suite green (476/476) afternpm run build.npm run lint,npm run format:check,npm run sync:check,npm run knip: clean for the added files (the pre-existingcli-initlint error andcli/init.tssecurity warnings are untouched and unrelated).index.tsxreports the violation and exits 1; a real Gift Cards screen is silent and exits 0.Linked context
Investigated from build
ed1cca00-a8c6-48ec-afd6-ed5961cb5e49(V2 native, from-scratch). Internal notes only; no customer PII or raw log lines.