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

Main method launcher #198 #200

Merged

Conversation

stevechy
Copy link
Contributor

@stevechy stevechy commented May 5, 2023

Implementing a launch method to use in main()

#198

/** Launch app instances after DOMContentLoaded.
*/
def launchOnContentLoaded[F[_] : Async](appDirectory: Map[String, () => TyrianAppF[F, _, _]]): Unit = {
val documentReady = new js.Promise((resolve, _reject) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the main <script> tag uses module or defer then it looks like the DOM will be ready when the script is loaded. In that case you could call launch directly.

<script type="module" src="/index.hash1.js"></script>
<script src="/index.hash2.js" nomodule defer></script>

Copy link
Member

@davesmith00000 davesmith00000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really good work! I've left some comments and questions for us to work through.

Apologies for taking too long to come back to you, I've been working on another PR that has just landed. Which unfortunately means you'll need to rebase / update this branch 😬 ...I'm hopeful that it shouldn't bother you too much, but you will need some of this:
#197 (comment)

I'm hoping to cut a release soon and I'd really love to include this change!

"CounterApp" -> (() => CounterApp),
"ChatApp" -> (() => ChatApp)
))
println("")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just ()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh thanks, this it was leftover from debugging, I will remove it


object Main {
def main(args: Array[String]): Unit =
TyrianAppF.launchOnContentLoaded(Map(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to change slightly, people shouldn't be pulling in TyrianAppF, they should be using TyrianApp from the IO or ZIO modules. Maybe we just add a companion object there that delegates to this thing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think also we could find a different name here to launchOnContentLoaded. 🤔

Is TyrianApp.onLoad(Map(..)) descriptive enough?

Would also be good to allow another constructor:

def launchOnContentLoaded[F[_] : Async](appDirectory: (String, () => TyrianAppF[F, _, _]])*): Unit

So that people can omit the Map:

TyrianAppF.launchOnContentLoaded(
  "CounterApp" -> () => CounterApp,
  "ChatApp" -> () => ChatApp
)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's also possible to leave out the thunk syntax somehow? So you just get:

TyrianAppF.launchOnContentLoaded(
  "CounterApp" -> CounterApp,
  "ChatApp" -> ChatApp
)

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I have added the companion objects, changed the method name to onLoad with varargs and removed the thunk syntax.

private def appElementFlags(tyrianAppElement: dom.HTMLElement): Map[String,String] =
val appFlags = for {
(dataAttr, attrValue) <- tyrianAppElement.dataset
if dataAttr.startsWith("tyrianAppFlag")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this prefix a bit large / wordy? In html form it takes up quite a lot of space?
data-tyrian-app-flag-...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could change it to tyrian-flag or flag ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tyrian-flag seems nice?

case Some(appSupplier) =>
appSupplier().launch(tyrianAppElement, appElementFlags(tyrianAppElement))
case _ =>
// Log a warning message?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Even just a println would be fine. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

examples/main-launcher/index.html Outdated Show resolved Hide resolved
@davesmith00000 davesmith00000 requested review from hobnob and bilki May 16, 2023 07:30
@davesmith00000
Copy link
Member

I've approved and run the workflow - please note that we have a couple of flaky http tests at the moment, so if it fails there it isn't you! :)

#199

@stevechy stevechy force-pushed the main-method-launcher-gh198 branch from dcaad10 to a00cbfc Compare May 16, 2023 15:19
@stevechy stevechy force-pushed the main-method-launcher-gh198 branch from a00cbfc to 48fed4a Compare May 16, 2023 15:24
@stevechy stevechy requested a review from davesmith00000 May 16, 2023 15:24
)

def router: Location => Msg =
_ => Msg.NavigateTo
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I did this correctly... just made the update do nothing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfectly valid, although I'd rename the event to Msg.Ignore or Msg.NoOp or something.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is another example taken from the IndigoSandbox object, just if you're interested. This one ignores internal links but follows external ones.

  def router: Location => Msg = Routing.externalOnly(Msg.NoOp, Msg.FollowLink(_))

  def update(model: Model): Msg => (Model, Cmd[Task, Msg]) =
    case Msg.NoOp =>
      (model, Cmd.None)

    case Msg.FollowLink(href) =>
      (model, Nav.loadUrl(href))

https://github.com/PurpleKingdomGames/tyrian/blob/main/indigo-sandbox/src/main/scala/example/IndigoSandbox.scala#L22

Copy link
Member

@davesmith00000 davesmith00000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

I've left more comments: It would be nice to change the data flag name, but everything else is just "if you want to." There's no real blockers here other than it occurs to me that I haven't actually tested it yet, so I should do that when I get a moment, but this is good work and I think it will be appreciated.

)

def router: Location => Msg =
_ => Msg.NavigateTo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfectly valid, although I'd rename the event to Msg.Ignore or Msg.NoOp or something.

TyrianAppF.onLoad(appDirectory: _*)

def launch[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
TyrianAppF.launch(appDirectory: _*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these versions, you can fix the type to IO and ZIO respectively, rather than F.

private def appElementFlags(tyrianAppElement: dom.HTMLElement): Map[String,String] =
val appFlags = for {
(dataAttr, attrValue) <- tyrianAppElement.dataset
if dataAttr.startsWith("tyrianAppFlag")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tyrian-flag seems nice?

)

def router: Location => Msg =
_ => Msg.NavigateTo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is another example taken from the IndigoSandbox object, just if you're interested. This one ignores internal links but follows external ones.

  def router: Location => Msg = Routing.externalOnly(Msg.NoOp, Msg.FollowLink(_))

  def update(model: Model): Msg => (Model, Cmd[Task, Msg]) =
    case Msg.NoOp =>
      (model, Cmd.None)

    case Msg.FollowLink(href) =>
      (model, Nav.loadUrl(href))

https://github.com/PurpleKingdomGames/tyrian/blob/main/indigo-sandbox/src/main/scala/example/IndigoSandbox.scala#L22

…ap. Update flag data-attr to data-tyrian-flag. Fixed the types to IO and ZIO in tyrian-io and tyrian-zio.
@stevechy
Copy link
Contributor Author

@davesmith00000 thank you for the feedback, I have updated the PR and I think I addressed all the key points. I won't be able to come back to this for a couple of days but hopefully this is in good shape now.

Copy link
Member

@davesmith00000 davesmith00000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested it - works great! Thank you very much for all the work. 🙏

@davesmith00000 davesmith00000 merged commit edfa36f into PurpleKingdomGames:main May 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants