29
loading...
This website collects cookies to deliver better user experience
no-restricted-syntax
to lint almost anything. Still, like any tool, eslint has its limits — often a precise rule bends eslint too much, and is not practical to support. For example, eslint can’t look into another module. Some smart plugins (like plugin-import) can work around that, but it’s not something I’d be comfortable doing myself. Luckily, I know several tricks that let you bypass these limitations!id
s are prohibited, and so on. Enforcing these restrictions with eslint was a breeze. Ensuring unique localStorage
keys across all apps is trickier: even if we specify that the keys must follow <appName>:<key>
convention, there’s no clear way to lint it.localStorage.setItem('settings:name')
prevents the users from extracting the keys to a common module, which is a good practice. Once the localStorage
is accessed with a variable key, localStorage.setItem(nameKey)
, all bets are off as you can’t peek into the contents of nameKey
. But here’s what you can do instead.appLocalStorage
, that would prefix all keys with appName
, along the lines ofexport const appLocalStorage = {
setItem(name) {
return localStorage.setItem(`${appName}:${key}`);
},
// etc
}
localStorage
with a combination of no-restricted-globals
and no-restricted-properties
or even a no-restricted-syntax: ['error', 'Identifier[name=localStorage]']
, forcing everyone to use the safe wrapper.forwardRef
if the raw component is just a function? Read on!localStorage
example, we could monkey-patch localStorage to give a warning whenever the key requested is not prefixed:const setItem = localStorage.setItem;
const prefix = `${appName}:`;
window.localStorage.setItem = (key, value) => {
if (!key.startsWith(prefix)) {
console.error(`localStorage: "${key}" must start with "${prefix}"`);
}
setItem(key, value);
}
console.error
withsetTimeout(() => {
throw new Error(`localStorage: "${key}" must start with "${prefix}"`);
}, 0);
setInterval(() => {
if (Object.keys(localStorage)).some(k => !k.startsWith(`${appName}:`)) {
console.error('...');
// throw new Error('...') works just as well
}
}, 1000);
const keys = Object.keys(localStorage);
expect(keys.every(k => k.startsWith(`${appName}:`))).toBeTrue();
afterEach
/ afterAll
to automatically check for invalid keys after each test. From here, it’s a matter of ensuring all localStorage
uses are covered with tests — the ease of this task depends on your coverage thresholds. Not universally applicable, but a helpful technique nevertheless.