Skip to content

Commit c5d0cbb

Browse files
authored
@W-17014785 new format for SSR rules (#170)
1 parent a334492 commit c5d0cbb

30 files changed

+2143
-105
lines changed

README.md

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ Example of `.eslintrc`:
3131
"rules": {
3232
"@lwc/lwc/no-deprecated": "error",
3333
"@lwc/lwc/valid-api": "error",
34-
"@lwc/lwc/no-document-query": "error"
34+
"@lwc/lwc/no-document-query": "error",
35+
"@lwc/lwc/ssr/no-unsupported-properties": "error"
3536
}
3637
}
3738
```
@@ -85,6 +86,9 @@ To choose from three configuration settings, install the [`eslint-config-lwc`](h
8586
| [lwc/no-restricted-browser-globals-during-ssr](./docs/rules/no-restricted-browser-globals-during-ssr.md) | disallow access to global browser APIs during SSR | |
8687
| [lwc/no-unsupported-ssr-properties](./docs/rules/no-unsupported-ssr-properties.md) | disallow access of unsupported properties in SSR | |
8788
| [lwc/no-node-env-in-ssr](./docs/rules/no-node-env-in-ssr.md) | disallow usage of process.env.NODE_ENV in SSR | |
89+
| [lwc/ssr/no-restricted-browser-globals](./docs/rules/ssr/no-restricted-browser-globals.md) | disallow access to global browser APIs during SSR | |
90+
| [lwc/ssr/no-unsupported-properties](./docs/rules/ssr/no-unsupported-properties.md) | disallow access of unsupported properties in SSR | |
91+
| [lwc/ssr/no-node-env](./docs/rules/ssr/no-node-env.md) | disallow usage of process.env.NODE_ENV in SSR | |
8892
| [lwc/valid-graphql-wire-adapter-callback-parameters](./docs/rules/valid-graphql-wire-adapter-callback-parameters.md) | ensure graphql wire adapters are using 'errors' instead of 'error' | |
8993
| [lwc/no-host-mutation-in-connected-callback](./docs/rules/no-host-mutation-in-connected-callback.md) | disallow the host element mutation in 'connectedCallback' | |
9094
| Rule ID | Description | Fixable |
@@ -101,13 +105,13 @@ To choose from three configuration settings, install the [`eslint-config-lwc`](h
101105
| [lwc/valid-api](./docs/rules/valid-api.md) | validate `api` decorator usage | |
102106
| [lwc/valid-track](./docs/rules/valid-track.md) | validate `track` decorator usage | |
103107
| [lwc/valid-wire](./docs/rules/valid-wire.md) | validate `wire` decorator usage | |
104-
| [lwc/no-restricted-browser-globals-during-ssr](./docs/rules/no-restricted-browser-globals-during-ssr.md) | disallow access to global browser APIs during SSR | |
105-
| [lwc/no-unsupported-ssr-properties](./docs/rules/no-unsupported-ssr-properties.md) | disallow access of unsupported properties in SSR | |
106-
| [lwc/no-node-env-in-ssr](./docs/rules/no-node-env-in-ssr.md) | disallow usage of process.env.NODE_ENV in SSR | |
108+
| [lwc/ssr/no-restricted-browser-globals](./docs/rules/ssr/no-restricted-browser-globals.md) | disallow access to global browser APIs during SSR | |
109+
| [lwc/ssr/no-unsupported-properties](./docs/rules/ssr/no-unsupported-properties.md) | disallow access of unsupported properties in SSR | |
110+
| [lwc/ssr/no-node-env](./docs/rules/ssr/no-node-env.md) | disallow usage of process.env.NODE_ENV in SSR | |
107111
| [lwc/valid-graphql-wire-adapter-callback-parameters](./docs/rules/valid-graphql-wire-adapter-callback-parameters.md) | ensure graphql wire adapters are using 'errors' instead of 'error' | |
108-
| [lwc/no-host-mutation-in-connected-callback](./docs/rules/no-host-mutation-in-connected-callback.md) | disallow the host element mutation in 'connectedCallback' | |
109-
| [lwc/ssr-no-static-imports-of-user-specific-scoped-modules](./docs/rules/ssr-no-static-imports-of-user-specific-scoped-modules.md) | disallow static imports of user-specific scoped modules in SSR-able components | |
110-
| [lwc/ssr-no-form-factor](./docs/rules/ssr-no-form-factor.md) | disallow formFactor in SSR-able components | |
112+
| [lwc/ssr/no-host-mutation-in-connected-callback](./docs/rules/ssr/no-host-mutation-in-connected-callback.md) | disallow the host element mutation in 'connectedCallback' | |
113+
| [lwc/ssr/no-static-imports-of-user-specific-scoped-modules](./docs/rules/ssr/no-static-imports-of-user-specific-scoped-modules.md) | disallow static imports of user-specific scoped modules in SSR-able components | |
114+
| [lwc/ssr/no-form-factor](./docs/rules/ssr/no-form-factor.md) | disallow formFactor in SSR-able components | |
111115

112116
### Best practices
113117

@@ -119,7 +123,7 @@ To choose from three configuration settings, install the [`eslint-config-lwc`](h
119123
| [lwc/no-template-children](./docs/rules/no-template-children.md) | prevent accessing the immediate children of this.template | |
120124
| [lwc/no-leaky-event-listeners](./docs/rules/no-leaky-event-listeners.md) | prevent event listeners from leaking memory | |
121125
| [lwc/prefer-custom-event](./docs/rules/prefer-custom-event.md) | suggest usage of `CustomEvent` over `Event` constructor | |
122-
| [lwc/ssr-no-unsupported-node-api](./docs/rules/ssr-no-unsupported-node-api.md) | disallow unsupported Node API calls in SSR-able components | |
126+
| [lwc/ssr/no-unsupported-node-api](./docs/rules/ssr/no-unsupported-node-api.md) | disallow unsupported Node API calls in SSR-able components | |
123127

124128
### Compat performance
125129

@@ -133,6 +137,9 @@ Older browsers like IE11 run LWC in compatibility mode. For more information abo
133137

134138
### Deprecated
135139

136-
| Rule ID | Replaced by |
137-
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
138-
| [lwc/no-dupe-class-members](./docs/rules/no-dupe-class-members.md) | [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members) |
140+
| Rule ID | Replaced by |
141+
| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
142+
| [lwc/no-dupe-class-members](./docs/rules/no-dupe-class-members.md) | [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members)(base eslint rule) |
143+
| [lwc/no-restricted-browser-globals-during-ssr](./docs/rules/no-restricted-browser-globals-during-ssr.md) | [lwc/ssr/no-restricted-browser-globals](./docs/rules/ssr/no-restricted-browser-globals.md) |
144+
| [lwc/no-unsupported-ssr-properties](./docs/rules/no-unsupported-ssr-properties.md) | [lwc/ssr/no-unsupported-properties](./docs/rules/ssr/no-unsupported-properties.md) |
145+
| [lwc/no-node-env-in-ssr](./docs/rules/no-node-en-in-ssr.md) | [lwc/ssr/no-node-env](./docs/rules/ssr/no-node-env.md) |

docs/rules/no-node-env-in-ssr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Disallow use of `process.env.NODE_ENV` during SSR (`lwc/no-node-env-in-ssr`)
22

3-
Using process.env.NODE_ENV during server-side rendering in JavaScript is not recommended because it can introduce unexpected behavior and bugs in your application. This environment variable is typically used for conditional logic related to development or production builds, which is more relevant on the client side.
3+
Using `process.env.NODE_ENV` during server-side rendering in JavaScript is not recommended because it can introduce unexpected behavior and bugs in your application. This environment variable is typically used for conditional logic related to development or production builds, which is more relevant on the client side.
44

55
## Rule Details
66

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Using @salesforce/client/formFactor in SSR-able components is not the best practice(`lwc/ssr-no-form-factor`)
1+
# Using @salesforce/client/formFactor in SSR-able components is not the best practice(`lwc/ssr/no-form-factor`)
22

33
## Rule details
44

docs/rules/no-host-mutation-in-connected-callback.md renamed to docs/rules/ssr/no-host-mutation-in-connected-callback.md

File renamed without changes.

docs/rules/ssr/no-node-env.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Disallow use of `process.env.NODE_ENV` during SSR (`lwc/ssr/no-node-env`)
2+
3+
Using `process.env.NODE_ENV` during server-side rendering in JavaScript is not recommended because it can introduce unexpected behavior and bugs in your application. This environment variable is typically used for conditional logic related to development or production builds, which is more relevant on the client side.
4+
5+
## Rule Details
6+
7+
Example of **incorrect** code for this rule:
8+
9+
```js
10+
import { LightningElement } from 'lwc';
11+
12+
export default class Foo extends LightningElement {
13+
connectedCallback() {
14+
if (process.env.NODE_ENV !== 'production') {
15+
console.log('Foo:connectedCallback');
16+
}
17+
}
18+
}
19+
```
20+
21+
Examples of **correct** code for this rule:
22+
23+
```js
24+
import { LightningElement } from 'lwc';
25+
26+
export default class Foo extends LightningElement {
27+
connectedCallback() {
28+
if (!import.meta.env.SSR && process.env.NODE_ENV !== 'production') {
29+
console.log('Foo:connectedCallback');
30+
}
31+
}
32+
}
33+
```
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Disallow access to global browser APIs during SSR (`lwc/ssr/no-restricted-browser-globals`)
2+
3+
Browser APIs must not be accessed when SSR is being done. This rule prevents usage of browser APIs like `DOMParser`, `DocumentFragment` etc.
4+
in `connectedCallback` (and in methods called from `connectedCallback` or anywhere when SSR is being done).
5+
6+
All browser globals, that are not available in Node, are not allowed.
7+
8+
## Rule Details
9+
10+
Examples of **incorrect** code for this rule:
11+
12+
```js
13+
import { LightningElement } from 'lwc';
14+
15+
export default class Foo extends LightningElement {
16+
connectedCallback() {
17+
const parser = new DOMParser();
18+
}
19+
}
20+
```
21+
22+
```js
23+
import { LightningElement } from 'lwc';
24+
25+
export default class Foo extends LightningElement {
26+
constructor() {
27+
this.handleResize = this.handleResize.bind(this);
28+
this.handleClick = this.handleClick.bind(this);
29+
}
30+
31+
connectedCallback() {
32+
globalThis.addEventListener('resize', this.handleResize);
33+
document.addEventListener('click', this.handleClick);
34+
}
35+
36+
disconnectedCallback() {
37+
globalThis.removeEventListener('resize', this.handleResize);
38+
document.removeEventListener('click', this.handleClick);
39+
}
40+
41+
handleResize(event) {
42+
/* ... */
43+
}
44+
45+
handleClick(event) {
46+
/* ... */
47+
}
48+
}
49+
```
50+
51+
Examples of **correct** code for this rule:
52+
53+
```js
54+
import { LightningElement } from 'lwc';
55+
56+
export default class Foo extends LightningElement {
57+
connectedCallback() {
58+
if (!import.meta.env.SSR) {
59+
const parser = new DOMParser();
60+
}
61+
}
62+
}
63+
```
64+
65+
```js
66+
import { LightningElement } from 'lwc';
67+
68+
export default class Foo extends LightningElement {
69+
constructor() {
70+
this.handleResize = this.handleResize.bind(this);
71+
this.handleClick = this.handleClick.bind(this);
72+
}
73+
74+
connectedCallback() {
75+
globalThis.addEventListener?.('resize', this.handleResize);
76+
globalThis.document?.addEventListener('click', this.handleClick);
77+
}
78+
79+
disconnectedCallback() {
80+
globalThis.removeEventListener?.('resize', this.handleResize);
81+
globalThis.document?.removeEventListener('click', this.handleClick);
82+
}
83+
84+
handleResize(event) {
85+
/* ... */
86+
}
87+
88+
handleClick(event) {
89+
/* ... */
90+
}
91+
}
92+
```
93+
94+
```js
95+
import { LightningElement } from 'lwc';
96+
97+
export default class Foo extends LightningElement {
98+
renderedCallback() {
99+
const parser = new DOMParser();
100+
}
101+
}
102+
```
103+
104+
## Options
105+
106+
The rule takes one option, an object, which has one key `restricted-globals` which is an object. The keys in the object
107+
are strings which represent the name of the global and the values can be booleans, `true` indicating that the global
108+
is restricted and `false` to indicate that the global is allowed (useful for overriding an already restricted global).
109+
110+
```json
111+
{ "restricted-globals": { "MyBrowserOnlyGlobal": true, "MyAvailableGlobal": false } }
112+
```

docs/rules/ssr-no-static-imports-of-user-specific-scoped-modules.md renamed to docs/rules/ssr/no-static-imports-of-user-specific-scoped-modules.md

File renamed without changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Disallow Node API Calls in SSR Context (`lwc/ssr-no-unsupported-node-api`)
1+
# Disallow Node API Calls in SSR Context (`lwc/ssr/no-unsupported-node-api`)
22

33
This rule disallows the use of unsupported Node API calls within components that may run during server-side rendering. These APIs are not available in client-side rendering environments and can lead to serious issues when used without proper safeguards. To avoid unexpected behavior and security vulnerabilities, certain problematic Node APIs should not be used in SSR contexts.
44

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Disallow access of properties on this during SSR (`lwc/ssr/no-unsupported-properties`)
2+
3+
Browser APIs must not be accessed when SSR is being done. This rule prevents usage of browser APIs like `querySelector`,
4+
`dispatchEvent`, on `this` in `connectedCallback` (and in methods called from `connectedCallback` or anywhere when
5+
SSR is being done).
6+
7+
## Rule Details
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```js
12+
import { LightningElement } from 'lwc';
13+
14+
export default class Foo extends LightningElement {
15+
connectedCallback() {
16+
this.querySelector('span')?.getAttribute?.('role');
17+
}
18+
}
19+
20+
export default class Foo extends LightningElement {
21+
connectedCallback() {
22+
this.dispatchEvent(new CustomEvent('customevent'));
23+
}
24+
}
25+
```
26+
27+
Examples of **correct** code for this rule:
28+
29+
```js
30+
import { LightningElement } from 'lwc';
31+
32+
export default class Foo extends LightningElement {
33+
connectedCallback() {
34+
if (!import.meta.env.SSR) {
35+
this.querySelector('span')?.getAttribute('role');
36+
}
37+
}
38+
}
39+
40+
export default class Foo extends LightningElement {
41+
connectedCallback() {
42+
if (!import.meta.env.SSR) {
43+
this.dispatchEvent(new CustomEvent('customevent'));
44+
}
45+
}
46+
}
47+
```
48+
49+
```js
50+
import { LightningElement } from 'lwc';
51+
52+
export default class Foo extends LightningElement {
53+
renderedCallback() {
54+
this.querySelector('span')?.foo();
55+
}
56+
}
57+
58+
export default class Foo extends LightningElement {
59+
renderedCallback() {
60+
// **Caution:** This lifecycle hook is very likely
61+
// to be called more than once.
62+
this.dispatchEvent(new CustomEvent('customevent'));
63+
}
64+
}
65+
```

lib/index.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@ const rules = {
3232
'no-restricted-browser-globals-during-ssr': require('./rules/no-restricted-browser-globals-during-ssr'),
3333
'no-unsupported-ssr-properties': require('./rules/no-unsupported-ssr-properties'),
3434
'no-node-env-in-ssr': require('./rules/no-node-env-in-ssr'),
35-
'ssr-no-unsupported-node-api': require('./rules/ssr-no-unsupported-node-api'),
36-
'no-host-mutation-in-connected-callback': require('./rules/no-host-mutation-in-connected-callback'),
37-
'ssr-no-static-imports-of-user-specific-scoped-modules': require('./rules/ssr-no-static-imports-of-user-specific-scoped-modules'),
38-
'ssr-no-form-factor': require('./rules/ssr-no-form-factor'),
35+
// SSR rules
36+
'ssr/no-host-mutation-in-connected-callback': require('./rules/ssr/no-host-mutation-in-connected-callback'),
37+
'ssr/no-restricted-browser-globals': require('./rules/ssr/no-restricted-browser-globals'),
38+
'ssr/no-unsupported-properties': require('./rules/ssr/no-unsupported-properties'),
39+
'ssr/no-node-env': require('./rules/ssr/no-node-env'),
40+
'ssr/no-unsupported-node-api': require('./rules/ssr/no-unsupported-node-api'),
41+
'ssr/no-static-imports-of-user-specific-scoped-modules': require('./rules/ssr/no-static-imports-of-user-specific-scoped-modules'),
42+
'ssr/no-form-factor': require('./rules/ssr/no-form-factor'),
3943
};
4044

4145
module.exports = {

0 commit comments

Comments
 (0)