Is this node error something I'm doing?

I’m seeing this node error:

~> rescript
~> node lib/es6/src/Set/Set.bs.js
(node:40746) 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)
/Users/stu/tmp/rescript/learn/node_modules/@rescript/core/lib/es6/src/Core__List.bs.js:3
import * as Curry from "rescript/lib/es6/curry.js";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1166:20)
    at Module._compile (node:internal/modules/cjs/loader:1210:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1300:10)
    at Module.load (node:internal/modules/cjs/loader:1103:32)
    at Module._load (node:internal/modules/cjs/loader:942:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:168:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)

Node.js v19.5.0

It’s from this (admittedly clumsy, just for learning purposes) ReScript module:

module type Set = {
  type set<'e>

  let empty: unit => set<'e>

  let singleton: 'e => set<'e>

  let size: set<'e> => int
}


module ArraySet: Set = {
  type set<'e> = array<'e>

  let empty = () => []

  let singleton = x => [x]

  let size = xs => Array.length(xs)
}


let aset_1 = ArraySet.singleton(42)
Console.log(aset_1)


module ListSet: Set = {
  type set<'e> = list<'e>

  let empty = () => list{}

  let singleton = x => list{x}

  let size = xs => List.length(xs)
}

let lset_1 = ListSet.singleton(42)
Console.log(lset_1)


module type SetLaws = {
  type set<'a>

  let singleton_size: 'a => bool
}


module SetLawsFor = (S: Set): SetLaws => {
 type set<'a> = S.set<'a>

 let singleton_size = x =>
   S.size(S.singleton(x)) == 1
}



module ArraySetLaws = SetLawsFor(ArraySet)
Console.log(ArraySetLaws.singleton_size(42))


module ListSetLaws = SetLawsFor(ListSet)
Console.log(ListSetLaws.singleton_size(42))

Any advice much appreciated.

Maybe this helps How to fix "cannot use import statement outside a module"

Or change the suffix in your bsconfig to mjs

Thanks – I’d already done that.

That worked, thanks. Should the official documentation be changed to recommend “.mjs” for new ReScript projects?

1 Like

I agree, although I prefer .bs.mjs

While I’m preferring es modules, I had troubles with some libraries (e.g. date-fns). So I don’t know if rescript should use it as default🤷

Thanks, I’ll keep that in mind.

Hello guys, im having similar Syntax error

can someone assist?

With the release of 11.0, I’m trying out rescript for the first time and immediately hit this issue. You can reproduce it using create-rescript-app and then setting “module” to “es6” in rescript and “type” to “module” in package.json. Despite this, Rescript Core itself does not handle es6 modules out of the box, resulting in similar errors to what’s above (an import of js_math from Core__Array, in my case).

As noted above, the easiest workaround is setting suffix to “res.mjs”. But given that the default is res.js and that most have now moved to es6 modules, this doesn’t seem ideal and obviously creates some friction for newcomers. We’re also thinking about integrating rescript into an existing project, where we set “type” to “module” in package.json, so having a mix of .js and .mjs files throughout our project is also not ideal.

For now, perhaps adding a question to the create script about module preference and additionally setting suffix to res.mjs when using es6 would work. But ideally, Core would support es6 natively.

(I’ll add that this was especially confusing because I didn’t expect the compiler to recompile Core, since it ships with .mjs files already, which would have worked just fine if used.)

Edit: OK I managed to reproduce your issue.

It’s not really a matter of Core supporting ES6 natively or not, since Core does support ES6 if you use .mjs. This is a node issue. How would you make a lib support both ES6 and commonJS otherwise?

We could indeed ask a question in create-rescript-app to ask if you want to use CJS or ES6 and adapt rescript.json accordingly to make it use a different suffix. Don’t hesitate to make a PR to create-rescript-app.

How would you make a lib support both ES6 and commonJS otherwise?

I have introduced it from Bundle ReScript libraries with dual-package exports. Applied to rescript-collection.

But since @rescript/core doesn’t use bundling, there’s no easy solution. I wrote RFC: New package-spec `"dual"` · Issue #6209 · rescript-lang/rescript-compiler · GitHub to solve this.

A possible choice is to keep the @rescript/core package dedicated to ReScript and leave the build process to the end-users instead of providing prebuilt mjs files.

What’s the downside? Installation/build speed?

It cannot be used in non-rescript projects.

Unless they have a build step, which they probably do.

1 Like

Without the prebuilt files, your rescript library can’t be used by JS/TS codebases