-
Notifications
You must be signed in to change notification settings - Fork 374
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
Script type module #1682
base: master
Are you sure you want to change the base?
Script type module #1682
Conversation
These two PRs seem like more work than I was expecting for this feature. Correct me if I'm wrong, but you can achieve what you're looking for right now with Hamlet as-is, via something like: let moduleContent = [julius|...|]
toWidget [hamlet|
<script type="module">#{renderJavascript moduleContent}
|] Am I misunderstanding the problem? |
You could probably do that, but I'm not sure how to get something like defaultLayout $ do
[jsModule|
import foo from 'bar';
foo();
|] to work as a widget without a newtype for the ToWidget instances. |
OK, but you've focused on a very specific API design that requires significant changes to two packages, when it seems like there are simpler alternatives available. I'm trying to start off from understanding the actual goals here. Instead, you're showing me a piece of code you want to write and asserting that it requires a |
You're right. This large an API change is almost certainly not the right way to go about this. I probably should have thought it through a bit more before opening the PR... In any case, after more thought, it seems like the simplest way to go about this would be to just make the new quasiquoters -jsModuleSettings :: Q ShakespeareSettings
-jsModuleSettings = do
- toJExp <- [|toJavascript|]
- wrapExp <- [|Javascript . (\js -> "<script type=\"module\">" <> js <> "</script>")|]
- unWrapExp <- [|unJavascript|]
- asJavascriptUrl' <- [|asJavascriptUrl|]
- return $ defaultShakespeareSettings { toBuilder = toJExp
- , wrap = wrapExp
- , unwrap = unWrapExp
- , modifyFinalValue = Just asJavascriptUrl'
- } EDIT: something like this is probably more appropriate asJsModuleUrl :: JavascriptUrl url -> HtmlUrl url
asJsModuleUrl = fmap
(\j -> toHtml $ "<script type=\"module\">\n" <> unJavascript j <> "\n</script>")
jsModuleSettings :: Q ShakespeareSettings
jsModuleSettings = do
settings <- javascriptSettings
asUrl' <- [|asJsModuleUrl|]
return $ settings { modifyFinalValue = Just asUrl' } Thank you for your quick responses so far and for taking the time to look this over. I really appreciate your willingness to add this feature and your work on Yesod as a whole. |
Sure, my pleasure. I'm going to admit that it's been a while since I've looked at this TH code myself, but it looks like what you're providing in your last comment makes a lot of sense. Have you tested if that will work for your use case? I'm not sure if this belongs in Shakespeare or Yesod itself, I could see arguments going either way, and I'm not particularly opinionated. For |
For having an inline The argument for having this functionality in yesod proper would be for it to play better with |
I'm not sure how that's playing out in practice. I would have thought each module file is essentially turning into its own HTML element which is being treated separately. But like I said, I haven't worked on the codebase in a while. |
The example you provided did not compile for me. I got it working with something like this: {-# LANGUAGE QuasiQuotes #-}
module YesodJavaScriptModule where
import Yesod
import Text.Julius
import Text.Blaze
import qualified Data.Text.Lazy as LT
import qualified Data.Text as T
data JavaScriptInjection
= JavaScriptInjection LT.Text
instance ToMarkup JavaScriptInjection where
toMarkup (JavaScriptInjection x) = preEscapedLazyText {-lazyText-} x
{-# INLINE toMarkup #-}
preEscapedToMarkup (JavaScriptInjection x) = preEscapedLazyText x
{-# INLINE preEscapedToMarkup #-}
toJavaScriptModule
:: MonadWidget m
=> ((Route (HandlerSite m) -> [(T.Text, T.Text)] -> T.Text) -> Javascript)
-> m ()
toJavaScriptModule javaScript = do
params <- getUrlRenderParams
let moduleContent = javaScript params
let stuff = JavaScriptInjection . renderJavascript
toWidget
[hamlet|
<script type="module">#{ (stuff moduleContent) }
|]
toJavaScriptImportMap
:: MonadWidget m
=>
( (Route (HandlerSite m)
-> [(T.Text, T.Text)]
-> T.Text)
-> Javascript
)
-> m ()
toJavaScriptImportMap importMap = do
params <- getUrlRenderParams
let moduleContent = importMap params
let stuff = JavaScriptInjection . renderJavascript
toWidget
[hamlet|
<script type="importmap">#{ (stuff moduleContent) }
|] and then using it like this: toJavaScriptModule $ mconcat
[ [julius| console.log("code 1") |]
, [julius| console.log("code 2") |]
, [julius| console.log("code 3") |]
] |
WIP #1681 yesodweb/shakespeare#253
Adding javascript modules via
jsModule/juliusModule/juliusModuleFile
etc. works, but I'm a little stuck on gettingwidgetFile
to work with this. Is adding the extra field toGWData
the best way to go about that or is there some other way that would involve less code duplication? Once that's figured out I'll bump the version number and add some descriptions in the haddocks.