I'm confused, the result in build/distributions is...
# javascript
j
I'm confused, the result in build/distributions is a somewhat correctly looking webpackd file. However, there is no exports open what so ever and the result from importing it into a javascript project and logging the object is:
Copy code
module {__esModule: true, Symbol(Symbol.toStringTag): "Module"}
The code that is supposted to be exported is from multiplatform common, but I also tried to export directly from the javascript target. What am I missing?
i
Hello, could you please specify, what do you want to import? Webpack is commonly used for browser needs, it bundle all modules in one javascript file, that browser can execute If you want to import your Kotlin/JS module from external JavaScript application, you can configure Webpack to bundle in “library” mode (https://webpack.js.org/configuration/output/#outputlibrary) or you can use “nodejs” target If you want to reuse your Kotlin/JS modules from another Kotlin/JS projects, you can publish Kotlin/JS module to Maven repository for example
j
As far as I gathered there was a lot of things needed to be done in order to make the output from js-dce and the javascript output to become exportable as a library. First and foremost it does not seem to support esModule system yet. So whatever code gets built needs to make sure it adds export default to the top of the file. Something like this:
Copy code
contents = contents.replace("(function (_, Kotlin) {", "export default (function (_, Kotlin) {")
        contents = contents.replace("}(module.exports, require('kotlin')));", "}({}, require('kotlin')));")
and then you need to make sure as you said, that webpack uses the library mode. Which for whatever reason works the best when using commonjs2 as a target
There is also the issue with missing babel dependencies on the produced output, especially if the output file contains data classes, enums and linkage between them, because of
typeof
I created a gradle task which creates this webpack config. It then uses the output from jc-dce and tries to glue this together into an exportable npm package.
i
ESModules are not supported yet, but webpack supports commonjs, amd and umd module sustems as well, as I know You can find pure compiler output in
build/js/packages/<package-name>/kotlin
folder
j
Yeah I tried that, but it has all the same problems as the js-dce does. Oh and also, yes the code/library is supposed to be used in a browser project
And I wanted the library to become as small as possible
i
Why do you want to declare all Kotlin/JS dependencies as entry of webpack? You can easily add configuration to your webpack config via
webpack.config.d
folder in your project root In this folder you can create
js
file with configuration of webpack config object, that you can call with
config
For example
webpack.config.d/additional.js
Copy code
config.output = config.output || {};
config.output.library = 'lib-commin'
config.output.libraryTarget = 'comminjs2'
config.output.libraryExport = 'default'
j
Oh yeah, so along with the custom webpack file, I also create a custom package.json, which has devDependencies needed. The reason is because for whatever reason
"@babel/runtime": "^7.6.0",
Is needed, I'm not sure if this is because of the project using the library or not, but I figure it should be the same
At any case. if i run:
npm ../build/js/packages/<package-name>/
And try to import that, I get issues with babel and
typeof
(My webproject is in another folder in the same root as the multiplatform project)
I'll try to do what you are suggesting, and give back with the specific "log problem"
(I'll also remove the dependency on
kotlinx-serialization-kotlinx-serialization-runtime
, since there is no npm dependency in existance for that right now) In the test of using the above folder as install source
i
Do you declare npm dependencies in
build.gradle
file?
j
No, only the
dependencies { implementation..}
in the javascript target
i
You can do it, it can support to work with npm You can find it in release notes of 1.3.40 (first version with this feature) https://blog.jetbrains.com/kotlin/2019/06/kotlin-1-3-40-released/ Part
Experimental support for NPM and Webpack
j
Yeah but what should I add? There is no public npm package for kotlin-serialization
Afaik
So the error that pops up trying to run
npm ../build/js/packages/<package-name>/
and then later in the webapp code using the exported library (which is transpiled with babel) i run
import * as libObj from 'lib-common';
When trying to print the
libObj
object to console I get
Cannot read property 'MyPackageName' of undefined
Which then points me towards this section:
Copy code
var package$MyPackageName = _.MyPackageName || (_.MyPackageName = {});
  package$MyPackageName.CoreRepository = CoreRepository;
  package$MyPackageName.Device = Device;
  package$MyPackageName.Game = Game;
And that is because
(function (_, Kotlin, $module$kotlinx_coroutines_core) {
never sends in the module.exports
so
_
is in this case undefined
i
Do you use DCE?
If possible, it will be great, if you share your project, it will reveal many of additional questions
j
I have it in the project, but is the output in
/build/js/packages/<package-name>/
not pure?
I can go ahead and publish a trimmed down repo of it all
i
Basically, webpack integrated to work with this folder And in this folder there is pure output of compiler DCE’s output will be in another folder
j
So it should not have affected this specific test
In essence, it feels like the kotlin javascript output format is not behaving well to export a library or a
default
The same result happens no matter what moduleKind i define in:
Copy code
kotlinOptions {
        moduleKind = "commonjs"
        metaInfo = true
        sourceMap = false
        sourceMapEmbedSources = null
        //outputFile = jsOutputFile
    }
@Ilya Goncharov [JB] https://github.com/Syrou/KotlinMultiplatformWithJavascriptNotLibraryFriendly So basicly build the :common module Write
npm install ../build/js/packages/companyxr-common
while inside the
webapp
-folder and then try
npm run start
This will give you an error with @babel and that it needs
runtime
, once you get passed that you will run into the error i posted above
(Given that you uncomment the rows in index.js)
i
Ok, I see problem Now we have no implemented story with JavaScript application, consuming Kotlin/JS module (it is in plan) The problem is how node (and webpack) resolve required modules It tries to find in local
node_modules
, then tries to find in parent’s
node_modules
etc When you run webpack in your
webapp
folder, you have babel installed only in
./webapp
node_modules
, but Kotlin/JS module is parallel hierarchy level in
./build/js
When webpack build bundle, it finds babel’s dependencies for Kotlin/JS module in
build/js/node_modules
instead of
webapp/node_modules
, where babel is installed
j
Yes, that is why i went ahead and created a gradle task as you can see in the build.gradle.kts which creates a custom
package.json
and
webpack.config.js
in order to solve that problem
But it still does not solve the issue where the exported kotlin javascript code does not seem to be mix nicly with how a default
exports default
or module.exports should behave
So that is in planning phase?
i
You have several options: 1. You can define
resolve.modules
for your webpack in
webapp
https://webpack.js.org/configuration/resolve/#resolvemodules You should define it in absolute style to point to node_modules of your webapp or in relative style based on
build/js/packages/<package-name>/kotlin
For example:
Copy code
resolve.modules = ['node_modules', '../../../../../webapp/node_modules]
2. You can change your layout You need to declare your own
package.json
in root of project In this case, npm install modules in root
node_modules
and node should find babel
j
So adding
resolve.modules = ['node_modules', '../../../../../webapp/node_modules]
inside the folder
webpack.config.d
as a new file?
i
No, you should patch your
webpack.config.js
in
webapp
I added to it:
Copy code
resolve: {
    modules: ['node_modules', '../../../../../webapp/node_modules']
}
It heals babel’s error during webpack start
But when I open webpack-dev-server page on the browser, I get error
Uncaught TypeError: Cannot read property 'company' of undefined
Without babel-loader, your sample works well It can be babel-related problem
j
Yeah thats the issue, because module.exports never get bound to the exported kotlin code
Thats why I did
Copy code
contents = contents.replace("(function (_, Kotlin) {", "export default (function (_, Kotlin) {")
        contents = contents.replace("}(module.exports, require('kotlin')));", "}({}, require('kotlin')));")
in the custom task that I created (Which is currently commented out)
Which makes sure the is a
export default
Because the reason we get that error is because
_
is indeed undefined
And that works as well
i
It is a bit strange for me, that it works without babel, and doesn’t works with babel Seems that it doesn’t works properly in this case and loose
module.exports
value
j
So if you add
"@babel/plugin-transform-modules-commonjs": "^7.6.0",
to devDependencies in the webapp
and then add it to the babel plugins in webpack
That solves that issue right?
Copy code
plugins: [
                '@babel/plugin-transform-regenerator',
                '@babel/plugin-transform-runtime',
                '@babel/plugin-syntax-dynamic-import',
                '@babel/plugin-transform-modules-commonjs'
              ],
i
Sorry, unfortunately I don’t know, what babel’s presets can solve this issue
j
Oh it does solve it, just wanted you to verify on your end. But now the issue with kotlin serialization remain. where I can't add it the the common project without the webapp compile getting problems again
since there is no npm repo for it
i
Why can’t you declare it in as usual maven dependency in build.gradle.kts?
j
Because it get exported to
build/js/packages/companyxr-common/package.json
as a dependency that does not exist
Resulting in:
npm ERR! 404 Not Found - GET <https://registry.npmjs.org/kotlinx-serialization-kotlinx-serialization-runtime> - Not found
i
The option is not to declare
companyxr-common
as dependencies in package.json, but as alias for webpack
j
How do you mean?
If I understand you correctly, this is what I tried with the js-dce solution I came up with:
Copy code
entry: {
        "kotlin":"./src/kotlin.js",
        "glootxr-common" :'./src/glootxr-common.js',
        "kotlinx-serialization-kotlinx-serialization-runtime": "./src/kotlinx-serialization-kotlinx-serialization-runtime.js",
        "kotlinx-coroutines-core":"./src/kotlinx-coroutines-core.js"

    },
    resolve: {
        alias: {
            "kotlin": path.resolve(__dirname, './src/kotlin.js'),
            "kotlinx-serialization-kotlinx-serialization-runtime": path.resolve(__dirname, './src/kotlinx-serialization-kotlinx-serialization-runtime.js'),
            "kotlinx-coroutines-core": path.resolve(__dirname, './src/kotlinx-coroutines-core.js')
        },
        extensions: [".js"]
    },
inside of webpack
(I have no clue what I'm doing, but it seems to be doing something)
i
You can add to
resolve
section of your
webpack.config.js
Copy code
alias: {
     "companyxr-common": path.resolve(__dirname, "../build/js/packages/companyxr-common")
}
And not install companyxr-common via npm
j
That is probably the best way to be honest. Question though, How would you do it then if this was all being done through DceJs?
So everything is minified
I know team members on web will be frustrated if i don't present a solution that is a bit slimmer
i
I find that you override DCE task, if js files are appeared in “shared” folder, you can configure alias for webpack on this folder instead of “build/js/...”
j
I'll try that, thanks so much for all your help! 🙂