React + Redux + Typescript Chrome 扩展弹出脚本 - Redux Devtools 显示 "No Store Found"
React + Redux + Typescript Chrome Extension Popup Script - Redux Devtools Shows "No Store Found"
我正在创建一个主要用于弹出脚本的 chrome 扩展。
Manifest.json
// public/manifest.json
{
"manifest_version": 3,
"version": "3.0.0",
"name": "__MSG_appName__",
"description": "__MSG_appDesc__",
"default_locale": "en",
"author": "lbragile",
"homepage_url": "some_url_not_relevant_to_question_at_hand",
"permissions": ["tabs", "storage"],
"optional_permissions": ["contextMenus", "alarms", "downloads", "downloads.shelf"],
"icons": {
"16": "images/logo16.png",
"48": "images/logo48.png",
"128": "images/logo128.png"
},
"action": {
"default_icon": {
"16": "images/logo16.png",
"48": "images/logo48.png",
"128": "images/logo128.png"
},
"default_popup": "index.html",
"default_title": "title"
},
"background": {
"service_worker": "background.js"
},
"incognito": "split"
}
Package.json
// package.json
{
"name": "name",
"version": "0.0.1",
"description": "description",
"author": "lbragile",
"private": true,
"dependencies": {
"nanoid": "^3.1.30",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
"redux": "^4.1.1"
},
"devDependencies": {
"@babel/core": "^7.13.14",
"@babel/preset-env": "^7.13.12",
"@babel/preset-react": "^7.13.13",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15",
"@types/chrome": "0.0.159",
"@types/express": "^4.17.13",
"@types/node": "^16.10.3",
"@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9",
"@types/react-redux": "^7.1.19",
"@types/react-router-dom": "^5.1.8",
"@types/redux-immutable-state-invariant": "^2.1.2",
"@types/remote-redux-devtools": "^0.5.5",
"@types/styled-components": "^5.1.12",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"babel-loader": "^8.2.3",
"babel-plugin-styled-components": "^1.13.2",
"copy-webpack-plugin": "^9.0.1",
"eslint": "^7.11.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-styled-components-a11y": "0.0.34",
"redux-devtools-extension": "^2.13.9",
"styled-components": "^5.3.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"ts-loader": "^9.2.6",
"typescript": "^4.3.5",
"url-loader": "^4.1.1",
"webpack": "^5.59.1",
"webpack-cli": "^4.9.1"
},
"scripts": {
"lint": "npx eslint {src,public}/**/**/*.[jt]s -c config/.eslintrc.js --ignore-path .gitignore .",
"lint:style": "npx stylelint {src,public}/**/**/*.css --config config/.stylelintrc.json",
"start": "webpack --config config/webpack.config.js --watch --progress"
},
"babel": {
"extends": "./config/.babelrc.json"
},
"eslintConfig": {
"extends": "./config/.eslintrc.js"
},
"stylelint": {
"extends": "./config/.stylelintrc.json"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Webpack
// config/webpack.config.js
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
entry: {
popup: path.resolve(__dirname, "../src/index.tsx"),
background: path.resolve(__dirname, "../src/background.ts"),
},
plugins: [
new CopyPlugin({
patterns: [{ from: "public", to: "." }],
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.ts(x)?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.png$/,
use: [
{
loader: "url-loader",
options: {
mimetype: "image/png",
},
},
],
},
],
},
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
mode: "production",
output: {
path: path.resolve(__dirname, `../dist`),
filename: "[name].js",
},
};
问题
我试过了redux-devtools-extension
:
// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import { Provider } from "react-redux";
import { createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "./store/reducers";
export const store = createStore(rootReducer, composeWithDevTools());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
显示:
我也试过使用 remote-redux-devtools
:
// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import { Provider } from "react-redux";
import { createStore } from "redux";
import devToolsEnhancer from "remote-redux-devtools";
import rootReducer from "./store/reducers";
export const store = createStore(rootReducer, devToolsEnhancer());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
这看起来更有希望,但商店中没有数据:
当我 运行 在浏览器中使用 npm start
(react-scripts start
) 时,我确实在 Redux DevTools
扩展中看到了商店,所以我不确定是什么问题是。
可能的想法
当我使用 React (react-scripts build
) 构建时,我可以很好地看到商店。问题是我不能使用 react,因为它的构建时间太慢,使用 webpack 似乎是最合乎逻辑的选择。这是构建输出:
有什么想法吗?
我认为问题出在以下code
中的webpack丑化__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
您可以尝试以下方法:
import { createStore, compose } from 'redux'
//same code as original but with bracket notation
const composeWithDevTools = (
typeof window !== 'undefined' && window["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"] ?
window["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"] :
function() {
if (arguments.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose;
return compose.apply(null, arguments);
}
);
//your original code but using your composeWithDevTools
export const store = createStore(rootReducer, composeWithDevTools());
您不需要从 redux-devtools-extension 导入 composeWithDevTools,因为您已经自己创建了它,但如果这解决了问题,您应该创建一个 issue 请求括号表示法,这样 uglify 就不会破解密码。
要查看编译后的代码是什么,您可以在 createStore 之前添加控制台日志:console.log("creating store")
然后您可以在 chrome devtools(Command+Shift+P 或 Control+Shift)中禁用源映射+P) 然后搜索控制台文本 creating store
快捷键是:command+alt+f 或 control+shift+f)
注意:这个答案最初是由 OP 作为对他们原始问题的编辑添加的,我刚刚将其作为答案重新发布。
A server 需要 运行 并且应该使用 remote redux devtools
而不是 redux devtools extension
。
最好的方法如下:
- 安装 npmjs。com/package/remotedev-server
- 添加
"remotedev": "remotedev --hostname=localhost --port=8080"
npm 脚本
- 运行以上脚本启动服务器
- 右键弹出窗口,
Redux DevTools > Open Remote DevTools
(不是inspect
)
- 设置 > 使用自定义本地服务器 > 输入在 npm 脚本中指定的主机名和端口。
这是我的商店的样子:
import { createStore } from "redux";
import { composeWithDevTools } from "remote-redux-devtools";
import rootReducer from "./store/reducers";
const composeEnhancers = composeWithDevTools({
realtime: true,
hostname: "localhost",
port: 8080
});
export const store = createStore(rootReducer, composeEnhancers());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
我正在创建一个主要用于弹出脚本的 chrome 扩展。
Manifest.json
// public/manifest.json
{
"manifest_version": 3,
"version": "3.0.0",
"name": "__MSG_appName__",
"description": "__MSG_appDesc__",
"default_locale": "en",
"author": "lbragile",
"homepage_url": "some_url_not_relevant_to_question_at_hand",
"permissions": ["tabs", "storage"],
"optional_permissions": ["contextMenus", "alarms", "downloads", "downloads.shelf"],
"icons": {
"16": "images/logo16.png",
"48": "images/logo48.png",
"128": "images/logo128.png"
},
"action": {
"default_icon": {
"16": "images/logo16.png",
"48": "images/logo48.png",
"128": "images/logo128.png"
},
"default_popup": "index.html",
"default_title": "title"
},
"background": {
"service_worker": "background.js"
},
"incognito": "split"
}
Package.json
// package.json
{
"name": "name",
"version": "0.0.1",
"description": "description",
"author": "lbragile",
"private": true,
"dependencies": {
"nanoid": "^3.1.30",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
"redux": "^4.1.1"
},
"devDependencies": {
"@babel/core": "^7.13.14",
"@babel/preset-env": "^7.13.12",
"@babel/preset-react": "^7.13.13",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15",
"@types/chrome": "0.0.159",
"@types/express": "^4.17.13",
"@types/node": "^16.10.3",
"@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9",
"@types/react-redux": "^7.1.19",
"@types/react-router-dom": "^5.1.8",
"@types/redux-immutable-state-invariant": "^2.1.2",
"@types/remote-redux-devtools": "^0.5.5",
"@types/styled-components": "^5.1.12",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"babel-loader": "^8.2.3",
"babel-plugin-styled-components": "^1.13.2",
"copy-webpack-plugin": "^9.0.1",
"eslint": "^7.11.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-styled-components-a11y": "0.0.34",
"redux-devtools-extension": "^2.13.9",
"styled-components": "^5.3.0",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"ts-loader": "^9.2.6",
"typescript": "^4.3.5",
"url-loader": "^4.1.1",
"webpack": "^5.59.1",
"webpack-cli": "^4.9.1"
},
"scripts": {
"lint": "npx eslint {src,public}/**/**/*.[jt]s -c config/.eslintrc.js --ignore-path .gitignore .",
"lint:style": "npx stylelint {src,public}/**/**/*.css --config config/.stylelintrc.json",
"start": "webpack --config config/webpack.config.js --watch --progress"
},
"babel": {
"extends": "./config/.babelrc.json"
},
"eslintConfig": {
"extends": "./config/.eslintrc.js"
},
"stylelint": {
"extends": "./config/.stylelintrc.json"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Webpack
// config/webpack.config.js
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
entry: {
popup: path.resolve(__dirname, "../src/index.tsx"),
background: path.resolve(__dirname, "../src/background.ts"),
},
plugins: [
new CopyPlugin({
patterns: [{ from: "public", to: "." }],
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.ts(x)?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.png$/,
use: [
{
loader: "url-loader",
options: {
mimetype: "image/png",
},
},
],
},
],
},
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
mode: "production",
output: {
path: path.resolve(__dirname, `../dist`),
filename: "[name].js",
},
};
问题
我试过了redux-devtools-extension
:
// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import { Provider } from "react-redux";
import { createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "./store/reducers";
export const store = createStore(rootReducer, composeWithDevTools());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
显示:
我也试过使用 remote-redux-devtools
:
// src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import { Provider } from "react-redux";
import { createStore } from "redux";
import devToolsEnhancer from "remote-redux-devtools";
import rootReducer from "./store/reducers";
export const store = createStore(rootReducer, devToolsEnhancer());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
这看起来更有希望,但商店中没有数据:
当我 运行 在浏览器中使用 npm start
(react-scripts start
) 时,我确实在 Redux DevTools
扩展中看到了商店,所以我不确定是什么问题是。
可能的想法
当我使用 React (react-scripts build
) 构建时,我可以很好地看到商店。问题是我不能使用 react,因为它的构建时间太慢,使用 webpack 似乎是最合乎逻辑的选择。这是构建输出:
有什么想法吗?
我认为问题出在以下code
中的webpack丑化__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
您可以尝试以下方法:
import { createStore, compose } from 'redux'
//same code as original but with bracket notation
const composeWithDevTools = (
typeof window !== 'undefined' && window["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"] ?
window["__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"] :
function() {
if (arguments.length === 0) return undefined;
if (typeof arguments[0] === 'object') return compose;
return compose.apply(null, arguments);
}
);
//your original code but using your composeWithDevTools
export const store = createStore(rootReducer, composeWithDevTools());
您不需要从 redux-devtools-extension 导入 composeWithDevTools,因为您已经自己创建了它,但如果这解决了问题,您应该创建一个 issue 请求括号表示法,这样 uglify 就不会破解密码。
要查看编译后的代码是什么,您可以在 createStore 之前添加控制台日志:console.log("creating store")
然后您可以在 chrome devtools(Command+Shift+P 或 Control+Shift)中禁用源映射+P) 然后搜索控制台文本 creating store
快捷键是:command+alt+f 或 control+shift+f)
注意:这个答案最初是由 OP 作为对他们原始问题的编辑添加的,我刚刚将其作为答案重新发布。
A server 需要 运行 并且应该使用 remote redux devtools
而不是 redux devtools extension
。
最好的方法如下:
- 安装 npmjs。com/package/remotedev-server
- 添加
"remotedev": "remotedev --hostname=localhost --port=8080"
npm 脚本 - 运行以上脚本启动服务器
- 右键弹出窗口,
Redux DevTools > Open Remote DevTools
(不是inspect
) - 设置 > 使用自定义本地服务器 > 输入在 npm 脚本中指定的主机名和端口。
这是我的商店的样子:
import { createStore } from "redux";
import { composeWithDevTools } from "remote-redux-devtools";
import rootReducer from "./store/reducers";
const composeEnhancers = composeWithDevTools({
realtime: true,
hostname: "localhost",
port: 8080
});
export const store = createStore(rootReducer, composeEnhancers());
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);