Hi there,
I've run into the issue "window is not defined" when trying to run the 'server.js' file. The error is as bellow:
$ NODE_ENV=production node build/server.js
/Users/sanguyen/Documents/Work/my-app/node_modules/react-ace/lib/editorOptions.js:31
if (window.ace) {
^
ReferenceError: window is not defined
at Object.getAceInstance (/Users/sanguyen/Documents/Work/my-app/node_modules/react-ace/lib/editorOptions.js:31:5)
at Object.<anonymous> (/Users/sanguyen/Documents/Work/my-app/node_modules/react-ace/lib/ace.js:31:27)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (/Users/sanguyen/Documents/Work/my-app/node_modules/react-ace/lib/index.js:3:13)
When I'm trying to use "@elastic/eui" packge in my app.
Steps to reproduce:
npx create-razzle-app my-app
cd my-app
yarn add @elastic/eui @elastic/datemath moment
import React from 'react';
import logo from './react.svg';
import './Home.css';
import { EuiFieldPassword } from '@elastic/eui';
class Home extends React.Component {
render() {
return <div className="Home">
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo" />
<h2>Welcome to Razzle</h2>
</div>
<p className="Home-intro">
To get started, edit <code>src/App.js</code> or <code>src/Home.js</code> and save to reload.
</p>
<ul className="Home-resources">
<li>
<a href="https://github.com/jaredpalmer/razzle">Docs</a>
</li>
<li>
<a href="https://github.com/jaredpalmer/razzle/issues">Issues</a>
</li>
<li>
<a href="https://palmer.chat">Community Slack</a>
</li>
</ul>
<EuiFieldPassword placeholder="Placeholder text" value={'helllow there'} onChange={() => {}} aria-label="Use aria labels when no actual label is in use" />
</div>;
}
}
export default Home;
yarn build
yarn start:prod
Expected: will start successfully without issue
Actual: getting 'window is not defined'
I know the 'window' or 'document' object will not used or available in Node. So, is there any way that we can fix this issue?
Thanks
You are rendering a rich text editor server side. This is a @elastic/eui or react-ace issue.
@fivethreeo got it. And Razzle supports SSR as default so it also means Razzle will not work if my app is using a rich text editor library?
BTW, since my app is currently using CRA with client side rendering and I'm thinking to convert to Razzle for SSR.
You could render something else server side.
@fivethreeo, Do you have any suggestion how to do that? Since, everything will be rendered under <App />.
As far as I know, whatever libraries/components which I used in the client side will be rendered in the server code.
`
ReactDomServer.renderToString(
<StaticRouter context={context} location={req.url}>
<App />
</StaticRouter>
);
const ssrEuiFieldPassword =
typeof window !== 'undefined' ? EuiFieldPassword : OtherComponent;
@fivethreeo, It seems doesn't work, I added like this:
class Home extends React.Component {
render() {
const ssrEuiFieldPassword = typeof window !== 'undefined' ? EuiFieldPassword : div;
return <div className="Home">
<div className="Home-header">
<img src={logo} className="Home-logo" alt="logo" />
<h2>Welcome to Razzle</h2>
</div>
<p className="Home-intro">
To get started, edit <code>src/App.js</code> or <code>src/Home.js</code> and save to reload.
</p>
<ul className="Home-resources">
<li>
<a href="https://github.com/jaredpalmer/razzle">Docs</a>
</li>
<li>
<a href="https://github.com/jaredpalmer/razzle/issues">Issues</a>
</li>
<li>
<a href="https://palmer.chat">Community Slack</a>
</li>
</ul>
<ssrEuiFieldPassword placeholder="Placeholder text" value={'helllow there'} onChange={() => {}} aria-label="Use aria labels when no actual label is in use" />
</div>;
}
}
export default Home;
I could start the app successfully but I ran into the issue when accessing http://localhost:3000
$ NODE_ENV=production node build/server.js
馃殌 started
(node:8236) UnhandledPromiseRejectionWarning: ReferenceError: window is not defined
at Object.getAceInstance (/Users/sanguyen/Documents/Work/my-app/node_modules/react-ace/lib/editorOptions.js:31:5)
at Object.<anonymous> (/Users/sanguyen/Documents/Work/my-app/node_modules/react-ace/lib/ace.js:31:27)
I would do it outside the component so you don鈥檛 redefine it on each render/mount.
Try
const ssrEuiFieldPassword =
process.env.BUILD_TARGET === 'client' ? EuiFieldPassword : OtherComponent;
Oh, misread that traceback. You need to do a conditional import/require.
const ssrEuiFieldPassword =
process.env.BUILD_TARGET === 'client' ? require('@elastic/eui').EuiFieldPassword : OtherComponent;
Thanks @fivethreeo, it's working!
@samjetski ok if you did this you will get some hydration errors in browser console, according to ReadDOM docs:
If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a state variable like this.state.isClient, which you can set to true in componentDidMount(). This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. Note that this approach will make your components slower because they have to render twice, so use it with caution.
so my suggestion here is to create a component called NoSSR like this:
class NoSSR extends React.Component {
state = {
isClient: false
}
componentDidMount() {
this.setState({ isClient: true })
}
render() {
const { isClient } = this.state
const { children } = this.props
return isClient ? children : null;
}
}
and use it in this way:
<NoSSR>
<EuiFieldPassword
placeholder="Placeholder text"
value={'helllow there'}
onChange={() => {}}
aria-label="Use aria labels when no actual label is in use"
/>
</NoSSR>
GG EZ
Please Close this issue after you read this message.
Closed due to inactivity. Holler if this is a mistake, and we'll re-open it.
so my suggestion here is to create a component called NoSSR like this:
class NoSSR extends React.Component { state = { isClient: false } componentDidMount() { this.setState({ isClient: true }) } render() { const { isClient } = this.state const { children } = this.props return isClient ? children : null; } }@nimaa77 I like your really nice solution for disabling SSR.
The solution is to disable SSR for your react-ace component. None of the examples given worked for me.
The below snippet is working in NextJS v10.0.3. Note that the use of require instead of import; your linter will probably flag this.
import React from "react";
import dynamic from "next/dynamic";
const Editor = dynamic(
async () => {
const ace = await require("react-ace");
require("ace-builds/src-noconflict/mode-javascript");
require("ace-builds/src-noconflict/theme-github");
return ace;
},
{
loading: () => (
<p>Loading</p>
),
ssr: false,
},
);
export default function CodeEditor(props) {
return (
<Editor
{...props}
/>
);
}
...and then use it where you like just as you would have done with AceEditor:
<CodeEditor
onChange={(text )=> console.log(text)}
mode="javascript"
theme="github"
showPrintMargin={false}
width="100%"
editorProps={{ $blockScrolling: true }}
/>
I realise this repo isn't directly related to react-ace but this issue is currently a top result on Google for this error message. Hopefully this helps someone else out.
Most helpful comment