badoo / Reaktive

Kotlin multi-platform implementation of Reactive Extensions
Apache License 2.0
1.18k stars 58 forks source link

Publish Reaktive node.js target to npm #488

Closed minaEweida closed 3 years ago

minaEweida commented 4 years ago

Is there any plans to publish Reaktive to npm? Recently we used reaktive in our lib to support node.js apps so we are publishing Reaktive to our internal artifactory since Reaktive is not published

arkivanov commented 4 years ago

Thanks @minaEweida we'll check.

minaEweida commented 4 years ago

Hi @arkivanov, if you are planning to do this, please make sure to mention that supported node.js version should be 12+ since MainScheduler is using globalThis which is supported for Node.js version 12.

Screen Shot 2020-07-21 at 3 00 12 PM
arkivanov commented 4 years ago

A related ticket: KT-41566

arkivanov commented 4 years ago

NPM publishing plugin is released: https://gitlab.com/lt.petuska/npm-publish/-/releases/v0.1.1

arkivanov commented 3 years ago

Looks like a good article about publishing to npm: https://zellwk.com/blog/publish-to-npm/

arkivanov commented 3 years ago

Maybe anybody want to contribute? We could not find anyone with experience in both Kotlin Multiplatform and NPM at the same time. From our side we could setup everything needed (like registering with the NPM repository, etc.)

minaEweida commented 3 years ago

We managed to publish our lib on our internal NPM and as a workaround we published reaktive artifacts as well. I will try to do the same here.

It felt like a work around but I will contribute what I did and let's see if we can make it better.

gciatto commented 3 years ago

NPM publishing would be very nice for my as it would enable its exploitation in my Kotlin MP project.

BTW I'm well aware of the issues related to publishing Kotlin MPP to NPM. I've implemented a simple plugin to simplify the process: https://github.com/gciatto/kt-npm-publish

It is not clear to me what's the limiting factor in this case, but I hope my plugin may help.

arkivanov commented 3 years ago

@gciatto-unibo The limiting factor here is the lack of expertise in this area. We will need to learn all the things first, hence the delay. As mentioned above we are happy to accept contributions for this task. And we will assist as much as we can.

gciatto commented 3 years ago

I have some degree of expertise concerning how to publish Kotlin-JS stuff on NPM. Let me know if and how I can help.

arkivanov commented 3 years ago

@gciatto-unibo Perhaps we should first define all the required steps. Some steps my require infrastructure changes, code changes, repository settings changes (secrets), registering with third-party services, etc. Would you be able to list the steps? Then we could delegate the tasks. Or if you have another vision or questions, please let me know.

arkivanov commented 3 years ago

@gciatto-unibo (and other interested people) should we publish only the IR variant or both?

Also it seems that for the IR mode we need to specify js { binaries.library() }, but it fails when BOTH mode is used. We can use IR-only mode and enable binaries.library() conditionally based on command line arguments. But may be there is a better way? Google and Slack are empty.

gciatto commented 3 years ago

@arkivanov the JS API should be equal, so any of them is fine. I currently rely on the legacy backend, but it's because I'm lazy. If in IR mode all tests succeed, I'd suggest sticking to that.

gciatto commented 3 years ago

@arkivanov Sorry for my late reply, I'll try to provide an overview of the steps below based on my experience. Everybody should feel free to correct me in case I'm wrong or imprecise---which is likely. Also, I'll assume knowledge about the JS and Node world, but please feel free to ask for details.

Essentially, assuming that you have a Kotlin MP project or a Kotlin JS project, there exist two Kotlin-to-JS workflows: one producing a single .js file for client-side usage, and the other producing Node projects, for server-side usage.

The former one can be summarised as follows:

Kotlin MPP/JS -[Kotlin compiler]-> JS sources -[Webpack]> Single .js file to be used as a static resource in web pages

The latter one can be summarised as follows:

Kotlin MPP/JS -[Kotlin compiler]-> Node Project containing JS sources and the `package.json` file

The two workflows are not mutually exclusive, and which one you'll use depend on how your Gradle build is configured.

My suggestion is to always use at least the Node option, as Webpack can be naturally applied to Node projects using the npm command-line tool. So, while Kotlin code transpiled into Node project for server-side usage can always be converted into a client-side JS script, Kotlin code transpiled into JS client-side script cannot be converted back into a Node project.

That said, I'll assume from now on that we can convert Kotlin MP/JS projects into Node projects. Node projects can be naturally deployed on the NPM repository using the npm command-line tool which should be included in any correctly configured Node environment. This is as simple as running the npm publish command into the root directory of the generated Node project. This can either be performed by directly using npm or via my aforementioned kt-npm-publish plugin, in case you want to automate that via Gradle. In both cases, a user must be registered on the NPM repository and they must have created a deploy token.

gciatto commented 3 years ago

There are now 2 potential sources of troubles when deploying your JS-transpiled code on NPM:

  1. ensuring the dependencies of your transpiled projects are libraries that are on NPM as well (otherwise JS developers will get a runtime error when they'll try to use your library)
  2. changing the name of the JS library you're going to publish on NPM, e.g. by adding an organization name
gciatto commented 3 years ago

Problem 1 arises because, when producing the Node project (and in particular the package.json file), the Kotlin compiler does not references JS dependencies from NPM, but rather it leverages on a particular notation (which I do not fully understand) that only works locally (cf. https://discuss.kotlinlang.org/t/local-dependencies-in-package-json-of-js-mpp-projects/19260).

So, unless your project has no dependency (which is unlikely, as it shall at least depend on Kotlin's Standard Library for JS), the package.json should be lifted (this is my own jargon) in such a way that dependencies only reference JS libraries that are or will be published on NPM.

Long story short, there is no automated way to do so (to the best of my knowledge) except for my kt-npm-publish plugin.

gciatto commented 3 years ago

Problem 2 only arises if you need/want to change the default project name generated by the Kotlin compiler. This is far from trivial, especially in multi-projects builds, because it is NOT sufficient to edit the generated package.json files to change the project names.

So for instance: if your root project is named foo and it has two Kotlin MP/JS sub-projects named bar and baz respectively, then the Kotlin compiler will generate the foo-bar and foo-baz projects. Let's assume this is not fine for your, as, for instance, you may be willing to publish both projects under a common organization, say @acme. This implies they should be renamed to @acme/foo-bar and @acme/foo-baz respectively. This implies their all occurrences of foo-* in all package.json files and in all .js files should be updated accordingly...

The matter gets complicated if the two projects are inter-dependent.

So, again, long story short: no automate way to do so. The only semi-automated way to do so I'm aware of is my kt-npm-publish plugin.

arkivanov commented 3 years ago

@gciatto-unibo Thanks for the input!

Problem 1 Here are all Reaktive's JS target dependencies:

All other are either Java-specific or samples, so no need to publish them I guess.

Problem 2 I read that the name prefix can be changed by using the rootProject.name setting in the settings.gradle file. We don't have this setting set yet, but if it really works and will not affect anything else, then we can set it to something like badoo-reaktive. In this case the name in the package.json file should be like badoo-reaktive-reaktive, badoo-reaktive-utils, etc. May be we could use this as a workaround?

The issue with both IR and Legacy modes enabled IR mode compiles just fine currently and all tests are green, and I also have feeling that it should be preferred. But as I mentioned in my previous message, I could not specify js { binaries.library() }, as Gradle sync fails saying it is not allowed for BOTH mode. Looks like we need a workaround here as well.

Registration with the NPM repository We will take of this step and provide updates in this issue.

PS I managed to roughly publish Reaktive to local NPM repository by enabling only IR mode, specifying js { binaries.library() } and running ./gradlew npmPublish. Seems like it was successful, but maybe I missed something like Problem 1 or anything else.

gciatto commented 3 years ago

Problem 1

Concerning reaktive, reactive-annotation, and utils, I agree that they should be publishable with no major issues.

Concerning reactive-testing... well it depends. Is that a library you use for testing in some Reaktive module or is it intended for letting people test their code when they use Reaktive? In the latter case, I believe reactive-testing should be published on NPM as well.

Concerning reaktive-coroutines, I bet it will be troublesome as kotlinx-coroutines-core-js is not yet on NPM, to the best of my knowledge. However, we may consider opening a ticket for that, and you may consider not publishing it for the moment. That would imply discouraging the usage reaktive-coroutines for Kotlin users willing to produce NodeJS projects. (E.g. I could not be using it in my project until reaktive-coroutines is on NPM)

Problem 2

In my experience, changing the rootProject may affect the naming of some Maven artifacts. So this may not be a trivial issue.

However, the real problem is different. Your proposal is essentially "let's put a badoo- prefix on all Reaktive-related packages published on NPM, to mimic Maven's groupIds", isn't it? If I correctly understand your proposal, my suggestion is to consider other options. In that way, NPM packages will be just a bunch of unrelated JS packages which happen to have the same prefix in their name. I believe that NPM's organization are the better option to mimic groupIds. But

So my suggestion is to reason about "how you want your JS-compiled libraries will be perceived by JS developers in the long term", and then stick to a decision.

The issue with both IR and Legacy modes enabled

Why can't you just use IR instead of BOTH?

Concerning your PS

Nice job! Now let's ensure the published library can work.

There are two tests you can manually perform:

  1. could you please report the output of the following command

    npm info <name of your Reaktive JS Package>

    This should let us inspect the dependencies of your package, to ensure they reference NPM packages.

  2. could you create a dummy Node project and use <name of your Reaktive JS Package> as a dependency, then run npm install and see if dependency resolution works?

arkivanov commented 3 years ago

Turned out we already have an account: https://www.npmjs.com/~bumble-core-services

arkivanov commented 3 years ago

@gciatto-unibo thanks again for your input.

Problem 1 reaktive-testing is supposed to be used in Kotlin projects for testing purposes. So perhaps we can skip its publication for now. reaktive-coroutines is widely used as far as I know, e.g. for interop with Ktor. There is also the -nmtc version of this module published from a separate branch (for Kotlin/Native multi-threaded coroutines). So it seems, even if we publish all modules without reaktive-coroutines, it is still will be unusable for most of the devs, right? Or maybe devs could publish coroutines manually to their local npm repos, as they probably doing it with Reaktive currently?

Problem 2 Agree. I checked the account link above, we have company prefixes for all existing packages. So perhaps for Reaktive we should prepend badoo@/, for consistency with the com.badoo package name in this repository. Are there any pitfalls with this approach? How complex would be the effort?

IR/BOTH modes We have BOTH modes enabled because we should still have developers who can't migrate to IR mode. One of the reasons is that all dependencies should support IR mode (or BOTH). Another reason could by possible compiler crashes (we had at least two blocking compiler bugs recently). So we should first find a way to specify js { binaries.library() }, or maybe add workarounds to the publication tasks (e.g. enabled only IR mode when publishing to NPM).

PS concerns I will try local publications again this Friday (28/05). Thanks for providing the steps!

arkivanov commented 3 years ago

@gciatto-unibo I installed the utils module locally.

Output of `npm info Reaktive-utils` ``` aivanov@aivanov-XPS-17-9700:~/dev/workspace/nodehw$ npm info Reaktive-utils Reaktive-utils@1.1.22 | Proprietary | deps: none | versions: 1 dist .tarball: http://localhost:4873/Reaktive-utils/-/Reaktive-utils-1.1.22.tgz .shasum: 0cc730e4ec938832763862cf1365f83155c12a47 .integrity: sha512-Irx7M/SlmmEww+ZX1NTMGkaVq6+PNrDKemzM94ozi8cOXr2q5OQMCiCj/KOzeSiGf0PCLIg/WV6twUlh714RsA== dist-tags: latest: 1.1.22 published 10 minutes ago ```

I also created and installed a dummy Node project with Reaktive-utils dependency.

Output of `npm info ArkIvanov-helloworld` ``` ArkIvanov-helloworld@1.0.0 | Proprietary | deps: 1 | versions: 1 dist .tarball: http://localhost:4873/ArkIvanov-helloworld/-/ArkIvanov-helloworld-1.0.0.tgz .shasum: 14985e2eb1c7a0145d5deca6c369bb258b8db8d6 .integrity: sha512-6rfamOWgLDsu7BbZsjAkEvpyXwdDhHVMMQ8cK5zRPKyFd4ptl5jwjibP+tvVtqWKHGVzxkp4rz4a97NSnt7o1A== dependencies: Reaktive-utils: ^1.1.22 dist-tags: latest: 1.0.0 published 5 minutes ago ```
gciatto commented 3 years ago

Could you please try the same process with a module which depends on some other module? Say reaktive instead of utils

arkivanov commented 3 years ago

@gciatto-unibo I have locally installed utils, reaktive-annotations and reaktive modules. Here are outputs:

Output of `npm info ArkIvanov-helloworld` ``` aivanov@aivanov-XPS-17-9700:~/dev/workspace/nodehw$ npm info ArkIvanov-helloworld ArkIvanov-helloworld@1.0.1 | Proprietary | deps: 1 | versions: 2 dist .tarball: http://localhost:4873/ArkIvanov-helloworld/-/ArkIvanov-helloworld-1.0.1.tgz .shasum: 25ff203a344ffdd1a19f7a76803935d6f77c7276 .integrity: sha512-IfSSAjc1inGF7Amgh/tRAx2jo1/fYwCmfya20KTh7NIkoMwIkKzhox1txtjKGq5fmld0VVmkUErOKhvEmTPAnQ== dependencies: Reaktive-reaktive: ^1.1.22 dist-tags: latest: 1.0.1 published just now ```
Output of `npm info Reaktive-reaktive` ``` aivanov@aivanov-XPS-17-9700:~/dev/workspace/nodehw$ npm info Reaktive-reaktive Reaktive-reaktive@1.1.22 | Proprietary | deps: none | versions: 1 dist .tarball: http://localhost:4873/Reaktive-reaktive/-/Reaktive-reaktive-1.1.22.tgz .shasum: 3b050ed0e46da507f06134852124fbaed7f8c591 .integrity: sha512-akcc5NapH6HZUKogCBO4DvqvQBdO1hEY7BvFjeAq3cwrZTn5ozZIPqGU3HnbK5ZtMdbchNZK+LXmSDWhqX2pNg== dist-tags: latest: 1.1.22 published 4 minutes ago ```
The content of `package.json` of the `reaktive` module: ``` { "name": "Reaktive-reaktive", "version": "1.1.22", "main": "Reaktive-reaktive.js", "types": "Reaktive-reaktive.d.ts", "devDependencies": { "dukat": "0.5.8-rc.4" }, "dependencies": { "Reaktive-reaktive": "^1.1.22" }, "peerDependencies": {}, "optionalDependencies": {}, "bundledDependencies": [] } ```

For some reason dependencies are not listed. Also I checked the content of the generated Reaktive-reaktive.js file, looks like it has the utils module bundled.

gciatto commented 3 years ago

Ok these won't work, I guess: they lack a dependency from the kotlin package on NPM.

I forgot to mention that, after compilation and before publishing, it is important to call the jsPublicPackageJson task

arkivanov commented 3 years ago

Alright, I was looking in the ./<module>/build/productionLibrary/ folder. But looks like the correct one is ./build/js/packages/<module>/. This is very confusing, since I was running a module's task and expected the output in the module's build folder. So now after running :reaktive:jsPublicPackageJson task, package.json of the reaktive module contains the following:

{
  "name": "Reaktive-reaktive",
  "version": "1.1.22",
  "main": "kotlin/Reaktive-reaktive.js",
  "devDependencies": {},
  "dependencies": {
    "Reaktive-utils": "1.1.22",
    "Reaktive-reaktive-annotations": "1.1.22",
    "kotlin": "file:/home/aivanov/dev/workspace/Reaktive/build/js/packages_imported/kotlin/1.5.0",
    "kotlin-test-js-runner": "file:/home/aivanov/dev/workspace/Reaktive/build/js/packages_imported/kotlin-test-js-runner/1.5.0",
    "kotlin-test": "file:/home/aivanov/dev/workspace/Reaktive/build/js/packages_imported/kotlin-test/1.5.0"
  },
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": []
}
arkivanov commented 3 years ago

Looks like there is an issue with kotlin dependency. Also not sure why there are test dependencies.

gciatto commented 3 years ago

Test dependencies are for running tests in IntelliJ during development, I believe.

BTW I'm pretty sure they must be removed.

Conversely, the kotlin dependency should be retained, and modified to refer to the official kotlin package on NPM, i.e. https://www.npmjs.com/package/kotlin. So your package.json should only contain the external dependency:

"kotlin": "^KT_VERSION"
arkivanov commented 3 years ago

So is there any way how we could solve the issue?

arkivanov commented 3 years ago

Perhaps better to wait for an official solution.

arkivanov commented 3 years ago

I talked to @SebastianAigner and they suggested to also check the npm-publish plugin. Will check it in a few days.

gciatto commented 3 years ago

Sorry for my late reply @arkivanov.

So is there any way how we could solve the issue?

Technically, the solution is to edit the package json manually. But one can always use Gradle to automate that.

Both my plugin and the npm-publish support doing so programmatically, via a Gradle task. I'd suggest to consider npm-publish too: indeed we are considering to merge our efforts.

gciatto commented 3 years ago

Ehy @arkivanov, any news?

arkivanov commented 3 years ago

@gciatto-unibo we are all on vacation this week, so I will check this next week. 😀

arkivanov commented 3 years ago

@gciatto-unibo So I tried the npm-publish plugin and the results are kinda the same. The kotlin deps are bundled, but it is mentioned in the plugin's readme: ... as they already come with all kotlin dependencies bundled into js output file.

What is more important, the Reaktive's own deps are also bundled, same as before without the npm-publish plugin.

  1. I checked the build/js/packages/Reaktive-reaktive/kotlin/Reaktive-reaktive.js file - it contains the code from the utils module

  2. After publications, the output of npm info @com.badoo/reaktive is:

    
    aivanov@aivanov-XPS-17-9700:~/dev/workspace/nodehw$ npm info @com.badoo/reaktive

@com.badoo/reaktive@1.1.22 | Proprietary | deps: none | versions: 1

dist .tarball: http://127.0.0.1:4873/@com.badoo%2freaktive/-/reaktive-1.1.22.tgz .shasum: eaf0c4a5e8c759dfeda8b9fb40c39ee9733b5c85 .integrity: sha512-59DZWb2CVBLCbBi1HbrhKnsm2XXujwrw9y6m2IHgw+G9F2RrbrR6ft8T29urUBhOD5FVgOJMgcG1DFv590Iarw==

dist-tags: latest: 1.1.22

published 12 minutes ago


So the dependencies are not listed, which is weird.

3. Here is the content of the `build/js/packages/Reaktive-reaktive/package.json` file:

{ "name": "Reaktive-reaktive", "version": "1.1.22", "main": "kotlin/Reaktive-reaktive.js", "devDependencies": { "dukat": "0.5.8-rc.4", "source-map-support": "0.5.19" }, "dependencies": { "Reaktive-utils": "1.1.22", "Reaktive-reaktive-annotations": "1.1.22", "kotlin": "file:/home/aivanov/dev/workspace/Reaktive/build/js/packages_imported/kotlin/1.5.10", "kotlin-test-js-runner": "file:/home/aivanov/dev/workspace/Reaktive/build/js/packages_imported/kotlin-test-js-runner/1.5.10", "kotlin-test": "file:/home/aivanov/dev/workspace/Reaktive/build/js/packages_imported/kotlin-test/1.5.10" }, "peerDependencies": {}, "optionalDependencies": {}, "bundledDependencies": [] }



I think we will need a hand from someone experienced in Kotlin/JS/Node/NPM/etc.
gciatto commented 3 years ago

The build/js/packages/Reaktive-reaktive/package.json you showed in your last message is not adequate for publishing:

Try to manually edit the build/js/packages/Reaktive-reaktive/package.json as follows, before publishing:

 {
  "name": "Reaktive-reaktive",
  "version": "1.1.22",
  "main": "kotlin/Reaktive-reaktive.js",
  "devDependencies": {
    "dukat": "0.5.8-rc.4",
    "source-map-support": "0.5.19",
    "kotlin-test": "1.5.10"
  },
  "dependencies": {
    "Reaktive-utils": "1.1.22",
    "Reaktive-reaktive-annotations": "1.1.22",
    "kotlin": "1.5.10",
  },
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": []
}

and the republish.

If this works, you must find a way to automatically generate a proper package.json before publishing. This can be achieved via gradle, using any plugin among mine and npm-publish... but they must be configured accordingly.

arkivanov commented 3 years ago

@gciatto-unibo Thanks, I will try. What about the statement that Kotlin dependencies are bundled in IR mode?

gciatto commented 3 years ago

@arkivanov, I sincerely do not recall where that statement is from.

What do you exactly mean by "bundled", in the first place? In the following, I'll assume that a "bundled Kotlin dependency" is something related to the Kt Stdlib for JS that may or may not be included in the Reaktive-reaktive JS package.

I find it very unlikely that the Reaktive-reaktive JS package includes a bundled Kotlin dependency. Think about it: it would be a waste of space for NPM packages to include bundled dependencies from other packages which are individually available on NPM.

Luckily for us, I argue there is a simple way to figure this out. There are 2 cases IMHO:

  1. either a kotlin-XXX.js file is included among the JS sources of the Reaktive-reaktive package and referenced somewhere in the kotlin/Reaktive-reaktive.js file (i.e. the entry point of your package)
  2. or the Kt stdlib is included in the kotlin/Reaktive-reaktive.js file itself. A third option (which I believe is the only possible one) is that Kt stdlib is not bundled.

Just to verify:

  1. have a look for .js files in the Reaktive-reaktive root dir
  2. have a look to the kotlin/Reaktive-reaktive.js: if you find a require("kotlin") statement somewhere, then the program is likely attempting to load a dependency which is expected to be declared in a package.json file and/or installed via NPM
arkivanov commented 3 years ago

@gciatto-unibo The "bundled" statement comes from the npm-publish plugin's readme. There is a comment for the bundleKotlinDependencies configuration flag.

I checked the locally published reaktive package on disk, it seems that it contains some code from the utils module, and also from the stdlib. Moreover, it does not contain most of the reaktive module's code, like map, flatMap are missing, etc. Perhaps they should be exported somehow? I have attached the package archive: reaktive.zip.

Also I found the following discussions which actually describe the issues we are having:

So overall there are at least two issues currently:

  1. I can't specify binaries.library() if BOTH mode is enabled - the Gradle configuration phase fails. It only works if the IR mode is used, but I think we need to keep BOTH for now.
  2. Transitive dependencies seems bundled - the stdlib, modules like utils, etc
gciatto commented 3 years ago

@arkivanov can you put your experiments on a branch, so that I can reproduce the publishing process on my machine? Otherwise it is pretty has for me to provide informed suggestions

arkivanov commented 3 years ago

@gciatto-unibo I will push my changes to a branch this Friday (Jul 02). Thanks again!

arkivanov commented 3 years ago

@gciatto-unibo I have pushed the code to the npm-publish branch:

  1. Added the npm-publish plugin: dev.petuska:npm-publish:2.0.3
  2. Configured the npm-publish plugin for the following modules: utils, reaktive-annotations and reaktive
  3. Switched JS compiler mode from both to ir
  4. Added binaries.library() for the js target

Just in case, I used Verdaccio as local NPM registry and the following Gradle task: publishJsNpmPublicationToRepository.

Thanks again!

gciatto commented 3 years ago

OK try with the following build.gradle.kts file for sub-project reaktive: (I had to switch to .kts as I'm not comfortable with Groovy ^^")

plugins {
    id("mpp-configuration")
    id("publish-configuration")
    id("detekt-configuration")
    id("dev.petuska.npm.publish") 
}

configuration {
    enableLinuxArm32Hfp()
}

kotlin {
    targets {
//            fromPreset(presets.jvm, 'jvmCommon')
//            fromPreset(presets.jvm, 'jvmJsCommon')
//            fromPreset(presets.linuxX64, 'jvmNativeCommon')
//            fromPreset(presets.linuxX64, 'nativeCommon')
//            fromPreset(presets.linuxArm32Hfp, 'nativeCommon')
//            fromPreset(presets.linuxX64, 'linuxCommon')

//            fromPreset(presets.iosX64, 'darwinCommon')
    }

    sourceSets {
        commonMain {
            dependencies {
                implementation(project(":utils"))
                implementation(project(":reaktive-annotations"))
            }
        }

        commonTest {
            dependencies {
                implementation(project(":reaktive-testing"))
            }
        }
    }
}

npmPublishing {
    repositories {
        repository("verdaccio") {
            registry = uri("http://localhost:4873")
            authToken = "ayC+KcY0bEgHF/s8YMtlF76FbGgPmKR8AMauiMRoI/M="
        }
    }

    organization = "com.badoo"
    access = PUBLIC

    publications {
        val js by getting {
            packageJson {
                dependencies {
                    "@com.badoo/utils" to version // refers to the current project's version
                    "@com.badoo/reaktive-annotations" to version // refers to the current project's version
                    "kotlin" to "1.5.10" // idk how to refer to the currently used version of kotlin... yet literals should be avoided here
                }
                devDependencies {
                    "dukat" to "0.5.8-rc.4"
                }
            }
        }
    }
}

essentially what I do here is to configure npm-publish to overwrite the dependencies of the generated package.json.

I succeeded in publishing the correct package on Verdaccio in this way.

For a complete example to work, you should perform a similar configuration for sub-projects utils and reaktive-annotations. After that, we must assess if import works... but I had not time to test that today

arkivanov commented 3 years ago

@gciatto-unibo Thanks for the results! I am wondering, what about the issue with the transitive dependencies being bundled into the reaktive module? Should this approach help?

gciatto commented 3 years ago

I checked the generated code. Dependencies are just declared in the package.json file, and they are dynamically loaded in by the Reaktive-reaktive.js script.

This is why I was suggesting to publish utils and reaktive-annotations on NPM as well

arkivanov commented 3 years ago

@gciatto-unibo I will double check with your approach. But when I was trying, I published both child modules first, and then published the reaktive module. Then I checked the js file in the Verdaccio folder, it contained the code from utils. E.g. there were AtomicReference, Clock, etc. And at the same time it did not contain any code from the reaktive module itself. E.g. there were no flatMap, combineLatest operators, etc.

arkivanov commented 3 years ago

@gciatto-unibo I tried the approach suggested by you. The dependency declarations seems fine now. But I believe there is still the issue with the published js files content. Please find the attached archive with the @com.badoo folder from Verdaccio.

How I publish:

  1. Set registry via command npm set registry http://127.0.0.1:4873
  2. Publish first utils and reaktive-annotations modules
  3. Publish reaktive module

Issues:

  1. The Reaktive-utils.js has just 72 lines of code, and does not contain anything useful. There is no AtomicReference, Clock, etc.
  2. The Reaktive-reaktive.js has just 1171 lines of code. It contains the code from the utils module, e.g. there is AtomicReference and Clock. But it does not contain any operators, e.g. there is no flatMap, combineLatest, etc.
  3. Should file names begin with Reaktive- prefix? Or it does not matter?

Thanks again for your help!

@com.badoo.zip

gciatto commented 3 years ago

Hello @arkivanov, apologies for my disappearing: I'm working on my thesis and I'm really close to 0 free time.

So, after conducting some experiments to better understand the IR backend (cf. https://github.com/mpetuska/npm-publish/issues/21) I realised my previous suggestions was partially misleading. Essentially, I was basing my suggestions on the functioning of the legacy backend, while you're using the IR.

The legacy backend used to create an almost 1-to-1 correspondence among the Kt projects and the Node projects. The IR backend apparently performs some bundling by default. To the best of my understading, if you intend yo use the IR backend, you should:

  1. specify binaries.executable() instead of binaries.library()
  2. mark public definitions in your Kotlin codebase with the @JsExport annotation, to prevent those classes from being removed by the backend's dead code elimination feature
  3. recompile

This should make the generated utils project contain useful JS code, which reaktive may reference and use.

Alternatively, you may switch to the legacy backend, where all symbols are exported by default and requires no experimental features.

mpetuska commented 3 years ago

You should use binaries.library() still. Otherwise generated executable will also embed all your npm dependencies as well (as opposed to lifting them out via webpack's externals)

arkivanov commented 3 years ago

@gciatto-unibo @mpetuska Big thanks for your inputs! I will try everything this Friday (30/07). The @JsExport annotation should potentially fix the issue with missing public APIs in the published .js files. However it's not clear how we can prevent things from dependent modules from being embedded into higher level modules? E.g. we have AtomicReference defined in the utils module, the reaktive modules depends on utils, the published .js file for reaktive module contains AtomicReference. Should we prevent it at all?