The `buildType` option doesn't work yet.
vixalien opened this issue ยท 18 comments
In the CLI, there's supposed to be an option called buildType
to change the output format to just generate a .d.ts file, however that doesn't seem to be implemented yet.
Because of this, ts-for-gir can't really replace gi.ts right now
@vixalien Unfortunately, we have not yet updated the documentation on the main branch, but hopefully this will happen soon. The option is still available in the 3.x branch. On the main branch the option has been removed, why do you need this to replace gi.ts?
We use gi.ts to generate typescript declaration files like the ones at https://gitlab.gnome.org/BrainBlasted/gi-typescript-definitions.
These files are included as submodules in apps where we can't use npm to install the types like Decibels and GNOME Sound Recorder.
I thought gi.js was being replaced by this so I thought this feature would be too much to miss.
@vixalien I have removed the option because it should not absolutely necessary for your case and this simplifies the maintenance effort. You can still generate the types, with the difference that a separate folder is created for each generated type and a *.js
and package.json
are generated in addition to the *.d.ts
(and other files like ambient imports etc) and dependencies are also imported using the package.json name.
However, the package.json is practical because it makes it easier to import the types, as typescript can then resolve this more easily. For this you need to add the path of your generated types (e.g. gi-typescript-definitions
) and the types to the tsconfig.json
like this:
{
"compilerOptions": {
"baseUrl": "../gi-typescript-definitions",
"types": ["gjs", "gio-2.0"],
"module": "ESNext",
"moduleResolution": "bundler"
}
}
Alternatively you can use a package manager like npm
, pnpm
or yarn
and add your types folder gi-typescript-definitions
to the workspace of your package manager, this way the self-generated NPM packages should also be recognised.
Then TypeScript should know the types for the imports like this (thanks to the ambient module definitions included in this types):
import GLib from 'gi://GLib?version=2.0';
So no bundler is necessary to use the types in this way. However, a bundler can also be used if, for example, one is used anyway, in which case the types could also be imported in this way (but this is not necessarily):
import GLib from '@girs/glib-2.0';
The .js
behind this package is then importing the real GJS module via import GLib from 'gi://GLib?version=2.0';
which should then be resolved by your bundler. This has the advantage that you do not have to add and maintain the types to tsconfig.json
in this way.
So there should be several ways to use the self-generated types anyway. Or do you have such a special setup that this is not possible for you? Then please explain this to me in more detail, we are of course very interested in everyone being able to use the types. I haven't fully tested this without the package manager yet (but is tested using yarn workspaces), so problems are not excluded, if it doesn't work as I described, I would of course work on a solution ๐
Edit
I have adapted my text again to make it easier to read
GJS doesn't use package.json
, so it is unused in our use-case
For this you need to add the path of your generated types (e.g. gi-typescript-definitions) and the types to the tsconfig.json like this:
This already worked with gi-typescript-definitions with the generated gi.d.ts
file. This file serves as an index for all the packages. The gi.d.ts file was 9generated by applying this pending MR](https://gitlab.gnome.org/ewlsh/gi.ts/-/merge_requests/1)
The .js behind this package is then importing the real GJS module via import GLib from 'gi://GLib?version=2.0'; which should then be resolved by your bundler. This has the advantage that you do not have to add and maintain the types to tsconfig.json in this way.
When using GJS directly, there is no need for any .js
file because GJS will resolve the GI imports directly.
All in all, the package.json and .js files tell me this is made for compatibility with node.js (presumably node-gtk). It also says in the README that support has been dropped for node-gtk, but we still have those files.
I strongly suspect that not generating these files (or at least adding an option not to) will ease the development process.
I have an example of an app where I use gi-typescript-definitions
with a bundler (in this case, esbuild), and I told esbuild just not to resolve the gi://*
files like this:
external: ["gi://*", "format", "gettext"],
If you are using another bundler and the @girs/glib-2.0
import syntax, you can write a simple plugin for your bundler that would rewrite that import to gi://GLib-2.0
.
I would also like to know if any apps import the types using the @girs/glib-2.0
from node
@vixalien Thanks for the feedback, I have a few more questions about your use case: Do you write your sources in TypeScript? And if so, how do you transpile the sources to JavaScript? Do you use tsc
for this? If so, how did you make it available on your system? I would have thought that there would be a dependency on Node.js anyway (and thus the use of NPM / package.json would not be a new dependency).
I know that GJS does not support package.json. In the suggestion I tried to explain, the package.json is not used at runtime but only in the previous process by tsc
and/or esbuild
.
For esbuild you just need to set the option bundle
to true and add everything you don't want to bundle to external
like gi://
and other imports you don't want to bundle. For the @girs/*
imports the bundling process results in gi://*
imports because that's what esbuild becomes from the .js
files. But as I said, the @girs/*
imports are optional anyway and you can also use the gi://*
imports directly without loosing type definition support.
I have now created a working example that shows how to generate the types by yourself and use them to create a simple GJS application with tsc
and npm
: https://github.com/gjsify/ts-for-gir-local-tsc-example
This example also uses the gi://*
imports directly.
And here an almost identical example, but uses esbuild
instead of tsc
to build the TypeScript code: https://github.com/gjsify/ts-for-gir-local-esbuild-example
The example also uses the direct gi://*
imports, but thanks to esbuild they could be replaced with @girs/*
imports and it would still work the same way.
You can find more examples in the ts-for-gir
repository, including some that use esbuild
, Vite
and Webpack
as bundlers, with gi://
or @girs/*
imports (so both usages are demonstrated). The examples in the ts-for-gir
repository all are using yarn
instead of npm
, because we are using yarn
for ts-for-gir
, but just like the examples I have created for you, they use the workspace feature to make the locally created types known to the development environment. All these examples are using GJS in the last step and are working. So they actually show quite well what different setups could look like. If there are any examples missing here, I will be happy to add more, for example for Rollup and Turbopack.
What I could also add would be support for a declaration file that contains all generated types, so that only one entry in tsconfig.json is necessary, if that would still help.
By the way: For the future I plan to support JSR which is a TypeScript runtime independent package registry. So it is independent of Node.js and supports Deno, Bun, Node.js and any other JavaScript runtime environments, so I think it makes sense to publish packages for GJS there instead on npmjs.com.
I understand, however, that the long-term goal should be to be able to completely do away with Node.js, and that is also my long-term goal. In the long term, I would like to run ts-for-gir itself with GJS instead of Node.js. But at the same time I think that it doesn't hurt to have a package format with metadata and we can just use the metadata format of the package.json
format, as this is widely used in the JavaScript universe anyway and is also supported by JSR and all bundlers I know, also esbuild has it's own package.json module resolution and is written in Go.
As far as I know, the GNOME Bundler is also working on TypeScript support. I still have to familiarise myself with this, but I am interested in how the types are handled there and to what extent we can work together here. Please don't get me wrong, if there really is a need for support without a package.json, I'll be happy to add it, but I'm not convinced yet.
@vixalien Did my examples help you or do you think it would be better to read support without package.json?
Hello. I didn't take much time to examine the situation so forgive me if my responses are a bit shallow, but it seems the issue is that the new direction of the project is trying to work with other JS runtimes (Node, Bun, Deno, etc...) while kind of forgetting GJS. I say this because of the addition of package.json
and moving to support registries npm
/jsr
which are not compatible with GJS.
With the current approach, ts-for-gir doesn't work with GJS, so we are still using outdated gi.ts. It would be nice to atleast have the old behavior of gi.ts and then maybe improve it from down the road.
As far as I know, the GNOME Bundler is also working on TypeScript support.
It's Workbench that's working on TypeScript support, and that actually requires projects like gi.ts and ts-for-gi, not the other way around.
By the way: For the future I plan to support JSR which is a TypeScript runtime independent package registry
Just so you know, this brings absolutely nothing to the table for GJS. GJS doesn't support package registries at all. Unless some work is done, jsr/node/cloudinary will almost mean nothing to GJS (unless you use BOTH Node and GJS, but that's another topic).
What I could also add would be support for a declaration file that contains all generated types, so that only one entry in tsconfig.json is necessary, if that would still help.
Yes. The package.json and all the additional files are really unused for GJS-based typescript solutions. All that's needed is that declaration file that links all generated types, like gi.d.ts
. GJS can't do import Gtk from "@girs/gtk-4.0"
.
@vixalien Okay then I will try to implement it again to be independent of a package.json
and a bundler. But I can't say just yet how quickly this will happen
Seems like recent changes made this possible (kinda). I have one question:
In the generated files, say gtk-4.0.d.ts
, there seem to be an import of ./gtk-4.0-import.d.ts
which in turn imports ./gtk-4.0.js
leading to a circular import. Is this behaviour correct?
This was not a conscious decision, but does not cause any problems as far as I know, if you think it can be cleaner I am happy about suggestions :)
would it be enough for you to have an all.d.ts
in the types
folder (which imports all the necessary types via a direct path, so that the package.json is not needed) and to keep the folders for each library? This would make the implementation easier
Yes :)
I'm having issues understanding the buildType
option :( at first I thought it might be closest to what GJS does.
I hope when the all.d.ts
file is generated (probably when buildType
is set to types
) the other files (README
, tsconfig.json
, typedoc.json
, ... won't be generated as well.
Also would be nice if the files are put directly inside the types
directory, as I don't see why they would need to be grouped otherwise (no README
, tsconfig
, etc..), behaviour would be similar to v3
@vixalien Is now implemented with the latest version and is the default. package.json
support must now be explicitly activated with --package
. Please try it out :)
Hey! Thanks very much for working on this!! I'll be trying it out soon ๐