How to import shell modules into prefs.js?

While writing a simple Shell extension, I’ve noticed that importing modules specific modules from Gnome Shell UI Javascript bindings, while trivial in extension.js, doesn’t seem to work in the preferences script prefs.js:


import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';

export const MyIndicator = GObject.registerClass({
    GTypeName: 'MyIndicator'
}, class MyIndicator extends PanelMenu.Button {

    static get Position() { return Object.freeze({
        'Left'   : 0,
        'Center' : 1,
        'Right'  : 2
    }); }

    // ...



import { ExtensionPreferences, gettext as _ } from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
import { MyIndicator } from './indicator.js';   // ImportError

export default class TestPreferences extends ExtensionPreferences {
    fillPreferencesWindow(window) {
        const settings = this.getSettings();
        // MyIndicator.Position['Left'] ...

leads to

ImportError: Unable to load file from: resource:///org/gnome/shell/ui/panelMenu.js (The resource at “/org/gnome/shell/ui/panelMenu.js” does not exist)

Is there any particular reason for this?
It would make sense to have the script used to generate the Preferences window dependent on the actual extension code, but instead the preferences window is limited to the ExtensionPreferences class, and this doesn’t seem to be discussed in the docs.

I understand that I can - as I’ve seen is commonly used in many extensions - either just re-declare any static objects that may be useful in parsing/setting extension preferences, or move them to a separate script without any dependency on GJS modules, but that does not seem the most straightforward approach.

Yes. gnome-shell’s JS code generally assumes that it is running in the gnome-shell process, and thus components like the top bar or overview are available, as well as compositor-specific libraries like Meta or Clutter.

Code like panelMenu would simply be broken in a completely different process like the preference dialog, so it’s not included in the code that is bundled with the dialog.