-
-
Notifications
You must be signed in to change notification settings - Fork 29
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
Main method launcher #198 #200
Conversation
/** Launch app instances after DOMContentLoaded. | ||
*/ | ||
def launchOnContentLoaded[F[_] : Async](appDirectory: Map[String, () => TyrianAppF[F, _, _]]): Unit = { | ||
val documentReady = new js.Promise((resolve, _reject) => { |
There was a problem hiding this comment.
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>
There was a problem hiding this 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("") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just ()
?
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
)
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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-...
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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? |
There was a problem hiding this comment.
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. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
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! :) |
dcaad10
to
a00cbfc
Compare
… TyrianApp companion objects.
a00cbfc
to
48fed4a
Compare
) | ||
|
||
def router: Location => Msg = | ||
_ => Msg.NavigateTo |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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))
There was a problem hiding this 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 |
There was a problem hiding this comment.
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: _*) |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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))
…ap. Update flag data-attr to data-tyrian-flag. Fixed the types to IO and ZIO in tyrian-io and tyrian-zio.
@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. |
There was a problem hiding this 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. 🙏
Implementing a launch method to use in
main()
#198