Search code examples
javascriptwebpackecmascript-6karma-mochakarma-webpack

Using ES6 and let/const with export / import and Karma/webpack - export at the top


export { test };

const test = (str) => {
    return str;
};

import { test } from './func';

describe('func', () => {
    describe('func', () => {
        it('should return the same string', () => {
            expect(test('hello world')).to.equal('hello world');
        });
    });
});

test-function is undefined because of hoisting, I suppose. Because if I do:

const test = (str) => {
    return str;
};

export { test };

The test works.

But, I would like to keep my exports in the top of the file for easy reference.

Any way to achieve that?

My karma.conf.js:

const webpackConfig = require('./webpack.config');
const fileGlob = 'src/**/*.test.js';

module.exports = (config) => {
    config.set({
        basePath: '',
        frameworks: ['mocha', 'chai'],
        files: [fileGlob],
        preprocessors: {
            [fileGlob]: ['webpack']
        },
        webpack: webpackConfig,
        webpackMiddleware: {noInfo: true},
        reporters: ['progress', 'mocha'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: false,
        browsers: ['Firefox'],
        singleRun: true,
        concurrency: Infinity,
    });
};

And relevant parts of package.json:

"devDependencies": {
    "webpack": "^3.5.5",

    "babel-core": "^6.26.0",

    "babel-loader": "^7.1.2",
    "babel-plugin-add-module-exports": "^0.2.1",
    "babel-preset-es2015": "^6.24.1",

    "chai": "^4.1.1",
    "mocha": "^3.5.0",
    "karma": "^1.7.0",
    "karma-chai": "^0.1.0",
    "karma-mocha": "^1.3.0",

    "karma-webpack": "^2.0.4",

  },

Solution

  • ES module import reflects the state of module export. Even though const decaration is not hoisted, it is in temporal dead zone when export { test } is evaluated, but when the module is imported export already reflects test actual value.

    The problem likely results from incorrect behaviour caused by module transpilation. Babel doesn't implement module exports correctly, this results in undefined export.

    As it can be seen here (available in browsers that support ES modules, i.e. latest Chrome), module export works as intended natively.

    TypeScript handles exports as intended, too.

    To make code compatible with existing implementations, it should be:

    export const test = (str) => {
        return str;
    };
    

    Or:

    const test = (str) => {
        return str;
    };
    
    export { test };
    

    Both are conventional ways to do exports, particularly because of this issue. Exports at the end of the module conform to coding habits that result from the use of CommonJS modules.