https://kotlinlang.org logo
#javascript
Title
# javascript
r

Robert Jaros

03/14/2024, 1:27 PM
What's the easiest way to configure Kotlin/JS app to generate two webpack bundles - one, standard for the browser and additional one for Node.js. I can do this by manually modifying js file in
webpack.config.d
so probably I can create a custom gradle task to do the same, but is there any other option?
e

Edoardo Luppi

03/14/2024, 1:50 PM
Maybe using the compilations concept? You can configure multiple compilations for the same source set, although I've never done it.
👍 1
r

Robert Jaros

03/14/2024, 2:33 PM
I don't think it will work. The compilation process is the same for both browser and node. The only difference is during bundling and packaging and the problem is there is only one
webpack.config.d
configuration for webpack.
e

Edoardo Luppi

03/14/2024, 2:37 PM
The
nodejs
configuration does not use Webpack btw. You can target node by having two compilations with
browser
and changing
webpackTask.configFile
depending on which one is running.
Never done it tho. You'll have to try.
r

Robert Jaros

03/14/2024, 2:50 PM
Kotlin gradle plugin doesn't like it.
Copy code
Declaring multiple Kotlin Targets of the same type is not recommended
and will become an error in the upcoming Kotlin releases.
e

Edoardo Luppi

03/14/2024, 2:50 PM
No no. Not targets, but compilations
Have a look at the docs, there should be a chapter on compilations
e

Edoardo Luppi

03/14/2024, 2:53 PM
Yup. The only thing I'm now unsure about is if you can effectively re-use the same source set for an additional compilation.
But what about just passing in a project property and changing behavior based on that? Looks easier.
t

turansky

03/14/2024, 2:55 PM
"One compilatition -> two bundles" works fine for simple cases
In simple case you can configure 2 entries (1 for Node, 1 for Browser)
In specific cases you will need second Webpack task - copy of default with modifications
r

Robert Jaros

03/14/2024, 2:58 PM
Do you know any example projects?
t

turansky

03/14/2024, 3:04 PM
I had examples in
kfc-plugins
😞
Probably more flexible (elegant) variant - separate subprojects for bundling.
Copy code
app\ (klib-only? js-only?)
app-browser\ (bundling-only)
    webpack.config.d\
app-node\ (bundling-only)
    webpack.config.d\
e

Edoardo Luppi

03/14/2024, 3:11 PM
I'd first check if there is an easier way to do it tho. I mean, passing in a project property like
-Ptarget=node/browser
and then having
Copy code
browser {
  webpackTask {
    configFile = if (isBrowserTarget) ... else ...
  }
}
doesn't look wrong. You'll also have to change the distribution output.
r

Robert Jaros

03/14/2024, 3:13 PM
I've already tried this way, but it wont allow me to build both bundles at the same time (I want both of them packaged in the destination jar)
e

Edoardo Luppi

03/14/2024, 3:13 PM
build both bundles at the same time
I don't think there is a way to have them built at the same time (with the same command)
Is that a necessary prerequisite? You could just add a custom task that depends on two other tasks.
👍 1
1
t

turansky

03/14/2024, 3:18 PM
I also expect, that 2 separate Webpack tasks must work fine.
r

Robert Jaros

03/14/2024, 3:43 PM
I can't find how to change directory where resources (e.g.
index.html
) are copied by
productionWebpack
task. I changed the options in
webpackTask {}
block, and js files are put where I want them, but the resources still go to
dist/js/productionExecutable
.
e

Edoardo Luppi

03/14/2024, 4:25 PM
That's something I'd also like to know 😆
r

Robert Jaros

03/14/2024, 4:26 PM
this partialy works:
Copy code
getByName("jsBrowserProductionExecutableDistributeResources", Copy::class).apply {
            destinationDir = file("build/dist/something/productionExecutable")
        }
copies the files to new dir but still leaves empty
js
directory
If anyone is interested, after hours of struggle I've managed to create a fully working custom production webpack task with this code:
Copy code
val jsBrowserProductionExecutableDistributeResources = tasks.getByName("jsBrowserProductionExecutableDistributeResources", Copy::class)
tasks.register("jsBrowserProductionExecutableDistributeResourcesSSR", Copy::class) {
    from(jsBrowserProductionExecutableDistributeResources.source)
    into("build/dist/js.ssr/productionExecutable")
}
val kotlinWebpackJs = tasks.getByName("jsBrowserProductionWebpack", KotlinWebpack::class)
tasks.register("jsBrowserProductionWebpackSSR", KotlinWebpack::class, kotlinWebpackJs.compilation, project.objects)
tasks.getByName("jsBrowserProductionWebpackSSR", KotlinWebpack::class).apply {
    dependsOn("jsBrowserProductionExecutableDistributeResourcesSSR", "jsProductionExecutableCompileSync")
    mode = KotlinWebpackConfig.Mode.PRODUCTION
    inputFilesDirectory.set(kotlinWebpackJs.inputFilesDirectory.get())
    entryModuleName.set(kotlinWebpackJs.entryModuleName.get())
    esModules.set(kotlinWebpackJs.esModules.get())
    outputDirectory.set(file("build/dist/js.ssr/productionExecutable"))
    mainOutputFileName.set("main.bundle.js")
    this.webpackConfigApplier {
        configDirectory = file("webpack.config.ssr.d")
    }
}
❤️ 3
e

Edoardo Luppi

03/15/2024, 10:14 AM
That looks neat. Thank you!