Anton Izmailov
Anton Izmailov

Reputation: 13

Webpack error: Unexpected token

friends! I have trouble with webpack build. In webpack I use babel 6^ + this presets:

presets: ['es2015', 'stage-1', 'react']

After npm start I catch error:

ERROR in ./src/common/components/layout/Header.js
Module build failed: SyntaxError: C:/Users/Anton/projects/isomorphic-redux-app/src/common/components/layout/Header.js: Unexpected token (13:15)
  11 |   }
  12 |
  13 |   handleToggle = () => this.setState({open: !this.state.open});
     |                ^
  14 |
  15 |   render() {
  16 |     return (

At first I thought that I have error in code, and I just copy/paste it from Material-UI docs, but it's broken too. Header.js file:

import React, { Component, PropTypes } from 'react';
import LeftNav from 'material-ui/lib/left-nav';
import AppBar from 'material-ui/lib/app-bar';
import RaisedButton from 'material-ui/lib/raised-button';

export default class Header extends Component {

  constructor(props) {
    super(props);
    this.state = {open: false};
  }

  handleToggle = () => this.setState({open: !this.state.open});

  render() {
    return (
      <div>
        <RaisedButton
          label="Controlled LeftNav That Opens From Right"
          onTouchTap={this.handleToggle} />
        <LeftNav width={200} openRight={true} open={this.state.open} >
          <AppBar title="AppBar"/>
        </LeftNav>
      </div>
    );
  }
}

And webpack.config:

var path = require('path');
var webpack = require('webpack');
var merge = require('merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');


var webpackConfig = {
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.NoErrorsPlugin()
  ]
};

if (process.env.NODE_ENV === 'production') {

  webpackConfig = merge(webpackConfig,{
    devtool: "source-map",
    entry : [
      './src/client/index.js'
    ],
    resolve: {
      extensions: ["", ".js", ".jsx"]
    },
    module: {
    loaders: [{
    test: /\.js$/,
    loader: 'babel',
    exclude: /node_modules/,
    include: __dirname,
    query: {
      presets: ['es2015', 'stage-1', 'react'],

    }
      },
      { 
        test: /\.jsx$/, 
        loader: 'babel', 
        exclude: /node_modules/,
        include: __dirname,
        query: {
          presets: ['es2015', 'stage-1', 'react'],

        }
      },
      { test: /\.(png|jpg|gif|jpeg)$/, loader: 'url-loader?limit=8192'},
      { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap') }
    ]},
    plugins : [
      new webpack.DefinePlugin({
       'process.env': {
          NODE_ENV: JSON.stringify('production')
        }
      }),
      new ExtractTextPlugin("app.css"),
      new webpack.optimize.UglifyJsPlugin({minimize: true})
    ]  
  });

}else{

  webpackConfig = merge(webpackConfig,{
    devtool: 'inline-source-map',
    module: {
      loaders: [{
    test: /\.js$/,
    loader: 'babel',
    exclude: /node_modules/,
    include: __dirname,
      env: {
        development: {
          plugins: [
            'react-transform'
          ],
          extra: {
            'react-transform': {
              transforms: [{
                transform:  'react-transform-hmr',
                imports: ['react'],
                locals:  ['module']
              },
              {
                transform: 'react-transform-catch-errors',
                imports: ['react','redbox-react' ]
              }
            ]}
          }
        }
      },//
        query: {
//          optional: ['runtime'],
      presets: ['es2015', 'stage-1', 'react'],

    }
  },
  { 
    test: /\.jsx$/, 
    loader: 'babel', 
    exclude: /node_modules/,
    include: __dirname,
    env: {
        development: {
          plugins: [
            'react-transform'
          ],
          extra: {
            'react-transform': {
              transforms: [{
                transform:  'react-transform-hmr',
                imports: ['react'],
                locals:  ['module']
              },
              {
                transform: 'react-transform-catch-errors',
                imports: ['react','redbox-react' ]
              }
            ]}
          }
        }
      },
    query: {
      presets: ['es2015', 'stage-1', 'react'],

    }
  },
  { test: /\.(png|jpg|gif|jpeg)$/, loader: 'url-loader?limit=8192'},
  { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap') }
]},
entry : [
  'webpack-hot-middleware/client',
  './src/client/index.js',
],
resolve: {
  extensions: ["", ".js", ".jsx"]
},
plugins : [
  new webpack.HotModuleReplacementPlugin(),
  new ExtractTextPlugin("app.css")
    ]  
  });

}

module.exports = webpackConfig;

How I can resolve it?

Upvotes: 1

Views: 4662

Answers (4)

user304290
user304290

Reputation:

You need to use Babel stage 1 to get class properties.

http://babeljs.io/docs/plugins/preset-stage-1/

step 1: add dependency as follows:

npm install babel-preset-stage-1 --save

step 2: change .babelrc file as follows:

{
  "presets": ["es2015", "react","stage-1"]
}

Upvotes: 0

jamieallen59
jamieallen59

Reputation: 23

If you want to use arrow functions on a class and avoid binding to the constructor (this bit):

this.handleToggle = this.handleToggle.bind(this);

Then you can use babel's transform class properties. To do this, download the module in your command line:

npm i --save babel-plugin-transform-class-properties

Then in your .babelrc:

{
  "plugins": ["transform-class-properties"]
}

Then you can use the cleaner syntax and remove binding in the constructor:

handleToggle = () => this.setState({open: !this.state.open});

This is supposed to be in the stage-0 or stage-1 preset, but I've only ever managed to make it work by referencing the plugin explicitly (as above).

Upvotes: 1

Davin Tryon
Davin Tryon

Reputation: 67296

You don't need the arrow function (and it is invalid syntax) here because you are defining a class method:

handleToggle = () => this.setState({open: !this.state.open});

Try this instead:

handleToggle() { this.setState({open: !this.state.open}); } 

However, because class methods don't automatically bind, you need to bind it in the constructor or when you use it:

constructor(props) {
    super(props);
    this.state = {open: false};
    this.handleToggle = this.handleToggle.bind(this);
  }

If you were inside the render or another class method, you would need to add const or equivalent to the front (when using assignment with =):

render() {
    const handleToggle = () => this.setState({open: !this.state.open});
}

Upvotes: 2

Abhishek Jain
Abhishek Jain

Reputation: 2977

If I am correct, you are trying to use property initializer which is an ES7 feature. To fix this, you will have to use stage-1 preset.

More information here

Upvotes: 0

Related Questions