DZakh / rescript-schema

🧬 The fastest parser in the entire JavaScript ecosystem with a focus on small bundle size and top-notch DX
MIT License
156 stars 7 forks source link

module type issue #45

Closed jmagaram closed 1 year ago

jmagaram commented 1 year ago

I'm trying to use your package in a project of mine. my package. I've been experimenting with functors to make untagged unions and wanted to see what happens if I use your library to validate each case in the union. I included your code as a dev-dependency and added it to bs-dependencies. But I'm getting this error below. My package.json has "type": "module" and my bsconfig has "module": "es6" so I'm not sure what I need to do.

(node:82597) 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/justinmagaram/Source/rescript-extras/node_modules/rescript-struct/src/S.bs.js:3
import * as Js_exn from "rescript/lib/es6/js_exn.js";
jmagaram commented 1 year ago

I'm realizing that with your package it is really easy to build very flexible untagged unions. Just make a struct for each case. Something like this. Anyway I still would like to understand the commonjs es6 issue.

  module TargetBuiltManually = {
    type t

    external fromNonNegativeInt: NonNegativeInt.t => t = "%identity"
    external fromShortString: ShortString.t => t = "%identity"
    external fromPoint: Point.t => t = "%identity"

    let toPoint = (i: t) => i->S.parseAnyWith(Point.struct)->ResultEx.toOption
    let toShortString = (i: t) => i->S.parseAnyWith(ShortString.struct)->ResultEx.toOption
    let toNonNegativeInt = (i: t) => i->S.parseAnyWith(NonNegativeInt.struct)->ResultEx.toOption

    let makeUnsafe = (i): t => Obj.magic(i)
    let make = i =>
      toPoint(i)
      ->Option.map(makeUnsafe)
      ->OptionEx.orElseWith(() => toShortString(i)->Option.map(makeUnsafe))
      ->OptionEx.orElseWith(() => toNonNegativeInt(i)->Option.map(makeUnsafe))

    let match = (value, ~onPoint, ~onInt, ~onShortString) => {
      let result =
        toPoint(value)
        ->Option.map(onPoint)
        ->OptionEx.orElseWith(() => toNonNegativeInt(value)->Option.map(onInt))
        ->OptionEx.orElseWith(() => toShortString(value)->Option.map(onShortString))
      switch result {
      | Some(_) => result
      | None => Js.Exn.raiseError("Unsafely cast value; did not pattern match.")
      }
    }
  }
jmagaram commented 1 year ago

I tried to create a simple repo scenario.

https://github.com/jmagaram/struct

It compiles fine. But try to run node Demo.bs.js and you get this error. Maybe this is a node issue? Your bsconfig is a commonjs and mine is es6. Maybe that is the problem? I want to use es6.

(node:6079) 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)
Waiting for the debugger to disconnect...
/Users/justinmagaram/Source/use-struct/node_modules/rescript-struct/src/S.bs.js:3
import * as Js_exn from "rescript/lib/es6/js_exn.js";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1159:20)
    at Module._compile (node:internal/modules/cjs/loader:1203:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1293:10)
    at Module.load (node:internal/modules/cjs/loader:1096:32)
    at Module._load (node:internal/modules/cjs/loader:935:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:168:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25
DZakh commented 1 year ago

It's a common rescript issue with ESM. To fix it, you need to use bs.mjs suffix in your bsconfig. Here are some context https://forum.rescript-lang.org/t/why-there-s-no-bs-mjs-suffix-option-in-bsconfig-json/3697/6

DZakh commented 1 year ago

Or remove type: module, and set "module": "commonjs". If you're working on a library, that's the preferable way.

jmagaram commented 1 year ago

Ok thanks. Why is it preferable to use "commonjs" in the library? Does someone who uses the library in an ESM project lose the benefits of ESM? Or will the user of the library have everything compiled as ESM even though the library is compiled as commonjs?

DZakh commented 1 year ago

That's because if you use type: "module" for a library, it won't work in applications with type: "commonjs". I've written more about this here https://forum.rescript-lang.org/t/why-there-s-no-bs-mjs-suffix-option-in-bsconfig-json/3697/6

This way it can be used in applications that want either commonjs and ESM (because rescript compiles the dependencies using the application's bsconfig)