SharePoint / sp-dev-docs

SharePoint & Viva Connections Developer Documentation
https://docs.microsoft.com/en-us/sharepoint/dev/
Creative Commons Attribution 4.0 International
1.24k stars 1k forks source link

Error using react-dom/server function renderToString #7033

Open lennertcc opened 3 years ago

lennertcc commented 3 years ago

Target SharePoint environment

SharePoint Online

What SharePoint development model, framework, SDK or API is this about?

💥 SharePoint Framework

Developer environment

Windows

What browser(s) / client(s) have you tested

Additional environment details

Describe the bug / error

When using import { renderToString } from 'react-dom/server';

and running gulp serve

the call to const stringElement = renderToString(<SomeReactComponent key={index} />)

runs into

react-dom-server.browser.development.js:2543 
Uncaught TypeError: Cannot read property 'getCurrentStack' of undefined
    at pushCurrentDebugStack (react-dom-server.browser.development.js:2543)
    at ReactDOMServerRenderer.read (react-dom-server.browser.development.js:3138)
    at renderToString (react-dom-server.browser.development.js:3628)
    at MySPFxReactComponent.tsx:204

Steps to reproduce

See bug description

Expected behavior

When packaging the solution and using it from the App Catalog, this error does not occur and the renderToString function works as expected.

ghost commented 3 years ago

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

c-eiser13 commented 3 years ago

I'm on SPFx 1.11.0 and having the same error trying to use renderToStaticMarkup from react-dom/server.

image

AJIXuMuK commented 2 years ago

@lennertcc @c-eiser13 - sorry for the long delay. Just to clarify - were you experiencing this error when debugging using local workbench?

lennertcc commented 2 years ago

No, I've always worked with debugging on actual SharePoint Online pages using ?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js or something similar

Thanks for working on this!

c-eiser13 commented 2 years ago

@AJIXuMuK se here, happens to me when running debugger against an actual site, I do not use local workbench. Thanks!

AJIXuMuK commented 2 years ago

Thank you @lennertcc, @c-eiser13 for the quick response. So the problem here is we always load production versions of react and react-dom. But when you reference react-dom/server in dev mode - it will load dev version. And that leads to the error.

We're discussing potential ways of loading development versions of react as it also could be beneficial for profiling (as discussed in #6548). But currently there are no ETAs for that.

As a workaround I can propose the next solution.

  1. change your import to use react-dom/server.browser as this is the correct module to reference client-side.
  2. Add additional processing in gulpfile.ls to always load production build:

    if (process.env.NODE_ENV !== 'production') {
    let reactDomServerContent = '';
    
    build.rig.addPreBuildTask({
    name: 'react-dom-server-prebuild',
    execute: async () => {
      try {
        reactDomServerContent = fs.readFileSync('./node_modules/react-dom/server.browser.js', 'utf8');
        fs.writeFileSync('./node_modules/react-dom/server.browser.js',
          `'use strict';
    module.exports = require('./cjs/react-dom-server.browser.production.min.js');
    `);
      } catch (e) {
        console.log(e);
      }
    }
    });
    
    build.rig.addPostBundleTask({
    name: 'react-dom-server-postbuild',
    execute: async () => {
      fs.writeFileSync('./node_modules/react-dom/server.browser.js', reactDomServerContent);
    }
    });
    }
CocoYubari commented 2 years ago

Thank you @lennertcc, @c-eiser13 for the quick response. So the problem here is we always load production versions of react and react-dom. But when you reference react-dom/server in dev mode - it will load dev version. And that leads to the error.

We're discussing potential ways of loading development versions of react as it also could be beneficial for profiling (as discussed in #6548). But currently there are no ETAs for that.

As a workaround I can propose the next solution.

  1. change your import to use react-dom/server.browser as this is the correct module to reference client-side.
  2. Add additional processing in gulpfile.ls to always load production build:
if (process.env.NODE_ENV !== 'production') {
  let reactDomServerContent = '';

  build.rig.addPreBuildTask({
    name: 'react-dom-server-prebuild',
    execute: async () => {
      try {
        reactDomServerContent = fs.readFileSync('./node_modules/react-dom/server.browser.js', 'utf8');
        fs.writeFileSync('./node_modules/react-dom/server.browser.js',
          `'use strict';
    module.exports = require('./cjs/react-dom-server.browser.production.min.js');
    `);
      } catch (e) {
        console.log(e);
      }
    }
  });

  build.rig.addPostBundleTask({
    name: 'react-dom-server-postbuild',
    execute: async () => {
      fs.writeFileSync('./node_modules/react-dom/server.browser.js', reactDomServerContent);
    }
  });
}

Thank you for the workaround. I applied it, but it's still not working for me. Is there any news regarding this issue? Are there checks I should run for this workaround to work properly? Loading the solution to the app catalog every time is rather time consuming, as well as using the local workbench only

HiltonGiesenow commented 2 years ago

@CocoYubari you might need to add const fs = require("fs"); to the top section of the file, under const build = require('@microsoft/sp-build-web');

CocoYubari commented 2 years ago

@HiltonGiesenow turned out I put that line in the wrong place, thank you!

bradleypregon commented 7 months ago

Thank you @lennertcc, @c-eiser13 for the quick response. So the problem here is we always load production versions of react and react-dom. But when you reference react-dom/server in dev mode - it will load dev version. And that leads to the error.

We're discussing potential ways of loading development versions of react as it also could be beneficial for profiling (as discussed in #6548). But currently there are no ETAs for that.

As a workaround I can propose the next solution.

  1. change your import to use react-dom/server.browser as this is the correct module to reference client-side.
  2. Add additional processing in gulpfile.ls to always load production build:
if (process.env.NODE_ENV !== 'production') {
  let reactDomServerContent = '';

  build.rig.addPreBuildTask({
    name: 'react-dom-server-prebuild',
    execute: async () => {
      try {
        reactDomServerContent = fs.readFileSync('./node_modules/react-dom/server.browser.js', 'utf8');
        fs.writeFileSync('./node_modules/react-dom/server.browser.js',
          `'use strict';
    module.exports = require('./cjs/react-dom-server.browser.production.min.js');
    `);
      } catch (e) {
        console.log(e);
      }
    }
  });

  build.rig.addPostBundleTask({
    name: 'react-dom-server-postbuild',
    execute: async () => {
      fs.writeFileSync('./node_modules/react-dom/server.browser.js', reactDomServerContent);
    }
  });
}

in 2024, this workaround is still working for me when needing to use renderToString.

Instead of import { ... } from 'react-dom/server.browser I have to use import { ... } from 'react-dom/server' in the respective file. Don't forget to add const fs = require("fs"); in the gulpfile as mentioned by @HiltonGiesenow

SPFx: 1.18.2 Node: v18.18.0 React/Dom: 17.0.1

Cheers!