|
1 | 1 | # kotlin-frontend-plugin
|
2 | 2 | Gradle plugin for kotlin frontend development
|
3 | 3 |
|
| 4 | +The plugin provides easy way to gather maven and npm dependencies, pack bundles (via webpack) and test frontend application using karma. By default the plugin generates all required configs for webpack, karma and manages the corresponding daemons. |
| 5 | + |
| 6 | +By using gradle continuous build you also can get hot module replacement feature (apply code changes in browser on the fly). See corresponding [section below](#hot-module-replacement). |
| 7 | + |
4 | 8 | # Howto
|
5 |
| -1. Install snapshot |
6 | 9 |
|
7 |
| -```bash |
8 |
| -git clone [email protected]:cy6erGn0m/kotlin-frontend-plugin.git |
9 |
| -cd kotlin-frontend-plugin/kotlin-frontend |
10 |
| -./gradlew publishToMavenLocal |
11 |
| -``` |
| 10 | +### Configure gradle project |
12 | 11 |
|
13 |
| -2. Configure your project |
| 12 | +Fist of all you have to apply plugin `org.jetbrains.kotlin.frontend` and setup kotlin |
14 | 13 |
|
15 | 14 | ```gradle
|
16 | 15 | buildscript {
|
17 |
| - ext.kotlin_version = '1.1.0-dev-5310' |
| 16 | + ext.kotlin_version = '1.1.0' |
18 | 17 |
|
19 | 18 | repositories {
|
20 | 19 | jcenter()
|
21 |
| - mavenLocal() |
22 | 20 | maven {
|
23 |
| - url "https://dl.bintray.com/kotlin/kotlin-dev" |
| 21 | + url "https://jitpack.io" |
24 | 22 | }
|
25 | 23 | }
|
26 | 24 |
|
27 | 25 | dependencies {
|
28 | 26 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
29 |
| - classpath "org.jetbrains.kotlin:kotlin-frontend:0.0.1-SNAPSHOT" |
| 27 | + classpath "com.github.cy6erGn0m:kotlin-frontend-plugin:568610baa1" |
30 | 28 | }
|
31 | 29 | }
|
32 | 30 |
|
33 | 31 |
|
34 | 32 | // apply plugin
|
35 | 33 | apply plugin: 'org.jetbrains.kotlin.frontend'
|
36 | 34 |
|
| 35 | +// apply kotlin2js |
| 36 | +apply plugin: 'kotlin2js' |
| 37 | +
|
| 38 | +// configure kotlin compiler |
| 39 | +compileKotlin2Js { |
| 40 | + kotlinOptions.metaInfo = true |
| 41 | + kotlinOptions.outputFile = "$project.buildDir.path/js/${project.name}.js" |
| 42 | + kotlinOptions.sourceMap = true |
| 43 | + kotlinOptions.moduleKind = 'commonjs' |
| 44 | + kotlinOptions.main = "call" |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +### Setup npm dependencies |
| 49 | + |
| 50 | +All frontend plugin settings are applied in `kotlinFrontend` section: |
| 51 | + |
| 52 | +``` |
37 | 53 | kotlinFrontend {
|
38 | 54 | npm {
|
39 |
| - // your application dependency |
40 |
| - dependency "style-loader" |
| 55 | + dependency "style-loader" // production dependency |
| 56 | + devDependency "karma" // development dependency |
| 57 | + } |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +### webpack bundler |
41 | 62 |
|
42 |
| - // development dependency |
43 |
| - devDependency("karma") |
| 63 | +To create webpack bundle (for both packaing and running dev server) |
| 64 | + |
| 65 | +``` |
| 66 | +kotlinFrontend { |
| 67 | + webpackBundle { |
| 68 | + bundleName = "main" |
44 | 69 | }
|
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +### complete example |
| 74 | + |
| 75 | +See [test/build.gradle](test/build.gradle) for full example |
| 76 | + |
| 77 | +# Building and running |
| 78 | + |
| 79 | +To run dev server (that also will build kotlin sources) |
| 80 | + |
| 81 | +`gradlew run` |
| 82 | + |
| 83 | +to pack bundle |
| 84 | + |
| 85 | +`gradle bundle` |
| 86 | + |
| 87 | +to stop running webpack and karma daemon |
| 88 | + |
| 89 | +`gradle stop` |
| 90 | + |
| 91 | +# Webpack |
| 92 | + |
| 93 | +webpack configuration |
45 | 94 |
|
| 95 | +``` |
| 96 | +kotlinFrontend { |
46 | 97 | webpackBundle {
|
47 | 98 | bundleName = "main"
|
48 |
| - contentPath = file('src/main/web') |
| 99 | + sourceMapEnabled = true | false // enable/disable source maps |
| 100 | + contentPath = file(...) // a file that represents a directory to be served by dev server) |
| 101 | + publicPath = "/" // web prefix |
| 102 | + port = 8088 // dev server port |
| 103 | + proxyUrl = "" | "http://...." // URL to be proxied, useful to proxy backend webserver |
| 104 | + stats = "errors-only" // log level |
49 | 105 | }
|
50 |
| - |
51 |
| -// rollupBundle { |
52 |
| -// bundleName = "rolledUp" |
53 |
| -// } |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +dev server log is located at `build/logs/webpack-dev-server.log` |
| 110 | + |
| 111 | +config file is generated at `build/webpack.config.js` |
| 112 | + |
| 113 | +## webpack config customization |
| 114 | + |
| 115 | +For webpack cnfig you can apply additional script by placing a small scripts to directory `webpack.config.d` that will be appended to the end of config script. Use number prefix to change order (it is very similar to UNIX rc.d config directories) |
| 116 | + |
| 117 | +Sample structure: |
| 118 | + |
| 119 | +- [DIR] webpack.config.d |
| 120 | + - css.js |
| 121 | + - minify.js |
| 122 | + - 10-apply-ealier.js |
| 123 | + - 20-apply-later.js |
| 124 | + |
| 125 | +# Karma |
| 126 | + |
| 127 | +karma configuration |
| 128 | + |
| 129 | +``` |
| 130 | +kotlinFrontend { |
| 131 | + karma { |
| 132 | + port = 9876 |
| 133 | + runnerPort = 9100 |
| 134 | + reporters = listOf("progress") |
| 135 | + frameworks = listOf("qunit") // for now only qunit works as intended |
| 136 | + preprocessors = listOf("...") |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +karma log is located at `build/logs/karma.log` |
| 142 | + |
| 143 | +config file is generated at `build/karma.conf.js` |
| 144 | + |
| 145 | +# Hot module replacement |
| 146 | + |
| 147 | +Webpack provides ability to apply code changes on the fly with no page reload (if possible). For reference see [Webpack Hot Module Replacement documentation](https://webpack.js.org/concepts/hot-module-replacement/) |
| 148 | + |
| 149 | +Webpack does a lot of work for you however to get it working well most likely you have to implement state save and restore functionality via webpack's API. See [HMR.kt](test/src/main/kotlin/test/hello/HMR.kt) for corresponding Kotlin external declarations for webpack API and [main.kt](test/src/main/kotlin/test/hello/main.kt) for sample save/load. |
54 | 150 |
|
55 |
| -// allBundles { |
56 |
| -// /* set properties for all bundles */ |
57 |
| -// } |
| 151 | +Briefly at module load accept HMR feature and listen for disposal |
58 | 152 |
|
59 |
| -// bundle("someBundler") { |
60 |
| -// .... |
61 |
| -// } |
| 153 | +```kotlin |
| 154 | +module.hot?.let { hot -> |
| 155 | + hot.accept() // accept hot reload |
| 156 | + |
| 157 | + hot.dispose { data -> // listen for disposal events |
| 158 | + data.my-fields = [your application state] // put your state in the 'data' object |
| 159 | + } |
62 | 160 | }
|
| 161 | +``` |
| 162 | + |
| 163 | +To get previously saved state at module load use `module.hot?.data` |
63 | 164 |
|
| 165 | +```kotlin |
| 166 | + module.hot?.data?.let { data -> // if we have previous state then we are in the middle of HMR |
| 167 | + myRestoreFunction(data) // so get state from the 'data' object |
| 168 | + } |
64 | 169 | ```
|
65 | 170 |
|
| 171 | +Finally use gradle continuous build with run task to get live replacement every time you change your code. |
| 172 | + |
| 173 | +``` |
| 174 | +gradlew -t run |
| 175 | +``` |
0 commit comments