Search code examples
javascriptnode.jsreactjsgoogle-cloud-functionsloadable-component

Getting error "Path" argument must be string while deploying React - Loadable components sample code in cloud functions


I'm trying to integrate Loadable components in my SSR project and that is working when I executed in localhost:3000, then I tried to deploy it in cloud function I am getting this error

[ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined

After that I tried to deploy loadable components server side rendering example, sample code also giving the same error.

I did some changes in package.json, server main.js and app.js file to work in Cloud functions

This is my server main.js file

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);

In this file I did these changes from example code app.listen to exports.supercharged = functions.https.onRequest(app); and I imported the const functions = require('firebase-functions');

This is my package.json file

{
  "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"
  }
}

In package file I replaced babel script to copy files to functions folder instead of lib

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

Here is my 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

Loadable componets has lot of code in app.js so I just replaced app.js with simple hello world text

Here is my firebase.json file

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

These all are the changes I made from the the loadable-components server side rendering async node example

I don't know what I missed here, Please assist me if I missed or need to add anything


Solution

  • Check by downgrading webpack to 4.31.0, Loadable components has some issues with webpack 5

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