jvail/spl.js

Importing into a Typescript frontend does not work correctly

remipassmoilesel opened this issue · 4 comments

Hi @jvail

Thanks for this beautiful work. I am trying to integrate spl.js in a typescript frontend. But I did not manage to import
the async version.

When I try a simple example:

import SPL from 'spl.js';

export async function splPlayground() {
    const db = await SPL().then(spl => spl.db(undefined));
    console.log(await db.exec('select spatialite_version()').get.first);
}

I got these errors:

ERROR in src/splPlayground.ts:4:28

TS2339: Property 'then' does not exist on type 'ISPLSync'.
    2 |
    3 | export async function splPlayground() {
  > 4 |     const db = await SPL().then(spl => spl.db(undefined));
      |                            ^^^^
    5 |

Code can be found in this repository: https://github.com/remipassmoilesel/spl.js-issue-2021-12-27
See splPlayground.js: https://github.com/remipassmoilesel/spl.js-issue-2021-12-27/blob/master/src/splPlayground.ts

In my opinion it is due to spl.js package.json structure:

    ...
    "main": "dist/spl.js",
    "browser": "dist/index.js",   <- Typescript does not seem to use that property
    ...

If I modify it like this, all works fine:

    ...
    "main": "dist/index.js",
    ...

Questions

  • Is there something that I am doing wrong ?
  • Could we only use index.ts without default export ? Since the types are named differently, it would then suffice to
    choose according to the target (node or browser)
    import {IAsyncSpl as Spl} from 'spl.js'
    import {ISyncSpl as Spl} from 'spl.js'
jvail commented

Hi @remipassmoilesel,

(removed by initial quick guess ... does not seem to be an issue with your code).

It is a bit puzzling that index.d.ts is not used. Maybe you can explicitly import spl.js/index.js? Maybe it is issue wit the bundler you are using?
I had a test with rollup to see if browser vs node dist does work and as far as I remember it did work well.

P.S.:
Took a look at your code. Unfortunately I have no experience with your setup. It may help to understand what react-scripts build actually does under the hood. Maybe you can pass something like --target browser?
As far as I understand it is OK to have two entry points (for node and browser) in the package.json. But different bundlers might treat it differently.

I think this is a Typescript error, not a bundler error. In my opinion, Typescript uses "index.ts", "main" or "types" fields of package.json, not "browser" field or something else. Bundlers can use all.

react-scripts are tools from https://create-react-app.dev/ and are used primarily for building web app (so no need to use --target browser) It use webpack under the hood to bundle the application.

If you didn't have a problem with rollup, maybe your test setup didn't check the types?

This deep import work:

import SPL from 'spl.js/dist/index';

But it is not very understandable. Maybe something like this can be clearer:

import SPL from 'spl.js/dist/browser';  
import SPL from 'spl.js/dist/node';      
import SPL from 'spl.js'; // Default one can be browser IMHO, as Spatialite bindings for nodejs looks more efficient
jvail commented

If you didn't have a problem with rollup, maybe your test setup didn't check the types?

Hm, yes, maybe. In the rollup plugin to resolve paths you can set a browser option and it will use the browser property in package.json.

So you are right: it seems to be a ts rather than webpack issue. Another workaround would be

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "spl.js": ["node_modules/spl.js/dist/index"]
    }
  }
}

I admit this is not very elegant. But why does ts not have an option to honor 'main' vs 'browser'? microsoft/TypeScript#21423