Another noob question: I'm trying to use JSDOM and...
# javascript
c
Another noob question: I'm trying to use JSDOM and the js import is:
const jsdom = require("jsdom"); const { JSDOM } = jsdom;
. For what I've understood, this is equivalent to
const JSDOM = require("jsdom").JSDOM
. Anyway when trying to use it with kotlin I'm having some issue since
JSDOM
is a constructor, but in kotlin is called as a function (and thus it fails with
Class constructor JSDOM cannot be invoked without 'new'
. Is it possible to call JSDOM as a constructor in any way? I've tried so many stuff, even using
js(require(jsdom).JSDOM).window as Window
but it fails with
ReferenceError: Window is not defined
s
You can do
val dom = js("new JSDOM(html)")
g
Are you using the external modifier like what is described here? https://kotlinlang.org/docs/reference/js-interop.html
c
js("new JSDOM(..)")
leads to
JSDOM is not defined
@gbaldeck I tried to define external classes, but can't actually define them the correct way.
Basically on js you can assign a constructor to a variable, while that's not possible in kotlin, so I think that's the problem
s
g
@coletz you can assign a constructor to a variable in kotlin, I've done it a lot. It would be a good idea to read up more on how to properly interop with javascript, that link i posted is a good starting point
Also if you check my github I have tons of examples in my sample projects, https://github.com/gbaldeck?tab=repositories
any one of my projects that have kt or kotlin in the name will be using kotlin/js interop with external libraries like what you are setting up
c
That JsModule should be in the js-interop page IMHO, thanks :)
@gbaldeck I've already used interop with js to import other node modules, but I'm not figuring out how to use it with jsdom. What I would do is the following:
Copy code
external fun require(module: String): dynamic
// with js one does: const jsdom = require('jsdom');
val jsdom = require("jsdom");
// with js one does: const { JSDOM } = jsdom
val JSDOM = jsdom.JSDOM // totally not sure about that

// then for calling with js: const dom = new JSDOM(html)
val dom = JSDOM(html) // not working
Sorry if I'm not understanding correctly :/
g
ah I see, it looks like you're doing it correctly, but JS imports are weird sometimes. In your main function do a
console.log("jsdom: ", jsdom)
in order to see what the object contains. It probably contains a
default
property or some other property that actually contains the full module. Then you can reference that by doing
val jsdom = require("jsdom").default
and your above code should work
as long as you use
@JsModule
as well
. Actually, if you are using webpack then your
require
statements hould be fine and you do not need
@JsModule
g
@JsModule
looks more idiomatic for me than
require
c
Totally agree
Dunno why slack wasn't loading some messages, btw jsdom contains JSDOM property, and in fact I'm accessing it but I still can't get it working. The JSDOM property is a constructor, in fact it's called with "new JSDOM()" . But if I try to use it, kotlin compiler generates a function and not a constructor, so it throws an exception (class constructor JSDOM cannot be invoked without 'new')
g
Yeah, I got it. Usage of Js* annotation sometimes tricky because libraries have different way to instantiate required stuff
g
Now that I'm looking through my old projects i think you're right @coletz, I never did instantiate an external constructor that i stored in a kotlin variable, i always did
js("new ImportedConstructor")
, and I honestly can't think of a way to do it besides something like this
fun JSDOM(html: dynamic): dynamic = js("new jsdom.JSDOM(html)")
c
seems like it's working with JsModule:
Copy code
@JsModule("jsdom")
abstract external class JsDom {
    class JSDOM(url: String){
        val window: Window
    }
}
thanks everyone guys!
g
@coletz so how do you end up instantiating that?
JsDom.JSDOM()
?
c
yes (with the argument)
g
@coletz I remembered that you can use
JsModule
at the file level as well, which would allow you you get rid of the
abstract external class JsDom
and just use
external class JSDOM
https://kotlinlang.org/docs/reference/js-modules.html#applying-jsmodule-to-packages
☝️ 2
c
yep, it's working!
Copy code
@file:JsModule("jsdom")
package mozilla

import org.w3c.dom.Window

external class JSDOM(html: String){
    val window: Window
}
now it's instantiated simply with
JSDOM(html)
, without jsdom. prefix
👍 2
g
Nice! So much better than
require
105 Views