Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot read property 'isReady' of undefined #18

Open
sayjeyhi opened this issue Apr 2, 2020 · 1 comment
Open

TypeError: Cannot read property 'isReady' of undefined #18

sayjeyhi opened this issue Apr 2, 2020 · 1 comment

Comments

@sayjeyhi
Copy link

sayjeyhi commented Apr 2, 2020

I did same steps as explained in example but got this error :

/Users/user/projcect/node_modules/used-styles/dist/es5/utils.js:39
    if (!def.isReady) {
             ^

TypeError: Cannot read property 'isReady' of undefined
    at Object.exports.assertIsReady (/Users/user/projcect/node_modules/used-styles/dist/es5/utils.js:39:14)
    at Transform.transform [as _transform] (/Users/user/projcect/node_modules/used-styles/dist/es5/reporters/used.js:37:21)

my code looks like :

import React from 'react';
import through from 'through';
import { renderToNodeStream } from 'react-dom/server';
import { StaticRouter, matchPath } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import { Provider as ReduxProvider } from 'react-redux';
import { ServerStyleSheet } from 'styled-components';
import { ChunkExtractor } from '@loadable/server';
import {
  createLink,
  createStyleStream,
  discoverProjectStyles,
} from 'used-styles';
import MultiStream from 'multistream';
import Hoc from 'components/Common/Hoc';

import { readableString } from './utils/readable';
import createStore from '../../app/config/configureStoreSSR';
import { indexHtml } from './indexHtml';

export async function renderServerSideApp(req, res) {
  const context = {};
  const helmetContext = {};

  /**
   * Styled component instance
   * @type {ServerStyleSheet}
   */
  const sheet = new ServerStyleSheet();

  try {
    const { store, history } = createStore(req.url);

    /**
     * A box of components which will load Server app
     * @returns {*}
     * @constructor
     */
    const ServerApp = () => (
      <HelmetProvider context={helmetContext}>
        <ReduxProvider store={store}>
          <StaticRouter history={history} location={req.url} context={context}>
            <Hoc routerProvider="server" />
          </StaticRouter>
        </ReduxProvider>
      </HelmetProvider>
    );

    const stats = require(`${process.cwd()}/build/${process.env.PUBLIC_URL}/loadable-stats.json`);
    const chunkExtractor = new ChunkExtractor({ stats });
  
    const stylesLookup = discoverProjectStyles(`${process.cwd()}/build`); // __dirname usually
  
    /**
     * Handle 404 and 301
     */
    if (context.url) {
      return res.redirect(301, context.url);
    }
    if (context.status === 404) {
      res.status(404);
    }
  
    const [header, footer] = indexHtml({
      helmet: helmetContext.helmet,
      state: store.getState(),
    });
  
    /**
     * Get styledComponents global styles
     */
    const jsx = chunkExtractor.collectChunks(
      sheet.collectStyles(<ServerApp />),
    );
  
    const endStream = readableString(footer);
  
    res.set({ 'content-type': 'text/html; charset=utf-8' });
    res.write([header, '<div id="root">'].join(''));
  
    // Pipe that HTML to the response
    const HtmlStream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx));
  
    const lookup = await stylesLookup;
    // create a style steam
    const styledStream = createStyleStream(
      lookup,
      style =>
        // _return_ link tag, and it will be appended to the stream output
        createLink(`dist/${style}`), // <link href="dist/mystyle.css />
    );
    new MultiStream([styledStream, endStream]).pipe(res);
  
  
    HtmlStream.pipe(
      .pipe(styledStream, { end: false }).pipe(
      through(
        function write(data) {
          this.queue(styledStream);
          this.queue(data);
        },
        async function end() {
          this.queue('</div>');
          this.queue(chunkExtractor.getScriptTags());
          this.queue(chunkExtractor.getStyleTags());
          this.queue(endStream);
          this.queue(null);
  
          res.end();
        },
      ),
    );
  } catch (error) {
    res.status(500).send('Oops, better luck next time!');
  }
}
@theKashey
Copy link
Owner

That means that const lookup = await stylesLookup; resolves to undefined. And it does. And it's easy to fix it.

However this is intended way to use it:

await stylesLookup;
 const styledStream = createStyleStream(
      stylesLookup, // use the same variable

Plus please scan styles only once, and better outside of the render function, so they would be ready a bit earlier.
Plus the scan operation is more or less expensive(they all got parsed with PostCSS and analysed), and it's better not to run it frequently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants