Skip to content

💬 Determine Extension Architecture #180

Description

@jasonplatts

Before moving too far forward with the Extension API and marketplace, we need to decide what type of environment will be used to run extensions.

JavaScript Core, https://developer.apple.com/documentation/javascriptcore, is an option. It does not support ESM, but as some have mentioned, there are ways to work around these limitations using build tools.

Initially, a Swift extension API is being developed.

However, we ultimately plan to take an approach similar to Raycast that was described by mathieudutour here, #180 (comment). The architecture involves using node and communicating with the CodeEdit application using JSON-RPC. A react-reconciler will allow extensions to create a custom UI with React components.

Thank you to everyone who contributed to the conversation! Please feel free to continue to add feedback and/or suggestions.

Activity

  1. added
    enhancementNew feature or request
    extensionsIssues related to the extension architecture in CodeEdit
    on Mar 22, 2022
  2. underthestars-zhy commented on Mar 23, 2022

    @underthestars-zhy

    First swift, then js. Swift is the easiest for us to implement.

  3. pkasila commented on Mar 26, 2022

    @pkasila
    Member

    I would prefer using Swift for extensions, but having JavaScript API would be nice to have also, considering that the app may be ported to iPadOS later.

    So, I think we need to provide Swift Extension API and prioritize it right now, but also export it to JavaScript.

  4. austincondiff commented on Mar 26, 2022

    @austincondiff
    Collaborator

    I'd imagine more Javascript devs would be using this than Swift devs because they would use Xcode for Swift development for the most part correct? I think both are important and I agree with our current path.

  5. henryhchchc commented on Mar 27, 2022

    @henryhchchc
    Member

    May I propose Lua as another option? Lua is small, portable, and fast. Actually neovim has a quite mature plugin ecosystem in Lua (see nvim-lua-guide). We can attract those plugin developers if we provide a Lua plugin interface.

  6. jasonplatts commented on Mar 28, 2022

    @jasonplatts
    CollaboratorAuthor

    That's an interesting option @henryhchchc. I think at this point we are probably best sticking with Swift and/or JavaScript as our primary focus.

    In my opinion, considering the large VS Code user base, most extensions developers are going to be looking to develop using JavaScript/TypeScript. Initially it will be important to encourage as many of those developers as possible to contribute and add features that aren't in the core application. I believe extensions are key to making CodeEdit usable for the majority of developers.

    Since this is a Mac-centric application, it would be really cool to have Swift as an option, but as @austincondiff mentioned, I don't think that is what most extension developers be looking to use. However, if that what is practical to begin, I'm all for it!

    Ultimately, I wish we could design this in a way that lets extension developers use whatever language they feel most comfortable. I don't want to discourage anyone from contributing. But, it probably isn't realistic without providing some form of language conversion. Additional extension language support is something we could maybe revisit further down the road?

  7. jasonplatts commented on Mar 28, 2022

    @jasonplatts
    CollaboratorAuthor

    To the Swift developers, @pkasila, @MarcoCarnevali, @underthestars-zhy, and any others, how could we go about writing this API in Swift and then packaging/compiling/submitting the extensions in an approachable way?

    Please correct me if I am wrong, VS Code uses the command line I think. Nova just takes care of everything via the GUI. There is a menu option to "Submit extension" and everything simply happens in the background. Not all developers like working in the command line, so it be nice to provide the ability for developers to build/submit the extensions from the GUI. Maybe we could require advanced builds to be performed from the command line?

  8. pkasila commented on Mar 28, 2022

    @pkasila
    Member

    So, in my opinion, Swift Extension Architecture can be implemented the way described below.

    Swift API

    So, let's say we have a CodeEditExtensionAPI package that declares protocols to work with API (the main one is CodeEditAPIProtocol). Both the CodeEdit app and extensions link to this package. Then, the API class, conforming to CodeEditAPIProtocol, is implemented in the CodeEdit app. Then, an object of this class should be passed to the extension, so it can interact with API.

    Loading extensions

    All extensions are loaded using dlopen at the runtime from dynamic libraries.

    Each dynamic library should have createExtension function as follows:

    @_cdecl("createExtension")
    public func createExtension() -> UnsafeMutableRawPointer {
        return Unmanaged.passRetained(HelloWorldExtensionBuilder()).toOpaque()
    }

    The API object is passed to the ExtensionBuilder.build function.

    More information about plugin system using dynamic libraries in Swift can be found here

    Compiling and packaging extension

    Extensions should be compiled as dynamic libraries (dylibs).

    The minimal extension's package structure should be as follows:

    HelloWorld.ceext
    | - manifest.json
    | - plugin.dylib
    
    • manifest.json stores the manifest of the extension
    • plugin.dylib is the dynamic library with the extension

    Submitting extensions

    I think there are 2 ways:

    • We simply create a Git repository for developers to submit their extensions using PRs (by providing a manifest and a link to the GitHub Release page or somewhere else as a JSON file): it will be pulled by the CodeEdit app and indexed on the device
    • We create a custom catalog service (marketplace) where (and there are 2 options)
      • both extensions' manifests and packages are submitted by the developer and stored by us
      • only extensions' manifests are stored by us and packages are stored by the developer somewhere else (e.g. GitHub Releases)

    Other languages

    • If we are speaking about using JavaScriptCore then we can conform this API to be exported to the JavaScriptCore
    • If we are speaking about any other language then there should be more or less similar way of exporting API
  9. jasonplatts commented on Mar 28, 2022

    @jasonplatts
    CollaboratorAuthor

    Awesome @pkasila!

  10. jasonplatts commented on Mar 28, 2022

    @jasonplatts
    CollaboratorAuthor

    Compiling and packaging extension

    Extensions should be compiled as dynamic libraries (dylibs).

    The minimal extension's package structure should be as follows:

    HelloWorld.ceext
    | - manifest.json
    | - plugin.dylib
    
    • manifest.json stores the manifest of the extension
    • plugin.dylib is the dynamic library with the extension

    Are we able to automate and simplify this process from the extension developers perspective through CodeEdit? Maybe a "Package and Submit Extension…" menu item?

  11. jasonplatts commented on Mar 28, 2022

    @jasonplatts
    CollaboratorAuthor

    Submitting extensions

    • both extensions' manifests and packages are submitted by the developer and stored by us

    I am in favor of this option if we can make it work. I understand there will be costs involved and it probably depends on community support. I think it's the most reliable choice.

    If extension developers provide their own storage, whether it be GitHub or something else, there is the possibility that these services might be down, causing some extensions to work and some other not, which could cause confusion to users. Our storage might go down too, but I would think it would likely be the entire extension library and we would at least have the ability to troubleshoot and/or explain the outage.

    We also run the risk of extensions being deleted, but still appearing in the extension library.

  12. pkasila commented on Mar 29, 2022

    @pkasila
    Member

    Are we able to automate and simplify this process from the extension developers perspective through CodeEdit? Maybe a "Package and Submit Extension…" menu item?

    I think we can determine whether an extension project is open. Any extension's project can be a Swift Package (with a dynamic library) with manifest.json file, so if CodeEdit (actually, a specific extension for extension developers) detects that this is an extension's project, then it adds a target for the extension to be published and this target handles packaging and submitting the extension to the store.

    I am in favor of this option if we can make it work. I understand there will be costs involved and it probably depends on community support. I think it's the most reliable choice.
    If extension developers provide their own storage, whether it be GitHub or something else, there is the possibility that these services might be down, causing some extensions to work and some other not, which could cause confusion to users. Our storage might go down too, but I would think it would likely be the entire extension library and we would at least have the ability to troubleshoot and/or explain the outage.
    We also run the risk of extensions being deleted, but still appearing in the extension library.

    I think that I'll try to play around with how API for the extensions store and the store itself can be implemented a little bit. And I'll write about what I think suits our needs better later.

  13. jasonplatts commented on Mar 29, 2022

    @jasonplatts
    CollaboratorAuthor

    Thanks @pkasila. Sounds to me like a solid starting point. I know there will be details to figure out and a lot of trial and error as we go.

  14. 29 remaining items

  15. FezVrasta commented on Apr 13, 2022

    @FezVrasta
    Contributor

    The main issue of Electron apps is not node, it's the rendering, and the huge amount of resources needed by each app. Having a node process run in background of a native app would be totally fine in my opinion.

  16. jasonplatts commented on Apr 13, 2022

    @jasonplatts
    CollaboratorAuthor

    I think something like that should be possible. I am not sure whether this was mentioned here already, but VSCode also has something called "activation events", where extensions are only activated once they are actually used, e.g. the C++ extension would only become active once a C++ file is opened or a C++ command is used.

    The same mechanisms could be used for hot-reloading where an application is deactivated, the source code is replaced and then activated again.

    It's the same in Nova too. I mentioned this briefly in issue #76 in the "Extension Entry Point" section. Both VS Code and Nova also include activation information in the extension manifest.

  17. deleted a comment from stale on Jun 20, 2022
  18. austincondiff commented on Jul 5, 2022

    @austincondiff
    Collaborator

    Based on a prior conversation on Discord with @josephschmitt @mattmassicotte @jasonplatts @pkasila @avdept and a few others, with the announcement of ExtensionKit in the latest WWDC which has been written about here, we have arrived at the following conclusion.

    We will use ExtensionKit and expose a Swift API with the goal of later exposing a Javascript API later on. This will allow us to move fast and remain true to our overall mission statement which is to create something as native as possible to create a more performant editor. I invite anyone who cares to add to this or to explore specifics around this chosen path to do so. I feel like we can close this issue once all the kinks have been ironed out as long as nobody objects to it as I feel like we have arrived at a conclusion here.

  19. austincondiff commented on Jul 25, 2022

    @austincondiff
    Collaborator

    I just wanted to leave a quick update in our progress. We've been taking this real slow because we really need to get this right to begin with because it will affect everything we do going forward.

    Our idea to execute on this is relatively simple. We will end up exposing a Swift API and JS API in parallel, Swift to start because we will obviously need Swift functions to do anything. Then either as we go or shortly after we will expose a JS API

    To get JS and Swift to play nicely we'd have a server/client model. We'd use Bun instead of Node for faster execution especially because it is based on JSCore rather than Chromium's JavaScript v8 engine. JavaScript execution using Bun can reach near-native speeds which is what we are looking for. Bun also supports modern JS and TypeScript out-of-the box.

    We would spin up a JavaScript service on Bun on application start that houses all of the users installed extensions. The app and each installed extension would communicate via XPC and/or JSON-RPC. I also found this project that can reconcile React JSX into JSON so that we can offer React components to render out our Swift views.

    We need to prove out this theory before we bring any of this to CodeEdit by creating a simple POC. That might look like a simple "hello world" Swift application. We might change the text or enter a name with an input and a button that a Javascript extension tells our Swift application to render, then when clicked, our JS extension will tell our Swift application to execute a specific function with a certain set of arguments in will provide.

    Once we get this POC done, we can start putting it into CodeEdit. We can tell it to add a new navigator, inspector, or debugger. We can tell it to add autosuggestions under certain conditions, add snippets, and add commands. Then we build from there.

    Before we begin putting a POC together, does anyone have any feedback on this approach?

    We also need to figure out the communication protocol. We have mentioned gRPC, JSON-RPC, and XPC. Any preference? Pros and cons?

  20. matthijseikelenboom commented on Sep 11, 2022

    @matthijseikelenboom
    Contributor

    This is what I know of the topic, so people, please correct me if I'm wrong.

    JSON-RPC (Personally never used it)
    Pros:

    • Human readable
    • Relative easy to learn
    • Language agnostic

    Cons:

    • Slower due to text encoding and decoding over the network
    • Not type save

    gRPC (Tinkered with this)
    Pros:

    • Fast, low latency
    • Widely used in micro-service architectures (So it's "battle-tested")
    • Type save
    • Auto generated code based on .proto files
    • Language agnostic

    Cons:

    • Not human readable, uses binary
    • Steep learning curve (In my opinion)

    XPC (Personally never used it, actually never heard of it prior)
    So, I don't really no the pros and cons of this. But it does seems like very few developers use this. The issue I see with that is that it could take more time develop the system if it's decided that this protocol is used. Also I have no idea how this would interact with the JavaScript API. The thing that it has going for it, is that it is Apple native, but I don't think that matters. So, my conclusion would be that I wouldn't recommend using XPC.

    gRPC has my personal preference, but on whether to use it would kind of depend on how many people in our community know how it works and/or want to learn how it works. As far as I know, it's mainly used in backend development and I assume most of the CodeEdit community are frontend developers.

  21. avdept commented on Sep 12, 2022

    @avdept
    Contributor

    I've worked with grpc for last few years and its really good tool to communicate between 2 servers. We don't really need human-readability, since there's nobody in between to read request/response data. Also I can't say it has steep curve. It has some issues if you compile it from sources for specific platform, but if you use prebuilt binaries then IDE should provide code completion for generated code.

    I have app that makes you to use UI to compile your proto files into specific language. https://github.com/avdept/Protobuf-GUI-Compiler

  22. matthijseikelenboom commented on Sep 15, 2022

    @matthijseikelenboom
    Contributor

    Perhaps we should discuss this topic in the next meeting because I think we should make a decision on this, because of the high priority.

  23. locked and limited conversation to collaborators on Oct 1, 2022
  24. converted this issue into a discussion #792 on Oct 1, 2022
  25. moved this from 🆕 New to 🏁 Complete in CodeEdit Projecton Feb 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    PRIORITYThis issue has priority over other issues.clarification neededFurther information is requestedenhancementNew feature or requestextensionsIssues related to the extension architecture in CodeEdit

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions