2

I would like to create a js library with Kotlin Multiplatform (an example of which is this project, where we have a webscocket server and a js client) which I will then build as a npm package and import in my Vue project (could be any other framework).

what I managed to do with chat project is:

  • build js sources with ./gradlew build
  • publish that via yarn publish (setting up remote registry url ofc)
  • add published package to package.json with (needed to update project name to @chat/client by hand in the generated package.json):
{
  "name": "@chat/client",
  "version": "0.0.1",
  "private": false,
  "workspaces": [
    "packages/chat-frontend",
    "packages/chat-frontend-test",
    "packages_imported/kotlin/1.6.21",
    "packages_imported/ktor-ktor-client-core-js-ir/2.0.0",
    "packages_imported/kotlin-test-js-runner/1.6.21"
  ],
  "resolutions": {},
  "devDependencies": {},
  "dependencies": {},
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": []
}
  • added @JsExport annotation on writeMessage in src/frontendMain/kotlin/main.kt

what I didn't manage is (in my Vue project):

  • import writeMessage, I exported in .kt file (it's visible in source, not exported though)
  • import anything via import * from '@chat/client'
  • or any other folder along '@chat/client/*'
  • use the generated files in any other way

The generated package structure is very odd:

~ ls build/js/*

build/js/package.json  build/js/yarn.lock

build/js/node_modules:
... (npm dependencies from Kotlin/JS module)

build/js/packages:
chat-frontend  chat-frontend-test

build/js/packages_imported:
... (Kotlin/JS dependencies)

~ ls build/js/packages/chat-frontend/*

build/js/packages/chat-frontend/package.json  build/js/packages/chat-frontend/webpack.config.js

build/js/packages/chat-frontend/kotlin:
chat-frontend  chat-frontend.js  chat-frontend.js.map  chat-frontend.meta.js
(chat-frontend contains package dir tree and a file frontend.kjsm)

build/js/packages/chat-frontend/kotlin-dce:
chat-frontend.js
ktor-*.js
kotlinx-*.js
... (compiler output ???)

build/js/packages/chat-frontend/node_modules:
... (webpack cli and dev-server files)

Do you have any clues, tips or an example project which does that? I've processed whole section of Kotlin/JS docs but there is no information on how to import Kotlin generated .js files in a js/ts project.

EDIT:

I've updated my fork of ktor-samples with Kotlin/JS build files: build-js folder and src/backendMain/resources/chat.js. Here's the link to chat folder of the fork project

Jakub Licznerski
  • 1,008
  • 1
  • 17
  • 33
  • you can do `npm install ` where PATH is the generated JS files from your kotlin project. It would be the PATH to build folder where `js` and `map` file resides. In your case above, it would be PATH to that `build/js/packages/chat-frontend/kotlin` – shaktiman_droid May 11 '22 at 20:59
  • isn't it the same as installing from a remote registry? I'll update the post with more info, I missed that part – Jakub Licznerski May 11 '22 at 21:01
  • yeah if you already have a remote npm module then yes, you can import that directly. – shaktiman_droid May 11 '22 at 21:02
  • yep, and that is exactly what I'm doing, I've updated the post maybe my problem is better understandable now – Jakub Licznerski May 11 '22 at 21:27
  • can you somehow share your generated `.js` file? Want to see how the export name looks like. You would need to import the exported name like `import chatlib from chat/client`. then try `console.log(chatlib)` and see if you see the reference. here `chatlib` or whatever the exported name is something you would find in your generated `js` file. – shaktiman_droid May 12 '22 at 18:18
  • yes, sure! I've updated the post with link to my fork, where I've just put the js build output. There are a few files that correspond to the said `chat.js` file, but the main output I guess is copied to `backendMain/resources/chat.js`. This file however seems to be minified. Thanks for helping me make sth out of this mess ;)! – Jakub Licznerski May 13 '22 at 12:09
  • what happens when you do `import chatlib from '@chat/client'` or `import * as chatlib from '@chat/client'';` and then do `console.log(chatlib)` – shaktiman_droid May 13 '22 at 14:08
  • @Jigar sorry for the delay, didn't notice your answer. So first of all there is a TS error: 'TS2307: Cannot find module '@chat/client' or its corresponding type declarations.'. When I Ctrl+Left click on it in Webstorm however, it takes me to the root of the dependency, where I have 'packages', 'packages_imported' and a 'package.json' as described in the post. – Jakub Licznerski May 22 '22 at 21:05
  • also I tried enforcing LEGACY compiler (instead of IR) and now I have several errors: ' Can't resolve imported dependency "kotlin"' and kotlin and ktor libraries. Plus 'Could not find a declaration file for module '@chat/client'. .../node_modules/@chat/client/kotlin/chat-frontend.js' implicitly has an 'any' type. Try `npm i --save-dev @types/chat__client` if it exists or add a new declaration (.d.ts) file containing `declare module '@chat/client';`' – Jakub Licznerski May 22 '22 at 21:14

2 Answers2

1

I will try to help

  1. Kotlin/JS has 2 kinds of compiler: legacy and IR. @JsExport affects only IR compiler. But from kotlin-dce folder, you use legacy compiler backend. In IR compiler, DCE (dead code elimination) is included into compiler and there is no folder kotlin-dce. You can change compiler kind in gradle.properties with kotlin.js.compiler=ir|legacy.
  2. When you build project with IR, packages/*/kotlin will fully contain your library (similar with legacy's kotlin-dce)
  3. Then you need to prepare appropriate package.json file with name and main fields (task :publicPackageJson could help with that, but check, if it is ok for your case)
  4. Now in Kotlin/JS export works with packages. It means, that if you export io.ktor.samples.chat.frontend.writeMessage, it will be exported as io.ktor.samples.chat.frontend.writeMessage in js. So to import it, you need import io and then find necessary declarations.
import { io } from '@chat/client`

io.ktor.samples.chat.frontend.writeMessage("hello")
  • I tried just copying packages and packages_imported and a generated package.json (changed name and private: false) and publishing it, but "warning Workspaces can only be enabled in private projects." plus "TS2307: Cannot find module '@signalling/client' or its corresponding type declarations.". Adding updateted package.json used for publishing. – Jakub Licznerski May 25 '22 at 13:49
0

In the case of classical (non-IR) js backend usage and you use only non-private NPM dependencies then the only thing that you need is to compile your Kotlin/js library (via :compileKotlinJs task), generate package.json for your library (via :publicPackageJson) and your package could be published to NPM or another private repository (by yarn publish).

After publication, you will have the ability to set your library as a dependency in any js project. (Note that the name and version of your library will be placed inside package.json (generated by :publicPackageJson task)).

Also, you can check this discussion. Hope it will help you.

  • hey Artem, thanks for the reply. I was able to publish the package, but cannot import the contents of it in another NPM-based project (please see comments under the post). – Jakub Licznerski May 22 '22 at 21:16