ESLint-Rules
Qwik 自带了一套 ESLint 规则,以帮助开发者编写更好的代码。
✅ 警告 在 'recommended' 规则集中
✅ 错误 在 'recommended' 规则集中
🔔 警告 在 'strict' 规则集中
🔔 错误 在 'strict' 规则集中
可能的问题
这些规则是可用的。
use-method-usage
检测无效的 use hooks 使用。✅
🔔
valid-lexical-scope
使用 tsc 类型检查器检测在 dollar ($) 作用域中无法序列化的数据的捕获。✅
🔔
loader-location
检测 loader$ 的声明位置。✅
🔔
no-react-props
禁止使用 React 特定的 className
/htmlFor
属性。✅
🔔
prefer-classlist
强制使用 classlist 属性而不是导入 classnames 助手。classlist 属性接受一个对象 { [class: string]: boolean }
,就像 classnames 一样。✅
🔔
jsx-no-script-url
禁止使用 javascript: URL。✅
🔔
jsx-key
禁止在迭代器/集合字面量中缺少 key
属性✅
🔔
unused-server
检测未使用的 server$() 函数。✅
🔔
jsx-img
出于性能原因,对于 <img> 元素,始终提供 width 和 height 属性,这将有助于防止布局变化。✅
🔔
jsx-a
为了获得完美的 SEO 分数,始终为 <a> 元素提供 href 属性。✅
🔔
no-use-visible-task
警告 "useVisibleTask$" 的使用,因为 Qwik 会尽力推迟客户端代码的执行时间。✅
🔔
详情
use-method-usage
检测无效的 use hooks 使用。useWrongFunction
这个规则的 正确 代码示例:
export const Counter = component$(() => {
const count = useSignal(0);
});
export const useCounter = () => {
const count = useSignal(0);
return count;
};
这个规则的 错误 代码示例:
export const Counter = (() => {
const count = useSignal(0);
});
use*
方法只能在 component$
函数或 use*
hooks(例如 useCounter
)中使用。
valid-lexical-scope
使用 tsc 类型检查器检测在 dollar ($) 作用域中无法序列化的数据的捕获。referencesOutside
这个规则的 正确 代码示例:
import { component$, useTask$, $ } from '@builder.io/qwik';
export const HelloWorld = component$(() => {
const print = $((msg: string) => {
console.log(msg);
});
useTask$(() => {
print("Hello World");
});
return <h1>Hello</h1>;
});
这个规则的 错误 代码示例:
import { component$, useTask$ } from '@builder.io/qwik';
export const HelloWorld = component$(() => {
const print = (msg: string) => {
console.log(msg);
};
useTask$(() => {
print("Hello World");
});
return <h1>Hello</h1>;
});
由于表达式无法序列化,必须使用 $( ... )
将其包装起来,以便优化器可以将代码拆分成小块。
invalidJsxDollar
这个规则的 正确 代码示例:
import { component$, $ } from '@builder.io/qwik';
export const HelloWorld = component$(() => {
const click = $(() => console.log());
return (
<button onClick$={click}>log it</button>
);
});
这个规则的 错误 代码示例:
import { component$ } from '@builder.io/qwik';
export const HelloWorld = component$(() => {
const click = () => console.log();
return (
<button onClick$={click}>log it</button>
);
});
事件处理程序必须使用 ${ ... }
包装。
mutableIdentifier
这个规则的 正确 代码示例:
import { component$ } from '@builder.io/qwik';
export const HelloWorld = component$(() => {
const person = { name: 'Bob' };
return (
<button onClick$={() => {
person.name = 'Alice';
}}>
{person.name}
</button>
);
});
这个规则的 错误 代码示例:
import { component$ } from '@builder.io/qwik';
export const HelloWorld = component$(() => {
let personName = 'Bob';
return (
<button onClick$={() => {
personName = 'Alice';
}}>
{personName}
</button>
);
});
不允许修改简单值。使用对象代替,并编辑其中一个属性。
loader-location
检测 loader$ 的声明位置。invalidLoaderLocation
这个规则的 正确 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
这个规则的 错误 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
这不是路由加载器的有效位置。它只能在 src/routes
文件夹中的 layout.tsx
或 index.tsx
文件中使用。
missingExport
这个规则的 正确 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
这个规则的 错误 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
路由加载器函数必须导出。
wrongName
这个规则的 正确 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
这个规则的 错误 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
export const getProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
路由加载器函数名必须以 use
开头。
recommendedValue
这个规则的 正确 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
export const useProductDetails = routeLoader$(async (requestEvent) => {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
});
这个规则的 错误 代码示例:
import { routeLoader$ } from '@builder.io/qwik-city';
async function fetcher() {
const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
const product = await res.json();
return product as Product;
}
export const useProductDetails = routeLoader$(fetcher);
建议内联箭头函数。这将有助于优化器确保不会将服务器代码泄漏到客户端构建中。
no-react-props
禁止使用 React 特定的className
/htmlFor
属性。prefer
这个规则的 正确 代码示例:
<MyReactComponent class="foo" for="#password" />;
这个规则的 错误 代码示例:
<MyReactComponent className="foo" htmlFor="#password" />;
优先使用 class
和 for
属性,而不是 className
和 htmlFor
。
prefer-classlist
强制使用 classlist 属性而不是导入 classnames 助手。classlist 属性接受一个对象{ [class: string]: boolean }
,就像 classnames 一样。preferClasslist
这个规则的 正确 代码示例:
import { component$ } from '@builder.io/qwik';
import styles from './MyComponent.module.css';
export default component$((props) => {
// 数组语法示例
return <div class={[
styles.container,
'p-8',
props.isHighAttention ? 'text-green-500' : 'text-slate-500',
{ active: true}
]}>Hello world</div>;
// 对象语法示例
return <div class={{
'text-green-500': props.isHighAttention,
'p-4': true
}}>Hello world</div>;
});
这个规则的 错误 代码示例:
import { component$ } from '@builder.io/qwik';
import classnames from 'classnames';
import styles from './MyComponent.module.css';
export default component$((props) => {
return <div class={classnames(
styles.container,
'p-8',
{
'text-green-500' : props.isHighAttention,
'text-slate-500' : !props.isHighAttention,
},
{ active: true}
)}>Hello world</div>;
});
应该使用 class 属性而不是任何第三方库,以有效地基于对象设置类。
jsx-no-script-url
禁止使用 javascript: URL。noJSURL
这个规则的 正确 代码示例:
<button onClick$={() => alert('open the door please')>ring</button>
这个规则的 错误 代码示例:
<button onClick$="javascript:alert('open the door please')">ring</button>
jsx-key
禁止在迭代器/集合字面量中缺少key
属性missingIterKey
这个规则的 正确 代码示例:
import { component$ } from '@builder.io/qwik';
export const Person = component$(() => {
const person = {
firstName: 'John',
lastName: 'Doe',
age: 32,
}
return (
<ul>
{Object.keys(person).map((color) => (
<li key={`person-${key}`}>{person[key]}</li>
)}
</ul>
);
});
这个规则的 错误 代码示例:
import { component$ } from '@builder.io/qwik';
export const Person = component$(() => {
const person = {
firstName: 'John',
lastName: 'Doe',
age: 32,
}
return (
<ul>
{Object.keys(person).map((color) => (
<li>{person[key]}</li>
)}
</ul>
);
});
迭代器中的元素缺少 key
属性。
missingIterKeyUsePrag
这个规则的 正确 代码示例:
import { component$ } from '@builder.io/qwik';
import Card from './Card';
import Summary from './Summary';
export const Person = component$(() => {
const person = {
firstName: 'John',
lastName: 'Doe',
age: 32,
}
return (
{Object.keys(person).map((color) => (
<Fragment key={`person-${key}`}>
<Card value={person[key]} />
<Summary value={person[key]} />
</Fragment>
)}
);
});
这个规则的 错误 代码示例:
import { component$ } from '@builder.io/qwik';
import Card from './Card';
import Summary from './Summary';
export const Person = component$(() => {
const person = {
firstName: 'John',
lastName: 'Doe',
age: 32,
}
return (
{Object.keys(person).map((color) => (
< key={`person-${key}`}>
<Card value={person[key]} />
<Summary value={person[key]} />
</>
)}
);
});
迭代器中的元素缺少 key
属性。key 属性可以提高渲染性能。简写的 fragment 语法不支持提供 key。请使用 <Fragment>
代替。
missingArrayKey
Examples of correct code for this rule:
import { component$ } from '@builder.io/qwik';
export const ColorList = component$(() => {
const colors = ['red', 'green', 'blue'];
return (
<ul>
{colors.map((color) => (
<li key={`color-${color}`}>{color}</li>
)}
</ul>
);
});
Examples of incorrect code for this rule:
import { component$ } from '@builder.io/qwik';
export const ColorList = component$(() => {
const colors = ['red', 'green', 'blue'];
return (
<ul>
{colors.map((color) => (
<li>{color}</li>
)}
</ul>
);
});
Missing key
prop for element in array. The key prop allows for improved rendering performance.
missingArrayKeyUsePrag
Examples of correct code for this rule:
import { component$, Fragment } from '@builder.io/qwik';
export const ColorList = component$(() => {
const colors = ['red', 'green', 'blue'];
return (
{colors.map((color) => (
<Fragment key={`color-${color}`}>
<h2>{color}</h2>
<p>The color "${color}" is a great color.</p>
</Fragment>
)}
);
});
Examples of incorrect code for this rule:
import { component$ } from '@builder.io/qwik';
export const ColorList = component$(() => {
const colors = ['red', 'green', 'blue'];
return (
{colors.map((color) => (
< key={`color-${color}`}>
<h2>{color}</h2>
<p>The color "${color}" is a great color.</p>
</>
)}
);
});
Missing key
prop for element in array. The key prop allows for improved rendering performance. Shorthand fragment syntax does not support providing keys. Use <Fragment>
instead
nonUniqueKeys
Examples of correct code for this rule:
import { component$ } from '@builder.io/qwik';
export const ColorList = component$(() => {
const colors = ['red', 'green', 'blue'];
return (
<ul>
{colors.map((color) => (
<li key={`color-${color}`}>{color}</li>
)}
</ul>
);
});
Examples of incorrect code for this rule:
import { component$ } from '@builder.io/qwik';
export const ColorList = component$(() => {
const colors = ['red', 'green', 'blue'];
return (
<ul>
{colors.map((color) => (
<li key="not-a-good-idea">{color}</li>
)}
</ul>
);
});
The key
prop must be unique.
unused-server
Detect unused server$() functions.unusedServer
Examples of correct code for this rule:
import { component$ } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';
const serverGreeter = server$((firstName: string, lastName: string) => {
const greeting = `Hello ${firstName} ${lastName}`;
return greeting;
});
export default component$(() => (
<button
onClick$={async () => {
const greeting = await serverGreeter('John', 'Doe');
alert(greeting);
}}
>
greet
</button>
);
);
Examples of incorrect code for this rule:
import { component$ } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';
const serverGreeter = server$((firstName: string, lastName: string) => {
const greeting = `Hello ${firstName} ${lastName}`;
return greeting;
});
export default component$(() => (
<button
onClick$={async () => {
const greeting = 'not using the server$ function';
alert(greeting);
}}
>
greet
</button>
);
);
A server$
function is declared, but never used.
jsx-img
For performance reasons, always provide width and height attributes for <img> elements, it will help to prevent layout shifts.noLocalSrc
Examples of correct code for this rule:
import Image from '~/media/image.png';
<Image />
Examples of incorrect code for this rule:
<img src="/image.png">
Serving images from public are not optimized, nor cached. Import images using ESM instead.
noWidthHeight
Examples of correct code for this rule:
<img width="200" height="600" src="/static/images/portrait-01.webp">
Examples of incorrect code for this rule:
<img src="/static/images/portrait-01.webp">
For performance reasons, always provide width and height attributes for <img>
elements, it will help to prevent layout shifts.
no-use-visible-task
Qwik tries very hard to defer client code execution for as long as possible. This is done to give the end-user the best possible user experience. Running code eagerly blocks the main thread, which prevents the user from interacting until the task is finished. "useVisibleTask$" is provided as an escape hatch.- useTask$ -> perform code execution in SSR mode.
- useOn() -> listen to events on the root element of the current component.
- useOnWindow() -> listen to events on the window object.
- useOnDocument() -> listen to events on the document object.