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

[EuiCollapsibleNav] document is not defined when using CollapsibleNav #4807

Closed
Paku580 opened this issue May 18, 2021 · 6 comments · Fixed by #5422
Closed

[EuiCollapsibleNav] document is not defined when using CollapsibleNav #4807

Paku580 opened this issue May 18, 2021 · 6 comments · Fixed by #5422
Assignees

Comments

@Paku580
Copy link

Paku580 commented May 18, 2021

I tried to add a EuiCollapsibleNav to your nextjs eui example here https://elastic.github.io/next-eui-starter/. This worked until i decided to restart the server. Then i got this weird error "document is not defined".

StackTrace:

ReferenceError: document is not defined
    at EuiOverlayMask (webpack-internal:///./node_modules/@elastic/eui/es/components/overlay_mask/overlay_mask.js:64:78)
    at processChild (.../next-eui-starter/node_modules/react-dom/cjs/react-dom-server.node.development.js:3353:14)
    at resolve (.../next-eui-starter/node_modules/react-dom/cjs/react-dom-server.node.development.js:3270:5)
    at ReactDOMServerRenderer.render (.../next-eui-starter/node_modules/react-dom/cjs/react-dom-server.node.development.js:3753:22)
    at ReactDOMServerRenderer.read (.../next-eui-starter/node_modules/react-dom/cjs/react-dom-server.node.development.js:3690:29)
    at renderToString (.../next-eui-starter/node_modules/react-dom/cjs/react-dom-server.node.development.js:4298:27)
    at Object.renderPage (.../next-eui-starter/node_modules/next/dist/next-server/server/render.js:54:854)
    at Function.getInitialProps (webpack-internal:///./node_modules/next/dist/pages/_document.js:141:19)
    at loadGetInitialProps (.../next-eui-starter/node_modules/next/dist/next-server/lib/utils.js:5:101)
    at renderToHTML (.../next-eui-starter/node_modules/next/dist/next-server/server/render.js:54:1145)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async .../next-eui-starter/node_modules/next/dist/next-server/server/next-server.js:112:97
    at async .../next-eui-starter/node_modules/next/dist/next-server/server/next-server.js:105:142
    at async DevServer.renderToHTMLWithComponents (.../next-eui-starter/node_modules/next/dist/next-server/server/next-server.js:137:387)
    at async DevServer.renderToHTML (.../next-eui-starter/node_modules/next/dist/next-server/server/next-server.js:138:522)

I then found out that this starter example doesn't use babel/polyfill so I thought this might be causing the problem.
So I added babel and the .babelrc file at the root of the project with following configuration:

{
  "comments": true,
  "presets": [
    ["@babel/env", {
      "useBuiltIns": "usage",
      "corejs": 3,
      "modules": "commonjs"
    }],
    ["@babel/typescript", { "isTSX": true, "allExtensions": true }],
    "@babel/react"
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    "pegjs-inline-precompile",
    "add-module-exports",
    "@babel/proposal-object-rest-spread",
    "@babel/proposal-class-properties"
  ]
}

This is the code i modified in the _app.tsx while trying to add the CollapsibleNav:

import { AppProps } from 'next/app';
import React, { FunctionComponent, useState } from 'react';
import {
  EuiCollapsibleNav,
  EuiCollapsibleNavGroup,
  EuiFlexGroup,
  EuiFlexItem,
  EuiHeader,
  EuiHeaderLogo,
  EuiHeaderSectionItemButton,
  EuiIcon,
  EuiListGroup,
  EuiPage,
} from '@elastic/eui';

import './app.scss';

import { EuiListGroupItemProps } from '@elastic/eui/src/components/list_group/list_group_item';

const EuiApp: FunctionComponent<AppProps> = ({ Component, pageProps }) => {
  const [navIsopen, setNavIsOpen] = useState(true);
  const LearnLinks: EuiListGroupItemProps[] = [
    { label: 'Docs', href: '#/navigation/collapsible-nav' },
    { label: 'Blogs', href: '#/navigation/collapsible-nav' },
    { label: 'Webinars', href: '#/navigation/collapsible-nav' },
    { label: 'Elastic.co', href: 'https://elastic.co' },
  ];
  const collapsibleNav = (
    <EuiCollapsibleNav
      isOpen={navIsopen}
      isDocked={false}
      showButtonIfDocked={true}
      button={
        <EuiHeaderSectionItemButton onClick={() => setNavIsOpen(!navIsopen)}>
          <EuiIcon type={'menu'} size="m" aria-hidden="true" />
        </EuiHeaderSectionItemButton>
      }
      onClose={() => setNavIsOpen(false)}>
      <EuiFlexItem className="eui-yScroll">
        <EuiCollapsibleNavGroup
          title="Learn"
          iconType="training"
          isCollapsible={true}
          initialIsOpen={false}>
          <EuiListGroup aria-label="Learn" listItems={LearnLinks} />
        </EuiCollapsibleNavGroup>
      </EuiFlexItem>
    </EuiCollapsibleNav>
  );
  const leftSectionItems = [
    collapsibleNav,
    // eslint-disable-next-line react/jsx-key
    <EuiHeaderLogo iconType="logoElastic">Elastic</EuiHeaderLogo>,
  ];
  return (
    <>
      <EuiFlexGroup gutterSize="none" direction="column">
        <EuiHeader
          position="fixed"
          sections={[
            {
              items: leftSectionItems,
              borders: 'right',
            },
          ]}
        />
        <EuiPage />
      </EuiFlexGroup>
    </>
  );
};

export default EuiApp;

I tried several things to solve this none of it worked yet.
Since the starter example uses an older version I tried upgrading it but that didn't solve it either.

I am out of ideas and don't know if this is an actual issue in elastic ui or I am just missing any specific configuration.
Following this doc https://elastic.github.io/eui/#/layout/header#the-elastic-navigation-pattern the code seems right so I guess I am missing some configuration but couldn't find anything about it.

@miukimiu
Copy link
Contributor

Hi @Paku580,

It seems that EuiOverlayMask is not supported in server-side rendering. I'm not 100% familiar with next-js so it's better to open an issue here: https://github.com/elastic/next-eui-starter/issues.

But I tested your code and this code seems to make it work:

const [_document, set_document] = React.useState(null)

React.useEffect(() => {
    set_document(document)
}, [])

I found the solution here: https://stackoverflow.com/questions/60629258/next-js-document-is-not-defined. And I don't actually know if it's a good idea or not. 🤷🏽

@thompsongl
Copy link
Contributor

Full support for server-side rendering isn't something we kept top-of-mind, but it is something we'd like to work towards.
The right approach would be to update EuiCollapsibleNav to check for the existence of document before executing the effect.

@Patil2099
Copy link

@miukimiu I would love to work on this issue. Can you guide me in solving this issue?

@jeepers3327
Copy link
Contributor

How about this one. Check first is component is mounted before rendering the whole app.

const EuiApp: FunctionComponent<AppProps> = ({ Component, pageProps }) => {
  const [isMounted, setIsMounted] = useState(false);
  const [navIsopen, setNavIsOpen] = useState(true);
  
  useEffect(() => {
    
    setIsMounted(true);
    
    return () =>  {
       setIsMounted(false);
    }
  
  }, []);
  
  const LearnLinks: EuiListGroupItemProps[] = [
    { label: 'Docs', href: '#/navigation/collapsible-nav' },
    { label: 'Blogs', href: '#/navigation/collapsible-nav' },
    { label: 'Webinars', href: '#/navigation/collapsible-nav' },
    { label: 'Elastic.co', href: 'https://elastic.co' },
  ];
  const collapsibleNav = (
    <EuiCollapsibleNav
      isOpen={navIsopen}
      isDocked={false}
      showButtonIfDocked={true}
      button={
        <EuiHeaderSectionItemButton onClick={() => setNavIsOpen(!navIsopen)}>
          <EuiIcon type={'menu'} size="m" aria-hidden="true" />
        </EuiHeaderSectionItemButton>
      }
      onClose={() => setNavIsOpen(false)}>
      <EuiFlexItem className="eui-yScroll">
        <EuiCollapsibleNavGroup
          title="Learn"
          iconType="training"
          isCollapsible={true}
          initialIsOpen={false}>
          <EuiListGroup aria-label="Learn" listItems={LearnLinks} />
        </EuiCollapsibleNavGroup>
      </EuiFlexItem>
    </EuiCollapsibleNav>
  );
  const leftSectionItems = [
    collapsibleNav,
    // eslint-disable-next-line react/jsx-key
    <EuiHeaderLogo iconType="logoElastic">Elastic</EuiHeaderLogo>,
  ];
  
  if (!isMounted) return null;
  
  return (
    <>
      <EuiFlexGroup gutterSize="none" direction="column">
        <EuiHeader
          position="fixed"
          sections={[
            {
              items: leftSectionItems,
              borders: 'right',
            },
          ]}
        />
        <EuiPage />
      </EuiFlexGroup>
    </>
  );
};

@github-actions
Copy link

👋 Hey there. This issue hasn't had any activity for 180 days. We'll automatically close it if that trend continues for another week. If you feel this issue is still valid and needs attention please let us know with a comment.

@b0r1sp
Copy link

b0r1sp commented Nov 26, 2021

Hi, any volunteers here to fix that nasty thing? In my case that issue popped up, when using next + flyout + property push - e.g.:

return (
      <>
          <EuiFlyout
            type="push"
            onClose={() => {}}
          >
          ...
          </EuiFlyout>
      </>
);

Quick fix:

if (typeof document !== 'undefined') {
  return (
    <>
        <EuiFlyout
          type="push"
          onClose={() => {}}
        >
        ...
        </EuiFlyout>
    </>
  ) else {
    return null;
};

FRom reading the source the fix would be to prevent calling document in EuiOverlayMask during ssr. From my understanding that should actually fix similar issues with EuiCollapsibleNav, EuiModal,...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment