Need help updating @theia/core and deploying it to a docker container

I’ve been successfully building a modified version of the theia-full docker image. However, I need to make a modification to the @theia/code, and while this works when developing locally, as soon as I try to use the updated package from within the docker container I get errors.

How to replicate

Steps

  1. Build @theia/core, and then run yarn pack to generate a theia-core-v1.0.0.tgz

  2. Update Dockerfile to add theia-core-v1.0.0.tgz to /home/theia folder

  3. Update @theia/core dependency in next.package.json [here[(https://github.com/theia-ide/theia-apps/blob/master/theia-full-docker/next.package.json#L15) to point to: file:///home/theia/theia-core-v1.0.0.tgz

  4. Build docker image (this will build my updated version of @theia/core)

  5. Boot docker container and connect

  6. Access theia via browser http://localhost:3000

The error I get

From here you will see theia’s spinner but will fail to load and give the following error in the browsers dev console (see screenshot at end):

Failed to start the frontend application. index.js:80:16
    exports index.js:80
Error: "Cannot apply @injectable decorator multiple times."
    injectable injectable.js:8
    <anonymous> Reflect.js:541
    <anonymous> Reflect.js:130
    a decorator_utils.js:42
    decorate decorator_utils.js:55
    <anonymous> widget.ts:27
    exports index.js:82

My understanding is that this issue is happening because each individual package is using a different core version (than the one I manually built).

How do I get past issue?

Screenshot of issue:

[original thread by Bradley Steinfeld]

@bsteinfeld do you happen to have your package.json that you can share?
I suspect there might be an issue where multiple versions of the same dependency are included in an application, or the yarn.lock (if you have one) might be outdated.

[Bradley Steinfeld]

Here is my package.json: https://gist.github.com/bsteinfeld/ff5ae904b770e82a8728310e558c4997

[Bradley Steinfeld]

The issue is likely with line 16. You can see here I’m mixing core 1.0.0 and next (which is likely 1.1.0-.

The problem is that each extension pulls the same version of core (next), but the core you included is your own. This means the application will not know how to resolve two versions of the same extension and thus you get the multi-injector error. In general, it is unadvised to directly modify an extension. Instead, you should create an extension which extends core to the functionality you require. The following approach will not work unfortunately.

[Bradley Steinfeld]

@vince-fugnitto Is there a way to re-build each extension with my custom core?

Correct, this is not possible when composing applications since multiple versions of the same extension cannot be resolved.

[Bradley Steinfeld]

So can I re-build each extension with my custom core? Or is there any other way to accomplish what I want?

I’ve been messing around with lerna a bit with no luck so far…

I think the proper way forward would be to create a new extension that extends core to do the changes you require. Directly modifying core is not the way forward as it will require modifying all dependent extensions. What kind of changes are you applying directly to core?

[Bradley Steinfeld]

I only have 1 very minor change I need to make.

I simply want to modify the getRestUrl function to the following:

getRestUrl(): URI {
        const newHost = this.host.replace(/:8888$/, ':3000');
        const newPathname = this.pathname.replace(/\/user\/\w+/, '');
        return new URI(`${this.httpScheme}//${newHost}${newPathname}${this.path}`);
}

This will fix routing issues I’m having with theia (in my environment I’m putting it behind a reverse proxy that appends /user/ to the path).

[Bradley Steinfeld]

@vince-fugnitto Would I be able to do this with a new extension?

@anton-kosyakov any thoughts on modifying this code from an extender POV?

On my side, I see two options:

  1. Make this class part of DI somehow.

  2. Hack: In your extension code, modify the prototype of the Endpoint class.

[Bradley Steinfeld]

So I’ve just rebuilt all packages with my customized core (via using tgz files from yarn pack).

I no longer see the “Cannot apply @injectable decorator multiple times.” error but now I’m seeing:

Failed to start the frontend application
    exports index.js:79
Error: "Could not unbind serviceIdentifier t"
    unbind  container.js:174
    rebind  container.js:166
    n  container.js:280
    default  monaco-frontend-module.ts:124
    load  container.js:113
    d.   index.js:26

[Bradley Steinfeld]

in service logs I see:

Error: No matching bindings found for serviceIdentifier: ProcessManager
...
Error: No matching bindings found for serviceIdentifier: Symbol(RawProcessFactory)

[Bradley Steinfeld]

I’m thinking the best would be to get my changes (cleaned up, and only activated via EnvVar) published the the official @theia/core.

[Bradley Steinfeld]

As such I’ve created the following issue: https://github.com/eclipse-theia/theia/issues/7484

@bsteinfeld I think contributing your change is the best way to go. But for the quick fix, Try adding your version of @theia/core to the resolutions block at the end of package.json. I’ve never tried with a “file://” dependency but it seems it should work.

One thing to know: your application pulls next versions of theia packages. It means that your local version of @theia/core can be missing updates that the rest of the platform has, in the next version of the packages you’ll pull each time you build your container. This will be very fragile. Use latest instead if you can, and checkout the v1.0.0 tag of the theia source code, so you have the correct baseline, then re-apply your change. This way you could rebase once a month, after the theia release.

Webviews are running fine in Gitpod behind reverse proxy without any modifications to Endpoint.

There are already many places to hook: