From 183dc409167b136900acd88c5af779990b2de0db Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Wed, 2 Apr 2025 18:35:00 +0200 Subject: [PATCH] [FIX] `Out of memory` while running app localy (#11341) # Introduction Lately encountering a lot of out of memory error when running twenty-front in watch mode with both TypeScript and lint checkers ```ts Error: Worker terminated due to reaching memory limit: JS heap out of memory at new NodeError (node:internal/errors:405:5) at [kOnExit] (node:internal/worker:287:26) at Worker..onexit (node:internal/worker:209:20) ``` The existing configuration looks like this: ```ts // packages/twenty-front/vite.config.ts 'cd ../.. && eslint packages/twenty-front --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs', ``` This is wrong as computing the root eslintrc completely omitting twenty-front's one ***and its ignorePattern*** so will be checking in `node_modules` etc checking for project-structure :). For example this a [snippet](https://gist.github.com/prastoin/d7f8ad4ef5eb2f7732209b756a38094c) of the above commands errors. We can see rule that should be disabled by `eslintrc.react.cjs` extension made from twenty-front `eslintrc` : ```ts /Users/paulrastoin/ws/twenty-two/packages/twenty-front/src/modules/settings/data-model/fields/forms/components/__stories__/SettingsDataModelFieldSettingsFormCard.stories.tsx 23:27 warning Forbidden non-null assertion @typescript-eslint/no-non-null-assertion ``` ## Fixes - consume the `twenty-front` package eslint configuration within the vite lint checker - eslint overrides extends are getting merged based on glob inclusion of their files declarations - any linted files should be included in one of our `tsconfig` - removed redundant and counter-productive negative `ignorePatterns`, as eslint will naturally only lint files within configuration file directory by default which will result making it go through local `node_modules` project structure ## Now Less cpu usage <3.5 gb and faster ```ts // from packages/twenty-front TIMING=1 npx eslint . --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs --debug #... Rule | Time (ms) | Relative :-----------------------------------------------|----------:|--------: project-structure/folder-structure | 19578.927 | 20.2% prettier/prettier | 13746.156 | 14.2% no-redeclare | 9546.570 | 9.9% @nx/workspace-explicit-boolean-predicates-in-if | 8167.805 | 8.4% @typescript-eslint/no-unused-vars | 6872.803 | 7.1% import/no-relative-packages | 6577.273 | 6.8% @nx/enforce-module-boundaries | 6520.945 | 6.7% import/no-duplicates | 4987.476 | 5.2% react/no-direct-mutation-state | 2323.082 | 2.4% react/require-render-return | 1155.261 | 1.2% ``` ## Conclusion Please note that `nx linter` might not be as strict as vite config eslint runner --------- Co-authored-by: Charles Bochet --- .eslintrc.cjs => .eslintrc.global.cjs | 1 + .eslintrc.react.cjs | 5 +--- .../twenty-chrome-extension/.eslintrc.cjs | 13 +++++++---- packages/twenty-emails/.eslintrc.cjs | 7 +++--- packages/twenty-front/.eslintrc.cjs | 7 +++--- packages/twenty-front/package.json | 23 ++++++++++++++++++- packages/twenty-front/project.json | 4 ---- packages/twenty-front/setupTests.ts | 2 +- packages/twenty-front/tsconfig.spec.json | 2 +- packages/twenty-front/vite.config.ts | 3 ++- packages/twenty-server/.eslintrc.cjs | 4 ++-- packages/twenty-shared/.eslintrc.cjs | 7 +++--- packages/twenty-ui/.eslintrc.cjs | 7 +++--- packages/twenty-website/.eslintrc.js | 2 +- yarn.lock | 23 ++++++++++++++++++- 15 files changed, 74 insertions(+), 36 deletions(-) rename .eslintrc.cjs => .eslintrc.global.cjs (99%) diff --git a/.eslintrc.cjs b/.eslintrc.global.cjs similarity index 99% rename from .eslintrc.cjs rename to .eslintrc.global.cjs index b56016745..2a8ab0b2a 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.global.cjs @@ -1,6 +1,7 @@ module.exports = { root: true, extends: ['plugin:prettier/recommended', 'plugin:lingui/recommended'], + ignorePatterns: ['node_modules'], plugins: [ '@nx', 'prefer-arrow', diff --git a/.eslintrc.react.cjs b/.eslintrc.react.cjs index 77c307222..ce434e84d 100644 --- a/.eslintrc.react.cjs +++ b/.eslintrc.react.cjs @@ -10,10 +10,7 @@ module.exports = { plugins: ['react-hooks', 'react-refresh'], overrides: [ { - files: ['*.ts', '*.tsx'], - parserOptions: { - project: ['./tsconfig.base.{json,*.json}'], - }, + files: ['**/*.ts', '**/*.tsx'], rules: { 'no-restricted-imports': [ 'error', diff --git a/packages/twenty-chrome-extension/.eslintrc.cjs b/packages/twenty-chrome-extension/.eslintrc.cjs index d5d38934e..836a34a41 100644 --- a/packages/twenty-chrome-extension/.eslintrc.cjs +++ b/packages/twenty-chrome-extension/.eslintrc.cjs @@ -1,11 +1,16 @@ module.exports = { - extends: ['../../.eslintrc.cjs', '../../.eslintrc.react.cjs'], - ignorePatterns: ['!**/*', 'node_modules', 'dist', '**/generated/*'], + root: true, + extends: ['../../.eslintrc.global.cjs', '../../.eslintrc.react.cjs'], + ignorePatterns: [ + 'node_modules', + 'dist', + '**/generated/*', + ], overrides: [ { - files: ['*.ts', '*.tsx'], + files: ['**/*.ts', '**/*.tsx'], parserOptions: { - project: ['packages/twenty-chrome-extension/tsconfig.{json,*.json}'], + project: ['packages/twenty-chrome-extension/tsconfig.*.json'], }, rules: { '@nx/workspace-explicit-boolean-predicates-in-if': 'warn', diff --git a/packages/twenty-emails/.eslintrc.cjs b/packages/twenty-emails/.eslintrc.cjs index fba68ff6c..db6260e8d 100644 --- a/packages/twenty-emails/.eslintrc.cjs +++ b/packages/twenty-emails/.eslintrc.cjs @@ -1,11 +1,10 @@ module.exports = { - extends: ['../../.eslintrc.cjs', '../../.eslintrc.react.cjs'], - ignorePatterns: ['!**/*'], + extends: ['../../.eslintrc.global.cjs', '../../.eslintrc.react.cjs'], overrides: [ { - files: ['*.ts', '*.tsx'], + files: ['**/*.ts', '**/*.tsx'], parserOptions: { - project: ['packages/twenty-emails/tsconfig.{json,*.json}'], + project: ['packages/twenty-emails/tsconfig.*.json'], }, rules: { '@nx/dependency-checks': 'error', diff --git a/packages/twenty-front/.eslintrc.cjs b/packages/twenty-front/.eslintrc.cjs index 7d4a4d87f..35782f8a4 100644 --- a/packages/twenty-front/.eslintrc.cjs +++ b/packages/twenty-front/.eslintrc.cjs @@ -1,9 +1,8 @@ const path = require('path'); module.exports = { - extends: ['../../.eslintrc.cjs', '../../.eslintrc.react.cjs'], + extends: ['../../.eslintrc.global.cjs', '../../.eslintrc.react.cjs'], ignorePatterns: [ - '!**/*', 'node_modules', 'mockServiceWorker.js', '**/generated*/*', @@ -19,9 +18,9 @@ module.exports = { ], overrides: [ { - files: ['*.ts', '*.tsx'], + files: ['**/*.ts', '**/*.tsx'], parserOptions: { - project: ['packages/twenty-front/tsconfig.{json,*.json}'], + project: ['packages/twenty-front/tsconfig.*.json'], }, plugins: ['project-structure'], settings: { diff --git a/packages/twenty-front/package.json b/packages/twenty-front/package.json index 1d8db18f4..d967ea576 100644 --- a/packages/twenty-front/package.json +++ b/packages/twenty-front/package.json @@ -62,6 +62,27 @@ "@lingui/cli": "^5.1.2", "@lingui/swc-plugin": "^5.1.0", "@lingui/vite-plugin": "^5.1.2", - "@types/file-saver": "^2" + "@types/file-saver": "^2", + "@typescript-eslint/eslint-plugin": "6.21.0", + "@typescript-eslint/experimental-utils": "^5.62.0", + "@typescript-eslint/parser": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "eslint": "^8.53.0", + "eslint-config-next": "14.0.4", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-lingui": "^0.9.0", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-project-structure": "^3.9.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.4", + "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-storybook": "^0.6.15", + "eslint-plugin-unicorn": "^51.0.1", + "eslint-plugin-unused-imports": "^3.0.0", + "optionator": "^0.9.1" } } diff --git a/packages/twenty-front/project.json b/packages/twenty-front/project.json index 4f541de4f..7453435fd 100644 --- a/packages/twenty-front/project.json +++ b/packages/twenty-front/project.json @@ -52,10 +52,6 @@ "typecheck": {}, "lint": { "options": { - "lintFilePatterns": [ - "{projectRoot}/src/**/*.{ts,tsx,json}", - "{projectRoot}/package.json" - ], "maxWarnings": 0, "reportUnusedDisableDirectives": "error" }, diff --git a/packages/twenty-front/setupTests.ts b/packages/twenty-front/setupTests.ts index d995aadc1..e5aa41c46 100644 --- a/packages/twenty-front/setupTests.ts +++ b/packages/twenty-front/setupTests.ts @@ -13,4 +13,4 @@ import '@testing-library/jest-dom'; */ global.structuredClone = (val) => { return JSON.parse(JSON.stringify(val)); -}; \ No newline at end of file +}; diff --git a/packages/twenty-front/tsconfig.spec.json b/packages/twenty-front/tsconfig.spec.json index 026604daa..d598c0976 100644 --- a/packages/twenty-front/tsconfig.spec.json +++ b/packages/twenty-front/tsconfig.spec.json @@ -4,7 +4,7 @@ "types": ["jest", "node"], "baseUrl": "../..", "paths": { - "@/*": ["./packages/twenty-front/src/modules/*"], + "@/*": ["./packages/twenty-front/src/modules/*"], "~/*": ["./packages/twenty-front/src/*"], "twenty-ui": ["./packages/twenty-ui/src/index.ts"], "@ui/*": ["./packages/twenty-ui/src/*"] diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index e694870ea..73839a395 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -63,7 +63,8 @@ export default defineConfig(({ command, mode }) => { if (VITE_DISABLE_ESLINT_CHECKER !== 'true') { checkers['eslint'] = { lintCommand: - 'cd ../.. && eslint packages/twenty-front --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs', + // Appended to packages/twenty-front/.eslintrc.cjs + 'eslint ../../packages/twenty-front --report-unused-disable-directives --max-warnings 0 --config .eslintrc.cjs', }; } diff --git a/packages/twenty-server/.eslintrc.cjs b/packages/twenty-server/.eslintrc.cjs index ee2aeedea..008a3fbbf 100644 --- a/packages/twenty-server/.eslintrc.cjs +++ b/packages/twenty-server/.eslintrc.cjs @@ -1,6 +1,6 @@ module.exports = { plugins: ['@stylistic'], - extends: ['../../.eslintrc.cjs'], + extends: ['../../.eslintrc.global.cjs'], ignorePatterns: [ 'src/engine/workspace-manager/demo-objects-prefill-data/**', 'src/engine/seeder/data-seeds/**', @@ -9,7 +9,7 @@ module.exports = { ], overrides: [ { - files: ['*.ts'], + files: ['**/*.ts'], parserOptions: { project: ['packages/twenty-server/tsconfig.json'], }, diff --git a/packages/twenty-shared/.eslintrc.cjs b/packages/twenty-shared/.eslintrc.cjs index dba2eae3d..01d83ee4f 100644 --- a/packages/twenty-shared/.eslintrc.cjs +++ b/packages/twenty-shared/.eslintrc.cjs @@ -1,11 +1,10 @@ module.exports = { - extends: ['../../.eslintrc.cjs'], - ignorePatterns: ['!**/*'], + extends: ['../../.eslintrc.global.cjs'], overrides: [ { - files: ['*.ts', '*.tsx'], + files: ['**/*.ts'], parserOptions: { - project: ['packages/twenty-shared/tsconfig.{json,*.json}'], + project: ['packages/twenty-shared/tsconfig.*.json'], }, rules: { '@nx/dependency-checks': 'error', diff --git a/packages/twenty-ui/.eslintrc.cjs b/packages/twenty-ui/.eslintrc.cjs index 50ca95121..b56288083 100644 --- a/packages/twenty-ui/.eslintrc.cjs +++ b/packages/twenty-ui/.eslintrc.cjs @@ -1,11 +1,10 @@ module.exports = { - extends: ['../../.eslintrc.cjs', '../../.eslintrc.react.cjs'], - ignorePatterns: ['!**/*'], + extends: ['../../.eslintrc.global.cjs', '../../.eslintrc.react.cjs'], overrides: [ { - files: ['*.ts', '*.tsx'], + files: ['**/*.ts', '**/*.tsx'], parserOptions: { - project: ['packages/twenty-ui/tsconfig.{json,*.json}'], + project: ['packages/twenty-ui/tsconfig.*.json'], }, rules: { 'no-restricted-imports': [ diff --git a/packages/twenty-website/.eslintrc.js b/packages/twenty-website/.eslintrc.js index 3afe9205c..0113d397a 100644 --- a/packages/twenty-website/.eslintrc.js +++ b/packages/twenty-website/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = { - extends: ['../../.eslintrc.cjs', 'plugin:@next/next/recommended'], + extends: ['../../.eslintrc.global.cjs', 'plugin:@next/next/recommended'], rules: { 'no-console': 'off', 'prefer-arrow/prefer-arrow-functions': 'off', diff --git a/yarn.lock b/yarn.lock index b8094650b..0ff368dfc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44955,7 +44955,7 @@ __metadata: languageName: node linkType: hard -"optionator@npm:^0.9.3": +"optionator@npm:^0.9.1, optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" dependencies: @@ -53144,10 +53144,31 @@ __metadata: "@tiptap/extension-text-style": "npm:^2.10.4" "@tiptap/react": "npm:^2.10.4" "@types/file-saver": "npm:^2" + "@typescript-eslint/eslint-plugin": "npm:6.21.0" + "@typescript-eslint/experimental-utils": "npm:^5.62.0" + "@typescript-eslint/parser": "npm:6.21.0" + "@typescript-eslint/utils": "npm:6.21.0" "@xyflow/react": "npm:^12.4.2" buffer: "npm:^6.0.3" docx: "npm:^9.1.0" + eslint: "npm:^8.53.0" + eslint-config-next: "npm:14.0.4" + eslint-config-prettier: "npm:^9.1.0" + eslint-plugin-import: "npm:2.29.1" + eslint-plugin-jsx-a11y: "npm:^6.8.0" + eslint-plugin-lingui: "npm:^0.9.0" + eslint-plugin-prefer-arrow: "npm:^1.2.3" + eslint-plugin-prettier: "npm:^5.1.2" + eslint-plugin-project-structure: "npm:^3.9.1" + eslint-plugin-react: "npm:^7.33.2" + eslint-plugin-react-hooks: "npm:^4.6.0" + eslint-plugin-react-refresh: "npm:^0.4.4" + eslint-plugin-simple-import-sort: "npm:^10.0.0" + eslint-plugin-storybook: "npm:^0.6.15" + eslint-plugin-unicorn: "npm:^51.0.1" + eslint-plugin-unused-imports: "npm:^3.0.0" file-saver: "npm:^2.0.5" + optionator: "npm:^0.9.1" recoil-sync: "npm:^0.2.0" transliteration: "npm:^2.3.5" twenty-shared: "workspace:*"