Chrome 扩展类型错误:未捕获的类型错误,无法读取未定义的属性“绑定”

时间:2021-03-10 02:53:21

标签: reactjs typescript webpack google-chrome-extension puppeteer

我正在使用 typescript 和 webpack 构建 chrome 扩展,并在将最近发布的节点模块引入我的项目后开始遇到一些错误。

我安装的模块:https://github.com/gregtuc/StockSocket

加载扩展程序时浏览器中出现错误

Uncaught TypeError: Cannot read property 'bind' of undefined

堆栈跟踪

contentscript.js:35159 (./node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js)
contentscript.js:83680 (__webpack_require__)
contentscript.js:36432 (./node_modules/puppeteer/lib/cjs/puppeteer/node/Puppeteer.js)
contentscript.js:83680 (__webpack_require__)
contentscript.js:34971 (./node_modules/puppeteer/lib/cjs/puppeteer/initialize-node.js)
contentscript.js:83680 (__webpack_require__)
contentscript.js:35022 (./node_modules/puppeteer/lib/cjs/puppeteer/node.js)
contentscript.js:83680 (__webpack_require__)
contentscript.js:24201 (./node_modules/puppeteer/cjs-entry.js)
contentscript.js:83680 (__webpack_require__)
contentscript.js:67322 (./node_modules/stocksocket/stocksocket.js)
contentscript.js:83680 (__webpack_require__)
contentscript.js:83765 (anonymous function)
contentscript.js:83792 (anonymous function)
contentscript.js:83794 (anonymous function)
...

const readdirAsync = util_1.promisify(fs.readdir.bind(fs));
const mkdirAsync = util_1.promisify(fs.mkdir.bind(fs));
const unlinkAsync = util_1.promisify(fs.unlink.bind(fs));
const chmodAsync = util_1.promisify(fs.chmod.bind(fs));
function existsAsync(filePath) {
    return new Promise((resolve) => {
        fs.access(filePath, (err) => resolve(!err));
    });
}

...

这是我的 webpack 配置文件

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { resolve } = require('path');
const webpack = require('webpack');

const tsRule = {
    test: /\.ts(x?)$/,
    exclude: /node_modules/,
    use: 'ts-loader',
};

const plugins = [
    new HtmlWebpackPlugin({
        template: 'src/popup-page/popup.html',
        filename: 'popup.html',
        chunks: ['popup'],
    }),
    new CopyWebpackPlugin({
        patterns: [{ from: 'public', to: '.' }],
    }),
    new CleanWebpackPlugin(),
    new webpack.ProvidePlugin({
        process: 'process/browser',
        Buffer: ['buffer', 'Buffer'],
    }),
];

module.exports = {
    mode: 'development',
    devtool: 'cheap-module-source-map',
    resolve: {
        fallback: {
            path: require.resolve('path-browserify'),
            util: require.resolve('util/'),
            fs: false,
            stream: require.resolve('stream-browserify'),
            constants: require.resolve('constants-browserify'),
            assert: require.resolve('assert/'),
            url: require.resolve('url/'),
            net: false,
            tls: false,
            https: require.resolve('https-browserify'),
            http: require.resolve('stream-http'),
            os: require.resolve('os-browserify/browser'),
            zlib: require.resolve('browserify-zlib'),
            child_process: false,
        },
    },
    entry: {
        popup: './src/popup-page/popup.tsx',
        contentscript: './src/contentscript.tsx',
    },
    output: {
        filename: '[name].js',
        path: resolve(__dirname, 'dist'),
    },
    module: {
        rules: [tsRule],
    },
    plugins,
};

这是我的 ts 配置

{
    "compilerOptions": {
        "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
        "module": "es6" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
        "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */,
        "strict": true /* Enable all strict type-checking options. */,
        "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
        "typeRoots": [
            "./types",
            "./node_modules/@types"
        ] /* List of folders to include type definitions from. */,
        "types": [
            "node"
        ] /* Type declaration files to be included in compilation. */,
        "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
        "skipLibCheck": true /* Skip type checking of declaration files. */,
        "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
    },
    "exclude": ["node_modules", "typings"]
}

还有我的 contentscript.tsx 文件

import React, { FC, useState, useRef } from 'react';
import { render } from 'react-dom';
import * as CSS from 'csstype';
import StockSocket from 'stocksocket';

interface Props {}

const divBar = document.createElement('div');
divBar.className = 'mini-ticker-extension';
divBar.style.backgroundColor = 'red';
divBar.style.position = 'sticky';
divBar.style.zIndex = '100000';
divBar.style.height = '50px';
divBar.style.top = '0';

export const TickerBar: FC<Props> = () => {
    interface TickerHash {}

    const [tickers, setTickers] = useState<TickerHash>();

    const tickerStyle: CSS.Properties = {
        padding: 0,
    };

    const stockPriceChanged = (data: any) => {
        console.log(data);
    };

    StockSocket.addTickers(['TSLA', 'NIO', 'NNDM', 'ETH-USD'], stockPriceChanged);

    return <p style={tickerStyle}>hello world</p>;
};

render(<TickerBar />, divBar);

document.querySelector('body')?.prepend(divBar);

之前我遇到了 webpack 错误,其中 'fs'、'child-process' 或 'path' 在编译时无法解析。我找到的解决方案据说在模块导出中包含了回退。包含它们之后,我的浏览器中出现了另一个错误,无法解析“进程”和“缓冲区”,因此我找到了另一个解决方案,导致我在插件数组的 webpack 配置中需要它。我不确定我处理这些解决方案的方式是否正确,以及它们是否可能导致这个新错误。如果有人能向我解释这些错误,我将不胜感激。

链接到我的存储库:https://github.com/bryanmoon1991/mini-ticker-extension

我正在尝试构建一个扩展程序,在您当前网页的顶部放置一个小栏,显示股票行情信息,以便您可以在继续浏览的同时关注所选股票行情。

我是一名初级开发者,这是我第一次使用 webpack。

1 个答案:

答案 0 :(得分:0)

您选择的模块 StockSocket 旨在用于 Node.js 环境而不是 Web 浏览器。出现“fs”、“childprocess”等错误是因为 StockSocket 本身(其依赖项之一)使用这些内置于 Node 中的模块,而不是浏览器。

简单地看一下 StockSocket 的源代码,它使用 puppeteer,这是一个用于控制无头 Web 浏览器的 node.js 库。这使得 StockSocket 不适合浏览器扩展。我会查看 StockSocket 的源代码,看看您是否可以使用浏览器 API 复制某些行为!