Hello! :wave::skin-tone-2: Let say I have a Kotli...
# javascript
s
Hello! 👋🏻 Let say I have a KotlinJS module in my project, named
moduleA
. I want to have another module that would be able to showcase how to use that
moduleA
. I have this right now:
Copy code
plugins {
    kotlin("multiplatform")
}

kotlin {
  js {
    browser()
  }

  sourceSets.jsMain.dependencies {
    implementation(project(":moduleA"))
  }
}
Inside my sample app, I have that
index.html
where it auto import
<script type="application/javascript" src="sampleApp.js"></script>
that is server by webpack. How can I access that
moduleA
from a
<script>
tag inside the index.html ? Thanks!
a
By default, the webpack merge (bundle) both your project and
moduleA
into the
sampleApp
so to make the app works you don't need to add the
script
tag for each of your dependencies.
s
Alright, so the
implementation
is fine to have that merged? And to access classes that are inside
moduleA
, is there some namespacing of some sort or they should be "at the root"? Currently, I have that index.html for the module, so in the javascript tag, I use
const some = new ModuleA.MyClass();
and if I try using
const some = new sampleApp.MyClass()
, I get an error
undefined is not a constructor
I did try to see what is part of
sampleApp
using
console.log(Object.getOwnPropertyNames(sampleApp));
and it show only test functions that are defined in the
sampleApp
module.
Inspecting the generated
sampleApp.js
file is quite challenging as it's a huge minified file
a
Ohh, I see. So your project is supposed to be a library to be consumed from JavaScript code, right?
s
That's right yes! I want to test that library in a "real case scenario" before shipping it
So is what you told me should be working? If not, how could I do that? Thanks
e
> How can I access that
moduleA
from a
<script>
tag inside the index.html My question is, why would you want to do that? To clarify, when you build
app
, which uses
moduleA
, you're effectively passing by Webpack and bundling every Gradle-defined dependency into one single file, as Artem mentioned. If you're planning on consuming
moduleA
as a standalone browser library, you're better off experimenting outside of Kotlin's realm, e.g. from an Angular or React app. That will make the behavior more obvious. Use
Copy code
js {
  browser()
  generateTypeScriptDefinitions()
}
to generate a consumable
d.ts
file from your
app
project. The outputted distribution can then be installed or linked through npm.
s
Because I want to keep this setup as simple as possible (ie: a gradle module with a single HTML file). I don't want to bother with another setup. It is pretty strange, I do see the
eval()
statement with all javascript inside it with my class but trying to create a new instance of it fail with
undefined is not a constructor
. So it's as if the eval didn't worked 🤔
a
@Sebastien Leclerc Lavallee this is what webpack generates for you. If you want to to have a library and not the app, you can specify:
Copy code
js {
  browser()
  binaries.library()
  generateTypeScriptDefinitions()
}
It will exclude the webpack bundling part, so you can access all the modules as is with the
script
tag
s
Thanks for the informations! I'll check this out
Ok so after a few tests and lot of head scratching... I think something is wrong. So I have
moduleA
and
app
. Treat both as libraries. Both are configured exactly the same with shared build.gradle.
Copy code
js {
        useEsModules()
        browser {
            webpackTask {
                output.library = "@some/$projectName"
                output.libraryTarget = "umd"
                compilations["main"].packageJson {
                    customField("name", "@some/$projectName")
                    customeField("types", "kotlin/${rootProject.name}-${project.name}.d.ts")
                }
            }
        }
        nodejs()
        binaries.library()
        binaries.executable()

        generateTypeScriptDefinitions()
        compilations.all {
            kotlinOptions {
                freeCompilerArgs += "-Xexpect-actual-classes"
            }
        }
    }
Module A is imported into app using
implementation(project(":moduleA"))
I have an index.html that have that script tag to import
app.js
Then I run
Copy code
./gradlew app:jsBrowserDevelopmentRun
When I execute that from index.html's Javascript:
Copy code
console.log(Object.getOwnPropertyNames(app));

// output:
(4) ['__esModule', 'SampleDemoClass', 'Some', 'makeCmp']
Other than
esModule
. all other 3 elements are stuff that are defined under app module only. Which mean that the only thing that is seen from the bundled .js file is stuff from
app
module. There are a few classes that have
@JsExport
If I do the same under
moduleA
and logging
getOwnPropertyNames
I see the whole list of classes there. So they are not bundled or shown from
app
module My understanding is that I should see all classes when running in
app
module