11

I'm not sure what I'm missing here. I'm working on a project using jspm and es6-module-loader. I've got an module defined as follows:

import hooks from './hooks';
import api from './api';
import tools from './tools';

const StencilUtils = {
    hooks: hooks,
    api: api,
    tools: tools,
};

export {hooks, api, tools};
export default StencilUtils;

/* global define */
(function(root) {
    if (typeof define === 'function' && define.amd) {
        define(function() {
            return (root.stencilUtils = StencilUtils);
        });
    } else if (typeof module === 'object' && module.exports) {
        module.exports = StencilUtils;
    } else {
        window.stencilUtils = StencilUtils;
    }
}(this));

I'm importing this module in another file, and using it like so:

import utils from 'bigcommerce/stencil-utils';

utils.hooks.on('cart-item-add', (event, form) => {
    // do stuff
});

When the files load, I get an error that utils is undefined. If I change the file to this:

import {hooks} from 'bigcommerce/stencil-utils';

hooks.on('cart-item-add', (event, form) => {
    // do stuff
});

It works correctly. So, it appears something is not working correctly with the default export statement. Is there something obviously wrong here with the import or export statements that would cause this issue?

flyingL123
  • 7,686
  • 11
  • 66
  • 135
  • 1
    Nothing *obvious*, no. – Bergi Mar 30 '16 at 03:36
  • 4
    You don't happen to have a circular dependency somewhere, do you? – Bergi Mar 30 '16 at 03:37
  • @Bergi not that I can see. I put a breakpoint immediately after the `import utils` line and the variable is undefined. I am really confused why that is happening. – flyingL123 Mar 30 '16 at 20:04
  • Yes, that sounds a lot like a circular dependency. Can you cut down on your modules to create a complete, reproducible example? – Bergi Mar 30 '16 at 20:08
  • I will try. It's hard to do because it's an existing project with lots of dependancies in place. Just to be sure though, does the circular dependency theory still fit even though the error only seems to occur with the default export? Exporting a named member from the module seems to work fine. – flyingL123 Mar 30 '16 at 20:23
  • Yes, it fits perfectly. The self-dependent module can use itself because its declarations have already been initialised, but it can't use the default-export object that has not yet been created. Btw, that's just another very good reason why you should use named exports over default-exporting objects. – Bergi Mar 30 '16 at 21:47
  • So what am I looking for exactly? A file that has an import statement to itself? Or could it be a file that imports another file and so on that somewhere down the line imports that original file again? – flyingL123 Mar 31 '16 at 01:11
  • Yes, both would form a circular dependency - although a file importing itself is very unusual (and won't cause *this* problem). – Bergi Mar 31 '16 at 01:13
  • Do any tools exist or is there some sort of strategy for finding this? Manually inspecting things is not getting me anywhere. – flyingL123 Mar 31 '16 at 01:14
  • I don't know any tools, no, although they shouldn't be that hard to build. As a strategy: the circle resolves over `stencil-utils` and the file that imports it (where you get the error), so that's a good place to start. If you still don't get anything, you could add a `console.log("initialising "+__filename)` to every single file, so you can check the log which modules have been loaded and which not when you get the exception. – Bergi Mar 31 '16 at 01:21
  • 1
    What, no upvotes for the circular dependency suggestion by @Bergi 's in one year?! That was totally it for me when I imported something that was undefined. Thanks. Upvoted comment. – Christiaan Westerbeek Aug 03 '18 at 14:52
  • @flyingL123 Facing the exact problem. Please update or accept the answer! That would help others – Balasubramanian Dec 13 '18 at 14:14
  • @Balasubramanian I never found a solution to this one, and the project has since been updated to use webpack so this hasn't come up. – flyingL123 Dec 13 '18 at 18:39

1 Answers1

12

I think there are two things around this issue:

  1. When you have named exports your access them through either importing as library or with object destruction.

Method 1

xyz.js

export const a = 1;

abc.js

import {a} from "xyz";

Method 2

xyz.js

export const a = 1;

abc.js

import {* as myModule} from "xyz";
console.log(myModule.a);

So in your case

export {hooks, api, tools};

it can be either

import * as utils from 'bigcommerce/stencil-utils';

or

import {hooks} from 'bigcommerce/stencil-utils';
  1. Default export statement is not proper

It can either be

export default {
    hooks: hooks,
    api: api,
    tools: tools,
};

Or

const StencilUtils = {
   hooks: hooks,
   api: api,
   tools: tools,
};
export { StencilUtils as default };

Hope this will help you. For more details see this

Yashika Garg
  • 2,346
  • 2
  • 15
  • 17
  • 4
    I don't think this is right. The default export syntax I show is fine according to the documentation (I think), and I tried your first default export example but that still did not fix the problem. – flyingL123 Apr 05 '16 at 14:56