diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3b1538dd..fac28cf5 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -12,10 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: nrwl/nx-set-shas@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 'lts/*' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f3ac63f..270b1e31 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.gitignore b/.gitignore index 2df6ebc3..34daf06a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ coverage .idea .eslintcache !packages/redux-devtools-slider-monitor/examples/todomvc/dist/index.html -.nx/cache +.nx diff --git a/README.md b/README.md index d1af9c91..8ff056c4 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ It can be used as a browser extension (for [Chrome](https://chrome.google.com/we ## Development -This is a monorepo powered by [pnpm](https://pnpm.io/) and [Nx](https://nx.dev/). [Install pnpm](https://pnpm.io/installation) and run `pnpm install` to get started. Each package's dependencies need to be built before the package itself can be built. You can either build all the packages (i.e., `pnpm run build:all`) or use Nx commands to build only the packages necessary for the packages you're working on (i.e., `pnpm nx build remotedev-redux-devtools-extension`). +This is a monorepo powered by [pnpm](https://pnpm.io/). [Install pnpm](https://pnpm.io/installation) and run `pnpm install` to get started. Each package's dependencies need to be built before the package itself can be built. You can either build all the packages (i.e., `pnpm run build:all`) or use pnpm workspace commands to build only the packages necessary for the packages you're working on (i.e., `pnpm --filter "remotedev-redux-devtools-extension" build`). ## Backers diff --git a/eslint.js.config.base.mjs b/eslint.js.config.base.mjs new file mode 100644 index 00000000..31f147f9 --- /dev/null +++ b/eslint.js.config.base.mjs @@ -0,0 +1,4 @@ +import eslint from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default [eslint.configs.recommended, eslintConfigPrettier]; diff --git a/eslint.js.react.jest.config.base.mjs b/eslint.js.react.jest.config.base.mjs new file mode 100644 index 00000000..47997596 --- /dev/null +++ b/eslint.js.react.jest.config.base.mjs @@ -0,0 +1,43 @@ +import eslint from '@eslint/js'; +import react from 'eslint-plugin-react'; +import { fixupPluginRules } from '@eslint/compat'; +import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; +import jest from 'eslint-plugin-jest'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default [ + { + files: ['test/**/*.js', 'test/**/*.jsx'], + ...eslint.configs.recommended, + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + ...react.configs.flat.recommended, + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + settings: { + react: { + version: 'detect', + }, + }, + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + plugins: { + 'react-hooks': fixupPluginRules(eslintPluginReactHooks), + }, + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + ...jest.configs['flat/recommended'], + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + ...jest.configs['jest/style'], + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + ...eslintConfigPrettier, + }, +]; diff --git a/eslint.ts.config.base.mjs b/eslint.ts.config.base.mjs new file mode 100644 index 00000000..2af98f40 --- /dev/null +++ b/eslint.ts.config.base.mjs @@ -0,0 +1,55 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default (tsconfigRootDir, files = ['**/*.ts'], project = true) => [ + { + files, + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files, + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files, + ...config, + })), + { + files, + languageOptions: { + parserOptions: { + project, + tsconfigRootDir, + }, + }, + }, + { + files, + ...eslintConfigPrettier, + }, + { + files, + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + }, + }, +]; diff --git a/eslint.ts.jest.config.base.mjs b/eslint.ts.jest.config.base.mjs new file mode 100644 index 00000000..fd916a03 --- /dev/null +++ b/eslint.ts.jest.config.base.mjs @@ -0,0 +1,64 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import jest from 'eslint-plugin-jest'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default (tsconfigRootDir) => [ + { + files: ['test/**/*.ts'], + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files: ['test/**/*.ts'], + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files: ['test/**/*.ts'], + ...config, + })), + { + files: ['test/**/*.ts'], + languageOptions: { + parserOptions: { + project: ['./tsconfig.test.json'], + tsconfigRootDir, + }, + }, + }, + { + files: ['test/**/*.ts'], + ...jest.configs['flat/recommended'], + }, + { + files: ['test/**/*.ts'], + ...jest.configs['jest/style'], + }, + { + files: ['test/**/*.ts'], + ...eslintConfigPrettier, + }, + { + files: ['test/**/*.ts'], + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + }, + }, +]; diff --git a/eslint.ts.react.config.base.mjs b/eslint.ts.react.config.base.mjs new file mode 100644 index 00000000..110f1e8a --- /dev/null +++ b/eslint.ts.react.config.base.mjs @@ -0,0 +1,89 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import react from 'eslint-plugin-react'; +import { fixupPluginRules } from '@eslint/compat'; +import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default ( + tsconfigRootDir, + files = ['**/*.ts', '**/*.tsx'], + project = true, +) => [ + { + files, + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files, + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files, + ...config, + })), + { + files, + languageOptions: { + parserOptions: { + project, + tsconfigRootDir, + }, + }, + }, + { + files, + ...react.configs.flat.recommended, + }, + { + files, + settings: { + react: { + version: 'detect', + }, + }, + }, + { + files, + plugins: { + 'react-hooks': fixupPluginRules(eslintPluginReactHooks), + }, + }, + { + files, + ...eslintConfigPrettier, + }, + { + files, + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-misused-promises': [ + 'error', + { + checksVoidReturn: { + attributes: false, + }, + }, + ], + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + 'react/prop-types': 'off', + }, + }, +]; diff --git a/eslint.ts.react.jest.config.base.mjs b/eslint.ts.react.jest.config.base.mjs new file mode 100644 index 00000000..f0db2ab2 --- /dev/null +++ b/eslint.ts.react.jest.config.base.mjs @@ -0,0 +1,85 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import react from 'eslint-plugin-react'; +import { fixupPluginRules } from '@eslint/compat'; +import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; +import jest from 'eslint-plugin-jest'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default (tsconfigRootDir) => [ + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...config, + })), + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + languageOptions: { + parserOptions: { + project: ['./tsconfig.test.json'], + tsconfigRootDir, + }, + }, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...react.configs.flat.recommended, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + settings: { + react: { + version: 'detect', + }, + }, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + plugins: { + 'react-hooks': fixupPluginRules(eslintPluginReactHooks), + }, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...jest.configs['flat/recommended'], + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...jest.configs['jest/style'], + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...eslintConfigPrettier, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + }, + }, +]; diff --git a/eslintrc.js.base.json b/eslintrc.js.base.json deleted file mode 100644 index a059126a..00000000 --- a/eslintrc.js.base.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parser": "@babel/eslint-parser" -} diff --git a/eslintrc.ts.base.json b/eslintrc.ts.base.json deleted file mode 100644 index cdd3764d..00000000 --- a/eslintrc.ts.base.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "prettier" - ], - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/eslintrc.ts.jest.base.json b/eslintrc.ts.jest.base.json deleted file mode 100644 index 8a8cde2d..00000000 --- a/eslintrc.ts.jest.base.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "plugins": ["jest"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:jest/recommended", - "plugin:jest/style", - "prettier" - ], - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/eslintrc.ts.react.base.json b/eslintrc.ts.react.base.json deleted file mode 100644 index f17dc31c..00000000 --- a/eslintrc.ts.react.base.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - } - }, - "plugins": ["@typescript-eslint", "react"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - "prettier" - ], - "settings": { - "react": { - "version": "detect" - } - }, - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-misused-promises": [ - "error", - { - "checksVoidReturn": { - "attributes": false - } - } - ], - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/eslintrc.ts.react.jest.base.json b/eslintrc.ts.react.jest.base.json deleted file mode 100644 index 80fbfee6..00000000 --- a/eslintrc.ts.react.jest.base.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "plugins": ["jest"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - "plugin:jest/recommended", - "plugin:jest/style", - "prettier" - ], - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/extension/.eslintignore b/extension/.eslintignore deleted file mode 100644 index d8c3bcd8..00000000 --- a/extension/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -examples diff --git a/extension/.eslintrc b/extension/.eslintrc deleted file mode 100644 index 69fd0840..00000000 --- a/extension/.eslintrc +++ /dev/null @@ -1,31 +0,0 @@ -{ - "root": true, - "extends": "eslint-config-airbnb", - "globals": { - "chrome": true, - "__DEVELOPMENT__": true - }, - "env": { - "browser": true, - "node": true - }, - "rules": { - "react/jsx-uses-react": 2, - "react/jsx-uses-vars": 2, - "react/react-in-jsx-scope": 2, - "react/jsx-quotes": 0, - "block-scoped-var": 0, - "padded-blocks": 0, - "quotes": [1, "single"], - "comma-style": [2, "last"], - "no-use-before-define": [0, "nofunc"], - "func-names": 0, - "prefer-const": 0, - "comma-dangle": 0, - "id-length": 0, - "indent": [2, 2, { "SwitchCase": 1 }], - "new-cap": [2, { "capIsNewExceptions": ["Test"] }], - "default-case": 0 - }, - "plugins": ["react"] -} diff --git a/extension/CHANGELOG.md b/extension/CHANGELOG.md index 88b0b2dc..e518de30 100644 --- a/extension/CHANGELOG.md +++ b/extension/CHANGELOG.md @@ -1,5 +1,60 @@ # remotedev-redux-devtools-extension +## 3.2.7 + +### Patch Changes + +- b25bf13: Send state from background when monitor connects + +## 3.2.6 + +### Patch Changes + +- 50d7682: Fix DevTools from losing connection + +## 3.2.5 + +### Patch Changes + +- eb3ac09: Add logging to background service worker + +## 3.2.4 + +### Patch Changes + +- f1d6158: Fix mocking Chrome API for Electron + +## 3.2.3 + +### Patch Changes + +- fd9f950: Fix monitoring on opening panel +- e49708d: Fix manifest.json for Edge + +## 3.2.1 + +### Patch Changes + +- abd03a7: Fix: only send data to extension if DevTools are open + +## 3.2.0 + +### Minor Changes + +- 83b2c19: Upgrade to Manifest V3 + +## 3.1.11 + +### Patch Changes + +- 73688e1: Fix releasing Firefox extension + +## 3.1.10 + +### Patch Changes + +- 2163bc3: Split large messages sent from background page to devpanel + ## 3.1.9 ### Patch Changes diff --git a/extension/build.mjs b/extension/build.mjs index 86971a68..9c378cf4 100644 --- a/extension/build.mjs +++ b/extension/build.mjs @@ -5,7 +5,7 @@ import pug from 'pug'; const args = process.argv.slice(2); const prod = !args.includes('--dev'); -const commonEsbuildOptions = { +await esbuild.build({ bundle: true, logLevel: 'info', outdir: 'dist', @@ -15,40 +15,24 @@ const commonEsbuildOptions = { 'process.env.NODE_ENV': prod ? '"production"' : '"development"', 'process.env.BABEL_ENV': prod ? '"production"' : '"development"', }, -}; - -await esbuild.build({ - ...commonEsbuildOptions, entryPoints: [ { out: 'background.bundle', in: 'src/background/index.ts' }, { out: 'options.bundle', in: 'src/options/index.tsx' }, - { out: 'window.bundle', in: 'src/window/index.tsx' }, { out: 'remote.bundle', in: 'src/remote/index.tsx' }, { out: 'devpanel.bundle', in: 'src/devpanel/index.tsx' }, { out: 'devtools.bundle', in: 'src/devtools/index.ts' }, { out: 'content.bundle', in: 'src/contentScript/index.ts' }, { out: 'page.bundle', in: 'src/pageScript/index.ts' }, - ...(prod ? [] : [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }]), ], loader: { '.woff2': 'file', }, }); -if (prod) { - await esbuild.build({ - ...commonEsbuildOptions, - entryPoints: [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }], - loader: { - '.js': 'text', - }, - }); -} - console.log(); console.log('Creating HTML files...'); -const htmlFiles = ['devpanel', 'devtools', 'options', 'remote', 'window']; +const htmlFiles = ['devpanel', 'devtools', 'options', 'remote']; for (const htmlFile of htmlFiles) { fs.writeFileSync( `dist/${htmlFile}.html`, diff --git a/extension/chrome/manifest.json b/extension/chrome/manifest.json index 7369d6c8..32153fd2 100644 --- a/extension/chrome/manifest.json +++ b/extension/chrome/manifest.json @@ -1,28 +1,22 @@ { - "version": "3.1.6", + "version": "3.2.7", "name": "Redux DevTools", "description": "Redux DevTools for debugging application's state changes.", "homepage_url": "https://github.com/reduxjs/redux-devtools", - "manifest_version": 2, - "page_action": { + "manifest_version": 3, + "action": { "default_icon": "img/logo/gray.png", "default_title": "Redux DevTools", - "default_popup": "window.html#popup" + "default_popup": "devpanel.html#popup" }, "commands": { - "devtools-left": { - "description": "DevTools window to left" - }, - "devtools-right": { - "description": "DevTools window to right" - }, - "devtools-bottom": { - "description": "DevTools window to bottom" + "devtools-window": { + "description": "DevTools window" }, "devtools-remote": { "description": "Remote DevTools" }, - "_execute_page_action": { + "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+E" } @@ -34,36 +28,37 @@ "128": "img/logo/128x128.png" }, "options_ui": { - "page": "options.html", - "chrome_style": true + "page": "options.html" }, "background": { - "scripts": ["background.bundle.js"], - "persistent": false + "service_worker": "background.bundle.js" }, "content_scripts": [ { "matches": [""], "exclude_globs": ["https://www.google*"], - "js": ["content.bundle.js", "pagewrap.bundle.js"], + "js": ["content.bundle.js"], "run_at": "document_start", "all_frames": true + }, + { + "matches": [""], + "exclude_globs": ["https://www.google*"], + "js": ["page.bundle.js"], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" } ], "devtools_page": "devtools.html", - "web_accessible_resources": ["page.bundle.js"], "externally_connectable": { "ids": ["*"] }, - "permissions": [ - "notifications", - "contextMenus", - "storage", - "file:///*", - "http://*/*", - "https://*/*" - ], - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;", + "permissions": ["notifications", "contextMenus", "storage"], + "host_permissions": ["file:///*", "http://*/*", "https://*/*"], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" + }, "update_url": "https://clients2.google.com/service/update2/crx", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdJEPwY92xUACA9CcDBDBmbdbp8Ap3cKQ0DJTUuVQvqb4FQAv8RtKY3iUjGvdwuAcSJQIZwHXcP2aNDH3TiFik/NhRK2GRW8X3OZyTdkuDueABGP2KEX8q1WQDgjX/rPIinGYztUrvoICw/UerMPwNW62jwGoVU3YhAGf+15CgX2Y6a4tppnf/+1mPedKPidh0RsM+aJY98rX+r1SPAHPcGzMjocLkqcT75DZBXer8VQN14tOOzRCd6T6oy7qm7eWru8lJwcY66qMQvhk0osqEod2G3nA7aTWpmqPFS66VEiecP9PgZlp8gQdgZ3dFhA62exydlD55JuRhiMIR63yQIDAQAB" } diff --git a/extension/docs/Architecture.md b/extension/docs/Architecture.md new file mode 100644 index 00000000..1c8137e1 --- /dev/null +++ b/extension/docs/Architecture.md @@ -0,0 +1,37 @@ +# Architecture Notes + +This document exists to keep track of how the different parts of the Redux DevTools interact, since it's easy to forget how it all works together. This is intended for internal purposes and is just a collection of notes to myself. + +## Entry Points + +### Window + +This is the default view that is shown in the Redux DevTools popup, the Chrome DevTools tab (if direct access to the background page is available), and new popup windows that are created. It has direct access to the background page via `chrome.runtime.getBackgroundPage`. + +### DevPanel + +This is the view that is shown in the Chrome DevTools tab if direct access to the background page is not available. + +Initially this was the view that was always used for the Chrome DevTools tab, but when support to directly access the background page from the DevTools tab was added, [the Window View became the preferred view](https://github.com/zalmoxisus/redux-devtools-extension/pull/580). + +### Remote + +This does not interact with the other parts of the extension at all, it just renders the `App` component from `@redux-devtools/app`. + +It can be triggered by hitting the "Remote" button in any of the other views, which calls `chrome.windows.create` and creates a new window. + +### DevTools + +This is the script that adds the Redux panel in the Chrome DevTools using `chrome.devtools.panels.create`. + +It creates a Window View if it has direct access to the background page, otherwise it creates a DevPanel View. + +Note that this used to always show the DevPanel View, but [started using the Window View by default](https://github.com/zalmoxisus/redux-devtools-extension/pull/580) once direct access to the background page was added to Chrome DevTools tabs. + +### Content Script + +Passes messages between the injected page script and the background page. + +It listens for messages from the injected page script using `window.addEventListener('message', ...)`. It knows the message is from the injected page script if `message.source` is `'@devtools-page'`. See the Chrome DevTools docs where this approach [is documented](https://developer.chrome.com/docs/extensions/how-to/devtools/extend-devtools#evaluated-scripts-to-devtools). + +It creates a connection to the background page using `chrome.runtime.connect` with the name `'tab'` when it receives the first message from the injected page script. diff --git a/extension/edge/manifest.json b/extension/edge/manifest.json index 00fb14e6..dfdc2e33 100644 --- a/extension/edge/manifest.json +++ b/extension/edge/manifest.json @@ -1,28 +1,22 @@ { - "version": "3.1.6", + "version": "3.2.7", "name": "Redux DevTools", "description": "Redux DevTools for debugging application's state changes.", "homepage_url": "https://github.com/reduxjs/redux-devtools", - "manifest_version": 2, - "page_action": { + "manifest_version": 3, + "action": { "default_icon": "img/logo/gray.png", "default_title": "Redux DevTools", - "default_popup": "window.html#popup" + "default_popup": "devpanel.html#popup" }, "commands": { - "devtools-left": { - "description": "DevTools window to left" - }, - "devtools-right": { - "description": "DevTools window to right" - }, - "devtools-bottom": { - "description": "DevTools window to bottom" + "devtools-window": { + "description": "DevTools window" }, "devtools-remote": { "description": "Remote DevTools" }, - "_execute_page_action": { + "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+E" } @@ -34,34 +28,35 @@ "128": "img/logo/128x128.png" }, "options_ui": { - "page": "options.html", - "chrome_style": true + "page": "options.html" }, "background": { - "scripts": ["background.bundle.js"], - "persistent": false + "service_worker": "background.bundle.js" }, "content_scripts": [ { "matches": [""], "exclude_globs": ["https://www.google*"], - "js": ["content.bundle.js", "pagewrap.bundle.js"], + "js": ["content.bundle.js"], "run_at": "document_start", "all_frames": true + }, + { + "matches": [""], + "exclude_globs": ["https://www.google*"], + "js": ["page.bundle.js"], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" } ], "devtools_page": "devtools.html", - "web_accessible_resources": ["page.bundle.js"], "externally_connectable": { "ids": ["*"] }, - "permissions": [ - "notifications", - "contextMenus", - "storage", - "file:///*", - "http://*/*", - "https://*/*" - ], - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" + "permissions": ["notifications", "contextMenus", "storage"], + "host_permissions": ["file:///*", "http://*/*", "https://*/*"], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" + } } diff --git a/extension/eslint.config.mjs b/extension/eslint.config.mjs new file mode 100644 index 00000000..18e89a79 --- /dev/null +++ b/extension/eslint.config.mjs @@ -0,0 +1,38 @@ +import globals from 'globals'; +import eslintJs from '../eslint.js.config.base.mjs'; +import eslintTsReact from '../eslint.ts.react.config.base.mjs'; +import eslintJsReactJest from '../eslint.js.react.jest.config.base.mjs'; + +export default [ + ...eslintJs, + ...eslintTsReact(import.meta.dirname), + ...eslintJsReactJest, + { + ignores: [ + 'chrome', + 'dist', + 'edge', + 'examples', + 'firefox', + 'test/electron/fixture/dist', + ], + }, + { + files: ['build.mjs'], + languageOptions: { + globals: { + ...globals.nodeBuiltin, + }, + }, + }, + { + files: ['test/**/*.js', 'test/**/*.jsx'], + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + EUI: true, + }, + }, + }, +]; diff --git a/extension/firefox/manifest.json b/extension/firefox/manifest.json index c19b76e8..857eb4a2 100644 --- a/extension/firefox/manifest.json +++ b/extension/firefox/manifest.json @@ -1,29 +1,22 @@ { - "version": "3.1.6", + "version": "3.2.7", "name": "Redux DevTools", - "manifest_version": 2, + "manifest_version": 3, "description": "Redux Developer Tools for debugging application state changes.", "homepage_url": "https://github.com/reduxjs/redux-devtools", - "applications": { + "browser_specific_settings": { "gecko": { - "id": "extension@redux.devtools", - "strict_min_version": "54.0" + "id": "extension@redux.devtools" } }, - "page_action": { + "action": { "default_icon": "img/logo/38x38.png", "default_title": "Redux DevTools", - "default_popup": "window.html#popup" + "default_popup": "devpanel.html#popup" }, "commands": { - "devtools-left": { - "description": "DevTools window to left" - }, - "devtools-right": { - "description": "DevTools window to right" - }, - "devtools-bottom": { - "description": "DevTools window to bottom" + "devtools-window": { + "description": "DevTools window" }, "devtools-remote": { "description": "Remote DevTools" @@ -43,21 +36,22 @@ "content_scripts": [ { "matches": [""], - "js": ["content.bundle.js", "pagewrap.bundle.js"], + "js": ["content.bundle.js"], "run_at": "document_start", "all_frames": true + }, + { + "matches": [""], + "js": ["page.bundle.js"], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" } ], "devtools_page": "devtools.html", - "web_accessible_resources": ["page.bundle.js"], - "permissions": [ - "notifications", - "contextMenus", - "tabs", - "storage", - "file:///*", - "http://*/*", - "https://*/*" - ], - "content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self' data:;" + "permissions": ["notifications", "contextMenus", "tabs", "storage"], + "host_permissions": ["file:///*", "http://*/*", "https://*/*"], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; img-src 'self' data:;" + } } diff --git a/extension/jest.config.js b/extension/jest.config.cjs similarity index 87% rename from extension/jest.config.js rename to extension/jest.config.cjs index 2c331668..64f413ba 100644 --- a/extension/jest.config.js +++ b/extension/jest.config.cjs @@ -3,7 +3,7 @@ module.exports = { testPathIgnorePatterns: ['/examples'], testEnvironment: 'jsdom', moduleNameMapper: { - '\\.css$': '/test/__mocks__/styleMock.ts', + '\\.css$': '/test/__mocks__/styleMock.js', }, transformIgnorePatterns: [ 'node_modules/(?!.pnpm|@babel/code-frame|@babel/highlight|@babel/helper-validator-identifier|chalk|d3|dateformat|delaunator|internmap|jsondiffpatch|lodash-es|nanoid|robust-predicates|uuid)', diff --git a/extension/package.json b/extension/package.json index 7cab99a3..fe10bbd7 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "remotedev-redux-devtools-extension", - "version": "3.1.9", + "version": "3.2.7", "description": "Redux Developer Tools for debugging application state changes.", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/extension", "license": "MIT", @@ -17,68 +17,65 @@ "clean": "rimraf dist && rimraf chrome/dist && rimraf edge/dist && rimraf firefox/dist", "test:app": "cross-env BABEL_ENV=test jest test/app", "test:chrome": "jest test/chrome", + "build:test:electron:fixture": "webpack --config test/electron/fixture/webpack.config.js", "test:electron": "pnpm run build:test:electron:fixture && jest test/electron", "test": "pnpm run test:app && pnpm run test:chrome && pnpm run test:electron", - "build:test:electron:fixture": "webpack --config test/electron/fixture/webpack.config.js", + "lint": "eslint .", "type-check": "tsc --noEmit" }, "dependencies": { - "@babel/polyfill": "^7.12.1", - "@emotion/react": "^11.11.4", - "@redux-devtools/app": "^6.0.1", - "@redux-devtools/core": "^4.0.0", - "@redux-devtools/instrument": "^2.1.0", - "@redux-devtools/serialize": "^0.4.1", - "@redux-devtools/slider-monitor": "^5.0.1", - "@redux-devtools/ui": "^1.3.2", - "@redux-devtools/utils": "^3.0.0", + "@emotion/react": "^11.13.3", + "@redux-devtools/app": "workspace:^", + "@redux-devtools/core": "workspace:^", + "@redux-devtools/instrument": "workspace:^", + "@redux-devtools/serialize": "workspace:^", + "@redux-devtools/slider-monitor": "workspace:^", + "@redux-devtools/ui": "workspace:^", + "@redux-devtools/utils": "workspace:^", + "@reduxjs/toolkit": "^2.2.7", "@types/jsan": "^3.1.5", "jsan": "^3.1.14", "localforage": "^1.10.0", - "lodash": "^4.17.21", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-icons": "^5.0.1", - "react-is": "^18.2.0", - "react-json-tree": "^0.19.0", - "react-redux": "^8.1.3", - "redux": "^4.2.1", + "lodash-es": "^4.17.21", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-icons": "^5.3.0", + "react-is": "^18.3.1", + "react-json-tree": "workspace:^", + "react-redux": "^9.1.2", + "redux": "^5.0.1", "redux-persist": "^6.0.0", "styled-components": "^5.3.11" }, "devDependencies": { - "@babel/core": "^7.24.3", - "@babel/preset-env": "^7.24.3", - "@babel/preset-react": "^7.24.1", - "@babel/preset-typescript": "^7.24.1", - "@babel/register": "^7.23.7", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^14.2.2", - "@types/chrome": "^0.0.263", - "@types/lodash": "^4.17.0", - "@types/react": "^18.2.72", - "@types/react-dom": "^18.2.22", + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.4", + "@babel/preset-react": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", + "@babel/register": "^7.24.6", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", + "@types/chrome": "^0.0.271", + "@types/lodash-es": "^4.17.12", + "@types/react": "^18.3.6", + "@types/react-dom": "^18.3.0", "@types/styled-components": "^5.1.34", - "chromedriver": "^118.0.1", + "chromedriver": "^126.0.5", "cross-env": "^7.0.3", - "electron": "^27.3.7", - "esbuild": "^0.20.2", - "eslint": "^8.57.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", - "eslint-plugin-react-hooks": "^4.6.0", - "immutable": "^4.3.5", + "electron": "^31.6.0", + "esbuild": "^0.23.1", + "globals": "^15.9.0", + "immutable": "^4.3.7", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "pug": "^3.0.2", - "rimraf": "^5.0.5", - "selenium-webdriver": "^4.18.1", + "pug": "^3.0.3", + "rimraf": "^6.0.1", + "selenium-webdriver": "^4.24.1", "sinon-chrome": "^3.0.1", - "ts-jest": "^29.1.2", - "typescript": "~5.3.3", - "webpack": "^5.91.0", + "ts-jest": "^29.2.5", + "typescript": "~5.5.4", + "webpack": "^5.94.0", "webpack-cli": "^5.1.4" } } diff --git a/extension/src/app/Actions.tsx b/extension/src/app/Actions.tsx index 00abd2b9..4261ee62 100644 --- a/extension/src/app/Actions.tsx +++ b/extension/src/app/Actions.tsx @@ -18,7 +18,7 @@ import { TopButtons, } from '@redux-devtools/app'; import { GoBroadcast } from 'react-icons/go'; -import { MdBorderBottom, MdBorderLeft, MdBorderRight } from 'react-icons/md'; +import { MdOutlineWindow } from 'react-icons/md'; import type { Position } from '../pageScript/api/openWindow'; import type { SingleMessage } from '../background/store/apiMiddleware'; @@ -29,25 +29,21 @@ interface OwnProps { } type Props = StateProps & DispatchProps & OwnProps; -declare global { - interface Window { - isElectron?: boolean; - } -} +const isElectron = navigator.userAgent.includes('Electron'); -function sendMessage(message: SingleMessage) { - chrome.runtime.sendMessage(message); +async function sendMessage(message: SingleMessage) { + await chrome.runtime.sendMessage(message); } class Actions extends Component { - openWindow = (position: Position) => { - sendMessage({ type: 'OPEN', position }); + openWindow = async (position: Position) => { + await sendMessage({ type: 'OPEN', position }); }; - openOptionsPage = () => { - if (navigator.userAgent.indexOf('Firefox') !== -1) { - sendMessage({ type: 'OPEN_OPTIONS' }); + openOptionsPage = async () => { + if (navigator.userAgent.includes('Firefox')) { + await sendMessage({ type: 'OPEN_OPTIONS' }); } else { - chrome.runtime.openOptionsPage(); + await chrome.runtime.openOptionsPage(); } }; @@ -89,7 +85,7 @@ class Actions extends Component { {features.import && } {position && (position !== '#popup' || - navigator.userAgent.indexOf('Firefox') !== -1) && } + navigator.userAgent.includes('Firefox')) && } @@ -98,37 +94,19 @@ class Actions extends Component { )} - {!window.isElectron && position !== '#left' && ( + {!isElectron && ( )} - {!window.isElectron && position !== '#right' && ( + {!isElectron && ( - )} - {!window.isElectron && position !== '#bottom' && ( - - )} - {!window.isElectron && ( -