kotlin-frontend-plugin
kotlin-frontend-plugin copied to clipboard
HMR stops working when using Gradle continuous build
Having following css webpack config:
config.module.rules.push(
{
test: /\.scss$/,
use: [
'style-loader', // creates style nodes from JS strings
'css-loader', // translates CSS into CommonJS
'sass-loader' // compiles Sass to CSS, using Node Sass by default
]
}
);
When I start my project with gradle run
, I can navigate to build/js/resources/css
, edit an SCSS file and HMR will reload the css properly:
[WDS] App updated. Recompiling...
client?245c:88 [WDS] App updated. Recompiling...
client?f152:88 [WDS] App updated. Recompiling...
client?245c:88 [WDS] App updated. Recompiling...
client?f152:271 [WDS] App hot update...
log.js?d5dc:24 [HMR] Checking for updates on the server...
client?245c:271 [WDS] App hot update...
log.js?d5dc:24 [HMR] Updated modules:
log.js?d5dc:16 [HMR] - ../../js/resources/css/banner.scss
log.js?d5dc:24 [HMR] App is up to date.
The downside is that I would like to change the actual SCSS file in src/main/resources
. This should work when using gradle -t run
. Changing the SCSS file in this mode, also updates the file in build/js/resources/css
and HMR applies the change as expected:
However, this only works twice. Starting from the 3rd change, no SCSS changes get applied anymore, no matter which SCSS file. HMR does not trigger in the browser, although the files in build/js/resources/css
are updated.
Browser log
[WDS] App updated. Recompiling...
client?245c:88 [WDS] App updated. Recompiling...
client?f152:88 [WDS] App updated. Recompiling...
client?245c:88 [WDS] App updated. Recompiling...
client?f152:271 [WDS] App hot update...
log.js?d5dc:24 [HMR] Checking for updates on the server...
client?245c:271 [WDS] App hot update...
log.js?d5dc:24 [HMR] Updated modules:
log.js?d5dc:16 [HMR] - ../../js/resources/css/banner.scss
log.js?d5dc:24 [HMR] App is up to date.
client?f152:88 [WDS] App updated. Recompiling...
client?245c:88 [WDS] App updated. Recompiling...
client?f152:271 [WDS] App hot update...
log.js?d5dc:24 [HMR] Checking for updates on the server...
client?245c:271 [WDS] App hot update...
log.js?d5dc:24 [HMR] Updated modules:
log.js?d5dc:16 [HMR] - ../../js/resources/css/banner.scss
log.js?d5dc:24 [HMR] App is up to date.
Webpack log
[34mℹ[39m [90m「wdm」[39m:
[34mℹ[39m [90m「wdm」[39m: Compiled successfully.
[34mℹ[39m [90m「wdm」[39m: Compiling...
[34mℹ[39m [90m「wdm」[39m:
[34mℹ[39m [90m「wdm」[39m: Compiled successfully.
[34mℹ[39m [90m「wdm」[39m: Compiling...
[34mℹ[39m [90m「wdm」[39m:
[34mℹ[39m [90m「wdm」[39m: Compiled successfully.
[34mℹ[39m [90m「wdm」[39m: Compiling...
[34mℹ[39m [90m「wdm」[39m:
[34mℹ[39m [90m「wdm」[39m: Compiled successfully.
Gradle log
Waiting for changes to input files of tasks...
deleted: /home/user/myproject/frontend/src/main/resources/css/banner.scss___jb_tmp___
new file: /home/user/myproject/frontend/src/main/resources/css/banner.scss
deleted: /home/user/myproject/frontend/src/main/resources/css/banner.scss___jb_old___
Change detected, executing build...
> Configure project :common
Kotlin Multiplatform Projects are an experimental feature.
> Configure project :frontend
Dev Mode: true
Source map generation is not enabled for kotlin task compileTestKotlin2Js
> Task :common:compileKotlinJs UP-TO-DATE
> Task :common:jsProcessResources NO-SOURCE
> Task :common:jsMainClasses UP-TO-DATE
> Task :common:jsJar UP-TO-DATE
> Task :frontend:npm-preunpack UP-TO-DATE
> Task :frontend:npm-configure UP-TO-DATE
> Task :frontend:npm-install UP-TO-DATE
> Task :frontend:npm-index UP-TO-DATE
> Task :frontend:npm-deps
> Task :frontend:npm
> Task :frontend:packages
> Task :frontend:compileKotlin2Js UP-TO-DATE
> Task :frontend:compileJava NO-SOURCE
> Task :frontend:processResources
> Task :frontend:classes
> Task :frontend:compileTestKotlin2Js NO-SOURCE
> Task :frontend:webpack-config UP-TO-DATE
> Task :frontend:karma-config SKIPPED
> Task :frontend:karma-start SKIPPED
> Task :frontend:processTestResources NO-SOURCE
> Task :frontend:runDceKotlinJs UP-TO-DATE
> Task :frontend:runDceTestKotlinJs NO-SOURCE
> Task :frontend:webpack-run
webpack is already running at http://localhost:8080/
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-coroutines-core.js as it exceeds the max of 500KB.
ℹ 「wdm」: wait until bundle finished: /frontend/frontend.bundle.js
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-html-js.js as it exceeds the max of 500KB.
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlin.js as it exceeds the max of 500KB.
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-coroutines-core.js as it exceeds the max of 500KB.
ℹ 「wdm」: wait until bundle finished: /frontend/frontend.bundle.js
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-html-js.js as it exceeds the max of 500KB.
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlin.js as it exceeds the max of 500KB.
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
> Task :frontend:run
BUILD SUCCESSFUL in 1s
12 actionable tasks: 3 executed, 9 up-to-date
Waiting for changes to input files of tasks...
deleted: /home/user/myproject/frontend/src/main/resources/css/banner.scss___jb_tmp___
new file: /home/user/myproject/frontend/src/main/resources/css/banner.scss
deleted: /home/user/myproject/frontend/src/main/resources/css/banner.scss___jb_old___
Change detected, executing build...
> Configure project :common
Kotlin Multiplatform Projects are an experimental feature.
> Configure project :frontend
Dev Mode: true
Source map generation is not enabled for kotlin task compileTestKotlin2Js
> Task :common:compileKotlinJs UP-TO-DATE
> Task :common:jsProcessResources NO-SOURCE
> Task :common:jsMainClasses UP-TO-DATE
> Task :common:jsJar UP-TO-DATE
> Task :frontend:npm-preunpack UP-TO-DATE
> Task :frontend:npm-configure UP-TO-DATE
> Task :frontend:npm-install UP-TO-DATE
> Task :frontend:npm-index UP-TO-DATE
> Task :frontend:npm-deps
> Task :frontend:npm
> Task :frontend:packages
> Task :frontend:compileKotlin2Js UP-TO-DATE
> Task :frontend:compileJava NO-SOURCE
> Task :frontend:processResources
> Task :frontend:classes
> Task :frontend:compileTestKotlin2Js NO-SOURCE
> Task :frontend:webpack-config UP-TO-DATE
> Task :frontend:karma-config SKIPPED
> Task :frontend:karma-start SKIPPED
> Task :frontend:processTestResources NO-SOURCE
> Task :frontend:runDceKotlinJs UP-TO-DATE
> Task :frontend:runDceTestKotlinJs NO-SOURCE
> Task :frontend:webpack-run
webpack is already running at http://localhost:8080/
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-coroutines-core.js as it exceeds the max of 500KB.
ℹ 「wdm」: wait until bundle finished: /frontend/frontend.bundle.js
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-html-js.js as it exceeds the max of 500KB.
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlin.js as it exceeds the max of 500KB.
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-coroutines-core.js as it exceeds the max of 500KB.
ℹ 「wdm」: wait until bundle finished: /frontend/frontend.bundle.js
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlinx-html-js.js as it exceeds the max of 500KB.
[BABEL] Note: The code generator has deoptimised the styling of /home/user/myproject/frontend/build/kotlin-js-min/main/kotlin.js as it exceeds the max of 500KB.
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
ℹ 「wdm」: Compiling...
ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
> Task :frontend:run
BUILD SUCCESSFUL in 1s
12 actionable tasks: 3 executed, 9 up-to-date
Waiting for changes to input files of tasks...
deleted: /home/user/myproject/frontend/src/main/resources/css/banner.scss___jb_tmp___
new file: /home/user/myproject/frontend/src/main/resources/css/banner.scss
deleted: /home/user/myproject/frontend/src/main/resources/css/banner.scss___jb_old___
Change detected, executing build...
> Configure project :common
Kotlin Multiplatform Projects are an experimental feature.
> Configure project :frontend
Dev Mode: true
Source map generation is not enabled for kotlin task compileTestKotlin2Js
> Task :common:compileKotlinJs UP-TO-DATE
> Task :common:jsProcessResources NO-SOURCE
> Task :common:jsMainClasses UP-TO-DATE
> Task :common:jsJar UP-TO-DATE
> Task :frontend:npm-preunpack UP-TO-DATE
> Task :frontend:npm-configure UP-TO-DATE
> Task :frontend:npm-install UP-TO-DATE
> Task :frontend:npm-index UP-TO-DATE
> Task :frontend:npm-deps
> Task :frontend:npm
> Task :frontend:packages
> Task :frontend:compileKotlin2Js UP-TO-DATE
> Task :frontend:compileJava NO-SOURCE
> Task :frontend:processResources
> Task :frontend:classes
> Task :frontend:compileTestKotlin2Js NO-SOURCE
> Task :frontend:webpack-config UP-TO-DATE
> Task :frontend:karma-config SKIPPED
> Task :frontend:karma-start SKIPPED
> Task :frontend:processTestResources NO-SOURCE
> Task :frontend:runDceKotlinJs UP-TO-DATE
> Task :frontend:runDceTestKotlinJs NO-SOURCE
> Task :frontend:webpack-run
webpack is already running at http://localhost:8080/
> Task :frontend:run
BUILD SUCCESSFUL in 1s
12 actionable tasks: 3 executed, 9 up-to-date
Waiting for changes to input files of tasks...
The most problematic thing is that the changes don't even get applied after full page reload. The only way to get the changes is by re-running gradle run
.
Since HMR with CSS worked already for me in the past, I used git bisect to figure out what change caused the above situation to appear.
Turns out this issue started to appear when I separated my resources into css
and img
subfolders. If I place all resources into src/main/resources
directly, HMR works as desired.
Workable for me, but very unexpected. I'm posting my config files here if someone wants to investigate. Somebody else might run into this issue easily ...
frontend/webpack.config.d/babel.js
config.module.rules.push({
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader'
});
frontend/webpack.config.d/css.js
config.module.rules.push(
{
test: /\.scss$/,
use: [
'style-loader', // creates style nodes from JS strings
'css-loader', // translates CSS into CommonJS
'sass-loader' // compiles Sass to CSS, using Node Sass by default
]
}
);
frontend/webpack.config.d/images.js
config.module.rules.push(
{
test: /\.(jpg|png)$/,
use: [
'file-loader?name=[name].[ext]'
]
}
);
frontend/build.gradle.kts
...
kotlinFrontend {
configure<KotlinFrontendExtension> {
bundle("webpack", delegateClosureOf<WebPackExtension> {
publicPath = "/frontend/"
port = 8080
proxyUrl = "http://localhost:9090"
mode = if (devMode) "development" else "production"
})
}
}
tasks {
"compileKotlin2Js"(Kotlin2JsCompile::class) {
kotlinOptions {
metaInfo = true
outputFile = "${project.buildDir.path}/js/${project.name}.js"
sourceMap = true
sourceMapEmbedSources = "always"
moduleKind = "commonjs"
main = "call"
}
}
}
sourceSets {
getByName("main").output.resourcesDir = file("build/js/resources")
}
tasks.withType<KotlinJsDce> {
dceOptions.devMode = devMode
}
Compiled webpack-dev-server-run.js
#!/usr/bin/env node
var path = require('path');
var fs = require('fs');
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var semver = require('semver');
var devServerVersion = require(__dirname + '/node_modules/webpack-dev-server/package.json').version;
// the following will be replaced with inline json
var RunConfig = {
"host": "localhost",
"port": 8080,
"shutDownPath": "/webpack/dev/server/shutdown",
"webPackConfig": "/home/user/myproject/frontend/build/webpack.config.js",
"contentPath": null,
"proxyUrl": "http://localhost:9090",
"publicPath": "/frontend/",
"sourceMap": true,
"stats": "errors-only",
"bundlePath": "/home/user/myproject/frontend/build/js/frontend.js",
"moduleName": "frontend"
};
var config = require(RunConfig.webPackConfig);
for (var name in config.entry) {
if (config.entry.hasOwnProperty(name)) {
config.entry[name] = [
"webpack-dev-server/client?http://" + RunConfig.host + ":" + RunConfig.port + "/",
"webpack/hot/dev-server",
config.entry[name]
];
}
}
if (!config.plugins) {
config.plugins = [];
}
config.plugins.push(new webpack.HotModuleReplacementPlugin());
if (RunConfig.sourceMap) {
config.module.rules.push({
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
});
config.devtool = "eval-source-map";
}
var devServerDefaultOptions = {
publicPath: RunConfig.publicPath,
contentBase: (RunConfig.contentPath ? RunConfig.contentPath : undefined),
stats: RunConfig.stats || "errors-only",
host: RunConfig.host,
hot: true,
inline: true,
proxy: (RunConfig.proxyUrl) ? {
"**": {
target: RunConfig.proxyUrl,
secure: false,
bypass: function (req, res, proxyOptions) {
if (RunConfig.contentPath) {
var file = path.join(RunConfig.contentPath, req.path);
if (fs.existsSync(file)) {
return req.path;
}
}
}
}
} : undefined
};
var before = {
value: function (app) {
app.get(RunConfig.shutDownPath, function (req, res) {
res.json({shutdown: 'ok'});
devServer.close();
});
},
writable: true
};
if (semver.satisfies(devServerVersion, '>=2.9.0')) {
Object.defineProperty(devServerDefaultOptions, 'before', before);
} else {
Object.defineProperty(devServerDefaultOptions, 'setup', before);
}
var compiler = webpack(config);
var devServer = new WebpackDevServer(compiler, Object.assign(devServerDefaultOptions, config.devServer));
devServer.listen(RunConfig.port, RunConfig.host);