部署 React 时出现错误“路径”参数必须是字符串 - 云函数中的可加载组件示例代码

Posted

技术标签:

【中文标题】部署 React 时出现错误“路径”参数必须是字符串 - 云函数中的可加载组件示例代码【英文标题】:Getting error "Path" argument must be string while deploying React - Loadable components sample code in cloud functions 【发布时间】:2021-08-10 07:24:14 【问题描述】:

我正在尝试将可加载组件集成到我的 s-s-r 项目中,当我在 localhost:3000 中执行时它正在工作,然后我尝试将它部署到云功能中我收到此错误

[ERR_INVALID_ARG_TYPE]:“路径”参数必须是字符串类型。收到未定义

之后我尝试部署loadable components server side rendering example,示例代码也给出了同样的错误。

我对 package.json、服务器 main.js 和 app.js 文件进行了一些更改,以便在云函数中工作

这是我的服务器 main.js 文件

import path from 'path'
import express from 'express'
import React from 'react'
import  renderToString  from 'react-dom/server'
import  ChunkExtractor  from '@loadable/server'
import App from '../client/App'
const functions = require('firebase-functions');
const app = express()


//app.use(express.static(path.join(__dirname, '../../public')))


const nodeStats = path.resolve(
  __dirname,
  '../../public/dist/async-node/loadable-stats.json',
)

const webStats = path.resolve(
  __dirname,
  '../../public/dist/web/loadable-stats.json',
)

app.get('*', (req, res) => 
  const nodeExtractor = new ChunkExtractor( statsFile: nodeStats )
  const  default: App  = nodeExtractor.requireEntrypoint()

  const webExtractor = new ChunkExtractor( statsFile: webStats )
  const jsx = webExtractor.collectChunks(<App />)

  const html = renderToString(jsx)

  res.set('content-type', 'text/html')
  res.send(`
      <!DOCTYPE html>
      <html>
        <head>
        $webExtractor.getLinkTags()
        $webExtractor.getStyleTags()
        </head>
        <body>
          <div id="main">$html</div>
          $webExtractor.getScriptTags()
        </body>
      </html>
    `)
)

// eslint-disable-next-line no-console
exports.supercharged = functions.https.onRequest(app);

在此文件中,我将示例代码 app.listen 更改为 exports.supercharged = functions.https.onRequest(app);,并导入了 const functions = require('firebase-functions');

这是我的 package.json 文件


  "private": true,
  "scripts": 
    "dev": "nodemon src/server/main.js",
    "build": "NODE_ENV=production yarn build:webpack && yarn build:functions",
    "build:webpack": "webpack",
    "build:functions": "babel -d functions src",
    "start": "NODE_ENV=production node functions/server/main.js",
    "deploy": "firebase deploy --only functions,hosting",
    "serve": "firebase serve --only functions,hosting"
  ,
  "devDependencies": 
    "@babel/cli": "^7.4.4",
    "@babel/core": "^7.6.2",
    "@babel/node": "^7.0.0",
    "@babel/preset-env": "^7.6.2",
    "@babel/preset-react": "^7.0.0",
    "@loadable/babel-plugin": "^5.10.3",
    "@loadable/component": "^5.10.3",
    "@loadable/server": "^5.10.3",
    "@loadable/webpack-plugin": "^5.7.1",
    "babel-loader": "^8.0.6",
    "css-loader": "^2.1.1",
    "mini-css-extract-plugin": "^0.6.0",
    "nodemon": "^1.19.0",
    "webpack": "^5.0.0-beta.16",
    "webpack-cli": "^3.3.2",
    "webpack-dev-middleware": "^3.6.2",
    "webpack-node-externals": "^1.7.2"
  ,
  "dependencies": 
    "core-js": "^3.0.1",
    "express": "^4.16.4",
    "firebase-admin": "^9.2.0",
    "firebase-functions": "^3.11.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6"
  

在包文件中,我替换了 babel 脚本以将文件复制到函数文件夹而不是 lib

"build:functions": "babel -d functions src", 

这是我的 app.js

import React from 'react'
// eslint-disable-next-line import/no-extraneous-dependencies
import loadable from '@loadable/component'

const App = () => (
  <div>
  Hello world
  </div>
)

export default App

可加载组件在 app.js 中有很多代码,所以我只是将 app.js 替换为简单的 hello world 文本

这是我的 firebase.json 文件


  "hosting": 
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      
        "source": "**",
        "function": "supercharged"
      
    ]
  

这些都是我从 loadable-components server side rendering async 节点示例中所做的更改

我不知道我在这里错过了什么,如果我错过了或需要添加任何东西,请帮助我

【问题讨论】:

您使用的是什么节点版本?如果节点版本小于 10.0.0,可能会发生这种情况 我用的是 14 .. 【参考方案1】:

正如@hilipati 所指出的,__dirname 没有定义。但是这个问题有一个更简单的解决方案,找到here

在使用__dirname之前,您可以覆盖默认行为,如

if(!__dirname) 
    __dirname = path.resolve(path.dirname(''));

或者,或者

if(!__dirname) 
    __dirname = path.resolve();

【讨论】:

没有 __dirname 有这个值 "/Volumes/React-Project/s-s-rAsync/functions/server"【参考方案2】:

根据我对路径的documentation 的阅读,没有必要将__dirname 提供给path.resolve()。它将解析任何给定相对路径的绝对路径,包括如果没有给出参数。

path.resolve(); // => '/root_path/current_working_directory'

带有相对路径:

const location = path.resolve('./your_relative_path/file.json')
// OR
const sameLocation = path.resolve('./your_relative_path', 'file.json')
// => '/root_path/current_working_directory/your_relative_path/file.json

此规则的例外是您输入非相对/绝对路径作为参数。然后它将尝试从右到左解析路径,直到形成有效路径:

path.resolve('/your_absolute_path/file.json')
// OR
path.resolve('/your_absolute_path', 'file.json')
// => '/your_absolute_path/file.json'

path.resolve('/your_absolute_path', '/file.json')
// => '/file.json'

path.resolve('/one_path', '/another_path', 'file.json')
// => '/another_path/file.json'

因此,您解析的代码应如下所示:

const nodeStats = path.resolve('../../public/dist/async-node/loadable-stats.json')

const webStats = path.resolve('../../public/dist/web/loadable-stats.json')

这将分别为您提供/Volumes/React-Project/s-s-rAsync/public/dist/async-node/loadable-stats.json/Volumes/React-Project/s-s-rAsync/public/dist/web/loadable-stats.json。这仍然适用于 Node 16.x

【讨论】:

【参考方案3】:

通过将 webpack 降级到 4.31.0 进行检查,可加载组件在 webpack 5 中存在一些问题

"webpack": "^4.31.0",
"webpack-cli": "^3.3.2",
"webpack-dev-middleware": "^3.6.2",
"webpack-node-externals": "^1.7.2"

【讨论】:

以上是关于部署 React 时出现错误“路径”参数必须是字符串 - 云函数中的可加载组件示例代码的主要内容,如果未能解决你的问题,请参考以下文章

从 v3 迁移到 v4 react-router 时出现错误

使用 create-react-app 部署 github 页面时出现 React-router 问题 [关闭]

GitHub Actions 部署构建时出现错误

在 ZEIT 上部署时出现 MongoDB 连接错误

为啥在尝试从 api 获取数据时出现此错误“TypeError:字符串索引必须是整数”?

尝试在 React 中映射子对象时出现未定义错误