Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with definitions imported across multiple .d.ts files (re pixi.js v6) #413

Open
mpcomplete opened this issue Apr 30, 2021 · 8 comments

Comments

@mpcomplete
Copy link

I ran into this issue when trying to update fable-pixi from pixi.js v5 to v6.

pixi.js type definition files have code like this:

import { AlphaFilter } from '@pixi/filter-alpha';

which gets translated by ts2fable into this:

type AlphaFilter = @pixi_filter_alpha.AlphaFilter

which is not valid. I'm actually not sure what the correct behavior here is, because the original fable-pixi handles this in a way that seems hand-written (see Fable.Pixi.js).

Here is the script I ran from within the ts2fable/ project dir:

npm install --save-dev pixi.js
npm run-script ts2fable node_modules/pixi.js/*.d.ts node_modules/\@pixi/*/*.d.ts Fable.Pixi.fs

Also, this generated everything in a single module. It was unclear from the ts2fable docs if there was a simple way to put the output of each file into its own module - maybe it just means running ts2fable separately and gluing them together manually?

@humhei
Copy link
Contributor

humhei commented May 1, 2021

Maybe you want this part in readme

You can also use --export(or -e) option to collect from multiple tsfiles

In below sample: All the related ts files in npm packages uifabric and office-ui-fabric-react will be compiled to OfficeReact.fs as a bundle

ts2fable node_modules/office-ui-fabric-react/lib/index.d.ts test-compile/OfficeReact.fs -e uifabric office-ui-fabric-react

@fwaris
Copy link

fwaris commented Jul 16, 2021

I have a similar issue with G6

I tried the 'office-ui' sample above and it works fine. However the type of import references being used in G6 (and Pixi) don't seem to work with ts2fable current version (compiled from source).

Here is the root TS file for G6:

import G6 from '@antv/g6-pc';
export * from '@antv/g6-pc';
export default G6;
export declare const version = "4.3.4";

G6 TS references are not relative (or maybe the "@" character is causing issues). ReactXP (which works in ts2fable) has relative references:

import * as ReactXP from './web/ReactXP';
export = ReactXP;

Is there a quick workaround that I can try.

PS: Is there a way to debug F# code in ts2fable. I am running "Watch Test" with mocha but breakpoints are not accepted by vscode.

@fwaris
Copy link

fwaris commented Jul 16, 2021

According to this [corrected] article. Non-relative path import requires the "tsconfig-paths" module. I have added the following to package.json:

"tsconfig-paths": "^3.10.1",

Also needed is a CompilerOptions setting called "paths". I am assuming that the place to do this is in bridge.fs but I can't seem to construct a "MapLike<ResizeArray>" value that "paths" requires.

        let createDummy tsPaths (sourceFiles: SourceFile list) =
            let options = jsOptions<CompilerOptions>(fun o ->
                o.target <- Some scriptTarget
                o.``module`` <- Some ModuleKind.CommonJS
                o.paths <- fun s ->                     
                            Some
                                [
                                "src/*", ResizeArray["src/*"]
                                ]
                                   
            )

Any suggestions?

@fwaris
Copy link

fwaris commented Jul 16, 2021

Looks like one has to implement MapLike<_> as it is an interface

    type TsPaths(vs:Dictionary<string,ResizeArray<string>>) =
        interface MapLike<ResizeArray<string>> with
            member _.Item with get(v) = vs.[v] and set key value = vs.[key] <- value

but still not sure about what the the path entries need to be to make this all work ...

@fwaris
Copy link

fwaris commented Jul 18, 2021

After much internet search, the bottom line is that the new style of import references in TS is not a javascript standard and hence it is not universally supported. In particular node does not support such references, out of the box.

The "tsconfig-paths" package supports the remapping of TS references to relative references, however, its implementation is not complete.

ts2fable internally loads the typescript compiler (in bridge.fs) to find the imports. It is not clear to me how to enable "tsconfig-paths" for the internally hosted compiler. I tried to require "tsconfig-paths/register" for ts2fable but it did not seem to work.

Admittedly I am not the expert in this area so instead of spending more time on g6, I switched to another graph library, cytoscape. The .ts definitions in DefinitelyTyped for cytoscape were processed correctly by ts2fable.

I have a feeling that fable users will increasingly run into this issue and hopefully more knowledgeable members of the community can find a solution.

@Booksbaum
Copy link
Contributor

in short: ts2fable doesn't seem to really handle re-exports at all....

In the example with ReactXP ts2fable doesn't actually detect "hey there's an import, let's load this" followed by "that imported stuff gets re-exported here again" -- but instead ts2fable just looks into all sub-directories and exports all .d.ts files it finds (requires --exports ...).
So instead of a re-export under the root-name, it's just a redirect to somewhere else (which dependencies usual are -- but not really when re-exported).

To test this with g6:

  • create an empty index.d.ts in @antv: "" > ./node_modules/@antv/index.d.ts
  • run ts2fable on that file: ts2fable ./node_modules/@antv/index.d.ts g6.fs --exports g6
    • --exports g6: exports all .d.ts-files in sub-dirs that contain g6
  • That should produce a lot of debug messages and F# file g6.fs with all the stuff from all the g6 packages.
    • But: this is just "export everything", not really re-exported like in g6/lib/index.d.ts....
    • And: names of modules are file paths (with _ instead of /)...
    • Might be possible to imitate re-export behaviour by using g6 as root and place all other g6-... d.ts files in sub-dirs


In fact ts2fable doesn't handle some of the stuff in g6/lib/index.d.ts at all:

  • import G6 from '...' is ignored because the import clause has no named bindings (like import {foo} from '...'):

    ts2fable/src/read.fs

    Lines 807 to 812 in f9d14a6

    match im.importClause with
    | None -> []
    | Some cl ->
    match cl.namedBindings with
    | None -> []
    | Some namedBindings ->
    • import * as G6 from '...' is handled. I think that's the same?
  • export * from '....' isn't handled at all:

    ts2fable/src/read.fs

    Lines 867 to 869 in f9d14a6

    | SyntaxKind.ExportDeclaration ->
    // printfn "TODO export statements"
    []

So yeah....unfortunately no real re-export dependency handling at all (sub-dir or somewhere else) -- just the option to export everything.

I think supporting this would require some major work. But might be reasonable. "Collection"-packages aren't that uncommon (D3 is quite similar).
Most of the work can probably be offloaded on to the TypeScript Compiler.


Some more stuff:

  • About new import styles in TS: Isn't that just ESM style? Which is a JavaScript standard. Most tools now support ESM -- but only in recent versions. In Node it seems to be stabilized with 15.3. ts2fable still uses node --require esm to run directly and rollup to convert into umd)
  • tsconfig-paths: According to the docs that's only needed when converting to JS -- which ts2fable isn't doing. TS Compiler can handle absolute paths.

About Breakpoints:
should work:

  • Set breakpoint somewhere in F# code
  • Start "WatchTest" Task in VS Code (or dotnet fake build -t WatchTest in terminal)
  • In VS Code: F5 or "Run And Debug" -> "Run Mocha Tests"

That should break when reaching your breakpoint.

Though: Debugging isn't that nice: quite a lot of code is Javascript (like all Fable implementations like List). And breakpoint locations are sometimes strange (inside of strings?).
Best set your breakpoint close to the thing you want to debug, instead of manually going there. And focus on a single test by changing it to only for that test.

But breakpoints per se should work.

Note: Just to be sure every dependency is downloaded, run ./fake.cmd build once.

@fwaris
Copy link

fwaris commented Jul 23, 2021

@Booksbaum thanks for your analysis.

I don't know enough about the node.js/javascript/ts ecosystem so your comments are probably right.

I was expecting/hoping that the discovery of the referenced modules could be delegated to the TS compiler. Maybe it is just a matter of being able to supply the right parameters (e.g. a tsconfig.json file)?

PS
I am able to debug using the method you have described (thanks!). However, I remember being able to set breakpoints in F# code. That does not seem to work with the latest bits. I can debug the generated javascript - which is quite easy to understand given the quality of the code generation.

@Booksbaum
Copy link
Contributor

I was expecting/hoping that the discovery of the referenced modules could be delegated to the TS compiler. Maybe it is just a matter of being able to supply the right parameters (e.g. a tsconfig.json file)?

Unfortunately it's not just that simple. Resolving a dependency is hopefully something the TS Compiler can do. But then we still need to recognize re-exports (-> dependencies that get exported again) and process the dependency files correctly (translating AND putting the generated code in the correct place).
And ts2fable already has a lot issues with just processing a single file :/ ....




I am able to debug using the method you have described (thanks!). However, I remember being able to set breakpoints in F# code. That does not seem to work with the latest bits. I can debug the generated javascript - which is quite easy to understand given the quality of the code generation.

My bad:
I didn't adjust .vscode/launch.json when updating the build script some time ago.
Debugging used some old leftovers of an old ts2fable build on my machine. No wonder the break points were in strange places...

-> Fixed in master

With this VS Code Breakpoints should work with source maps (-> F# code).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants