gjsify / gnome-shell

GJS TypeScript type definitions for GNOME Shell Extensions
MIT License
55 stars 5 forks source link

[question] Cannot import Gtk using const { Gtk } = imports.gi; #4

Closed piorkov closed 11 months ago

piorkov commented 1 year ago

Hey, this is my first interaction with gnome-shell extension and typescript. My learning consists of modifying an example from this repo. However, I can't import the GtK library using:

const { Gtk } = imports.gi;

I got error "Property 'Gtk' does not exist on type 'GjsGiImports'.ts(2339)" I also tried to use import

import  { Gtk } from '@girs/gtk-4.0';

but it didn't like probably gnome-shell after I got an error: ReferenceError: require is not defined

I don't know what the problem is, am I making some kind of mistake ?

piorkov commented 1 year ago

tl;dr: I think this is what my problem is related to: https://github.com/evanw/esbuild/issues/3166

I did a little reading of articles on the web and found that GJS does not support require. From what I understood as I am using Gnome 42 one way to import is to use imports.gi . However, typescript has a problem with this so I have to use import in the code. And this will solve the compilation problem for me. But I still have a problem with the runtime.

While manually editing the resulting js file, I noticed that esbuild is using the wrong files from @girs to import. I tried for several hours but couldn't get esbuild to use the cjs files. Moments ago I found this issue https://github.com/evanw/esbuild/issues/3166 created by @JumpLink However, I do not see a satisfactory solution there. Is the only solution plugin + onResolve ??

jboillot commented 1 year ago

Hello, I had the same problem as you, and I found a "workaround". I share it if it can help :

const { Clutter, Gio, GLib, St } = imports.gi;

import type Clutter_t from '@girs/clutter-12';
import type Gio_t from '@girs/gio-2.0';
import type GLib_t from '@girs/glib-2.0';
import type St_t from '@girs/st-12';

Then, you only have to use the _t suffixed version when make explicit the types.

(you may prefer this syntax:

import type Gio from '@girs/gio-2.0';
const gio = imports.gi.Gio;

)

piorkov commented 1 year ago

@jboillot Interesting WA. I decided to write a plugin for esbuild:

let girsResolverPlugin = {
    name: '@girs resolver',
    setup(build) {
        build.onResolve({ filter: /^@girs\// }, (args) => {
            const packagePath = path.join(
                args.resolveDir,
                '../node_modules',
                args.path,
                'package.json',
            );
            if (!fs.existsSync(packagePath))
                return {
                    errors: "Module ${args.path} doesn't have package.json",
                };

            const packageData = fs.readFileSync(packagePath, 'utf8');
            try {
                const packageJson = JSON.parse(packageData);
                if (
                    'exports' in packageJson &&
                    packageJson.exports['.'] &&
                    packageJson.exports['.']['require'] &&
                    packageJson.exports['.']['require']['default']
                ) {
                    return {
                        path: path.join(
                            args.resolveDir,
                            '../node_modules',
                            args.path,
                            packageJson.exports['.']['require']['default'],
                        ),
                    };
                } else if ('main' in packageJson) {
                    return {
                        path: path.join(
                            args.resolveDir,
                            '../node_modules',
                            args.path,
                            packageJson.main,
                        ),
                    };
                } else {
                    return {
                        errors: "Module ${args.path} doesn't have 'exports' or 'main' field in package.json",
                    };
                }
            } catch (parseErr) {
                return {
                    errors: 'Module ${args.path} package.json parse error',
                };
            }
        });
    },
};

However, I faced a problem with gtk4 that I don't know how to solve. I do not know how, but all this code generated by esbuild:

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// node_modules/@girs/gtk-4.0/gtk-4.0.cjs
var require_gtk_4_0 = __commonJS({
  "node_modules/@girs/gtk-4.0/gtk-4.0.cjs"(exports, module2) {
    imports.gi.versions.Gtk = "4.0";
    var Gtk2 = imports.gi.Gtk;
    module2.exports = Gtk2;
  }
});

// src/prefs.ts
var import_gtk_4 = __toESM(require_gtk_4_0());
imports.gi.versions.Gtk = "4.0";

causes Gtk4 to try to access functions not offered by the libraries on my system:

GLib.Error g-invoke-error-quark: Could not locate gtk_ordering_from_cmpfunc: 'gtk_ordering_from_cmpfunc': /lib/x86_64-linux-gnu/libgtk-4.so.1: undefined symbol: gtk_ordering_from_cmpfunc

gtk_ordering_from_cmpfunc was added in GTK4.2 and I have GTK4.1. When I do normal imports in JS this problem does not occur. I don't understand the cause of this problem....

JumpLink commented 11 months ago

Since this package has now been completely converted to ESM (but CJS still exists) and ESM is now also to be used for GNOME Shell 45, this issue may have been resolved.