Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hypothetical Tokamak router module #203

Open
MaxDesiatov opened this issue Jul 22, 2020 · 13 comments
Open

Hypothetical Tokamak router module #203

MaxDesiatov opened this issue Jul 22, 2020 · 13 comments
Labels
API design API design and prototyping is needed

Comments

@MaxDesiatov
Copy link
Collaborator

MaxDesiatov commented Jul 22, 2020

I had a look at SwiftWebUI Router and it's great stuff, thank you for developing this @carson-katri! I hope it could be used with Tokamak with slight modifications.

In the meantime, I'm just spitballing some requirements for a new router API that I hope could be designed and implemented at some point in the future:

  1. Ideally it would be compatible with SwiftUI, i.e. you recompile your code for Apple platforms and this router package is able to handle deep links (and maybe even user activities for Handoff too?) seamlessly.
  2. I'm not a fan of routes specified as strings. I wonder if an API could be created that's statically typed, but still provides enough flexibility, maybe something like this?
enum AppRoute: Codable {
  case orders
  case orderDetails(id: Int)
  case admin(AdminRoute)
}

enum AdminRoute: Codable {
  case users
  case userDetails(id: Int)
}

The complication here is that Codable doesn't play well with enums well out of the box. Maybe an alternative could be built (doesn't have to rely on Codable actually) with something like CasePaths?

  1. It should be modular and composable, so that an external package (say an admin user-management package akin to the example above) could be integrated into any app and its routing tree without assuming absolute paths. E.g. I deploy the app to example.com/app, the app itself ideally shouldn't assume absolute paths to allow that deployment, but also if it integrates the user management package URLs like example.com/app/admin/users should work seamlessly too.
  2. Similarly, integrating resources should also compose without any absolute path assumptions in light of Add Image implementation, bump JSKit to 0.9.0 #155 and Add static file support swiftwasm/carton#38 so that packages/targets that declare resoruces with same names don't experience URL clashes. This one's probably harder, but just as important I think.
  3. I'm not sure how it should integrate with the new lifecycle App and Scene types, I think routes belong to views first, but I might be wrong. Actual prototype code might be needed to clarify this.
  4. Static websites support? Hard to specify any requirements for that until we have static HTML rendering actually working.
@MaxDesiatov MaxDesiatov added the API design API design and prototyping is needed label Jul 22, 2020
@j-f1
Copy link
Member

j-f1 commented Jul 22, 2020

Something to consider is whether the API should be top-level (specify your routes all at once in some sort of structure inside App or Scene) or more organic (like React Router which lets you have multiple routers in different parts of the app).

@carson-katri
Copy link
Member

I’ve actually experimented with static rendering and got something up and working fairly quickly. I can make a PR if that’d be of interest...

@j-f1
Copy link
Member

j-f1 commented Jul 22, 2020

Static websites support? Hard to specify any requirements for that until we have static HTML rendering actually working.

It would be pretty useful if there was a way to statically export all the valid routes as HTML files/serverless functions like Gatsby or Next.js do so it could be uploaded to a static host and have proper server-side 404s.

@MaxDesiatov
Copy link
Collaborator Author

MaxDesiatov commented Jul 22, 2020

@j-f1 yes, I think I'd prefer the latter React-Router-inspired approach, otherwise I'm not sure how to make relative URL composability work from points 3. and 4. I mentioned in the issue description.

It would be pretty useful if there was a way to statically export all the valid routes as HTML files/serverless functions like Gatsby or Next.js do so it could be uploaded to a static host and have proper server-side 404s.

Totally, I'd imagine the renderer would traverse all views while generating HTML anyway, it could then record all the routes and split the generated HTML into separate files for separate routes at later stages of the rendering pipeline.

I’ve actually experimented with static rendering and got something up and working fairly quickly. I can make a PR if that’d be of interest...

@carson-katri I'm very interested! I want tokamak.dev to become a proper website with docs and demos and a landing page, all built with Tokamak as much as possible, maybe we could pre-render your TokamakDocs app with that?

@j-f1
Copy link
Member

j-f1 commented Jul 22, 2020

Inspiration: Django, React Router, Vue Router, SwiftUI (based on old react router api), Flask, React Navigation (react native)

@j-f1
Copy link
Member

j-f1 commented Aug 22, 2020

@carson-katri
Copy link
Member

carson-katri commented Aug 22, 2020

I actually have an almost working type-safe Router package. I'm still working on the SwiftUI implementation, and then it should be able to support Tokamak after that (although it relies on PreferenceKey which I don't quite have working in the toolbar branch). Here's what it'd look like:

// Routes.swift
enum AppRoutes: Routes {
  case orders
  case orderDetails(id: Int, OrderRoutes?)
  static let defaultRoute: Self = .orders
}

enum OrderRoutes: Routes {
  case overview
  case bill
  static let defaultRoute: Self = .overview
}

// ContentView.swift
struct ContentView : View {
  var body: some View {
    Router(AppRoutes.self) {
      Route(AppRoutes.orders) {
        List(Order.sampleData) {
          RouterLink($0.name, to: AppRoutes.orderDetails(id: $0.id, .overview)) // Link to a specific Route
        }
      }
      Route(AppRoutes.orderDetails) { order in // enum cases can be used as functions
        Router(OrderRoutes.self) { // Sub Routers
          if case let .orderDetails(id, _) = order {
            Route(OrderRoutes.overview) { OverviewView(id: id) }
            Route(OrderRoutes.bill) { BillView(id: id) }
          }
        }
      }
    }
  }
}

It has a RouteEncoder and RouteDecoder, so you can navigate directly to a route from a String:

AppRoutes.orderDetails(id: 0, .overview) <-> "orderDetails/0/overview"

Any Codable type (besides Collections ATM) can also be used in a route string:

struct Todo: Codable {
  let id: Int
  let task: String
}
TodoRoutes.todo(.init(id: 0, task: "Pick up dinner")) <-> "todo/0/Pick%20up%20dinner"

@MaxDesiatov
Copy link
Collaborator Author

As far as I understand, it would satisfy all the requirements from the original post, this is amazing! 👏

@MaxDesiatov
Copy link
Collaborator Author

MaxDesiatov commented Aug 22, 2020

I wonder if it would make sense as a separate package in a separate repository so that SwiftUI people could use it without adding a dependency on Tokamak? It would need something like

#if canImport(TokamakShim)
import TokamakShim
#elseif canImport(SwiftUI)
import SwiftUI
#else
#error("Add a dependency on the Tokamak repository")
#endif

to allow linking it all without a dependency on Tokamak on Apple platforms (target dependency conditions in Package.swift won't help because swiftlang/swift-package-manager#2749 was merged after SwiftPM 5.3 was branched off).

I have a separate TokamakUI organization ready, maybe it's time to move it all there together with TokamakDocs, so that we don't pollute the SwiftWasm organization?

@carson-katri
Copy link
Member

That's seems like a good idea.

@MaxDesiatov
Copy link
Collaborator Author

Please feel free to create a separate repository under you account in the meantime. I'll transfer the main Tokamak repo to that org and set up the permissions later next week when I get access to my Mac again, and you can transfer yours if you'd like to do so at all when you're ready.

@carson-katri
Copy link
Member

carson-katri commented Aug 24, 2020

I've got the code up at carson-katri/router. There are definitely improvements to be made, so feel free to open issues/PRs there now. Also, it only supports SwiftUI ATM.

@MaxDesiatov
Copy link
Collaborator Author

Just stumbled upon this routing code from the parsing library by the Point-Free folks, seems like an interesting alternative to Codable...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API design API design and prototyping is needed
Development

No branches or pull requests

3 participants