talyssonoc / react-laravel

Package for using ReactJS with Laravel
896 stars 90 forks source link

undefined:13: ReferenceError: document is not defined #77

Closed aprilmintacpineda closed 7 years ago

aprilmintacpineda commented 7 years ago

I'm using gulp to mix all my scripts into public/js/app.js.

web.php

Route::get('{slug}', function ($slug) {
    return view('index');
})->where('slug', '(?![api])([A-Za-z\/\-]+)');

index.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>React Laravel</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="{{ asset('css/app.css') }}">
</head>
<body>
    <div id="app">
        @react_component('Testing', ['initialData' => 'This is prerendered data'])
    </div>
    <script type="text/javascript" src="{{ asset('js/app.js') }}"></script>
</body>
</html>

My Components

I only have one component I am using to test things out, which is at root-dir/resources/js/components. then I have my app.js as an entry point for my gulp located at root-dir/resources/js/app.js.

app.js (entry point)

import React from 'react';
import ReactDOM from 'react-dom';

import Testing from './components/Testing';

ReactDOM.render(
    <Testing/>,
    document.getElementById('app')
);

Testing.js (component)

import React from 'react';

const Testing = React.createClass({
    render () {
        console.log(this.props.initialData);

        return (
            <h1>Hello World</h1>
        );
    }
});

export default Testing;

and When I load my page I get this output error:

undefined:13: ReferenceError: document is not defined

I've trying using this instead:

{!! React::render('Testing', ['initialData' => 'Hue']) !!}

but still the same output.

react.php

<?php

return [
  'source'     => base_path('node_modules/react/dist/react.min.js'),
  'dom-source' => base_path('node_modules/react-dom/dist/react-dom.min.js'),
  'dom-server-source' => base_path('node_modules/react-dom/dist/react-dom-server.min.js'),
  'components' => base_path('public/js/app.js')
];

btw my npm is throwing me this whenever I do npm ls

npm ERR! peer dep missing: react@^0.14.7, required by react-dom-server@0.0.5
npm ERR! peer dep missing: fbjs@^0.7.2, required by react-dom-server@0.0.5
npm ERR! peer dep missing: react-children@^0.0.3, required by react-dom-server@0.0.5
npm ERR! peer dep missing: react-universal@^0.0.3, required by react-dom-server@0.0.5
aprilmintacpineda commented 7 years ago

I got it, I know where the error is coming from, I think it is because of this:

import React from 'react';
import ReactDOM from 'react-dom';

import Testing from './components/Testing';

ReactDOM.render(
    <Testing/>,
    document.getElementById('app')
);

The line document.getElementById('app') is causing the error, the document right there is undefined because when you run this line on v8 there is no document object, at least this is my theory. how to fix this,,,

talyssonoc commented 7 years ago

@four-eyes-04-04 you don't need to mount the component on the DOM yourself, that's what the JS part of this lib is for, it will mount it for you where you use the @react_component! It's done right here: https://github.com/talyssonoc/react-laravel/blob/master/assets/react_ujs.js#L35

aprilmintacpineda commented 7 years ago

@talyssonoc

I tried that out:

resources/assets/js/app.js (entry point)

import Greet from './components/Greet';

resources/assets/js/components/Greet.js

import React from 'react';

const Greet = React.createClass({
    render () {
        console.log(this.props.initialData);

        return (
            <h1>Hello World</h1>
        );
    }
});

export default Greet;

index.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>React Laravel</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="{{ asset('css/app.css') }}">
</head>
<body>
    <div id="app">
        @react_component('Greet', ['initialData' => 'This is prerendered data'])
    </div>
    <script type="text/javascript" src="{{ asset('js/app.js') }}"></script>
</body>
</html>

now I got:

V8Js::compileString():1: ReferenceError: Greet is not defined

Do you guys have a working sample project?

talyssonoc commented 7 years ago

I think Babel is trolling you 😞 . Look how it compiles your entry point: https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&code=import%20Greet%20from%20'.%2Fcomponents%2FGreet'%3B

There's no Greet variable there... Just for testing sake, could you try to do something like that?

https://babeljs.io/repl/#?babili=false&evaluate=false&lineWrap=false&presets=es2015%2Cstage-2&code=import%20_Greet%20from%20'.%2Fcomponents%2FGreet'%3B%0A%0Aconst%20Greet%20%3D%20_Greet%3B

aprilmintacpineda commented 7 years ago

@talyssonoc

if I do:

const Greet = require('./components/Greet.js');

it would say No module loaders

if I do:

import _Greet from './components/Greet';

const Greet = _Greet;

It would say unexpected token import.

Don't you have a sample project that has at least 2 components? I think that would help me to understand react-laravel's work flow so much more. I'll be better if it uses Gulp and webpack to mix all the scripts into one js file.

aprilmintacpineda commented 7 years ago

I tried to do this:

app.js (entry point for gulp webpack)

import React from 'react';
import ReactDOM from 'react-dom';

var Greet = require('./components/Greet');

still I got:

V8Js::compileString():1: ReferenceError: Greet is not defined

then I tried:

import React from 'react';
import ReactDOM from 'react-dom';

import _Greet from './components/Greet';

var Greet = _Greet;

which doesn't make sense because it's kind of like a redundant declaration but still worth a shot, hehe I got the same output though.

TomCaserta commented 7 years ago

Just took a glance over it, it could be babel/browserify as it bundles the source and wraps them. I am not sure if there is a better way of doing it (I am sure there is - or at least we can make some modifications to the library to make it better for browserify compiled bundles) but previously I had to export my components to the window. To do that you have to do something like the following:

import Greet from "./components/Greet";
window["Greet"] = Greet;
talyssonoc commented 7 years ago

@TomCaserta's solution is also a good one. Since we'll need it to be on the window object anyway for the mounting after the page load (read the end of this section: https://github.com/talyssonoc/react-laravel#configurations)

aprilmintacpineda commented 7 years ago

@TomCaserta your solution worked!

app.js (entry point for webpack)

import Greet from './components/Greet';
window.Greet = Greet;

Greet.js

import React from 'react';

const Greet = React.createClass({
    render () {
        return (
            <h1>{this.props.title}</h1>
        );
    }
});

export default Greet;

index.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>React Laravel</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="{{ asset('css/app.css') }}">
</head>
<body>
    <div id="app">
        @react_component('Greet', ['title' => 'this is an intial data'])
    </div>
    <script type="text/javascript" src="{{ asset('js/app.js') }}"></script>
</body>
</html>

however

Isn't it a pain in the ass to do all that? I just imported it which creates a variable greet then I have to add that on the window object. It would be better to simply allow us to write like this:

import Greet from './components/Greet';

because that window.Greet = Greet adds an unnecessary redundancy.

aprilmintacpineda commented 7 years ago

@talyssonoc sorry, my bad, I didn't read that part, hehe.

talyssonoc commented 7 years ago

@four-eyes-04-04 unfortunately we need to do something like that (expect the component to being on window) because we need a way to reach it from react-laravel's JS file (https://github.com/talyssonoc/react-laravel/blob/master/assets/react_ujs.js#L32) to mount it after the page load. Maybe you could use CommonJS in your app.js file and do window.Greet = require('./components/Greet'), it seems less bloated, what do you think?

aprilmintacpineda commented 7 years ago

@talyssonoc @TomCaserta thank you both 💯 👍

if I have more question or run into trouble, I hope to see you guys here again! :-)