Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use React with ES6 #193

Closed
Aerendir opened this issue Oct 31, 2017 · 10 comments
Closed

How to use React with ES6 #193

Aerendir opened this issue Oct 31, 2017 · 10 comments
Labels

Comments

@Aerendir
Copy link

I'd like to use ES6 to write React components.

Currently I've configured Encore as the documentation suggests:

var Encore = require('@symfony/webpack-encore');

Encore
    // directory where all compiled assets will be stored
    .setOutputPath('web/build/')

    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/build')

    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()

    // will output as web/build/app.js
    .addEntry('main', './src/AppBundle/Resources/assets/js/_main.js')

    // will output as web/build/global.css
    .addStyleEntry('global', './src/AppBundle/Resources/assets/css/_global.scss')

    // allow sass/scss files to be processed
    .enableSassLoader()

    // allow legacy applications to use $/jQuery as a global variable
    .autoProvidejQuery()

    .enableSourceMaps(!Encore.isProduction())

    // create hashed filenames (e.g. app.abc123.css)
    .enableVersioning()

    // Enable react
    .enableReactPreset()
;

// export the final configuration
module.exports = Encore.getWebpackConfig();

So I'm using enableReactPreset().

But how can I use also ES6 transpiling?

This is my very first attempt to use it, and I'm a real beginner in the Javascript world, so, please, be very patient :)

@Lyrkan
Copy link
Collaborator

Lyrkan commented Oct 31, 2017

Hi @Aerendir,

Unless I'm misunderstanding your question I'd say that you don't have anything else to do.

You should be able to write your code using ES6 and it should be transpiled correctly by Babel using the default settings provided by Encore (unless you have a .babelrc file in your project), in this case:

{
    cacheDirectory: true,
    presets: [
        ['env', {
            modules: false,
            targets: {
                browsers: '> 1%',
                uglify: true
            },
            useBuiltIns: true
        }],
        'react'
    ],
    plugins: []
}

@Aerendir
Copy link
Author

@Lyrkan it seems it is not sufficient.

If I try to compile this code:

export default class Todo extends React.Component {
    constructor(props) {
        super(props);

        // Set initial state
        this.state = {
            data: props.data
        }
    }

    changeStatus = () => {
        let update = {
            opened: !this.state.data.opened
        };

        // Retrieve the todos of the list
        Axios.put(this.state.data['@id'], update)
            .then((response) => {
                let data = this.state.data;
                data.opened = !data.opened;
                this.setState({data: data});
            })
            .catch(function (error) {
                console.log(error);
            });
    }

    render() {
        let status = this.state.data.opened ? 'opened' : 'closed';
        return (
            <li className={"todo " + status} data-endpoint={this.state.data['@id']}>
                <div className="status">
                    <input type="checkbox" checked={!this.state.data.opened} onChange={this.changeStatus}/>
                </div>
                <a href={window.Routing.generate('todo_list_todo_show', {account: this.props.todoList.account.id, list: this.props.todoList.id, todo: this.state.data.id}, true)}>{this.state.data.name}</a>
            </li>
        );
    }
}

This is the error I receive:

Aerendir$ ./node_modules/.bin/encore/ dev
Running webpack ...

(node:1737) DeprecationWarning: Chunk.modules is deprecated. Use Chunk.getNumberOfModules/mapModules/forEachModule/containsModule instead.
 ERROR  Failed to compile with 1 errors                                                                                                                                                                                  5:06:32 PM

 error  in ./src/Coommercio/Bundle/TodoBundle/Resources/assets/js/Todo.jsx

Syntax Error: Unexpected token (20:17)

  18 |     }
  19 | 
> 20 |     changeStatus = () => {
     |                  ^
  21 |         let update = {
  22 |             opened: !this.state.data.opened
  23 |         };



 @ ./src/Coommercio/Bundle/TodoBundle/Resources/assets/js/TodoList.jsx 18:0-26
 @ ./src/Coommercio/Bundle/TodoBundle/Resources/assets/js/TodoBundle.jsx
 @ ./src/AppBundle/Resources/assets/js/_main.js

So there is something I'm missing, but I don't know what...

@Lyrkan
Copy link
Collaborator

Lyrkan commented Oct 31, 2017

An ES6 class can only contain method definitions, not assignments.

In your case you should probably have something like this:

export default class Todo extends React.Component {
    constructor(props) {
        // ...
    }

    changeStatus() {
        // ...
    }

    render() {
        // ...
    }
}

@stof
Copy link
Member

stof commented Oct 31, 2017

Having assignment of arrow functions in a class is not part of ES6. It is part of a draft proposal for an upcoming ES version.
Babel is able to transpile it, but you will need to enable this transformation in the babelrc file. The default babel config shipped in Encore when you don't configure babel does not enable the transpilation of experimental features.

@Aerendir
Copy link
Author

It is something suggested here: https://stackoverflow.com/a/47031631/1399706

But eventually the user who replied made an error calling it an ES6 feature...

Reading further, it seems that to use the feature I have to install stage-1 Babel preset.

At this point, the question is: how can I do this with Encore?

@Lyrkan
Copy link
Collaborator

Lyrkan commented Oct 31, 2017

Add it first using yarn: yarn add --dev babel-preset-stage-1
Then call the configureBabel() method in your webpack.config.js file:

.configureBabel((config) => {
    config.presets.push('stage-1');
})

@Lyrkan
Copy link
Collaborator

Lyrkan commented Oct 31, 2017

It looks like it is now in the stage-3 preset by the way, so you could also probably use that one.

Another option would be to directly use the transform-class-properties plugin if you only need that feature.

@weaverryan
Copy link
Member

@Aerendir Just to keep things in perspective, the feature you're trying to use is still a draft feature. That's why using it (and setting up Webpack/Encore to compile it) take a bit more setup. You can totally use it - but since you mentioned you're still new to the JavaScript world, it might be even better to just avoid the feature.

If I understand things correctly, you could make your code look like the earlier suggestion - #193 (comment) - and change this.changeStatus to this.changeStatus() in render (i.e. call it like a function).

Let us know what you find out! :)

@abhinavkumar940
Copy link

If it helps, this is what I am using and it supports arrow functions, spread operators etc.

`
    // webpack.config.js
    var Encore = require('@symfony/webpack-encore');

    Encore
    // directory where all compiled assets will be stored
    .setOutputPath('web/build/')

    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/build')

    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()

    // will output as web/build/app.js
    .addEntry('app', ["babel-polyfill", './assets/js/index.js'])

    // will output as web/build/global.css
    .addStyleEntry('global', './assets/css/global.scss')

    // allow sass/scss files to be processed
    .enableSassLoader()

    // allow legacy applications to use $/jQuery as a global variable
    .autoProvidejQuery()

    .enableSourceMaps(!Encore.isProduction())

    // Enable ReactJS
    .enableReactPreset()

    .configureBabel(function(babelConfig) {
        babelConfig.plugins = ["transform-object-rest-spread","transform-class-properties"]
    })

// create hashed filenames (e.g. app.abc123.css)
// .enableVersioning()
;

// export the final configuration
module.exports = Encore.getWebpackConfig();`

As you can guess, I had to install those two babel plugins but it all works fine now. Please feel free to ask for more details if you need any.

Thanks,
Abhinav

@Aerendir
Copy link
Author

Thank you for all of your replies!

For the moment I decided to go the standard way, to not keep too many things on the table: I prefere to first learn the standard way of doing things, then draft features when I really need it.

In the mean time, I'll keep this post in the references so, when I will be ready, I'll have all the information at hand!

Thank you again for your support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants