kotlin icon indicating copy to clipboard operation
kotlin copied to clipboard

Kotlin/JS codegen compiler extension

Open Soarex16 opened this issue 3 years ago • 3 comments

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.

Soarex16 avatar Aug 22 '22 16:08 Soarex16

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 https://github.com/google/j2cl/issues/93 It says they are currently working on kotlinjs support/interop. @gkdn

LifeIsStrange avatar Aug 23 '22 22:08 LifeIsStrange

@LifeIsStrange I think you should write it on YouTrack

Soarex16 avatar Aug 29 '22 13:08 Soarex16

@broadwaylamb, I've split this PR into smaller parts: https://github.com/JetBrains/kotlin/pull/4989 and https://github.com/JetBrains/kotlin/pull/4988

Soarex16 avatar Oct 16 '22 23:10 Soarex16