-
Notifications
You must be signed in to change notification settings - Fork 192
feat(react-doctor): add TanStack Start (14), TanStack Query (6), and Vercel Best Practices (2) rules #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(react-doctor): add TanStack Start (14), TanStack Query (6), and Vercel Best Practices (2) rules #124
Changes from 13 commits
c1b204a
e9ccd2c
34b7828
aa04fda
c33e66f
65fcd73
fd09b45
b2b5f30
72223fc
f6f23e1
9747794
89f4129
0de8ba9
40e65d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,12 @@ import { | |
| ANIMATION_CALLBACK_NAMES, | ||
| BLUR_VALUE_PATTERN, | ||
| EFFECT_HOOK_NAMES, | ||
| EXECUTABLE_SCRIPT_TYPES, | ||
| LARGE_BLUR_THRESHOLD_PX, | ||
| LAYOUT_PROPERTIES, | ||
| LOADING_STATE_PATTERN, | ||
| MOTION_ANIMATE_PROPS, | ||
| SCRIPT_LOADING_ATTRIBUTES, | ||
| } from "../constants.js"; | ||
| import { | ||
| getEffectCallback, | ||
|
|
@@ -422,3 +424,45 @@ export const renderingHydrationNoFlicker: Rule = { | |
| }, | ||
| }), | ||
| }; | ||
|
|
||
| export const renderingScriptDeferAsync: Rule = { | ||
| create: (context: RuleContext) => ({ | ||
| JSXOpeningElement(node: EsTreeNode) { | ||
| if (node.name?.type !== "JSXIdentifier" || node.name.name !== "script") return; | ||
|
|
||
| const attributes = node.attributes ?? []; | ||
| const hasSrc = attributes.some( | ||
| (attr: EsTreeNode) => | ||
| attr.type === "JSXAttribute" && | ||
| attr.name?.type === "JSXIdentifier" && | ||
| attr.name.name === "src", | ||
| ); | ||
|
|
||
| if (!hasSrc) return; | ||
|
|
||
| const typeAttribute = attributes.find( | ||
| (attr: EsTreeNode) => | ||
| attr.type === "JSXAttribute" && | ||
| attr.name?.type === "JSXIdentifier" && | ||
| attr.name.name === "type", | ||
| ); | ||
| const typeValue = typeAttribute?.value?.type === "Literal" ? typeAttribute.value.value : null; | ||
| if (typeof typeValue === "string" && !EXECUTABLE_SCRIPT_TYPES.has(typeValue)) return; | ||
|
|
||
| const hasLoadingStrategy = attributes.some( | ||
| (attr: EsTreeNode) => | ||
| attr.type === "JSXAttribute" && | ||
| attr.name?.type === "JSXIdentifier" && | ||
| SCRIPT_LOADING_ATTRIBUTES.has(attr.name.name), | ||
| ); | ||
|
|
||
| if (!hasLoadingStrategy) { | ||
| context.report({ | ||
| node, | ||
| message: | ||
| "<script src> without defer or async — blocks HTML parsing and delays First Contentful Paint. Add defer for DOM-dependent scripts or async for independent ones", | ||
| }); | ||
| } | ||
| }, | ||
| }), | ||
| }; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. False positive on
|
||


Uh oh!
There was an error while loading. Please reload this page.