Razzle: Fenster ist nicht definiert

Erstellt am 11. Feb. 2020  ·  14Kommentare  ·  Quelle: jaredpalmer/razzle

Hi,

Ich bin auf das Problem „Fenster ist nicht definiert“ gestoßen, als ich versuchte, die Datei „server.js“ auszuführen. Der Fehler ist wie folgt:

$ 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)

Wenn ich versuche, das Paket „@elastic/eui“ in meiner App zu verwenden.

Schritte zum Reproduzieren:

  1. Erstellen Sie eine neue Anwendung
npx create-razzle-app my-app
  1. Installiert erforderliche Pakete
cd my-app
yarn add @elastic/eui @elastic/datemath moment
  1. Öffnen Sie Home.js und ersetzen Sie den Inhalt wie folgt
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;

  1. Bauen
yarn build
  1. Starten Sie die server.js
yarn start:prod

Erwartet: wird ohne Probleme erfolgreich gestartet
Aktuell: 'Fenster ist nicht definiert' erhalten

Ich weiß, dass das Objekt „Fenster“ oder „Dokument“ in Node nicht verwendet wird oder verfügbar ist. Gibt es also eine Möglichkeit, dieses Problem zu beheben?

Danke

Hilfreichster Kommentar

const ssrEuiFieldPassword =
  process.env.BUILD_TARGET === 'client' ? require('@elastic/eui').EuiFieldPassword : OtherComponent;

Alle 14 Kommentare

Sie rendern serverseitig einen Rich-Text-Editor. Dies ist ein @elastic/eui- oder React-Ace-Problem.

@fivethreeo hat es verstanden. Und Razzle unterstützt SSR standardmäßig, was bedeutet, dass Razzle nicht funktioniert, wenn meine App eine Rich-Text-Editor-Bibliothek verwendet?
Übrigens, da meine App derzeit CRA mit clientseitigem Rendering verwendet und ich überlege, für SSR in Razzle zu konvertieren.

Sie könnten etwas anderes serverseitig rendern.

@fivethreeo , hast du einen Vorschlag, wie man das macht? Da wird alles unter <App /> gerendert.

Soweit ich weiß, werden alle Bibliotheken/Komponenten, die ich auf der Clientseite verwendet habe, im Servercode gerendert.

` ReactDomServer.renderToString( <StaticRouter context={context} location={req.url}> <App /> </StaticRouter> );

const ssrEuiFieldPassword =
  typeof window !== 'undefined' ? EuiFieldPassword : OtherComponent;

@fivethreeo , es scheint nicht zu funktionieren, ich habe so hinzugefügt:

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;

Ich konnte die App erfolgreich starten, aber ich bin auf das Problem gestoßen, als ich auf http://localhost :3000 zugegriffen habe

$ 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)

Ich würde es außerhalb der Komponente tun, damit Sie es nicht bei jedem Rendern / Mounten neu definieren.

Versuchen

const ssrEuiFieldPassword =
  process.env.BUILD_TARGET === 'client' ? EuiFieldPassword : OtherComponent;

Oh, das Traceback falsch verstanden. Sie müssen einen bedingten Import/Require durchführen.

const ssrEuiFieldPassword =
  process.env.BUILD_TARGET === 'client' ? require('@elastic/eui').EuiFieldPassword : OtherComponent;

Danke @fivethreeo , es funktioniert!

@samjetski ok, wenn Sie dies getan haben, erhalten Sie laut ReadDOM-Dokumentation einige Hydratationsfehler in der Browserkonsole:

Wenn Sie auf dem Server und dem Client absichtlich etwas anderes rendern müssen, können Sie ein Two-Pass-Rendering durchführen. Komponenten, die auf dem Client etwas anderes rendern, können eine Statusvariable wie this.state.isClient lesen, die Sie in componentDidMount() auf true setzen können. Auf diese Weise rendert der anfängliche Renderdurchgang denselben Inhalt wie der Server, wodurch Fehlanpassungen vermieden werden, aber ein zusätzlicher Durchlauf erfolgt synchron direkt nach der Hydration. Beachten Sie, dass dieser Ansatz Ihre Komponenten langsamer macht, da sie zweimal gerendert werden müssen, verwenden Sie ihn also mit Vorsicht.

Mein Vorschlag hier ist also, eine Komponente namens NoSSR wie folgt zu erstellen:

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;
  }
}

und verwende es so:

<NoSSR>
  <EuiFieldPassword 
      placeholder="Placeholder text" 
      value={'helllow there'} 
      onChange={() => {}} 
      aria-label="Use aria labels when no actual label is in use" 
    />
</NoSSR>

GGEZ

Bitte schließen Sie dieses Problem, nachdem Sie diese Nachricht gelesen haben.

Wegen Inaktivität geschlossen. Holler, wenn dies ein Fehler ist, und wir werden es wieder öffnen.

Mein Vorschlag hier ist also, eine Komponente namens NoSSR wie folgt zu erstellen:

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 Ich mag deine wirklich nette Lösung zum Deaktivieren von SSR.

Die Lösung besteht darin, SSR für Ihre React-Ace-Komponente zu deaktivieren. Keines der angegebenen Beispiele hat bei mir funktioniert.

Das folgende Snippet funktioniert in NextJS v10.0.3. Beachten Sie, dass die Verwendung von require anstelle von import ; Ihr Linter wird dies wahrscheinlich melden.

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}
        />
    );
}

...und verwenden Sie es dann dort, wo Sie möchten, genau wie Sie es mit AceEditor getan hätten:

<CodeEditor
    onChange={(text )=> console.log(text)}
    mode="javascript"
    theme="github"
    showPrintMargin={false}
    width="100%"
    editorProps={{ $blockScrolling: true }}
/>

Mir ist klar, dass dieses Repo nicht direkt mit React-Ace zusammenhängt, aber dieses Problem ist derzeit ein Top-Ergebnis bei Google für diese Fehlermeldung. Hoffentlich hilft das jemand anderem weiter.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

GouthamKD picture GouthamKD  ·  3Kommentare

sebmor picture sebmor  ·  4Kommentare

pseudo-su picture pseudo-su  ·  3Kommentare

corydeppen picture corydeppen  ·  3Kommentare

alexjoyner picture alexjoyner  ·  3Kommentare