ESLint Plugin
The official ESLint plugin for Flexium helps you write better code by enforcing best practices and catching common mistakes.
Installation
npm install eslint-plugin-flexium --save-devBasic Usage
Add flexium to the plugins section of your .eslintrc configuration file and extend the recommended config:
{
"plugins": ["flexium"],
"extends": ["plugin:flexium/recommended"]
}Configurations
The plugin provides three preset configurations:
| Configuration | Description | Use Case |
|---|---|---|
recommended | Balanced rules for most projects | General development |
strict | Stricter rules for production code | Production applications |
all | Enable all rules as errors | Maximum code quality enforcement |
Using Configurations
{
"extends": ["plugin:flexium/recommended"]
}{
"extends": ["plugin:flexium/strict"]
}{
"extends": ["plugin:flexium/all"]
}Custom Configuration
Configure rules individually to match your project's needs:
{
"plugins": ["flexium"],
"rules": {
"flexium/no-signal-outside-reactive": "warn",
"flexium/effect-cleanup": "warn",
"flexium/no-side-effect-in-computed": "error",
"flexium/prefer-sync": "off"
}
}Rules
flexium/no-signal-outside-reactive
Disallow reading signal values outside of reactive contexts.
Why? Signal reads outside of use(), computed(), or JSX will not be tracked and won't trigger re-renders.
Bad
const [count, setCount] = use(0);
// ❌ Signal read outside reactive context - won't trigger updates
if (count > 5) {
doSomething();
}Good
const [count, setCount] = use(0);
// ✅ Signal read inside effect
use(() => {
if (count > 5) {
doSomething();
}
});
// ✅ Signal read inside computed
const [shouldDoSomething] = use(() => count > 5, [count]);
// ✅ Signal read inside JSX
const App = () => (
<div>
{count > 5 && <div>Count is greater than 5</div>}
</div>
);flexium/effect-cleanup
Enforce cleanup functions in effects that add event listeners or timers.
Why? Effects that add event listeners or timers without cleanup can cause memory leaks.
Bad
// ❌ No cleanup for event listener
use(() => {
window.addEventListener('resize', handleResize);
});
// ❌ No cleanup for timer
use(() => {
const interval = setInterval(() => {
console.log('Tick');
}, 1000);
});Good
// ✅ Returns cleanup function for event listener
use(() => {
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
});
// ✅ Returns cleanup function for timer
use(() => {
const interval = setInterval(() => {
console.log('Tick');
}, 1000);
return () => clearInterval(interval);
});
// ✅ Effect without listeners/timers doesn't need cleanup
use(() => {
console.log('Count changed:', count);
});flexium/no-side-effect-in-computed
Disallow side effects in computed functions.
Why? Computed values should be pure functions. Side effects belong in use().
Bad
// ❌ Side effect in computed (console.log)
const [doubled] = use(() => {
console.log('Computing...');
return count * 2;
});
// ❌ Mutation in computed
const [users] = use([]);
const [sortedUsers] = use(() => {
return users.sort(); // Mutates original array!
}, [users]);
// ❌ DOM manipulation in computed
const [displayText] = use(() => {
document.title = String(count); // DOM side effect!
return `Count: ${count}`;
}, [count]);Good
// ✅ Pure computed
const [doubled] = use(() => count * 2, [count]);
// ✅ Side effect in effect
use(() => {
console.log('Count changed:', count);
});
// ✅ Non-mutating computed
const [sortedUsers] = use(() => {
return [...users].sort(); // Creates new array
}, [users]);
// ✅ DOM manipulation in effect
use(() => {
document.title = String(count);
});flexium/prefer-sync
Suggest using sync() when multiple signals are updated consecutively.
Why? Multiple signal updates without syncing can cause unnecessary re-renders.
Bad
// ⚠️ Warning - multiple updates without sync (3 separate re-renders)
setCount(1);
setName('test');
setActive(true);
// ⚠️ Multiple signal updates in a function
function updateUser(id: number, data: UserData) {
setUserId(id);
setUserName(data.name);
setUserEmail(data.email);
setUserActive(data.active);
}Good
import { sync } from 'flexium/core';
// ✅ Synced updates (single re-render)
sync(() => {
setCount(1);
setName('test');
setActive(true);
});
// ✅ Synced function
function updateUser(id: number, data: UserData) {
sync(() => {
setUserId(id);
setUserName(data.name);
setUserEmail(data.email);
setUserActive(data.active);
});
}
// ✅ Single signal update doesn't need syncing
setCount(1);Configuration
Configure the threshold for when to warn about consecutive updates:
{
"flexium/prefer-sync": ["warn", { "threshold": 2 }]
}Options:
threshold(default:2): Number of consecutive signal updates before warning.
Integration with Other Configs
The Flexium ESLint plugin works alongside other ESLint configurations:
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:flexium/recommended"
],
"plugins": ["@typescript-eslint", "flexium"],
"rules": {
// Override specific rules if needed
"flexium/prefer-sync": "off"
}
}TypeScript Support
The plugin fully supports TypeScript projects. Make sure to install the TypeScript ESLint parser:
npm install @typescript-eslint/parser --save-dev{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["flexium"],
"extends": ["plugin:flexium/recommended"]
}Common Issues
Rule Not Working
If a rule isn't being enforced:
- Verify the plugin is listed in
pluginsarray - Check that the rule is enabled in your config
- Ensure your file extensions are included in ESLint's
--extoption - Restart your editor/IDE
Too Many Warnings
If you're getting too many warnings during migration:
- Start with
recommendedconfig instead ofstrictorall - Disable specific rules temporarily:json
{ "extends": ["plugin:flexium/recommended"], "rules": { "flexium/prefer-sync": "off" } } - Fix violations incrementally
- Gradually enable stricter rules
False Positives
If you encounter false positives:
Use ESLint disable comments for specific cases:
javascript// eslint-disable-next-line flexium/no-signal-outside-reactive const initialValue = count;Report the issue on GitHub
Best Practices
Use the Recommended Config
Start with the recommended config and customize from there:
{
"extends": ["plugin:flexium/recommended"],
"rules": {
// Add project-specific overrides here
}
}Enable Auto-Fix
Many rules support auto-fix. Run ESLint with the --fix flag:
npx eslint . --fixIntegrate with Your Editor
Install ESLint extensions for your editor:
- VS Code: ESLint Extension
- WebStorm: Built-in ESLint support
- Vim: ALE or coc-eslint
Use Pre-Commit Hooks
Enforce ESLint checks before commits using husky and lint-staged:
// package.json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix"]
}
}Migrating Existing Projects
When adding ESLint to an existing Flexium project:
Install dependencies:
bashnpm install eslint eslint-plugin-flexium --save-devCreate configuration:
json{ "extends": ["plugin:flexium/recommended"] }Run ESLint:
bashnpx eslint .Fix automatically fixable issues:
bashnpx eslint . --fixFix remaining issues manually, using the rule documentation as a guide
Enable stricter rules gradually as your codebase improves