airbnb / hypernova-react

React bindings for Hypernova.
https://github.com/airbnb/hypernova
MIT License
248 stars 43 forks source link

Unexpected token import #40

Closed aftabnaveed closed 6 years ago

aftabnaveed commented 6 years ago

When I replace my hypernova.js file with the example code provided I get this error. I am using Create React App and my hypernova.js file is placed outside the src folder. Here is my code.

import { renderReact } from 'hypernova-react';
import App from './src/App';

export default renderReact(
    'App.hypernova.js', // this file's name (or really any unique name)
    App,
);
node hypernova.js 
/srv/project/theme/adminlte/ui/hypernova.js:1
(function (exports, require, module, __filename, __dirname) { import { renderReact } from 'hypernova-react';
                                                              ^^^^^^

SyntaxError: Unexpected token import
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:542:28)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:383:7)
    at startup (bootstrap_node.js:149:9)
ljharb commented 6 years ago

You can't use import/export in node without babel; you'll probably need to use require in that file.

aftabnaveed commented 6 years ago

I understand and using Create React App which has babel. The example is not very clear about how and where to add that code?

aftabnaveed commented 6 years ago

I am new to Node and want to use Hypernova along with PHP. Does it expect the build file if React is using Babel?

ljharb commented 6 years ago

The examples in our readme use import and export, but node doesn't support that natively. So, you'll need to use require and module.exports = on any files that aren't processed by babel - for CRA, I assume that means "outside of src".

aftabnaveed commented 6 years ago

Thanks for the response, my App.js which is an ES6 file looks like this

import React, {Component} from 'react';

import Navigation from './Navigation';
import MainArea from './MainArea';

class App extends Component {
  render() {
    return (
        <div className="App">
            <Navigation/>
            <MainArea />
        </div>
    );
  }
}

export default App;

I still get that import error even if I use require('./src/App') in my hypernova component export file.

My question is do I need to separately configure Es6 for node and hypernova? Can I just not use what comes with CRA?

ljharb commented 6 years ago

CRA doesn't have server-rendering, so it's highly unlikely you can get hypernova working with it without ejecting.

We can keep discussing here, but since this isn't related to hypernova, but rather general node questions, I'm going to close the issue.

aftabnaveed commented 6 years ago

Well, the example here is using ES6,

import { renderReact } from 'hypernova-react';
import MyComponent from './src/MyComponent.jsx';

export default renderReact(
  'MyComponent.hypernova.js', // this file's name (or really any unique name)
  MyComponent,
);

I already have the CRA ejected for other purposes and made it work with V8 engine on the server side. It just does not mention how to make ES6 work with node and for that matter hypernova.

goatslacker commented 6 years ago

Change that to

const { renderReact } = require('hypernova-react');
const MyComponent = require('./src/MyComponent.jsx');

module.exports = renderReact('MyComponent.hypernova.js', MyComponent);
aftabnaveed commented 6 years ago

Thanks, @goatslacker, does that mean my MyComponent.jsx also has to be in ES5 syntax?

goatslacker commented 6 years ago

has to be in ES5 syntax

Partially.

Node supports parts of ES6, one of the parts that it doesn't support is the module syntax since Node has its own module system.

Here's a list of features you can use with each version of Node: http://node.green/

After all,

const { renderReact } = require('hypernova-react');

is part ES6 since it uses object destructuring.

ljharb commented 6 years ago

(Don't forget to uncheck the "harmony" checkbox on node.green)

aftabnaveed commented 6 years ago

Thanks guys for your patience being new to Node I did not had any idea what was going on. I am now able to transpile my code from babel to ES5 which is then passed to Hypernova. All I had to do was was add babel dev dependencies to my project.

Here is how my Create React App package.json now looks

{
  "name": "ui",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "bootstrap": "^4.0.0",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.1.1",
    "reactstrap": "^5.0.0-beta.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "build-ssr": "webpack --config webpack.ssr.config.js",
    "start-ssr": "node ./src/ssr/hypernova-server.js"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "hypernova": "^2.2.3",
    "hypernova-react": "^2.1.0",
    "svg-loader": "^0.0.2",
    "webpack-node-externals": "^1.6.0"
  }
}

and webpack.config.ssr.json

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
    entry: './app/ssr.js',
    target: 'node',
    externals: [nodeExternals()],
    output: {
        libraryTarget: 'commonjs',
        path: path.join(__dirname, 'ssr'),
        filename: 'ssr-bundle.js'
    },
    module: {
        rules: [
            { test: /\.jsx?$/, use: 'babel-loader', exclude: /node_modules/ },
            { test: /\.svg?$/, use: 'svg-loader' },
            { test: /\.css?$/, use: 'css-loader' },
            { test: /\.(gif|png|jpe?g|svg)$/i, use: 'image-webpack-loader' },
        ]
    },
    resolve: {
        modules: ['app', 'node_modules'],
        extensions: ['.js', '.jsx']
    },
};