Blame

6dd66b Melisha Dsouza 2026-01-15 06:45:47 1
# **Javascript**
2
c50891 Melisha Dsouza 2026-01-16 08:18:45 3
4
| Field | Value |
5
| ------------- | --------------------------------- |
6
| Author | Malakhov Dmitry (Dmitry Malakhov) |
7
| Audience | TS / JS Developers & Engineers |
8
| Revision | 0.0.1 |
9
| Revision Date | 12.02.2026 |
10
| Description | Initial version |
11
6dd66b Melisha Dsouza 2026-01-15 06:45:47 12
### **Preface**
c50891 Melisha Dsouza 2026-01-16 08:18:45 13
The purpose of this document is to reach the same general code writing and code organization requirement across all of our JS and TS repositories. This is mostly not about the attention of manual spelling checks - being the developers, we should reach the full automatization where it’s possible. Still there are some topics that are not very obvious for being changed automatically - most of them are covered in this doc.
14
15
The industry standard principles are considered as core and default requirements for any developer, such things as SOLID require a separate book; DRY and others are too obvious to mention.
16
17
All of us are using different development environments and IDEs, and this option should never be limited - we may use VSCode, Cursor, IntelliJIDEA, vim, and event notepad or nano for some cases. I’m going to provide a setup, suitable for VSCode/Cursor, that will enrich the experience of working with this software in a separate section of this document.
18
19
The document is covering the different environments: general, backend and browser specific cases.
20
21
First of all, it is important to note that any contemporary JS/TS developer is considered as NodeJS first. We use the code environment to write readable code to build it into the plain JS, that we can call a machine-ready - it will contain the polyfills, it can be minified and even obfuscated. On the build step, NodeJS engine is always involved, and this requires the knowledge of this platform for the developer. So, let’s fix this fact - most of the requirements there are related to the source code we write - not the build target.
22
23
There are rule level labels defined in the document, helping to define the strictness of a section or a rule.
24
25
### **Modules system**
26
==**Must**== The ESM modules should be in use in the source code only, instead of the cases when we write plain JS files for immediate evaluation with NodeJS engine for some cases.
27
28
==**Should**== Try to follow the condition of partial imports and exports where you don’t need the entire module:
29
- Instead of
30
- import crypto from “node:crypto”
31
- Use
32
- import { publicEncrypt, randomBytes } from “node:crypto”
33
Organize your own code exports to provide it in the same way.
34
35
### **Packages management**
36
We’re not limited by using different packaging engines, such as npm, yarn, pnpm etc. It should be defined on the repository level by the repo owner. But, once it’s defined, no other package manager should be used in this repo - it shouldn’t contain yarn.lock and package-lock.json files simultaneously, for example.
37
38
==**Must**== Lock files should be always included into the git index.
39
40
==**Should**== Once some external package is upgraded even into a minor version, the developer should pass the automated tests suite locally to ensure that nothing is impacted with this update.
41
42
==**Recommended**== Any project or repo should have a policy for the scheduled or event-based upgrade of the external libraries due to the safety purposes.
43
44
==**Must**== The “engines” section of package.json files should contain the most of software versions, at least, node and package manager versions.
45
46
==**Must**== The development dependencies should never come to the target build. For this, ensure that it’s contained in the “devDependencies” section of the package.json:
47
- linters/prettier
48
- testing frameworks
49
- builders and bundlers
50
- types
51
-
52
53
==**Recommended**== It is also appreciated if the version of the module is defined in the package.json file.
54
55
### **Node modules**
56
==**Recommended**== Some package managers may provide their own way of keeping the installed dependencies. If you are not aware of this feature, it’s highly likely you don’t need it. It may lead to unexpected behaviour of some features like type resolution in TS monorepo workspaces.
57
58
Solution for modern yarn versions: place “.yarnrc.yml” file at the root of the repo. It should contain the line:
59
60
nodeLinker: node-modules
61
62
### **Repository secrets handling**
63
64
==**Must**== It is obvious that we should never commit the secrets to avoid exposing it.
65
Always add .env files to gitinore for the backend projects.
66
67
In the case of frontend application, there’s no sense in it - all code is public, so you may commit the environment files safely.
68
69
### **Compilers**
70
==**Recommended**== It is very welcomed and appreciated to use the Typescript in all of the new projects. It provides type safety, readability and more other useful features of working with the source code.
71
72
In case it's a legacy backend JS repo, use babel to provide all of the modern JS features for the source code.
73
74
```Javascript
75
.babelrc config file:
76
{
77
"presets": [
78
[
79
"env",
80
{
81
"targets": {
82
"node": "current"
83
}
84
}
85
]
86
],
87
"sourceMaps": "inline",
88
"retainLines": true,
89
"plugins": ["transform-optional-chaining"]
90
}
91
92
```
93
94
==**Recommended**== If it’s a frontend repo, try to pick a modern bundler, such as Vite and Typescript as the compiler.
95
96
Avoid using Webpack bundler where possible, once you compare the build time with Vite, you will never wish to switch back.
97
98
### **Monorepository recipes**
99
==**Optional**== The modern package managers provide awesome experience and features of working with monorepos. I’ll try to cover the yarn case, anyone who is familiar with pnpm is welcomed to extend this section.
100
101
Ensure you’re working with the latest yarn version installed globally.
102
103
In package.json, add the root section “workspaces”. Reference for example:
104
105
```JavaScript
106
"workspaces": [
107
"src/*",
108
"packages/*",
109
"bots/*",
110
"swagger",
111
"e2e-tests"
112
]
113
114
```
115
116
117
==**Optional**== There are even more development tools allowing to speed up the development process of working with the workspaces. It provides tasks caching, watch modes and lot more:
118
- Turborepo
119
- Nix
120
121
### **Linting and formatting**
122
This section is dedicated to the things that may alleviate most of the boring standards, such as indentation, quotes and semi signs in our code.
123
124
There are 2 kinds of linting and formatting approaches, and mostly we use the both:
125
- **IDE-level**: resolves it automatically on the fly while typing, pasting the code or saving the file. Mark the linting errors in the editor window.
126
- **CLI-level**: tools for check, format the file or the entire repository and show the report with the console commands. Useful for the CI jobswe may receive a non-zero exit code if some developer has ignored the rules described there.
127
128
==**Recommended**== For the FE repositories, most of the described below are probably not actual, as most of the modern FE frameworks provide their own set of formatting on repo initialization. If not, please use it.
129
130
#### **.editorconfig file**
131
132
==**Must**== The purpose of this file is to align a few possible requirements amongst the different IDEs. You may consider it as a small contract between the different code environments helping you to reach the same formatting while you are writing.
133
134
Minimum and safe default case:
135
```JavaScript
136
.editorconfig
137
root = true
138
139
[*]
140
charset = utf-8
141
end_of_line = lf
142
insert_final_newline = true
143
trim_trailing_whitespace = true
144
indent_style = space
145
indent_size = 2
146
```
147
#### **Prettier (general)**
148
==**Must**== Both prettier and eslint packages are mandatory for the projects, and it works simultaneously.
149
150
Install npm package: “prettier”
151
152
```JavaScript
153
.prettierrc.mjs
154
export const prettierConfig = {
155
arrowParens: "avoid",
156
printWidth: 80,
157
semi: true,
158
singleQuote: false,
159
tabWidth: 2,
160
trailingComma: "all",
161
};
162
163
```
164
#### **ESLint common configs**
165
==**Must**==
166
```JavaScript
167
common.config.mjs
168
import importPlugin from "eslint-plugin-import";
169
import prettier from "eslint-plugin-prettier";
170
171
export const commonConfigs = [
172
importPlugin.flatConfigs.recommended,
173
importPlugin.configs.typescript,
174
175
{
176
ignores: ["dist"],
177
},
178
179
{
180
plugins: {
181
prettier,
182
},
183
rules: {
184
"prettier/prettier": [
185
"warn",
186
{
187
endOfLine: "auto",
188
},
189
],
190
},
191
},
192
193
{
194
files: ["**/*.{js,mjs,cjs,ts}"],
195
languageOptions: {
196
ecmaVersion: "latest",
197
sourceType: "module",
198
},
199
rules: {
200
"import/exports-last": ["error"],
201
"import/first": ["error"],
202
"import/named": ["error"],
203
"import/newline-after-import": ["warn", { considerComments: true }],
204
"import/no-absolute-path": ["error"],
205
"import/no-empty-named-blocks": ["error"],
206
"import/no-extraneous-dependencies": ["error"],
207
"import/no-relative-packages": "error",
208
"import/no-self-import": "error",
209
"import/order": [
210
"warn",
211
{
212
alphabetize: {
213
caseInsensitive: false,
214
order: "asc",
215
orderImportKind: "asc",
216
},
217
groups: [
218
"builtin",
219
"external",
220
"internal",
221
"parent",
222
"sibling",
223
"index",
224
],
225
named: {
226
enabled: true,
227
export: true,
228
import: true,
229
require: true,
230
types: "types-last",
231
},
232
"newlines-between": "always",
233
},
234
],
235
},
236
},
237
238
{
239
settings: {
240
"import/internal-regex": "^@lib/",
241
"import/resolver": {
242
node: true,
243
typescript: true,
244
},
245
},
246
},
247
];
248
249
```
250
251
### **ESLint config for Javascript **
252
253
==**Optional**==
254
255
Install packages:
256
```
257
eslint
258
eslint-plugin-import
259
eslint-plugin-prettier
260
eslint-plugin-jest
261
eslint-plugin-mocha
262
@eslint/js
263
globals
264
```
265
```Javascript
266
eslint.config.mjs
267
import pluginJs from "@eslint/js";
268
import pluginChaiFriendly from "eslint-plugin-chai-friendly";
269
import mochaPlugin from "eslint-plugin-mocha";
270
import globals from "globals";
271
272
import { commonConfigs } from "./common.config.mjs";
273
274
/** @type {import('eslint').Linter.Config[]} */
275
export const jsConfig = [
276
{ languageOptions: { globals: globals.node } },
277
278
pluginJs.configs.recommended,
279
mochaPlugin.configs.flat.recommended,
280
...commonConfigs,
281
282
{
283
ignores: ["*.ts"],
284
},
285
286
{
287
files: ["test/**/*.js"],
288
languageOptions: { globals: globals.mocha },
289
plugins: { "chai-friendly": pluginChaiFriendly, mocha: mochaPlugin },
290
rules: {
291
"mocha/no-async-describe": "off",
292
"mocha/no-mocha-arrows": "off",
293
},
294
},
295
];
296
297
```
298
299
### **ESLint config for Typescript**
300
==**Optional**==
301
302
Add packages:
303
```
304
eslint
305
eslint-plugin-import
306
eslint-plugin-prettier
307
eslint-plugin-jest
308
eslint-plugin-mocha
309
globals
310
@types/eslint__js
311
@typescript-eslint/eslint-plugin
312
@typescript-eslint/parser
313
eslint-import-resolver-typescript
314
typescript-eslint
315
```
316
317
```JavaScript
318
eslint.config.mjs
319
import eslint from "@eslint/js";
320
import pluginJest from "eslint-plugin-jest";
321
import {
322
config as tsEslintConfig,
323
configs as tsEslintConfigs,
324
} from "typescript-eslint";
325
326
import { commonConfigs } from "./common.config.mjs";
327
export default tsEslintConfig(
328
eslint.configs.recommended,
329
...tsEslintConfigs.strictTypeChecked,
330
...tsEslintConfigs.stylisticTypeChecked,
331
...commonConfigs,
332
333
{
334
languageOptions: {
335
parserOptions: {
336
project: ["./tsconfig.eslint.json"],
337
tsconfigRootDir: process.cwd(),
338
},
339
},
340
},
341
342
// Jest test files
343
{
344
files: ["**/*.spec.ts", "**/*.test.ts"],
345
languageOptions: {
346
globals: pluginJest.environments.globals.globals,
347
},
348
plugins: { jest: pluginJest },
349
rules: {
350
"jest/no-disabled-tests": "warn",
351
"jest/no-focused-tests": "warn",
352
"jest/no-identical-title": "error",
353
"jest/prefer-to-have-length": "warn",
354
"jest/valid-expect": "error",
355
},
356
},
357
358
{
359
files: ["**/*.js", "**/*.mjs"],
360
...tsEslintConfigs.disableTypeChecked,
361
},
362
);
363
364
365
366
```
367
368
```JavaScript
369
tsconfig.eslint.json
370
{
371
"extends": "./tsconfig.json",
372
"compilerOptions": {
373
"noEmit": true,
374
"types": ["jest", "node"]
375
},
376
"include": ["src", "jest.config.ts", "jest.setup.ts", "**/*.spec.ts"],
377
"exclude": ["dist"]
378
}
379
380
```
381
382
For monorepo, avoid copy-pasting these config files across all workspaces - remember DRY principle. Create a new workspace package and export it from there.
383
384
Add commands in your package.json file:
385
386
```
387
"lint:fix": "eslint --fix",
388
"lint": "eslint",
389
```
390
391
### **VSCode setup **
392
==**Recommended**==
393
394
Install the extensions:
395
```
396
dbaeumer.vscode-eslint
397
esbenp.prettier-vscode
398
editorconfig.editorconfig
399
```
400
Create .vscode folder at the root of your repo, add the file “settings.json”:
401
```JavaScript
402
settings.json
403
{
404
"cSpell.enabled": false,
405
"editor.codeActionsOnSave": {
406
"source.fixAll.eslint": "explicit"
407
},
408
"editor.defaultFormatter": "esbenp.prettier-vscode",
409
"editor.formatOnPaste": true,
410
"editor.formatOnSave": true,
411
"eslint.useESLintClass": true,
412
"eslint.enable": true,
413
"eslint.validate": ["javascript", "typescript"],
414
"eslint.format.enable": true,
415
"eslint.workingDirectories": [
416
{
417
"mode": "auto"
418
}
419
],
420
"search.exclude": {
421
"**/.pnp.*": true,
422
"**/.yarn": true
423
},
424
"[json]": {
425
"editor.codeActionsOnSave": {
426
"source.fixAll": "never"
427
}
428
},
429
"typescript.preferences.importModuleSpecifier": "relative"
430
}
431
432
```
433
434
### **Testing framework selection**
435
==**Recommended**==
436
437
In most of our legacy backend repositories, the “mocha” is in use, but I advise migration to “jest”. Why is it better:
438
- Extended possibilities of mocking the modules, functions, properties. You may be sure you’re testing only your internal code with no side impact.
439
- Rich variety of the reporters. You may report into a file or a command line the details and output
440
- Watch mode with filters by file or testcase name
441
- Report on code coverage with the tests.