Search code examples
javascriptecmascript-6babeljsgrunt-babel

Grunt watch task failing to transpile ES6 code


I'm using grunt and grunt-babel to transpile ES6 code whenever I change an es6 file. However, it seems like I have an error in one of those files, as I get this message when I make a change

Waiting...
>> File "scripts/test.es6.js" changed.
Running "babel:files" (babel) task
Warning: scripts/actions.es6.js: Unexpected token (38:5) Used --force, continuing.

Done, but with warnings.
Completed in 0.758s at Mon Sep 14 2015 20:11:53 GMT-0700 (PDT) - Waiting...

I have a few questions.

  1. scripts/test.es6.js is a correct ES6 file, yet the ES5 version of it doesn't appear in my output folder when it is changed because of an error in scripts/actions.es6.js - why?
  2. How do I find this error in my ES6 code?
  3. Why isn't the force flag causing this to compile?

Thanks

This is test.es6.js

class Person {                                          // The 'class' keyword
    constructor(name, age) {                            // Constructors
        this.name = name;
        this.age = age;
    }
}

class Developer extends Person {                        // The 'extends' keyword
    constructor(name, age, ...languages) {              // Rest parameters
        super(name, age);                               // Super calls
        this.languages = [...languages];                // The spread operator
    }
    printLanguages() {                                  // Short method definitions
        for(let lang of this.languages) {               // The for..of loop
            console.log(lang);
        }
    }
}

let me = new Developer("James", 23, "ES5", "ES6");     // Block scoping hello

This is actions.es6.js

/*
 * Action types
 */

export const REQUEST_DISTRICTS = 'REQUEST_DISTRICTS';

export function requestDistricts(geoState) {
    return {
        type: REQUEST_DISTRICTS,
        geoState
    };
}

export const RECEIVE_DISTRICTS = 'RECEIVE_DISTRICTS';

export function receiveDistricts(geoState, json) {
    return {
        type: RECEIVE_DISTRICTS,
        geoState,
        receivedAt: Date.now(),
        districts: json.data.districts.map(district => district.data)
    }
}

export function fetchDistricts(geoState) {

    return function (dispatch) {
        dispatch(requestDistricts(geoState));
        var districtsDfd = $.ajax({
            url: "http://localhost:8080/districts/",
            type: "GET",
            dataType: "json"
        });
        var demographiesDfd = [];
        $.when(districtsDfd).then(function(data, textStatus, jqXhr){
            if (data) {
                _.each(data, datum => 
                    var id = datum.id;
                    demographiesDfd.push($.getJSON("http://localhost:8080/district/${id}/demography"));
                );
            }
        });
        $.when(...demographiesDfd).done(result =>
            //so I have demographic data right now. 
            dispatch(receiveDistricts(geoState, result));
        );
    }
}

The error is happening on var id = datum.id;


Solution

  • scripts/test.es6.js is a correct ES6 file...

    Yes, but scripts/actions.es6.js isn't. The line Warning: scripts/actions.es6.js: Unexpected token (38:5) Used --force, continuing. is telling you that actions.es6.js has an unexpected token. E.g., it cannot be compiled. That's stopping the Babel task. Apparently, Babel is compiling actions.es6.js before test.es6.js and bombing when it finds the error in actions.es6.js.

    How do I find this error in my ES6 code?

    Look at line 38, character 5 of actions.es6.js. That's what the (38:5) in the error message is pointing out. Fix the error there, and Babel will be able to continue compiling.

    Why isn't the force flag causing this to compile?

    The --force flag just tells Grunt to keep going, but Babel's already failed.


    You've posted your code for actions.es6.js, the bug is indeed near line 38 (it's on line 37, but it's common for an error not to actually occur until the next line). You need { at the end of line 37 and } before the ); on line 40:

    _.each(data, datum => {
        var id = datum.id;
        demographiesDfd.push($.getJSON("http://localhost:8080/district/${id}/demography"));
    });
    

    ...or if you're not going to use id for anything other than the one place in the template string, you can keep it a one-liner:

    _.each(data, datum => demographiesDfd.push($.getJSON("http://localhost:8080/district/${datum.id}/demography")));
    

    With an arrow function, if you have multiple statements, you must use braces. In general, I recommend using braces for any arrow function that isn't one short expression (for me, it has to be short enough to be on the => line, but others have a different view). E.g., this is fine:

    someArray.map(entry => entry.prop);
    

    ...but when you get into things that are much longer than that, it's going to be clearer to either break it out into a named function, or use a block and return.