Ok @aseigo here it is as promised, and only 4 weeks delayed !
I pushed this out quickly because it had been sitting in my drafts for a few weeks, so let me know if anything seems off.
Ok @aseigo here it is as promised, and only 4 weeks delayed !
I pushed this out quickly because it had been sitting in my drafts for a few weeks, so let me know if anything seems off.
Awesome! Thanks; will read it today and let you know if I have any feedback. Thanks for writing this up, most usefulā¦
Let me know specifically if there are any areas that Iām glossing over, especially with the JS stuff.
@ChaseGilliam is there a reason why webpack is run as a server instead of emitting static js? Is that related to the bit at the end:
Iāll leave it as an exercise for readers to explore pushing multiple js files to the client and combining Webpackās lazy loading to push files on demand.
If so could you elaborate on that?
Minus webpack, as far as I can tell all thats needed to enable http2 is the updated deps, the cert, and the changed https endpoint config. Neat!
why webpack is run as a server instead of emitting static js
This is just in development mode so that you can make use of code reloading. For production you would use webpack -p
or similar to build production assets.
Minus webpack, as far as I can tell all thats needed to enable http2 is the updated deps, the cert, and the changed https endpoint config.
Right, thatās basically the minimal set of requirements. However, webpack gives you nice tools for splitting your JavaScriot into N small files. This helps you leverage HTTP/sās multiplexing. I didnāt want to go into too much detail on that point, because Webpack 4 will have some major changes, and I want to revisit the topic once their ecosystem has transitioned to their new APIs.
Also, thanks for checking out the guide!
iāve been reading up on http2 push and it needs to be initiated from server. Can you tell me what you were thinking about regarding webpack lazy load and push?
Webpackās lazy load is well suited to pulling js on an as needed basis, but I suppose you could you it for push, Iām just not sure how. In general Iām still thinking through how best use push with Phoenix, and when to use that vs. channels/web sockets.
defmodule Http2TodayWeb.LayoutView do
use Http2TodayWeb, :view
def js_script_tag do
if Mix.env == :prod do
# In production we'll just reference the file
"""
<script src="<%= static_path(@conn, "/js/vendor.js") %>"></script>
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
"""
else
# In development mode we'll load it from our webpack dev server
"""
<script src="https://localhost:8080/vendor.js"></script>
<script src="https://localhost:8080/app.js"></script>
"""
end
end
# Ditto for the css
def css_link_tag do
if Mix.env == :prod do
"<link rel=\"stylesheet\" href=\"<%= static_path(@conn, \"/css/app.css\") %>"
else
"<link rel=\"stylesheet\" type=\"text/css\" href=\"https://localhost:8080/css/app.css\" />"
end
end
end
can be somewhat optimized if you move if
outside of the function
defmodule Http2TodayWeb.LayoutView do
use Http2TodayWeb, :view
js_script_tag =
if Mix.env == :prod do
# In production we'll just reference the file
"""
<script src="<%= static_path(Http2TodayWeb.Endpoint, "/js/vendor.js") %>"></script>
<script src="<%= static_path(Http2TodayWeb.Endpoint, "/js/app.js") %>"></script>
"""
else
# In development mode we'll load it from our webpack dev server
"""
<script src="https://localhost:8080/vendor.js"></script>
<script src="https://localhost:8080/app.js"></script>
"""
end
def js_script_tag, do: unquote(js_script_tag)
# Ditto for the css
css_link_tag =
if Mix.env == :prod do
"<link rel=\"stylesheet\" href=\"<%= static_path(Http2TodayWeb.Endpoint, \"/css/app.css\") %>"
else
"<link rel=\"stylesheet\" type=\"text/css\" href=\"https://localhost:8080/css/app.css\" />"
end
def css_link_tag, do: unquote(css_link_tag)
end
if you care about small performance gains ā¦
Not just a performance cain, but you want to keep Mix.*
calls outside of function calls so they stay at compile-time only. If you deploy a release then Mix will not exist (itās a build system after all) so that would crash if inside a function (you can unquote
it to move it outside the function if necessary). ^.^
Yeah, thatās much more important, didnāt think of that ā¦
@idi527 and @OvermindDL1, thatās a great point. Iāll make a note and update the post soon.
what would that look like in this case? Iāve never used unquote
for that sort of thing.
env = Mix.env()
def func(), do: unquote(env)
probably.
and that works in prod?
When this code gets compiled, Mix.env
still presumably works. And then in prod itās the same as
def func(), do: :prod
So, yes.
Oh, of course. That makes sense. Thanks!
Yeah if you do something like:
def blah() do
IO.inspect(unquote(Mix.env()))
end
Itāll get compiled like:
def blah() do
IO.inspect(:dev)
end
For whatever the environment is.
oh cool. Iāll have to start using that.
Do note, if you ever want to encode something that is not a basic value then youāll need to escape it into the AST, so change the unquote(...)
into being unquote(Macro.escape(...))
, this also means you cannot encode transient values like PIDās and REFās.
I finally got around to updating this to use unquote.
defp env do
unquote(Mix.env())
end
Thanks for the help!