React-native-web: Critical styles missing during server render with Next.js

Created on 21 Aug 2018  Â·  11Comments  Â·  Source: necolas/react-native-web

The problem
When server rendering a Next.js application, the "critical" styles for the given page are missing. They apply correctly, however, in the client.

How to reproduce
Simplified test case: https://github.com/HealthTeacher/nextjs-rnw

Steps to reproduce:

  1. Clone the test case.
  2. yarn install
  3. yarn start
  4. Open http://localhost:3000
  5. Disable JavaScript in your browser.
  6. Refresh the page.

Expected behavior
The "critical" styles for the page are rendered by the server.

Environment (include versions). Did this work in previous versions?

  • React Native for Web (version): 0.8.9
  • React (version): 16.4.2
  • Browser: macOS Safari

Notes:

All 11 comments

I am using RNW here in Este and it seems it works. Maybe it can help.

https://github.com/este/este

@steida thanks for the tip. Unfortunately, you are utilizing the CommonJS version of RNW’s modules, which I am already able to get working.

My primary goal is to have server styles work when I compile RNW’s ES module exports with Babel.

Have you looked into why? What's different about the bundle?

@necolas I have done a fair amount of debugging, but have been unable to identify what is going wrong.

The only piece I’ve noticed and don’t quite understand is that, on the server, this._sheet is always null here because it is only set on the client. That means any non-initialStyles _never_ gets “inserted” into the style sheet. How/where are styles inserted on the server?

If you don’t have any specific thoughts or guidance, I’ll try to dive deeper and see if I can find something. I understand you can’t debug every integration/application.

Thank you for your hard work on RNW.

Yeah the server only needs rules pushed into the array.

My first thought is that webpack is dropping some code. If the issue didn't exist for cjs understanding the difference between the 2 module formats is probably where I'd start

@necolas below is a log of a single page load run. I'm not sure what is occurring here.

Context

  • Any > NAME is just a top-level console.log from the file NAME.
  • Any > NAME.METHOD is a console.log from within the method itself (e.g. the constructor method of ReactNativeStyleResolver).
  • The number at the end of WebStyleSheet.constructor is a simple index incremented at the top of the WebStyleSheet file as an attempt to understand how many times the file is imported and the class instantiated.

ES Modules Log

> styleResolver
> ReactNativeStyleResolver.constructor
> ReactNativeStyleResolver.init
> StyleSheetManager.constructor
> WebStyleSheet.constructor 0

> createDOMProps
> NativeMethodsMixin
> styleResolver
> ReactNativeStyleResolver.constructor
> ReactNativeStyleResolver.init
> StyleSheetManager.constructor
> WebStyleSheet.constructor 0

> createDOMProps
> NativeMethodsMixin
> renderApplication
> renderApplication.getApplication
> ReactNativeStyleResolver.init
> StyleSheetManager.constructor
> WebStyleSheet.constructor 1

CJS Modules Log

> styleResolver
> ReactNativeStyleResolver.constructor
> ReactNativeStyleResolver.init
> StyleSheetManager.constructor
> WebStyleSheet.constructor 0

> createDOMProps
> NativeMethodsMixin
> renderApplication
> renderApplication.getApplication
> ReactNativeStyleResolver.init
> StyleSheetManager.constructor
> WebStyleSheet.constructor 1

As you can see, the top-level styleResolver file (and the resulting method chain) logs twice for ES modules, but once for CJS modules. I presume the duplicative execution of styleResolver is the culprit for resetting this._cssRules and emptying the custom styles on the server. createDOMProps and NativeMethodsMixin depend upon styleResolver, but those only show up in the second run.

Questions

  1. Why would > styleResolver show up twice?
  2. What file causes > styleResolver to run the first time?
  3. Why would createDOMProps and NativeMethodsMixin not show up in the second run?

I'll try to keep digging, but wanted to pose these questions in case something stood out to you. My second question is the primary question blocking me from digging deeper.

Thanks again for the help.

@necolas below is the dependency tree arriving at styleResolver.js for Next.js' page/index.js (root route) and pages/_document.js (shared wrapping component for each page). During execution,styleResolver.js is imported first by pages/index.js and then later by pages/_document.js. The bolded styleResolver.js below (i.e. iii underneath pages/_document.js) is the focus of the issue.

When using ES modules, a breakpoint in styleResolver.js is hit _twice_. When using CJS modules, the breakpoint is hit _once_. With CJS, it seems as though webpack caches the singleton styleResolver and does not import the file a second time.

Do you know why the styleResolver.js singleton executes twice for ES modules, but only once for CJS modules?

  • pages/index.js

    1. Text

    2. TextStylePropTypes.js

    3. applyNativeProps.js

    4. NativeMethodsMixin.js

    5. createDOMProps.js

    6. styleResolver.js

  • pages/_document.js

    1. AppRegistery.js

    2. renderApplication.js

    3. styleResolver.js - CJS never hits a debugger here, ES does.

Do you know why the styleResolver.js singleton executes twice for ES modules, but only once for CJS modules?

Nope. Can't tell if this is a webpack or Next.js thing either

Can't tell if this is a webpack or Next.js thing either

Alright. I agree this is likely not an issue with RNW. I'll close this issue and open an issue in the Next.js community.

Thank you for guidance.

Oh I don't know, it might be something to do with RNW. I don't mind leaving this open until we know what the issue is

I was able to resolve this issue by upgrading to next@^7.0.0-canary.15. The explanation of this issue may be found here.

TL;DR – webpack doesn't use require.cache when compiling to the Node.js target, instead it uses it's own installed modules cache, which caused issues for the way Next.js bundled pages.

Was this page helpful?
0 / 5 - 0 ratings