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

feat(v2): add a way to exclude components from build-time prerendering #2323

Merged
merged 11 commits into from
Mar 29, 2020

Conversation

lex111
Copy link
Contributor

@lex111 lex111 commented Feb 26, 2020

Motivation

Resolve #2273.

Have you read the Contributing Guidelines on pull requests?

Yes

Test Plan

  1. Inside ClientOnly put component that used window object, eg.

Related PRs

(If this PR adds or changes functionality, please take some time to update the docs at https://github.com/facebook/docusaurus, and link to your PR here.)

@lex111 lex111 added the pr: new feature This PR adds a new API or behavior. label Feb 26, 2020
@lex111 lex111 requested a review from yangshun February 26, 2020 00:40
@lex111 lex111 requested a review from wgao19 as a code owner February 26, 2020 00:40
@facebook-github-bot facebook-github-bot added the CLA Signed Signed Facebook CLA label Feb 26, 2020
@docusaurus-bot
Copy link
Contributor

docusaurus-bot commented Feb 26, 2020

Deploy preview for docusaurus-2 ready!

Built with commit 63ee326

https://deploy-preview-2323--docusaurus-2.netlify.com

@yangshun yangshun changed the title feat(v2): add a way to exclude components from SSR within JSX feat(v2): add a way to exclude components from server prerendering within JSX Feb 26, 2020
import React, {useEffect, useState} from 'react';

const ClientOnly = ({children}) => {
const [isClient, setIsClient] = useState(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think isComponentMounted will be a better name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

import React, {useEffect, useState} from 'react';

const BrowserOnly = ({children}) => {
const [isClient, setIsClient] = useState(false);
Copy link
Contributor

@yangshun yangshun Feb 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw I'm wondering if we can use the ExecutionEnvironment.canUseDOM instead, then there's no need for a state right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why so? This state is needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the diff between doing your way and this:

function BrowserOnly({children}) => {
  return ExecutionEnvironment.canUseDOM && children;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seemed to me that all the work of this component is to use useEffect, isn't it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and I think we don't even need useEffect here. Can you try what I've proposed and see whether there's any difference? :/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that none of the options actually works, it really puzzled me and in complete dismay 🤒

P.S. For the test, I used the @u-wave/react-vimeo component in the MDX file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So even your current implementation doesn't work? Luckily we test out first lol. Maybe the component is running some side effects that relies on browser environments being present during import. In that case there's no way around it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly, rather why something does not work, this component on some dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some investigation I found out that build fails if a component using a window object is imported, how is this possible? Therefore the BrowserOnly component is useless here 🤷‍♂️

@yangshun yangshun changed the title feat(v2): add a way to exclude components from server prerendering within JSX feat(v2): add a way to exclude components from build-time prerendering within JSX Feb 26, 2020
@yangshun yangshun changed the title feat(v2): add a way to exclude components from build-time prerendering within JSX feat(v2): add a way to exclude components from build-time prerendering Feb 26, 2020
Copy link
Contributor

@yangshun yangshun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went to test this component out and it doesn't seem to work. I'm not sure why but I think we can't let the children be JSX, we have to let it be a render function.

To reproduce the bug, add

<BrowserOnly>{window.location.pathname}</BrowserOnly>

to any page and try to build it. It will fail.

But if you do this:

<BrowserOnly>{() => window.location.pathname}</BrowserOnly>

along with the suggested change of doing children() within BrowserOnly.js, it will be fine.

Will need to change the docs also and say the contents have to be a render function. Will also be good to have tests.


import React, {useEffect, useState} from 'react';

const BrowserOnly = ({children}) => {
Copy link
Contributor

@yangshun yangshun Feb 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also works and is shorter IMO.

function BrowserOnly({children}) {
  return ExecutionEnvironment.canUseDOM && children != null && <>{children()}</>;
};

Let's use function declaration for functional components.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, although this does not solve the issue of importing components using window.

For example, if I just import this component in the MDX file, then I will have an error during the building that the window is not defined.

import {Replay} from 'vimond-replay';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, users will have to lazy load the component after the component has mounted. There's no way we can handle that with the suggested component here.

@yangshun
Copy link
Contributor

@lex111 shall we try to get this into the next release?

@lex111
Copy link
Contributor Author

lex111 commented Mar 28, 2020

@yangshun done ✔️

@lex111 lex111 added this to the v2.0.0-alpha.49 milestone Mar 28, 2020
Copy link
Contributor

@yangshun yangshun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will fix this if you don't get to it by tonight so that we can include this in the next release.

import BrowserOnly from '@docusaurus/BrowserOnly';

<BrowserOnly>
{/* Something that should be excluded during build process prerendering. */}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to give an example to show that children should be a render function and not normal children.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, done ✔️

website/docs/docusaurus-core.md Outdated Show resolved Hide resolved
@yangshun yangshun merged commit 8143af6 into master Mar 29, 2020
@yangshun yangshun deleted the feat-exclude-ssr branch March 29, 2020 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Signed Facebook CLA pr: new feature This PR adds a new API or behavior.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[v2] add a way to exclude components from SSR within JSX
4 participants