You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on May 17, 2023. It is now read-only.
Copy file name to clipboardExpand all lines: Building Web Applications with React and Kotlin JS/02_Setting_up.md
+18-34Lines changed: 18 additions & 34 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,70 +4,54 @@
4
4
5
5
To get started, let's make sure we have installed an up-to-date development environment. All we need to get started is:
6
6
7
-
- IntelliJ IDEA (version `2020.1` or above) with the Kotlin plugin (`1.4.0` or above) – [Download/Install](https://www.jetbrains.com/idea/download/)
7
+
- IntelliJ IDEA (version `2020.3` or above) with the Kotlin plugin (`1.4.30` or above) – [Download/Install](https://www.jetbrains.com/idea/download/)
8
8
9
9
10
10
### Setting up the project
11
11
12
-
We are going to set up our project using the `org.jetbrains.kotlin.js` Gradle plugin. This state-of-the-art plugin takes care of managing a development environment for us that uses all the latest and greatest things from the JavaScript ecosystem – under the hood, it equips us with a `yarn` and `webpack` installation. If we need to make adjustments, we can do so through Gradle – and with just a little bit of configuration, it will allow us to accomplish all the tasks we are going to encounter on our learning journey.
12
+
For this tutorial, we have made a starter template available that includes all configuration and required dependencies for the project.
13
13
14
-
The easiest way to get started is through the wizard provided by IntelliJ IDEA. From the splash screen or from the `File` menu, we select `New/Project...`. We choose the `Gradle` category, turn on the `Kotlin DSL build script`, and select only `Kotlin/JS for browser` as our target:
14
+
[**Please clone the project repository from GitHub, and open it in IntelliJ IDEA.**](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle)
15
15
16
-

16
+
The template repository contains a basic Kotlin/JS Gradle project for us to build our project. Because it already contains all dependencies that we will need throughout the hands-on, **you don't need to make any changes to the Gradle configuration.**
17
17
18
-
After clicking the `Next` button, we get to give our project a name. I named my project `confexplorer` – because that is what we are building – but feel free to get creative with your naming:
18
+
It is still beneficial to understand what artifacts are being used for the application, so let's have a closer look at our project template and the dependencies and configuration it relies on.
19
19
20
-

21
-
22
-
After clicking finish, we can lean back for a few seconds as Gradle initialises a blank project for us that supports JavaScript as a Kotlin compilation target. Once the import has finished, it's time to bring in all those dependencies we will require for the rest of the hands-on.
23
20
24
21
#### Gradle dependencies and tasks
25
22
26
-
Throughout the hands-on, we will make use of React, some external dependencies, and even some Kotlin-specific libraries. To save ourselves from running Gradle imports after each chapter, we will add all dependencies right now. The topics related to each set of dependencies is described in the annotated chapter.
27
-
28
-
Inside our `build.gradle.kts` file, let's make sure that our `repositories` block looks as follows:
Throughout the hands-on, we will make use of React, some external dependencies, and even some Kotlin-specific libraries. The topics related to each set of dependencies is described in the annotated chapter.
37
24
38
-
Now that we have all sources for our dependencies, let's make sure we include everything we need in our `dependencies` block.
After editing the file, IntelliJ IDEA will automatically prompt us to import the changed Gradle files. Alternatively, we can also press the "🔁 Reimport All Gradle Projects" button in the Gradle tool window.
67
51
68
52
#### HTML page
69
53
70
-
Because we can't run JavaScript out of nowhere, we need to provide an HTML page (linked to our compiled JS file) that can be loaded in a browser. Let's create the file `/src/main/resources/index.html`and fill it with the following content:
54
+
Because we can't run JavaScript out of nowhere, we also need an HTML page to insert out HTML into. The file `/src/main/resources/index.html`is provided and filled accordingly:
71
55
72
56
```xml
73
57
<!doctype html>
@@ -83,9 +67,9 @@ Because we can't run JavaScript out of nowhere, we need to provide an HTML page
83
67
</html>
84
68
```
85
69
86
-
Depending on how we named our project, the embedded `js` file has a different name. For example, if you named your project `followingAlong`, make sure to embed `followingAlong.js`. Thanks to the Gradle plugin, all of our code and dependencies will be bundled up into this single JavaScript artifact that bears the same name as our project.
70
+
Depending on how we named our project, the embedded `js` file has a different name. So, if you're working in a project named`followingAlong`, make sure to embed `followingAlong.js`. Thanks to the Gradle plugin, all of our code and dependencies will be bundled up into this single JavaScript artifact that bears the same name as our project.
87
71
88
-
Now, before we write a proper "Hello, World" with actual Markup, let's start with a very simple and visual example – a solid colored page. This is just to verify that what we're building is actually reaching the browser and executes fine. For this, we create the file `src/main/kotlin/Main.kt` and fill it with the following Kotlin code snippet:
72
+
Now, before we write a proper "Hello, World" with actual markup, we start with a very simple and visual example – a solid colored page. This is just to verify that what we're building is actually reaching the browser and executes fine. For this, we have the file `src/main/kotlin/Main.kt`, filled with the following code snippet:
Copy file name to clipboardExpand all lines: Building Web Applications with React and Kotlin JS/03_A_First_Static_Page.md
+20-9Lines changed: 20 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -102,23 +102,35 @@ Type or paste the above code as the contents of your `render` call. If IntelliJ
102
102
103
103
While writing HTML in Kotlin just for the sake of it is a noble idea, there are actually a lot more benefits to writing your HTML directly inside Kotlin. A big advantage of using this domain specific language is that we can manipulate our website content using language constructs we are already familiar with. Whether it's conditions, loops, collections, or string interpolation, we can expect them to work the same in HTML as they would in Kotlin.
104
104
105
-
Now, instead of hardcoding the list of videos, let's actually define them as a list of Kotlin objects and display those objects instead. We'll create a simple class to hold together the attributes of a video (we can do this in `Main.kt` or a file of our choice):
105
+
Now, instead of hardcoding the list of videos, let's actually define them as a list of Kotlin objects and display those objects instead. We'll create a simple data class to hold together the attributes of a video called `KotlinVideo`(we can do this in `Main.kt` or a file of our choice). We will also define a corresponding `external interface` – more on that later.
106
106
107
107
```kotlin
108
-
data classVideo(valid:Int, valtitle:String, valspeaker:String, valvideoUrl:String)
108
+
externalinterfaceVideo {
109
+
val id:Int
110
+
val title:String
111
+
val speaker:String
112
+
val videoUrl:String
113
+
}
114
+
115
+
data classKotlinVideo(
116
+
overridevalid:Int,
117
+
overridevaltitle:String,
118
+
overridevalspeaker:String,
119
+
overridevalvideoUrl:String
120
+
) : Video
109
121
```
110
122
111
123
Then, let's fill up the two lists for unwatched videos and watched videos respectively. For now, we can just have these declarations at file-level inside our `Main.kt`:
112
124
113
125
```kotlin
114
126
val unwatchedVideos =listOf(
115
-
Video(1, "Building and breaking things", "John Doe", "https://youtu.be/PsaFVLr8t4E"),
116
-
Video(2, "The development process", "Jane Smith", "https://youtu.be/PsaFVLr8t4E"),
117
-
Video(3, "The Web 7.0", "Matt Miller", "https://youtu.be/PsaFVLr8t4E")
127
+
KotlinVideo(1, "Building and breaking things", "John Doe", "https://youtu.be/PsaFVLr8t4E"),
128
+
KotlinVideo(2, "The development process", "Jane Smith", "https://youtu.be/PsaFVLr8t4E"),
129
+
KotlinVideo(3, "The Web 7.0", "Matt Miller", "https://youtu.be/PsaFVLr8t4E")
And we make sure to use this interface in the `App` class:
22
22
23
23
```kotlin
24
+
@JsExport
24
25
classApp : RComponent<RProps, AppState>()
25
26
```
26
27
27
28
Let's delete the `VideoListState` since we're storing it somewhere further up our hierarchy now. Since we've made the list effectively stateless at this point (by moving all of the state out of the component), we can revert its class definition back to inherit the default state.
Copy file name to clipboardExpand all lines: Building Web Applications with React and Kotlin JS/07_Using_Packages_From_NPM.md
+16-11Lines changed: 16 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,46 +6,51 @@ First up and probably the most obvious missing functionality is the video player
6
6
7
7
### Adding the video player component
8
8
9
-
We need to replace our placeholder video component with one that can actually show the YouTube videos we're linking by adding in a ready-made video player for React. We'll use the `react-player` component to show the video and control the appearance of the player. We can take a look at some of the documentation for it and its API in the GitHub [README](https://github.com/CookPete/react-player/blob/master/README.md).
9
+
We need to replace our placeholder video component with one that can actually show the YouTube videos we're linking by adding in a ready-made video player for React. We'll use the `react-youtube-lite` component to show the video and control the appearance of the player. We can take a look at some of the documentation for it and its API in the GitHub [README](https://www.npmjs.com/package/react-youtube-lite).
10
10
11
-
In the beginning, we have already added the `react-player` package to our Gradle build file. This was the responsible snippet:
11
+
In the beginning, we have already added the `react-youtube-lite` package to our Gradle build file. This was the responsible snippet:
You're seeing that right – NPM dependencies can be added to a Gradle build file via the `npm` function. The yarn installation managed by the Gradle plugin will take care of downloading, installing and updating those NPM dependencies for you.
23
23
24
-
Since we want to use this module from Kotlin, we need to tell our compiler what the component interface looks like – what kind of things are okay to invoke, to set, or to read from this external component, so that we remain safe, and can count on tool support. To do this, let's create a file called `ReactPlayer.kt`, with the following contents:
24
+
Since we want to use this module from Kotlin, we need to tell our compiler what the component interface looks like – what kind of things are okay to invoke, to set, or to read from this external component, so that we remain safe, and can count on tool support. To do this, let's create a file called `ReactYouTube.kt`, with the following contents:
25
25
26
26
```kotlin
27
-
@file:JsModule("react-player")
27
+
@file:JsModule("react-youtube-lite")
28
28
@file:JsNonModule
29
29
30
30
importreact.*
31
31
32
-
@JsName("default")
32
+
@JsName("ReactYouTubeLite")
33
33
externalval reactPlayer:RClass<dynamic>
34
34
```
35
35
36
-
Because JavaScript imports/exports isn't the simplest topic, it can sometimes be tricky to find the correct combination between annotations to get the Kotlin compiler on the same page as us. These last two lines are equivalent to a JavaScript import like `require("react-player").default;`. It tells the compiler that we're certain we'll get a component conforming to `RClass<dynamic>` at runtime.
36
+
Because JavaScript imports/exports isn't the simplest topic, it can sometimes be tricky to find the correct combination between annotations to get the Kotlin compiler on the same page as us. These last two lines are equivalent to a JavaScript import like `require("react-youtube-lite").default;`. It tells the compiler that we're certain we'll get a component conforming to `RClass<dynamic>` at runtime.
37
37
38
38
#### Typed wrappers for the video player component
39
39
40
40
However, in this configuration, we're giving up a lot of the benefits that Kotlin gives us. The declaration of `dynamic` essentially tells the compiler to just accept whatever we give it, at the risk of breaking things at runtime (also commonly known as *in production*).
41
41
42
-
Fortunately, we know the structure of the interfaces used by the imported components (or can infer them rather quickly from the [README](https://github.com/CookPete/react-player#usage)), so making our wrappers typesafe is a rather straightforward task. We can define a typesafe external interface which allows us to set the URL as we see fit. And we modify the `ReactPlayer` definition accordingly:
42
+
Fortunately, we know the structure of the interfaces used by the imported components (or can infer them rather quickly from the [README](https://www.npmjs.com/package/react-youtube-lite)), so making our wrappers typesafe is a rather straightforward task. We can define a typesafe external interface which allows us to set the URL as we see fit. And we modify the `ReactPlayer` definition accordingly:
@@ -62,16 +63,6 @@ Let's look at what's happening in this *suspending function*. We `fetch` a video
62
63
63
64
A function call like `window.fetch` returns a `Promise` object. We would have to define a callback handler which gets invoked once the `Promise` is *resolved* and a result is available. However, since we are using coroutines in our project, we can `await` those promises. We're writing code that looks sequential but remains non-blocking. Whenever a function like `await()` is called, the method stops its execution (it *suspends*, hence the keyword). It continues execution once the `Promise` can be resolved.
64
65
65
-
The individual variables were only used for illustration purposes, though. In reality, we can, of course, chain all calls together. We'll end up with a single expression, so we can even use the expression body syntax to express the same processing steps as above:
To allow the `heroku/gradle` buildpack to run properly, a `stage` task needs to be present in our Gradle build file. Luckily, it is equivalent to our `build` task, so the changes we have to make at the bottom of our `build.gradle.kts` file are very limited:
31
+
To allow the `heroku/gradle` buildpack to run properly, a `stage` task needs to be present in our Gradle build file. Luckily, it is equivalent to our `build` task – and, as luck would have it, the corresponding alias is already included at the bottom of our Gradle build file:
32
32
33
33
```kotlin
34
34
// Heroku Deployment (chapter 9)
@@ -61,4 +61,4 @@ If everything has gone according to plan, we will see the URL under which we can
You can find the state of the project after this section on the `step-08-deploying-to-production` branch in the [GitHub](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle/tree/step-08-deploying-to-production) repository.
64
+
You can find the state of the project after this section on the `final` branch in the [GitHub](https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle/tree/final) repository.
0 commit comments