2022年2月

Bug描述

  • react 17 引入 @cosmjs/amino运行,报错如下:

    Compiled with problems:X
    
    ERROR in ./node_modules/cipher-base/index.js 3:16-43
    
    Module not found: Error: Can't resolve 'stream' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/cipher-base'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
        - install 'stream-browserify'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "stream": false }
    
    ERROR in ./node_modules/hash-base/node_modules/safe-buffer/index.js 4:13-30
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/hash-base/node_modules/safe-buffer'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }
    
    ERROR in ./node_modules/libsodium/dist/modules/libsodium.js 49:23-46
    
    Module not found: Error: Can't resolve 'path' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/libsodium/dist/modules'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
        - install 'path-browserify'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "path": false }
    
    ERROR in ./node_modules/readable-stream/lib/_stream_readable.js 46:13-37
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/readable-stream/lib'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }
    
    ERROR in ./node_modules/readable-stream/lib/_stream_writable.js 70:13-37
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/readable-stream/lib'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }
    
    ERROR in ./node_modules/readable-stream/lib/internal/streams/buffer_list.js 74:15-32
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/readable-stream/lib/internal/streams'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }
    
    ERROR in ./node_modules/ripemd160/index.js 3:13-37
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/ripemd160'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }
    
    ERROR in ./node_modules/safe-buffer/index.js 2:13-30
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/safe-buffer'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }
    
    ERROR in ./node_modules/string_decoder/node_modules/safe-buffer/index.js 4:13-30
    
    Module not found: Error: Can't resolve 'buffer' in '/Users/eason/Desktop/untitled folder/react17-cosmjs-conflect2/node_modules/string_decoder/node_modules/safe-buffer'
    
    BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
    This is no longer the case. Verify if you need this module and configure a polyfill for it.
    
    If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "buffer": require.resolve("buffer/") }'
        - install 'buffer'
    If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "buffer": false }

复现步骤

  1. 新建react项目

    npx create-react-app react17-cosmjs-conflect
  2. 安装@cosmjs/amino

    npm i @cosmjs/amino
  3. 在/src/index.js引入@cosmjs/stargate

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import reportWebVitals from './reportWebVitals';
    
    import {decodeBech32Pubkey} from '@cosmjs/amino'
    console.log(decodeBech32Pubkey)
    
    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );
    reportWebVitals();
  4. 运行

    npm run start
  5. 报错如开篇所示

Bug原因

npx create-react-app命令创建的React17默认调用的是webpack5,相比webpack4,精简了很多自带的包,需要手动安装才行

解决方法1

将react-scripts由默认的5.0.0改为4.0.3,npm i [email protected]即可

解决方法2

  1. 将react 17的webpack config从node_modules里暴露出来,如果提示git uncommitted就先commit一下

    npm run eject
  2. 安装这4个包:

    npm i stream-browserify buffer path-browserify crypto-browserify crypto-browserify
  3. 根据报错提示配置 /config/webpack.config.js

    搜索“resolve:”,在resolve内添加fallback节点,内容如下

    fallback: {
      "stream": require.resolve("stream-browserify"),
      "buffer": require.resolve("buffer/"),
      "path": require.resolve("path-browserify"),
      "crypto": require.resolve("crypto-browserify")
    }
  4. 这时候再npm run start运行就没有error了,但是有40个warning,都是关于cosmjs缺少source map的,如果不想看到这个错误,可以在跟resolve节点同级的地方添加以下属性,搜索“resolve:”,在上一行放:

    ignoreWarnings: [/Failed to parse source map/],

提示:如果没有将webpack config从node_modules里暴露出来,直接在项目根目录创建webpack.config.js文件去配置无法解决此bug

  1. install package

    yarn add react-router-dom
  2. in scr/App.tsx

    import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
    import MainPage from './pages/MainPage/MainPage'
    import User from './pages/User/User'
    import HomePage from './pages/HomePage/HomePage'
    export default function App() {
        return (
            <Router>
                <Routes>
              <Route path='/' element={<MainPage />}>
                <Route index element={<HomePage />} />
                <Route path='user' element={<User />} />
              </Route>
            </Routes>
            </Router>
        )
    }
  3. in src/pages/MainPage/MainPage.tsx

    import { Outlet } from "react-router-dom"
    export default function App() {
        return (
            <div>
                <div>Navigator</div>
                <Outlet context={{username: 'Tommy'}} />
            </div>
        )
    }
  4. in src/pages/User/User.tsx

    import { useOutletContext } from "react-router-dom"
    export default function App() {
        const context: any = useOutletContext()
        return (
            <div>
                <div>context.username</div>
            </div>
        )
    }

npm i cheerio

const fs = require("fs");
const cheerio = require("cheerio");
fs.readFile("./yt.html", "utf-8", (err, data) => {
  if (err) throw err; // /user/brhm8900/videos
  const $ = cheerio.load(data);
  $("#video-title").each(function () {
    const title = $(this).text();
    if ($(this).text().indexOf("S06E") > -1) {
      console.log($(this).attr("href"));
    }
  });
});

'use strict';
exports.main = async (event, context) => {
    let headers = event.headers
    delete headers.host
    const res = await uniCloud.httpclient.request(event.queryStringParameters.url, {
        method: event.httpMethod,
        headers: headers,
        content: event.body,
        rejectUnauthorized: false,
        followRedirect: true
    })
    return {
        // mpserverlessComposedResponse: true, // https://uniapp.dcloud.io/uniCloud/http?id=integrationresponse
        statusCode: res.status,
        headers: res.headers,
        body: res.data.toString()
    }
}

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Add network to keplr</title>
    <style>
      input {width: 256px; padding: 5px}
      td {padding: 5px}
    </style>
    <link rel="icon" type="image/svg+xml" href="https://docs.keplr.app/favicon-svg.svg">
  </head>
  <body>
    <div style="max-width: 512px; margin: 0 auto; padding-top: 100px">
      <table border="0">
        <tr>
          <td>chainId</td>
          <td><input id="chainId" value="xxxChain"></td>
        </tr>
        <tr>
          <td>rpc</td>
          <td><input id="rpc" value="http://ip:26657"></td>
        </tr>
        <tr>
          <td>rest</td>
          <td><input id="rest" value="http://ip:1317"></td>
        </tr>
        <tr>
          <td>prefix</td>
          <td><input id="prefix" value="jolt"></td>
        </tr>
        <tr>
          <td>coinDenom</td>
          <td><input id="coinDenom" value="VUSD"></td>
        </tr>
        <tr>
          <td>coinDecimals</td>
          <td><input id="coinDecimals" value="0"></td>
        </tr>
        <tr>
          <td>gasPriceStep</td>
          <td><input id="gasPriceStep" value="0.01"></td>
        </tr>
        <tr>
          <td>walletUrlForStaking</td>
          <td><input id="walletUrlForStaking" value="url"></td>
        </tr>
        <tr>
          <td><button onclick="submit()">Submit</button></td>
          <td></td>
        </tr>
      </table>
      <p>Usage: https://docs.keplr.app/api/suggest-chain.html</p>
    </div>
    <script>
      submit = async () => {
        if (!keplr) {
          alert("Please install keplr extension"); return
        }
        const prefix = document.getElementById('prefix').value
        const coinDenom = document.getElementById('coinDenom').value
        const coinDecimals = parseInt(document.getElementById('coinDecimals').value)
        const gasPriceStep = Number(document.getElementById('gasPriceStep').value)
        await keplr.experimentalSuggestChain({
          chainId: document.getElementById('chainId').value,
          chainName: document.getElementById('chainId').value,
          rpc: document.getElementById('rpc').value,
          rest: document.getElementById('rest').value,
          bip44: {
            coinType: 118,
          },
          bech32Config: {
            bech32PrefixAccAddr: prefix,
            bech32PrefixAccPub: prefix + "pub",
            bech32PrefixValAddr: prefix + "valoper",
            bech32PrefixValPub: prefix + "valoperpub",
            bech32PrefixConsAddr: prefix + "valcons",
            bech32PrefixConsPub: prefix + "valconspub",
          },
          currencies: [
            { 
              coinDenom: coinDenom,
              coinMinimalDenom: coinDenom,
              coinDecimals: coinDecimals
            }, 
          ],
          feeCurrencies: [
            {
              coinDenom: coinDenom, 
              coinMinimalDenom: coinDenom,
              coinDecimals: coinDecimals
            },
          ],
          stakeCurrency: {
            coinDenom: coinDenom,
            coinMinimalDenom: coinDenom,
            coinDecimals: coinDecimals
          },
          coinType: 118,
          gasPriceStep: { 
            low: gasPriceStep,
            average: gasPriceStep*2,
            high: gasPriceStep*3,
          },
          walletUrlForStaking: document.getElementById('walletUrlForStaking').value
        })
      }
    </script>
  </body>
</html>