How to create a util

Hi, I have created a function in utils using “ember g util is-monthend”.

Here is the function:

export default function isMonthend() {
let today = new Date();
let month = today.getMonth();
today.setDate(today.getDate() + 3);

return today.getMonth() !== month;
}

If I import it according to the docs I get a compiler error:

C:\DEV\git\collections-webapp\collections\components\customer-health-check\action-log.js: @ember/utils does not have a isMonthend export
  4 | import { action } from "@ember/object";
  5 | import { tracked } from "@glimmer/tracking";
> 6 | import { isMonthend } from "@ember/utils";
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If I reference the filename, the compiler is happy, but then I get an error at runtime.

import { isMonthend } from "@ember/utils/is-monthend.js";

Uncaught (in promise) Error: Could not find module `@ember/utils/is-monthend.js` imported from `collections/components/customer-health-check/action-log`
    at missingModule (loader.js:247)
    at findModule (loader.js:258)
    at Module.findDeps (loader.js:168)
    at findModule (loader.js:262)
    at requireModule (loader.js:24)
    at Class._extractDefaultExport (index.js:463)
    at Class.resolveOther (index.js:123)
    at Class.resolve (index.js:186)
    at resolve (index.js:1204)
    at Registry.resolve (index.js:744)

Any help is appreciated.

My version is ember-cli: 3:20.2

When you export like this:

export default function isMonthend() {

e.g. a default export, the function is the only export from the module. This is fine (though you can use a named export if you want). The problem is with your import. And I think there are actually two problems. The first is the path:

import { isMonthend } from "@ember/utils";
                            ^^^^

When you generate a util in your project it won’t be under the ember namespace it will be in your project namespace. So in your case I think it would be in collections/utils/is-monthend (though I’m not sure if the app/addon name is collections or not, you need to verify. Either way if you generate a util function Ember should put it in <project root>/{app|addon}/utils/name-of-util.js (if it’s an app it will put it in app if it’s an addon it will put it in addon). Then your import path will be <project name>/utils/name-of-util (no .js).

The second issue is the part where you are destructuring the import:

import { isMonthend } from "@ember/utils";
       ^            ^

When you wrap an import name in brackets like this it’s destructuring the default export which is usually all the exports from a module combined in an object. Like if you said:

export default { isMonthend }

at the bottom of your util file this import might work. Or if you just removed default from your export line. But since you are exporting the function as the default export (which is conventional, so I would leave it that way unless you want ot export multiple functions from this file), you’re trying to destructure a function which doesn’t work. To solve this just remove those curlies like this:

import isMonthend from <correct path>;

Anyway sorry that was a little long winded but it’s helpful to understand the filesystem and module import/export syntax.

The TLDR is you should change your import to this:

import isMonthend from "<project name>/utils/is-monthend";
1 Like

That’s great, thank you very much. Thanks for the background info, too. It’s very helpful.