Всем привет,
Я столкнулся с проблемой «окно не определено» при попытке запустить файл «server.js». Ошибка выглядит следующим образом:
$ 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)
Когда я пытаюсь использовать пакет @elastic/eui в своем приложении.
Действия по воспроизведению:
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
Ожидается: запустится успешно без проблем
Фактически: получение «окно не определено»
Я знаю, что объект «окно» или «документ» не будет использоваться или доступен в Node. Итак, есть ли способ решить эту проблему?
Спасибо
Вы визуализируете серверную часть редактора форматированного текста. Это проблема @elastic/eui или react-ace.
@fivethreeo понял. И Razzle поддерживает SSR по умолчанию, так что это также означает, что Razzle не будет работать, если мое приложение использует библиотеку расширенного текстового редактора?
Кстати, поскольку мое приложение в настоящее время использует CRA с рендерингом на стороне клиента, и я думаю перейти на Razzle для SSR.
Вы можете сделать что-то еще на стороне сервера.
@fivethreeo , у вас есть предложения, как это сделать? Поскольку все будет отображаться под <App />
.
Насколько я знаю, любые библиотеки/компоненты, которые я использовал на стороне клиента, будут отображаться в коде сервера.
`
ReactDomServer.renderToString(
<StaticRouter context={context} location={req.url}>
<App />
</StaticRouter>
);
const ssrEuiFieldPassword =
typeof window !== 'undefined' ? EuiFieldPassword : OtherComponent;
@fivethreeo , кажется, не работает, я добавил так:
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;
Я мог успешно запустить приложение, но столкнулся с проблемой при доступе к 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)
Я бы сделал это вне компонента, чтобы вы не переопределяли его при каждом рендеринге/монтировании.
Пытаться
const ssrEuiFieldPassword =
process.env.BUILD_TARGET === 'client' ? EuiFieldPassword : OtherComponent;
О, неправильно прочитал этот след. Вам нужно выполнить условный импорт/требовать.
const ssrEuiFieldPassword =
process.env.BUILD_TARGET === 'client' ? require('@elastic/eui').EuiFieldPassword : OtherComponent;
Спасибо @fivethreeo , все работает!
@samjetski хорошо, если вы это сделаете, вы получите некоторые ошибки гидратации в консоли браузера, согласно документам ReadDOM :
Если вам намеренно нужно отображать что-то другое на сервере и на клиенте, вы можете выполнить двухпроходный рендеринг. Компоненты, которые отображают что-то другое на клиенте, могут считывать переменную состояния, такую как this.state.isClient, для которой вы можете установить значение true в componentDidMount(). Таким образом, начальный проход рендеринга будет отображать тот же контент, что и сервер, избегая несоответствий, но дополнительный проход будет выполняться синхронно сразу после гидратации. Обратите внимание, что этот подход сделает ваши компоненты медленнее, потому что они должны рендериться дважды, поэтому используйте его с осторожностью.
поэтому я предлагаю создать компонент с именем NoSSR следующим образом:
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;
}
}
и используйте его таким образом:
<NoSSR>
<EuiFieldPassword
placeholder="Placeholder text"
value={'helllow there'}
onChange={() => {}}
aria-label="Use aria labels when no actual label is in use"
/>
</NoSSR>
ГГ ЭЗ
Пожалуйста, закройте эту проблему после прочтения этого сообщения.
Закрыт из-за бездействия. Крикните, если это ошибка, и мы снова откроем его.
поэтому я предлагаю создать компонент с именем NoSSR следующим образом:
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 Мне нравится ваше действительно хорошее решение для отключения SSR.
Решение состоит в том, чтобы отключить SSR для вашего компонента react-ace. Ни один из приведенных примеров не работал для меня.
Фрагмент ниже работает в NextJS v10.0.3. Обратите внимание, что использование require
вместо import
; ваш линтер, вероятно, отметит это.
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}
/>
);
}
...и затем используйте его, где хотите, так же, как если бы вы делали это с AceEditor:
<CodeEditor
onChange={(text )=> console.log(text)}
mode="javascript"
theme="github"
showPrintMargin={false}
width="100%"
editorProps={{ $blockScrolling: true }}
/>
Я понимаю, что это репо не имеет прямого отношения к react-ace, но эта проблема в настоящее время является лучшим результатом в Google для этого сообщения об ошибке. Надеюсь, это поможет кому-то еще.
Самый полезный комментарий