Can I use external libraries which use the ES6 mod...
# javascript
e
Can I use external libraries which use the ES6 module system?
a
If you use ES-modules in your project - yes. To enable it you should call
useEsModules
inside your
js
block inside the
build.gradle
file
In nodejs it's also possible with commonjs
So, if you use NodeJS and commonjs module system - the answer also yes
Or webpack
It also could work with the mixed module systems
e
Thanks! So what I'm doing is: 1. generate a series of JS files (use ES6) 2. copy a dummy
package.json
into the output folder At this point the result package layout is as per screenshot. Each file has a
export default class
3. at this point, how am I supposed to import those classes into my Kotlin module using externals?
And to import that package as a dependency, I'm using
Copy code
jsMain {
  dependencies {
    implementation(npm("antlr4", "4.13.1-patch-1"))

    val pathToLocalNpmModule = rootProject.layout.projectDirectory.dir("generated-packages/${project.name}-js")
    val canonicalPath = pathToLocalNpmModule.asFile.canonicalPath
    implementation(npm("parsers-js", "file:$canonicalPath"))
  }
}
a
Copy code
// file: JsFaultReportLexer.kt
@file:JsModule("your-package/JsFaultReportLexer")

@JsName("default")
external class JsFaultReportLexer
But why don't you want to import them directly without the externals?
e
But why don't you want to import them directly without the externals?
Mmm, what do you mean without externals?
a
You want to import a Kotlin declaration into another Kotlin module right?
Or
JsFaultReportLexer
is generated not from a kotlin source code?
e
Oh no no. The files under
parsers-js
are generated by another tool (ANTLR). And unfortunately those use the ES6 module system, not CommonJS.
a
So yes, in this case, you could use the code I mentioned above.
gratitude thank you 1
e
To have a clearer picture: I'm using ANTLR to write parsers. In a multiplatform context, ANTLR will output Java files for the JVM target, and JS files for the JS target. The JVM target is straightforward, the JS one is not so much. The JS environment where all of this will run is VS Code, which doesn't support yet loading ESM IIRC.
Tried the suggestion, and when running a dummy test case, I get
Copy code
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\edoardo.luppi\...\build\js\node_modules\parsers-js\JsFaultReportLexer.js from C:\Users\edoardo.luppi\...\build\js\packages\parsers-test\kotlin\parsers-test.js not supported.
Instead change the require of JsFaultReportLexer.js in C:\Users\edoardo.luppi\IdeaProjects\...\build\js\packages\parsers-test\kotlin\parsers-test.js to a dynamic import() which is available in all CommonJS modules.
    at C:\Users\edoardo.luppi\...\build\js\packages\parsers-test\kotlin\parsers-test.js:5:29
    at Object.<anonymous> (C:\Users\edoardo.luppi\...\build\js\packages\parsers-test\kotlin\parsers-test.js:18:2)
I might be better off transpiling those files to CommonJS with Webpack
a
Seems like the files use commonjs, instead of ES-modules
At least it uses
require
function inside
e
Yup I can see the K/JS outputted test code uses
require
(I did call
useEsModules
btw)
a
Is it possible that you called something like
js("require(...)")
somewhere?
e
I very doubt so, there is basically no code in
jsMain
or
jsTest
Snippet of the
parsers-test.js
file
Copy code
(function (root, factory) {
  if (typeof define === 'function' && define.amd)
    define(['exports', 'parsers-js/JsFaultReportLexer', './kotlin-kotlin-stdlib.js', './kotlin-kotlin-test-kotlin-test-js-ir.js'], factory);
  else if (typeof exports === 'object')
    factory(module.exports, require('parsers-js/JsFaultReportLexer'),
a
Where did you define
useEsModules
? Because seems like the file generated with UMD module system
All the generated files with ESM contain
.mjs
file extension
e
Snippet of the plugin that does the configuration. See at the bottom
Copy code
project.kmpExtension.js(<http://KotlinJsCompilerType.IR|KotlinJsCompilerType.IR>) {
  moduleName = project.name

  nodejs {
    if (generatePackage) {
      // Generate the distribution packages under "/generated-packages".
      // This allows using the outputted packages as part of a workspace more easily
      distribution {
        val rootDir = project.rootProject.layout.projectDirectory
        val generatedPackagesDir = rootDir.dir("generated-packages/${project.name}")
        outputDirectory.set(generatedPackagesDir)
      }
    }

    testTask {
      useMocha {
        timeout = "0" // Override default 2s timeout
      }

      filter.isFailOnNoMatchingTests = true
    }
  }

  binaries.library()

  // Electron doesn't support ES modules yet. Switch to useEsModules() once it does.
  // See <https://github.com/electron/electron/pull/37535>
  if (jsNodeConfig.useEsModules.getOrElse(false)) {
    useEsModules()
  } else {
    useCommonJs()
  }

  ...
a
Could you try to add
useEsModules
inside the testTask, just to check if it works
e
Sure
No difference + it messes up the source sets for some reason
Btw the prod compilation does indeed create a .mjs file. Seems like the issue is only for tests
a
Could you please create a ticket?
e
Will do! Need to try to transpile those js files to CJS with Babel first
🙏 1
Thanks btw
Commented on https://youtrack.jetbrains.com/issue/KT-56818, which is similar. Let me know if I need a new issue tho.