Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin/JS codegen compiler extension #4925

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Soarex16
Copy link
Contributor

Motivation

Currently, the code generation process (IR to JS conversion) is fixed and cannot be modified by plugins. This on the one hand leaves flexibility for compiler developers, but at the same time does not allows to customize transformations at later stages of compilation.

For example, currently, there is no way to generate multiple .js files for one module. Such abilities a very useful in some scenarios like Web Workers API.

This PR aims to provide some basic implementation for such extension points.

Safe harbor

It's also worth noting that the changes I'm suggesting don't consider many edge cases - for example, incremental compilation, bundle size, etc. Therefore, I propose to join the discussion to design a better solution that considers various use cases.

The main question - why can't this be done at the IR level? This is due to the fact that in some situations, plugin developers need the ability to perform platform optimizations and have access to the infrastructure of the corresponding backend.

As far as I know, the compiler has bytecode post-processing for the JVM platform, but this tool is not available for plugins. There is no such functionality in the JS IR backend (to be more precise, it is not highlighted as an explicit post-processing stage).

Proposed compiler changes

The following must be taken into account here:

  • Since incremental compilation works with both IR and JS AST, it is necessary to keep the caches up to date.
  • Since we want to generate additional .js files, dead code elimination needs to know about the declarations that exist in these files. To do this, we need to be able to add new DCE roots.
  • Plugins need information about the structure of the resulting artifacts. This point is not fully thought through. The main use case is the Web Worker API - at compile time we need to know which files will be generated because Worker constructor accepts script URL. It is worth mentioning that support for web workers is a separate issue and for now I will not touch on the details of implementing their support in Kotlin.
  • Plugins also need the ability to get and modify information about modules. This is necessary so that the generated modules can refer to declarations from other modules.

Use cases

The main reason to inject into code generation process - there is currently no way to emit multiple .js files for a single module. The community needs this functionality because its absence makes it difficult to implement Kotlin/JS in the following scenarios:

  • Web Workers API requires workers-related code to be in a separate file. Also, because workers executes in a separate thread, programmers must use importScripts(...) to include dependencies in worker context.
  • Code splitting and lazy loading. A common scenario in modern web applications is that some heavy component (Web IDE for ex.) should not load when not in use. Also in this case we want some guaranties from the compiler that we don't use declarations that haven't yet been loaded.
  • Developing browser plugins using WebExtensions API requires to have separate files for UI elements, background worker, etc.
  • As Roman Elizarom mentions, in Kotlin/JVM for testing purposes you can have main in each .kt class.

Samples

This PR also includes a sample plugin to demonstrate the process of generating multiple .js files for a single module.

Add ir2js extensions to test infrastructure

Code cleanup (compiler core)
@abelkov abelkov added the JS label Aug 23, 2022
@LifeIsStrange
Copy link

LifeIsStrange commented Aug 23, 2022

Enabling interop between KotlinJS and JSweet (transpiled Java) would be a major improvement to Kotlin.
I suppose? allowing custom compiler plugins to do transforms at multiple stages might be a primitive that helps towards KotlinJS/JSweet interop. (although in theory the JSes should already be mostly compatible, the lack of KotlinJS/JSweet interop is mostly a lack of IDE support and gradle mpp support.
Still this could help with edge cases and performance.
@lgrignon friendly ping for awareness

The same apply for the J2CL project
google/j2cl#93
It says they are currently working on kotlinjs support/interop.
@gkdn

@Soarex16
Copy link
Contributor Author

@LifeIsStrange I think you should write it on YouTrack

@broadwaylamb broadwaylamb self-requested a review September 12, 2022 15:41
Copy link
Contributor

@broadwaylamb broadwaylamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Soarex16 thank you for your pull request!

For ease of review and to increase the chance of this being merged, please split this into two PRs: one for introducing the extension point, and another for the web workers plugin.

@Soarex16
Copy link
Contributor Author

@broadwaylamb, I've split this PR into smaller parts: #4989 and #4988

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants