kay-tee
November 24, 2021, 12:02pm
1
I’m trying to write a binding that gives me this:
import axios from "axios";
axios.get("http://localhost:3005/characters").then(function (resp) {
return Promise.resolve((console.log(resp.data)));
});
I tried something similar to an example from the “Bindings Cookbook” that seemed like it would get me there based on the example:
@module("axios") external get: string => Js.Promise.t<'data> = "get";
let _ = get("http://localhost:3005/characters")->then(resp => resolve(Js.log(resp["data"])))
but it gives me this JavaScript:
// Generated by ReScript, PLEASE EDIT WITH CARE
import * as Axios from "axios";
var Axios$1 = {};
Axios.get("http://localhost:3005/characters").then(function (resp) {
return Promise.resolve((console.log(resp.data), undefined));
});
export {
Axios$1 as Axios,
}
/* Not a pure module */
Running the JavaScript code gives me an error “TypeError: Axios.get” is not a function".
Any help would be greatly appreciated.
fham
November 24, 2021, 1:13pm
3
Your binding and the generated code look correct, do you have axios
installed correctly?
I use axios myself (together with bs-axios) and the generated code is pretty much the same.
tsnobip
November 24, 2021, 2:17pm
4
It’s likely because you’re using ES6, axios here is a default import, so you need to add a scope("default")
like this:
@scope("default") @module("axios") external get: string => Js.Promise.t<'data> = "get";
let _ = get("http://localhost:3005/characters")->then(resp => resolve(Js.log(resp["data"])))
1 Like
kay-tee
November 25, 2021, 4:17am
5
Adding @scope (“default”) did the trick!
kswope
October 1, 2022, 9:30pm
6
It took me hours of aimless wanderings to find this solution, which was blind luck when I was about to give up and go back to commonjs. Is this not in the documentation? It seems important.
Maybe here? Interop Cheatsheet | ReScript Language Manual
@scope is in there, but for mundane things like Math.random(), not for using @scope as a hack to get around es6 default import weirdness, as demonstrated here in my working solution:
type pool
@module("pg") @scope("default") @new external pool: unit => pool = "Pool"
import * as Pg from "pg";
var pool = new (Pg.default.Pool)();
Here’s a relevant issue that seems abandoned.
opened 12:57PM - 24 May 21 UTC
Note ES6's default import can not be faithfully translated into commonjs, so if … you design an API, please don't use
default exports/imports. This issue is to help reduce the main of dealing with js libraries using default.
Current state:
```res
@module("express") external express: unit => express = "default"
```
In ES6, it is compiled into
```js
import Express from "express";
```
In CommonJS, it is compiled into
```js
var Express = require('express').default
```
This conforms to Babel's convention, however NodeJS and Babel disagree on such convention,
both convention make sense based on their tradeoffs.
Here I am proposing treating another `external` style as ES6 import:
```res
@module external express: unit => express = "express"
```
This in commonjs is compiled into
```res
var Express = require("express")
```
In ES6, it is compiled into
```res
import * as Express from "express";
```
Note from binding's point of view, `import * as E` rarely makes sense, sine in ES6, you can not export the whole module as an object, so I am proposing in ES6, it compiles into
```res
import Express from 'express'
```
With my proposed change, we have two ways to express default import, one way is to match babel semantics, the other is to match Node semantics
1 Like
DZakh
October 2, 2022, 9:18am
7
There’s an alternative solution:
type axios
@module("axios") external axios: axios = "default"
@send external get: (axios, string) => Js.Promise.t<'data> = "get"
let _ =
axios->get("http://localhost:3005/characters")
|> Js.Promise.then_(resp => {
Js.log(resp["data"])
Js.Promise.resolve()
})
1 Like