From 5495c1c538fa9b6d55ed891a1a4e2f5f7e2cb376 Mon Sep 17 00:00:00 2001 From: ahmad abdolsaheb Date: Fri, 13 Nov 2026 15:03:08 +0300 Subject: [PATCH 1/5] build: move from Create React App to Vite, React 19 and Node 24 CRA is deprecated and Node 20 is end of life. Netlify now publishes dist/. REACT_APP_ env vars still work, so no Netlify change is needed for Sentry. --- .eslintrc | 19 - .eslintrc-base.json | 175 - .gitignore | 5 +- .npmrc | 3 - .nvmrc | 2 +- .prettierignore | 4 + .prettierrc | 3 +- README.md | 12 +- eslint.config.js | 35 + public/index.html => index.html | 5 +- netlify.toml | 6 +- package-lock.json | 23954 ++++++------------------------ package.json | 81 +- sample.env | 6 +- src/index.js | 16 - src/main.jsx | 19 + src/setupTests.js | 22 - vite.config.js | 16 + 18 files changed, 4996 insertions(+), 19387 deletions(-) delete mode 100644 .eslintrc delete mode 100644 .eslintrc-base.json create mode 100644 .prettierignore create mode 100644 eslint.config.js rename public/index.html => index.html (96%) delete mode 100644 src/index.js create mode 100644 src/main.jsx delete mode 100644 src/setupTests.js create mode 100644 vite.config.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index f9804cf1..00000000 --- a/.eslintrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": [ - "react-app", - "./.eslintrc-base.json", - "plugin:prettier/recommended" - ], - "globals": { - "Promise": true, - "window": true, - "$": true, - "ga": true, - "jQuery": true, - "router": true - }, - "settings": { - "import/ignore": ["node_modules", "\\.json$"], - "import/extensions": [".js", ".jsx"] - } -} diff --git a/.eslintrc-base.json b/.eslintrc-base.json deleted file mode 100644 index 331d94d9..00000000 --- a/.eslintrc-base.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "rules": { - "max-len": [ - "error", - { "code": 80, "ignoreUrls": true, "ignoreTemplateLiterals": true } - ], - "block-scoped-var": 0, - "brace-style": [2, "1tbs", { "allowSingleLine": true }], - "camelcase": 2, - "comma-dangle": 2, - "comma-spacing": [2, { "before": false, "after": true }], - "comma-style": [2, "last"], - "complexity": 0, - "consistent-return": 2, - "consistent-this": 0, - "curly": 2, - "default-case": 2, - "dot-notation": 0, - "eol-last": 2, - "eqeqeq": 2, - "func-call-spacing": 2, - "func-names": 0, - "func-style": 0, - "guard-for-in": 2, - "handle-callback-err": 2, - "import/default": 2, - "import/export": 2, - "import/extensions": [0, "always"], - "import/first": 2, - "import/named": 2, - "import/namespace": 2, - "import/newline-after-import": 2, - "import/no-duplicates": 2, - "import/no-unresolved": 2, - "import/unambiguous": 2, - "jsx-quotes": [2, "prefer-single"], - "key-spacing": [2, { "beforeColon": false, "afterColon": true }], - "keyword-spacing": [2], - "max-depth": 0, - "max-nested-callbacks": 0, - "max-params": 0, - "max-statements": 0, - "new-cap": 0, - "new-parens": 2, - "no-alert": 2, - "no-array-constructor": 2, - "no-bitwise": 2, - "no-caller": 2, - "no-cond-assign": 2, - "no-console": 0, - "no-constant-condition": 2, - "no-control-regex": 2, - "no-debugger": 2, - "no-delete-var": 2, - "no-div-regex": 2, - "no-dupe-keys": 2, - "no-else-return": 0, - "no-empty": 2, - "no-empty-character-class": 2, - "no-eq-null": 2, - "no-eval": 2, - "no-ex-assign": 2, - "no-extend-native": 2, - "no-extra-bind": 2, - "no-extra-boolean-cast": 2, - "no-extra-parens": 0, - "no-extra-semi": 2, - "no-fallthrough": 2, - "no-floating-decimal": 2, - "no-func-assign": 2, - "no-global-assign": 2, - "no-implied-eval": 2, - "no-inline-comments": 2, - "no-inner-declarations": 2, - "no-invalid-regexp": 2, - "no-irregular-whitespace": 2, - "no-iterator": 2, - "no-label-var": 2, - "no-labels": 2, - "no-lone-blocks": 2, - "no-lonely-if": 2, - "no-loop-func": 2, - "no-mixed-requires": 0, - "no-mixed-spaces-and-tabs": 2, - "no-multi-spaces": 2, - "no-multi-str": 2, - "no-multiple-empty-lines": [2, { "max": 2 }], - "no-nested-ternary": 2, - "no-new": 2, - "no-new-func": 2, - "no-new-object": 2, - "no-new-require": 2, - "no-new-wrappers": 2, - "no-obj-calls": 2, - "no-octal": 2, - "no-octal-escape": 2, - "no-path-concat": 2, - "no-plusplus": 0, - "no-process-env": 0, - "no-process-exit": 2, - "no-proto": 2, - "no-regex-spaces": 2, - "no-reserved-keys": 0, - "no-restricted-modules": 0, - "no-return-assign": 2, - "no-script-url": 2, - "no-self-compare": 2, - "no-sequences": 2, - "no-shadow": 0, - "no-shadow-restricted-names": 2, - "no-sparse-arrays": 2, - "no-sync": 0, - "no-ternary": 0, - "no-trailing-spaces": 2, - "no-undef": 2, - "no-undef-init": 2, - "no-undefined": 2, - "no-underscore-dangle": 0, - "no-unreachable": 2, - "no-unsafe-negation": 2, - "no-unused-expressions": 2, - "no-unused-vars": 2, - "no-use-before-define": 0, - "no-void": 0, - "no-warning-comments": [2, { "terms": ["fixme"], "location": "start" }], - "no-with": 2, - "one-var": 0, - "operator-assignment": 0, - "padded-blocks": 0, - "prettier/prettier": "error", - "quote-props": [2, "as-needed"], - "quotes": [2, "single", "avoid-escape"], - "radix": 2, - "react/display-name": 2, - "react/jsx-boolean-value": [2, "always"], - "react/jsx-closing-bracket-location": [ - 2, - { "selfClosing": "line-aligned", "nonEmpty": "props-aligned" } - ], - "react/jsx-no-undef": 2, - "react/jsx-sort-props": [2, { "ignoreCase": true }], - "react/jsx-uses-react": 2, - "react/jsx-uses-vars": 2, - "react/jsx-wrap-multilines": 2, - "react/no-did-mount-set-state": 2, - "react/no-did-update-set-state": 2, - "react/no-multi-comp": [2, { "ignoreStateless": true }], - "react/no-unescaped-entities": 0, - "react/no-unknown-property": 2, - "react/prop-types": 2, - "react/react-in-jsx-scope": 2, - "react/self-closing-comp": 2, - "react/sort-prop-types": 2, - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "error", - "semi": [2, "always"], - "semi-spacing": [2, { "before": false, "after": true }], - "sort-vars": 0, - "space-before-blocks": [2, "always"], - "space-before-function-paren": [2, "never"], - "space-in-brackets": 0, - "space-in-parens": 0, - "space-infix-ops": 2, - "space-unary-ops": [2, { "words": true, "nonwords": false }], - "spaced-comment": [2, "always", { "exceptions": ["-"] }], - "strict": 0, - "use-isnan": 2, - "valid-jsdoc": 0, - "valid-typeof": 2, - "vars-on-top": 0, - "wrap-iife": [2, "any"], - "wrap-regex": 2, - "yoda": 0 - } -} diff --git a/.gitignore b/.gitignore index 340ac145..f0f3202f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ .env.production.local # production -/build +/dist # misc .DS_Store @@ -36,3 +36,6 @@ yarn-error.log* ### Netlify ### .netlify + +# cypress +/cypress/screenshots diff --git a/.npmrc b/.npmrc index 4976a3dc..b6f27f13 100644 --- a/.npmrc +++ b/.npmrc @@ -1,4 +1 @@ -CYPRESS_INSTALL_BINARY=0 engine-strict=true -enable-pre-post-scripts=true -package-manager-strict=false diff --git a/.nvmrc b/.nvmrc index 5bd68117..a45fd52c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.19.0 +24 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..207c5479 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +dist +package-lock.json +cypress/videos +cypress/screenshots diff --git a/.prettierrc b/.prettierrc index 5e01cb48..4378a1f0 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "endOfLine":"auto", + "endOfLine": "auto", "semi": true, "singleQuote": true, "jsxSingleQuote": true, @@ -7,4 +7,3 @@ "trailingComma": "none", "arrowParens": "avoid" } - \ No newline at end of file diff --git a/README.md b/README.md index d4f38b2d..8173f581 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,19 @@ ## Coderadio Client UI -This repository powers the current client application for the Code Radio at: . +This repository powers the current client application for the Code Radio at: . Eventually we will move this over to our Gatsby based client application for our curriculum and user profiles. You can learn more about the coderadio here: ### Local setup -`npm ci` then `npm start` will open the app. +Use the Node version in `.nvmrc` (`nvm use`), then: -To send errors to Sentry: `cp sample.env .env.local` and fill in the Sentry DSN from the project settings \ No newline at end of file +- `npm ci` installs dependencies +- `npm start` runs the dev server on +- `npm test` runs the unit tests +- `npm run e2e` starts the dev server and runs the Cypress tests +- `npm run lint` checks ESLint and Prettier + +To send errors to Sentry: `cp sample.env .env.local` and fill in the Sentry DSN from the project settings. The same file lets you point a local build at a different AzuraCast server. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..3541a0f5 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,35 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import prettier from 'eslint-config-prettier'; + +export default [ + { ignores: ['dist', 'cypress/videos', 'cypress/screenshots'] }, + js.configs.recommended, + reactHooks.configs.flat.recommended, + { + files: ['**/*.{js,jsx}'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: { ...globals.browser }, + parserOptions: { ecmaFeatures: { jsx: true } } + } + }, + { + files: ['src/**/*.test.{js,jsx}', 'src/test/**'], + languageOptions: { globals: { ...globals.node } } + }, + { + files: ['cypress/**', '*.config.js'], + languageOptions: { + globals: { + ...globals.node, + ...globals.mocha, + cy: 'readonly', + expect: 'readonly' + } + } + }, + prettier +]; diff --git a/public/index.html b/index.html similarity index 96% rename from public/index.html rename to index.html index eb265242..82b79387 100644 --- a/public/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + @@ -100,8 +100,9 @@
+ -