:wave: Hey everyone! I have a multi-module Kotlin...
# javascript
g
👋 Hey everyone! I have a multi-module KotlinJS setup and I've noticed that my root
package.json
file does not have a
main
entry point, while all my module `package.json`s do have corresponding entries for the main
.js
file. I'm aware we can customise these by doing something like the below, but that only changes the relevant module's
package.json
.
Copy code
js(IR) {
    compilations["main"].packageJson {
        customField(
            "dependencies", mapOf(
                "a" to "b"
            )
        )
    }
}
Is there a way to modify the root
package.json
, i.e. the one that lives in
build/js/package.json
? I basically want to add a
main
property pointing to my module entry point.
1
My root
package.json
looks like this
Copy code
{
  "name": "thecodinglove-kmp",
  "version": "unspecified",
  "private": true,
  "workspaces": [
    "packages/thecodinglove-kmp-appJs",
    "packages/thecodinglove-kmp-appJs-test",
    "packages/thecodinglove-kmp-kmp-module-b",
    "packages/thecodinglove-kmp-kmp-module-b-test",
    "packages/thecodinglove-kmp-module-a",
    "packages/thecodinglove-kmp-module-a-test",
    "packages_imported/kotlin/1.7.20-RC",
    "packages_imported/kotlin-test-js-runner/1.7.20-RC",
    "packages_imported/kotlin-test/1.7.20-RC"
  ],
  "resolutions": {},
  "devDependencies": {},
  "dependencies": {},
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": []
}
which seems okay but there's no
main
entry 🤔
b
Just add binaries.executable to relevant targets if you want a main.
My bad, I meant binaries.library()
Then after build your packaged distribution will be in build/productionLibrary along with proper package.json
👍 1
Finally build/js is an intermediate output and should never be directly relied upon
g
Thanks! I already have binaries.executable() in one of my modules which is the entry point of the app. Its package.json reflects this correctly. However the rootPackageJson gradle task builds a package.json that contains all my subprojects as workspaces but without a main entry point, so i was hoping for a way to set that somehow. I’ve tried modifying the root projects build.gradle file but that just generates another workspace for it and doesn’t seem to affect the root level package.json.
Finally build/js is an intermediate output and should never be directly relied upon
Im using a nodejs target so I don’t have webpack or the ability to set an output directory. What would be a reliable output folder for nodejs?
b
Why do you need an entrypoint for a workspace?
g
I’m integrating with Firebase Cloud Functions which seems to require the package.json to have a “main” entry that points to the entry point js file
Here’s the project in question https://github.com/gchristov/thecodinglove-kmp
b
Then you don't need a workspace package.json, do you?
Just use binaries config and proper distribution output (i.e. not build/js as I've mentioned before)
👍 1
g
I’m pretty new to the js world but as far as I understand based on the docs npm workspaces are used to help manage multi package builds and their npm dependencies, which is what I have - a multi module kotlinjs node setup where each module is effectively linked as a workspace in package.json. So when npm instals dependencies theyll get properly symlinked in node_modules This all seems okay so far but I’ll investigate having a proper distribution folder as you say 👍
b
In kotlin js world gradle does that. Npm is just an implementation details
g
I see. Thanks for the info and feedback! 🙇 As far as I understand there’s still no way to specify distribution output for nodejs targets, right? Looks like browser targets support it through webpack. If this is the case, what would you recommend as a way to specify an output directory for the executable files for node?
b
There should be. Just specify binaries.library (or binary) and look through your build/ folder
Or are you saying that nodejs does not have binaries dsl in gradle?
Here's an outdated sample of mine for azure functions, might give you some ideas https://github.com/mpetuska/template-azure-functions-kotlin-js
👀 1
g
There should be. Just specify binaries.library (or binary) and look through your build/ folder
Yep, I'm already specifying
binaries.executable()
for
nodejs
, similarly to what the IntelliJ template/online sample do, and all I get is
build/js
which contains the resulting binaries.
Copy code
js(IR) {
  binaries.executable()
  nodejs()
}
I also don't think
KotlinJsBinaryContainer
for
nodejs
supports further customisation, based on the dsl reference here (and what I tried with the latest version). However,
browserjs
does support
webpack
and
distribution
config blocks which allow us to set output destination. Thanks for the sample btw, some great stuff over there!
b
What gradle command do you run?
If you must customise package.json, you could try my #npm-publish plugin
👀 1
g
What gradle command do you run?
./gradlew assemble
. I essentially would like to run this as part of a CI job which would generate the binaries to be exported over to Firebase Cloud Functions
(it actually already does that but I'd like to do it in a multiplatform idiomatic way if possible)
b
Assemble should work, but can you run "gradle clean build" command and let me know what directories are created in your build folder?
👍 1
Can't remember which one you need to look for and don't have a pc nearby to check
g
Here's a screenshot of the result. I have 3 modules and I'm showing the
build
folders of all of them. Based on this the root project's
build
contains only a
js
folder with the binaries
Expanding that root
build/js
further, it contains the
.js
files with all the individual submodules which all seems correct to me, unless I'm missing something 🙂
Also, the output is the same when I create a vanilla project with the
NodeJS
IntelliJ template, which I suspect is what Gradle uses when I run
./gradlew run
(which executes the NodeJs project)
b
Which module has binaries configured? Does root module have any source files?
Also, again, build/js dir should be ignored, it's not meant for human-use
👍 1
It's the same as gradle/maven cache :)
Ah, I remember now. The js outputs you need are in compileSync folder(s)!
g
Which module has binaries configured? Does root module have any source files?
The
appJs
module has a binary configured. The root project doesn't have any KotinJS config, only this:
Copy code
allprojects {
    repositories {
        mavenCentral()
    }
}
b
Nodejs might not have dustribution assembly implemented yet though, but npm-publish plugin can handle that for you if you don't mind adding an extra plugin
Ok, so since root project has no sources then you should just ignore it's build dir
g
Ah when expanding
compileSync
I'm finding this! Quite interesting 😅
b
Yep, sadly no out of the box package.json - thus the need for an extra plugin
Or you could hack something with a custom task
g
Ahh I see, is this what
npm-publish
could help with?
b
Absolutely (the sample I've linked uses it)
Just apply the plugin and run assemble task. Then look for output in build/npm
Or is it build/packages, can't recall 😀
g
Awesome, will have a look! Thanks again for taking the time to investigate this - has been a learning experience 🙇
b
Hah, that's how I've learned myself. The community here is awesome!
🙌 1
💯 1
g
Last question (for the moment haha). These executables will require their npm dependencies, eg firebase-functions. I know we can specify them as implementation(npm(..)) but how would that be resolved when the code from compileSync is deployed? I guess the dependency should be listed in package.json so that npm can fetch it and install under node_modules? Unless there is some gradle magic im missing 🤔
b
npm-publish will sort out your package.jsom with proper dependencies. Just be sure to use binaries.library (not executable)
In short, firebase will install all your dependencies from package.json. IF you use binaries.executable, all dependencies are bundled inside js output (thus no package.json)
g
Brilliant, thanks again! 🙏
Thanks for all suggestions here @Big Chungus 🙇 I can confirm that the
npm-publish
plugin simplifies all this and I end up with a correct
package.json
when using
implementation(npm(..))
+
binaries.library
configuration.
🎉 3
b
Splendid. Glad to hear you got it sorted.
g
@Big Chungus Sorry for re-ping but I have a somewhat related question 😅 How does the
npm-publish
plugin handle
npm()
dependencies of submodules? My main app module is set as
binaries.library()
and I'm applying the
dev.petuska.npm.publish
plugin which gives me a correct package.json containing any
npm
dependencies I've added to that module. However, if I try to move the same
npm
dependency to a sub-module I get
Error: Cannot find module
errors, which makes me think that the submodule's
npm
dependencies aren't included or I'm missing some config. The submodule itself is marked as
js(IR) { nodejs() }
b
No, not at the moment, however this is certainly a nice feature to have. Can you raise an issue on the repo for this please?
I'm surprised it took this long for someone to bump into this limitation to be honest 😀
g
Yep will raise an issue 👍 Interesting that it doesn’t work out of the box with KotlinJs. With gradles multi module support I would have thought it would be a much more common thing to do. Non npm deps work as expected 🤷 As a workaround I’ll list all npm deps in the main app module for now, which will make them available anywhere.
👍 1
Opened an issue. Feel free to edit if something's not clear 👍
155 Views