Giter Club home page Giter Club logo

kweb-core's Introduction

Kweb - A Kotlin web framework

Quick Start

Read the Introduction or Getting Started from the Kweb User Manual.

Why another web framework?

Kweb is designed to make it easy for developers to create modern websites without having to worry about the complexities of communication between the server and the browser. With a unified codebase, you can focus on creating an intuitive and user-friendly interface, rather than spending time on technical details. By streamlining the development process, Kweb makes it easier to build functional and beautiful websites that meet the needs of your users.

How does it work?

Kweb is a remote interface for a web browser's DOM (Document Object Model). With Kweb, you can create and manipulate DOM elements, and listen for and handle events, all using an intuitive Kotlin DSL that mirrors the structure of the HTML being created. Kweb is built on the Ktor framework, which handles HTTP, HTTPS, and WebSocket transport, and is optimized to minimize latency and resource usage on both the server and browser.

Example

import kweb.*
import kweb.InputType.text


fun main() {
    Kweb(port = 16097) {
        doc.body {
            val name = kvar("")
            div {
                h1().text("Enter Your Name")
                input(type = text).value = name
            }
            div {
                span().text(name.map { "Hello, $it" })
            }
        }
    }
}

This example illustrates creating DOM elements, modifying elements, KVars, and binding input elements.

Learn More

Friends of Kweb

YourKit supports open source projects with innovative and intelligent tools for monitoring and profiling Java and .NET applications. YourKit is the creator of YourKit Java Profiler, YourKit .NET Profiler, and YourKit YouMonitor.

YourKit Logo

kweb-core's People

Contributors

3flex avatar alkoclick avatar alvir avatar andrewcrowe avatar asemy avatar benjaminfaal avatar betschwa avatar blakelee avatar chandrin94 avatar cyneath avatar dependabot[bot] avatar derek52 avatar ethanmdavidson avatar gtod avatar irian3x3 avatar jdvalenzuelah avatar jifffffy avatar maanooak avatar marad avatar null-dev avatar potatocurry avatar rpanic avatar sanity avatar sigmadeltasoftware avatar stangls avatar swishy avatar tcrawford-figure avatar toddharrison avatar todo-actions[bot] avatar wooky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kweb-core's Issues

Housekeeping on client connections

Information on WebSocket connection to clients is kept in KWeb.clients, currently a ConcurrentHashMap.

This means that they won't be deleted until the server is restarted. We should keep track of when clients disconnect from the server and delete any associated data.

Typo on website

I had a little trouble setting up Kweb on maven until I realized there was a typo on the maven section of this page: http://kweb.io/use/getting-started.html.

In the code block underneath: For Maven users, add this to the repositories section of your pom.xml:

On the second last line:
<repository><id>ktor</id><url>"http://dl.bintray.com/kotlin/ktor"</url></repository>
should be:
<repository><id>ktor</id><url>http://dl.bintray.com/kotlin/ktor</url></repository> (removed the quotes)

Fix possible Firefox routing bug

reported by: @MrPowerGamerBR

Also, I think I found a bug (only happens in Firefox)

If I'm accessing the website (example: 127.0.0.1/path), if I change the URL on the address bar and change it to 127.0.0.1/anotherpath, it doesn't redirect it stays on the 127.0.0.1/path
it works on chromium.

Client updates are inconstant with duplicated tabs

Configuration:

Chrome: Version 56.0.2924.87 (64-bit)
Linux (Ubuntu 16.04)

When running the example from your-first-kwebsite I noticed that multiple browser tabs accessing the kweb server behave differently depending on if they navigated to the URL or if they were created using "Right-click -> Duplicate" in chrome.

URL navigated tabs behavior:

  • Each tab updates the server's count val.
  • The h1 text is updated on each click.

Duplicate tabs behavior:

  • First tab behaves as expected on its own.
  • When the second tab is made using "Right-click -> Duplicate", it displays the count at the time it was duplicated. Clicking the second tab updates the first tab's count but does not update its own count.

Steps to reproduce:

  • Run the example

  • Open a second tab and navigate to the example URL

  • Observe each tab responding to being clicked

  • Remove one tab

  • Duplicate the remaining tab by right clicking the tab and selecting "Duplicate"

  • Observe the original tab responding to both tabs being clicked

  • Observe the duplicate tab not responding to either tab being clicked

I figure this issue is low severity since kweb is only in alpha. This may have some crossover with #2

Replace custom Observable with an off-the-shelf library

Currently kweb implements a simple Observable container, which is used by Kweb's binding functionality.

Consider whether we'd be better off with a pre-existing library, RxKotlin may be suitable, but I've only spent 2 minutes looking at it so this needs to be verified.

Improve exception reporting

[ktor-pool-1-thread-14] INFO io.kweb.demo.Joker - Create clicked
[ForkJoinPool.commonPool-worker-1] ERROR io.kweb.WebBrowser -         at com.github.sanity.shoebox.OrderedViewSet$1.invoke(OrderedViewSet.kt:24)
        at com.github.sanity.shoebox.OrderedViewSet$1.invoke(OrderedViewSet.kt:8)
        at com.github.sanity.shoebox.View$1.invoke(View.kt:27)
        at com.github.sanity.shoebox.View$1.invoke(View.kt:12)
        at com.github.sanity.shoebox.Shoebox.set(Shoebox.kt:78)
        at io.kweb.demo.JokerKt$main$1$$special$$inlined$route$lambda$1$1$3$1$1.doResume(joker.kt:89)

is thrown by:

                is BinarySearchResult.Exact -> throw RuntimeException("Listener called for value already in list ($keyValue)")

But the exception itself is not included in the output (from kweb-demo)

[Discussion] How do we handle state?

A problem that will be faced by most people using kweb, and for which no clear pattern or recommendations currently exist, is how to handle state.

Kweb should be particularly well suited to keeping browser-state in sync with server-state in realtime, think how Facebook updates automatically when users post comments or do various other activities.

But we need to come up with some recommendations for how to do this. Where do we keep state? How do we keep it in sync with persisted state (perhaps in a database)? How do we notify the UI about changes to the state, and how do we modify state in response to UI changes? What lessons can be learned from the JavaScript ecosystem?

I'm keeping an open mind on this for now, but here is some potentially relevant reading material (please feel free to add, comment, discuss, etc):

typo in docCookie.getItems function name

kweb_bootstrap defines docCookie with a "getItems" function (with an 's' on the end)
https://github.com/kwebio/core/blob/master/src/main/resources/io/kweb/kweb_bootstrap.html#L201

CookieReceiver tries to call docCookie.getItem (without the 's' on the end)
https://github.com/kwebio/core/blob/master/src/main/kotlin/io/kweb/dom/cookies/CookieReceiver.kt#L43

doc.cookie.getString("test") throws "Error evaluating docCookies.getItem("test");: TypeError: docCookies.getItem is not a function"

Flesh out JQuery plugin

I've made a very basic start on the JQuery plugin to illustrate how simple it is, see here.

Hopefully, it is fairly clear how this can be extended to support additional JQuery commands quite painlessly.

Make communication channel more robust

There is some evidence that websockets may not be reliable in some circumstances. @gtod did some research on the subject, which I've pasted below.

There are steps that can be taken to make them more robust, for example this JS library that we should be able to implement quite easily in KWeb. We could also fall-back to "comet"-style polling if there is a problem with websockets (perhaps because the user agent is older).

See WebSockets: caution required and You might not need a websocket. Some of the issues discussed in both the articles and accompanying hacker news discussions follow.

Flaky client websocket connections

Especially over mobile when the user loses their office wifi and reverts to 4G or 3G. What will happen in kweb?

Use Server Sent Events instead

From You might not need a WebSocket:

Arnout Kazemier (“WebSuckets”, Primus) recently posed this thought about EventSource: “It’s there. It’s really cool. It has automatic reconnect. It works through proxies […]. And it’s streaming. So why are we not using it?” Good question.

Of course, it's unidirectional...

Using https exclusively

Looks like we can use nginx as a reverse proxy for websockets so that needs to be tested.

Messaging patterns

See MessageBus for a Rails messaging protocol as opposed to using the raw bidirectional websocket.

Connections are lower level than AJAX/apollo-client

AJAX requests mean we don't care about TCP/IP, persistent connections, re-connections, timeouts. By using a websocket directly some of these issues are now back in our face.

Writing to a closed websocket can crash your iphone.

This is/was Safari in 2013. websuckets (2013)

Firefox can create ghost connections when you connects during ws.onclose

websuckets (2013)

Mobile providers block differently

websuckets (2013)

Corporate firewalls block ws ports

Obviated by using HTTPS exclusively? This is an older issue, I think ws connections are now happy to coexist on port 443...

Bind existing HTML into the kweb DSL

So, this will give users the option to write HTML or reuse existing HTML. We'll have a code generation step which basically just converts it to a bindable object made from the internal DSL. The idea here is just to cut out the "busy work" a developer would have to do to convert traditional HTML to the DSL.

@sanity We talked about this a bit. Will probably wrap CSS into this too (IE: not make a CSS DSL but add the stylessheets in post when kweb renders the page). If you're okay with that solution for CSS for now, then I'll refer to this issue on the CSS DSL issue

Edit: Advantage here being we could include support for scss in kweb by doing this

Diagnose failure to redirect to /

reported by: @MrPowerGamerBR

Code that illustrates problem.

{
        doc.body.new {
            route {
                path("/") {
                    h1().text("Hello World!")

                    button().text("Home Page").on.click {
                        url.path.value = "/"
                    }

                    button().text("Test Page").on.click {
                        url.path.value = "/test"
                    }
                }

                path("/test") { params ->
                    button().text("Home Page").on.click {
                        url.path.value = "/"
                    }

                    button().text("Test Page 2").on.click {
                        url.path.value = "/test2"
                    }
                }

                path("/test2") { params ->
                    h1().text("Test Page 2!")

                    button().text("Home Page").on.click {
                        url.path.value = "/"
                    }
                }
            }
        }
    }

Enable TLS and HTTPS with Ktor-Access

Currently, there is no way to give Ktor options for Ktor-specific settings like SSL certificates and SSL ports, since these options have to be handed to Ktor before starting the Jetty server.
To implement this, probably a Kweb-Configuration workflow would be needed to configure Ktor without exposing too much.

Automatic path-to-object serialization/deserialization

Note: While it will require a decent understanding of Kotlin reflection, this is a very self-contained project and thus might be an ideal choice for someone interested in getting their feet wet as a Kweb contributor. If you want to tackle it please comment below to avoid duplicated effort

I've been working on routing, and have an approach that's both relatively simple and I think very powerful.

One thing that would add greatly to it is some code that could convert a URL path like /users/123/friends/94 into an object representation of the path, like Users(id=123, Friend(id = 94)), similar to how Gson converts JSON into object representations and back again.

For example, let's create an object representation of our webapps paths as follows:

sealed class Entity {
  data class User(val id : Int, val userEntity : UserEntity) : Entity()
  class Root() : Entity()
}

sealed class UserEntity {
  class Root() : UserEntity()
  data class Friend(val id : Int) : UserEntity()
  class Settings() : UserEntity()
}

Note the use of sealed classes, this will be nice when we use when expressions to render the paths.

Here are some paths and the object equivalents:

/users/32 -> Entity.User(32, UserEntity.Root())
/users/152/friends/22 -> Entity.User(152, UserEntity.Friend(22))
/ -> Entity.Root()

Additionally, while defaults should be sensible and consistent with REST conventions for URL format, it should be possible to use annotations to override the default translations from path to object (much as with Gson).

JPMS/Jigsaw Support

Java 9+ versions ship with the module system and it's becoming more and more common, having just crossed 1000 maven projects fully supporting it (correctly).

Is there a plan for kweb to support JPMS modules? There are definitely quite a few collisions when attempting to use it that way out of the box

Allow custom configuration of Ktor to support HTTPS

What are your thoughts on exposing the kweb ktor builder to the developer so that the user can create their own routes (for like a public API) without having to spin up a new jetty instance. There could be some really interesting Spring/neo4j integrations if we did that. Essentially that would allow the developer to create their webapp on the same application level as their backend and it might also help with the browser caching issue since we'd just have access to a Spring database or whatever the developer is planning on using for a db.

The alternative to not exposing ktor would basically be http requests between the backend (whatever it's done in) and kweb through http on the same server which is kind of silly.

Create a DSL for CSS

Just as we've created a DSL for HTML (or started to) we're going to need a DSL for CSS. This should be usable both for adding to the document , but also for individual 'style' attributes on elements (considering that the latter can't contain newlines).

Would also be nice if the JQuery plugin could reuse elements of this DSL for it's implementation of .css().

Toggling visibility/rendering

Hi, just wondering if there is an example of toggling visibility of views, or maybe removing them all together.

Basically I want something like dropdown menu with dynamically generated elements tied to shoebox, but I'm not sure how to do it properly.

Migrate from Gson to Kotlin serialization

Kotlin Serialization uses a compiler plugin to avoid needing to use reflection for JSON object serialization. Currently Kweb uses Gson for this purpose, which does rely on reflection.

Reopen the last closed tab shortcut (Ctrl+Shift+T) has inconsistent behavior

Configuration:

Chrome: Version 56.0.2924.87 (64-bit)
Linux (Ubuntu 16.04)
Kweb version 0.2.2

When running the example from your-first-kwebsite, using the "reopen the last closed tab" shortcut (Ctrl+Shift+T) causes various issues.

The following steps produce an IllegalStateException exception:

  • Run the example
  • Close the tab
  • Reopen last closed tab (ctrl+shift+t)
  • Click the example to increment the counter
  • Observe exception in terminal

The following steps produce strange behavior similar to duplicating tabs #28:

  • Run the example
  • Open a second tab and navigate to the example URL
  • Close the first tab
  • Reopen last closed tab (Ctrl+Shift+T)
  • Observe second tab responding to clicks from both tabs
  • Observe reopened tab not responding to clicks from either tab

Fomantic plugin adds non-existing stylesheet/src link to fomantic.min.css/js instead of semantic.min.css/js

Using kweb 0.4.8 with the fomantic plugin as referenced by the documentation does not work for me.

It seems that the plugin creates a non-resolvable link like https://cdn.jsdelivr.net/npm/[email protected]/dist/fomantic.min.css´ in FomanticUIPlugin.kt .

The Fomantic documentation however refers to semantic.
https://fomantic-ui.com/introduction/getting-started.html :

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.js"></script>

Implement true server-side rendering with rehydration of HTML document

Currently Kweb supplies the initial page-building instructions in JavaScript, which works fine, but may have limitations for SEO, and may also delay page render time.

We should be able to use a library like https://jsoup.org to build the DOM in HTML in the initial page sent to the client, rather than as a sequence of JavaScript instructions.

This will touch a lot of the same code as #53, so while they're independent, it's worth being familiar with both before tackling either.

authentication

Hello everyone, is there an example with authentication?

Cache javascript functions in-browser

Currently Kweb sends instructions to the browser, which are either predefined for common operations (eg. createElement), or executed using eval() for rarer operations. These operations can be triggered using execute(), evaluate(), and some other related functions on the WebBrowser class.

This approach should be replaced by one in which the first call to a JavaScript function results in the function being sent to the client and parsed using new Function().

This could be exposed by modifying WebBrowser.execute() and related functions to support, perhaps something like:

   Kweb(port = ..) { 
     val username : String = // ..
     execute("""alert("Hi {name}, I'm an alert box");""", "name" to username)
   }

Importantly, this function is then cached such that future calls to the function (with different parameters) can be sent to the browser with only a reference to the cached function and the parameter values.

The advantages here are to remove any eval() overhead, while replacing the current Instruction mechanism with something that achieves the same efficiency benefit but without having to manually create each special case.

An implementation thought: We should probably use randomly generated variable names for the parameters as a precaution against variable name clashes, unless there is a way to ensure that can't happen.

If we go with that syntax for the function template we can use Ktor's RoutingPath, as we already do in routing.kt.

Exception running todoApp.kt

Reported on reddit:

[pool-1-thread-1] INFO se.unir.kotlin.App - Rendering Add Item button
[qtp913190639-16] ERROR ktor.application - Websocket handler failed
java.lang.NoSuchMethodError: com.github.salomonbrys.kotson.GsonBuilderKt.removeTypeWildcards(Ljava/lang/reflect/Type;)Ljava/lang/reflect/Type;
    at io.kweb.Kweb$4$2$6.invokeSuspend(Kweb.kt:494)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:236)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680)
    at java.lang.Thread.run(Thread.java:748)

Dependencies looks ok:

<dependency>
  <groupId>com.github.kwebio</groupId>
  <artifactId>core</artifactId>
  <version>0.3.12</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.7.25</version>
</dependency>

Debug mode to track JavaScript errors back to where and what was logged

In a debug mode we could store a stacktrace (apparently the best way is new Throwable().getStackTrace()) and the raw javascript that was sent with each execute() or evaluate() statement, associated with an id.

If eval() throws an error when the browser executes it - this can then be caught and returned to the server which can then associate it with the stacktrace and raw js that caused it.

Unit test the kweb-browser communications

Embarrassingly kweb currently has no unit tests. This is due to the fact that almost every part of its lowest level code interacts with a web browser, and so testing them without using a real web browser wouldn't be very useful.

One possibility is PhantomJS. It's a headless web browser designed for just this type of thing, and there are Java bindings for it.

This ticket isn't to implement comprehensive unit tests, but rather the first step of this, which is to show that phantomjs can be used for this in conjunction with a Kotlin unit testing library like kotlintest.

Just one or two example tests to show it works will be fine, and then we can all get started on implementing tests for everything else.

Push initial "setup" commands to client in HTML page for faster rendering

Currently KWeb doesn't send any commands to the client until the client has connected back to the server via websockets. This likely causes a delay before the page renders.

The KWeb class could be modified such that the createPage function, which typically handles initial page setup, runs prior to kweb_bootstrap.html being sent to the client, and then commands generated by createPage can be embedded directly in the initial HTML page, which should lead to the page rendering faster.

This will require that any messages the client attempts to send back to the server prior to the websocket being set up will need to be stored in the client until the websocket is ready, and then sent.

SemanticUIClasses should be immutable

Currently SemanticUIClasses is mutable, this is lazy and can lead to problems if a SemanticUIClasses instance is accidentally reused.

Its structure should be changed to make it an immutable object.

Artifact jar name is unhelpful

The current KWeb jar that is up on jitpack.io is named core-0.4.18.jar. This is a very unhelpful name and judging by the buildscripts, it looks (to me) also unintentional.

I thought it was just me, but apparently the logs also confirm it:

Build artifacts:
com.github.kwebio:core:0.4.18

Files: 
com/github/kwebio/core/0.4.18
com/github/kwebio/core/0.4.18/build.log
com/github/kwebio/core/0.4.18/core-0.4.18-javadoc.jar
com/github/kwebio/core/0.4.18/core-0.4.18-sources.jar
com/github/kwebio/core/0.4.18/core-0.4.18.jar
com/github/kwebio/core/0.4.18/core-0.4.18.pom
com/github/kwebio/core/0.4.18/core-0.4.18.pom.md5
com/github/kwebio/core/0.4.18/core-0.4.18.pom.sha1

Support serving resources, API calls, and other "non-kweb" services

Currently KWeb only listens on the / path, to which it responds with kweb_bootstrap.html, and the /ws path over which it communicates with the client via websockets.

KWeb should allow these to be configured - in particular listening on other paths for the kweb_bootstrap.html, and also wiring up paths to pass alternate data, perhaps loaded from a file, a resource, or elsewhere.

For a KWeb app, the URL of the page is just one aspect of the page's state, albeit one that can be determined by the user depending on what URL they choose to visit.

Should also investigate browser-history stuff to see how best to incorporate it.

Pre-load DOM instructions to fire instantly on an event

Currently when a listener is attached to an event, when the event fires a message is sent from client to server which responds by executing a callback, that may send further instructions to the client. This may incur a noticeable delay.

We should "pre-load" instructions to the client which execute without delay until some server communication is required, and only then should the client wait on a server message.

It's possible that this could be achieved in a mostly programmer-transparent way through coroutines, I can elaborate if anyone is interested.

Kweb.io broken example links

There appear to be some broken links on the kweb.io site. I didn't see a repo for the site--is this the right place for the issue?

Broken links:

On the More examples page:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.