ESLint 规则

Qwik 自带一套 ESLint 规则,帮助开发者编写更好的代码。

警告 在 'recommended' 规则集中

错误 在 'recommended' 规则集中

🔔 警告 在 'strict' 规则集中

🔔 错误 在 'strict' 规则集中

可能的问题

这些规则可用。

详情

use-method-usage

检测 use 钩子的无效使用。

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* 钩子(例如 useCounter)内使用。

valid-lexical-scope

使用 tsc 类型检查器检测在美元 ($) 范围中捕获不可序列化数据的行为。

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

此规则的正确代码示例

src/routes/product/[productId]/index.tsx
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/components/product/product.tsx
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.tsxindex.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" />;

优先使用 classfor 属性而不是 classNamehtmlFor

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) => {
  // Array syntax example
  return <div class={[
    styles.container, 
    'p-8', 
    props.isHighAttention ? 'text-green-500' : 'text-slate-500',
    { active: true}
  ]}>Hello world</div>;
 
  // Object syntax example
  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 属性可以提高渲染性能。简写片段语法不支持提供 key。请改用 <Fragment>

missingArrayKey

此规则的正确代码示例

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>
  );
});

此规则的错误代码示例

import { component$ } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    <ul>
      {colors.map((color) => (
        <li>{color}</li>
      )}
    </ul>
  );
});

数组中的元素缺少 key 属性。key 属性可以提高渲染性能。

missingArrayKeyUsePrag

此规则的正确代码示例

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>
    )}
  );
});

此规则的错误代码示例

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>
      </>
    )}
  );
});

数组中的元素缺少 key 属性。key 属性可以提高渲染性能。简写片段语法不支持提供 key。请改用 <Fragment>

nonUniqueKeys

此规则的正确代码示例

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>
  );
});

此规则的错误代码示例

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>
  );
});

key 属性必须是唯一的。

unused-server

检测未使用的 server$() 函数。

unusedServer

此规则的正确代码示例

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>
  );
);

此规则的错误代码示例

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>
  );
);

声明了一个 server$ 函数,但从未使用过。

jsx-img

出于性能原因,始终为 <img> 元素提供 width 和 height 属性,这将有助于防止布局偏移。

noLocalSrc

此规则的正确代码示例

import Image from '~/media/image.png';
<Image />

此规则的错误代码示例

<img src="/image.png">

从 public 目录提供图像既没有优化,也没有缓存。请使用 ESM 导入图像。

noWidthHeight

此规则的正确代码示例

<img width="200" height="600" src="/static/images/portrait-01.webp">

此规则的错误代码示例

<img src="/static/images/portrait-01.webp">

出于性能原因,始终为 <img> 元素提供 width 和 height 属性,这将有助于防止布局偏移。

jsx-a

为了获得完美的 SEO 分数,始终为 <a> 元素提供 href 属性。

noHref

no-use-visible-task

检测 useVisibleTask$() 函数。

noUseVisibleTask

贡献者

感谢所有帮助改进这份文档的贡献者!

  • zanettin
  • hbendev
  • manucorporat
  • gioboa
  • maiieul