How to tune babel loader to properly import a module named macro.js when using CRA

Hi,

In order to create a VTK class, macro.js module needs to be imported. When I import this module (import macro from '@kitware/vtk.js/macro') in my application I get an error: SyntaxError: Cannot use import statement outside a module. My application is based on react-scripts from create-react-app. If I copy an original file macro.js from @kitware/vtk.js to my local source folder I still get an error. Even if I remove all the contents of macro.js file I get an error: The macro imported from "../macro" must be wrapped in "createMacro" which you can get from "babel-plugin-macros". Please refer to the documentation to see how to do this properly: https://github.com/kentcdodds/babel-plugin-macros/blob/master/other/docs/author.md#writing-a-macro. However, when I rename macro.js to macro2.js the error is gone.

Looks like CRA uses some special loader for macro.js files. Is there some way how can I disable this macro loader?

Best regards,
Stas

Hum, thanks for bringing that up to our attention. I’m wondering if you could exclude @kitware/vtk.js from that loader?

Hi, this appears to be a conflict with babel-plugin-macros. Specifically, babel-plugin-macros runs on any file that matches [./]macro(\.c?js)?$, which is why you get that error.

As for resolution, CRA is limiting when it comes to customization. The easiest approach on your side is to eject your config, and then add a babel.config.js as shown here: False positive in macrosRegex · Issue #131 · kentcdodds/babel-plugin-macros · GitHub. Unfortunately you cannot customize babel config in CRA without ejecting.

As far as I know, there is no other easy approach. Maybe you can switch to a CRA alternative like Neutrino, which will allow you to customize babel.config.js. Unfortunately babel-plugin-macros has not shown any interest in narrowing their regex matches (see this issue), and CRA has not exposed isMacrosName, so I think your only options are to eject or switch tooling.

Update: you should check out customize-cra to see if you can make modifications to the babel config to add a custom isMacrosName that looks like the following:

isMacrosName: (name) => /[./]macro(\.c?js)?$/.test(name) && name.indexOf("@kitware/vtk.js") === -1

Thank you @Forrest! I will look into it. Another way of customizing CRA without ejecting is to use craco.

1 Like

Update: there is now a new patch to vtk.js that should be able to side-step this issue: WIP Fix #1996 and add debounced function cancellation by floryst · Pull Request #1997 · Kitware/vtk-js · GitHub

Another update: the latest vtk.js now publishes an alternative name for macro.js: macros.js (note the extra “s”).

If you are using macro.js and run into this issue, please update your imports to using macros.js. If you are using macro.js just fine, carry on – macro.js is published to keep backwards-compatibility.

I am having the same problem importing vtkimagedata where I am getting “SyntaxError: Cannot use import statement outside a module”. Is there a specific way to include ES Modules in a simple Nodejs app?

For example:
node --input-type=module --eval “import macro from ‘@kitware/vtk.js/macros.js’;”

(node:19464) Warning: To load an ES module, set “type”: “module” in the package.json or use the .mjs extension.
(Use node --trace-warnings ... to show where the warning was created)
…\node_modules@kitware\vtk.js\macros.js:1
import _slicedToArray from ‘@babel/runtime/helpers/slicedToArray’;
^^^^^^
SyntaxError: Cannot use import statement outside a module

Ah, I don’t think we included the "type": "module" line in the generated package.json. I’ll see about getting that resolved.

You’re right, I had to add “type”: “module” and deal with additional 2 files under vendor folder (I renamed them to .mjs). Thanks for the help!