
What if NextJS was just... Rust ft Perseus and Sycamore
What if NextJS was just... Rust ft Perseus and Sycamore
https://framesurge.sh/perseus/en-US/
https://sycamore-rs.netlify.app/
Content
0.259 -> Welcome back to Let's Code!
1.614 -> Today, we're gonna go a
2.811 -> level up from Sycamore
4.446 -> and talk about Perseus. Perseus
6.679 -> is that higher level meta
8.314 -> framework on top of Sycamore's
10.004 -> reactive bindings. So you
11.68 -> can think of Sycamore
12.838 -> as the core library with
14.874 -> the reactivity and with the
17.029 -> ability to render to Html.
19.399 -> And you can think of
20.076 -> Per as the higher level
22.229 -> tooling, the scale wall validate,
24.66 -> the server side rendering and
26.294 -> hydrate on the client. But
28.501 -> not just the hydrate functionality,
31.133 -> rather the additional functionality and
33.804 -> framework built ins that make
35.239 -> that work seamlessly. Through your
37.37 -> entire application through multiple routes
39.05 -> and multiple pages. Before we
40.69 -> get directly into Perseus, however,
42.93 -> I wanna take a look
44.024 -> at what it looks like
45.223 -> in Sycamore to do
46.222 -> a couple of the things
47.301 -> that Perseus is doing for
48.54 -> us so that we have
49.658 -> something to compare to from
51.457 -> the raw binding that S
53.055 -> gives us to the high
54.27 -> level metaphor framework that Perseus
55.75 -> is. So here we've got
56.91 -> an example of hydration We've
59.15 -> gotten index as usual the
61.124 -> cargo tom with the dependencies
62.882 -> and the main dot that
64.001 -> has our entire application in
65.239 -> it. Now, a curious thing
66.678 -> about this example is that
67.876 -> it includes the pre rendered
69.93 -> or server side rendered at
71.17 -> Html in the index dot
72.73 -> Html file here. So when
74.45 -> we look in the main
75.13 -> dot, you can see that
76.65 -> there's a render to string
77.984 -> much like react or other
79.223 -> frameworks have a render to
80.541 -> string that accepts a view
82.418 -> that, of course accepts the
83.536 -> context as usual or the
84.695 -> scope and also our application
86.943 -> and renders that to a
87.94 -> string and then logs it
88.737 -> out to the console. If
90.013 -> we look at the console,
91.886 -> we can see that Html
93.561 -> output So this render to
95.053 -> string is actually running anywhere
97.131 -> we run this in this
98.169 -> case in the browser. But
99.608 -> that's just a function call
101.525 -> to show us that the
103.098 -> rendered string does indeed output
104.776 -> what's in the index dot
106.015 -> html file. So if you're
107.533 -> expecting this to be a
108.452 -> full, like, running server and
110.983 -> client, this is not that.
112.298 -> This is just an index
113.653 -> dot Html file with some
115.765 -> Html that was rendered out
117.359 -> and copied into that file.
118.89 -> And then we also call
120.53 -> Ci more And you can
122.05 -> see that second isn't a
123.53 -> lot different than what we
124.49 -> pass to render the string.
126.063 -> Because our app isn't really
127.259 -> doing anything special. We're not
128.934 -> passing in any extra data
130.369 -> dependencies or doing anything that
133.119 -> would require this. If we
135.008 -> look at the index dot
136.203 -> Html, you can see that
137.439 -> there are data attributes specifically
139.909 -> data h k. That include
143.034 -> numeric tree is what I'll
144.113 -> call it. So it's... The
145.591 -> root here is one. And
147.309 -> then if we go down
148.827 -> the list of items, the
150.586 -> Ids change. Now I believe
152.317 -> what's happening is that everything
153.872 -> that is a root element
155.587 -> is getting the root of
157.022 -> one for the Id. So
158.338 -> you'll see one dot on
159.335 -> this paragraph tag inside of
160.531 -> the body you'll see b
161.863 -> r on the... On the
163.22 -> brake tag inside of the
164.217 -> body. And you'll see one
165.494 -> dot two on this brake
166.572 -> tag that's also at the
167.769 -> root. But something like this
169.245 -> d that has additional children
171.256 -> inside of it, will get
172.373 -> the Id too as the
173.81 -> rude Id. And as far
174.968 -> as I can tell, this
175.886 -> occurs because it passes basically
179.333 -> first when assigning these Ids.
181.287 -> So it'll get all the
182.484 -> top level stuff and then
183.761 -> it'll start back at the
184.718 -> top and then it'll go
185.715 -> through the next layer or
187.57 -> all of the ones that
188.17 -> have children and assign those
189.57 -> Ids and then as you
190.85 -> go down that list, the
193.01 -> second Id increments So two
195.224 -> things interesting here, there are
196.662 -> Ids for all of our
197.541 -> elements and there are these
200.258 -> Html comments. Now I believe
201.936 -> that these html comments are
203.946 -> significant. Although I have not
205.501 -> confirmed that, because this reminds
208.529 -> me of the way that
209.645 -> react used to do things.
210.522 -> It was ids and then
212.132 -> it was things like comments,
213.609 -> and they just need a
214.687 -> way to mark different places
216.802 -> in the dom to re
218.998 -> attach to on the client
220.115 -> side. So this all works.
221.37 -> It adds tracks, resets. You've
225.53 -> got a paragraph here that
226.89 -> is not hydrated. So if
228.704 -> we go in and I
230.939 -> can find the disabled Javascript
232.694 -> button and we refresh the
234.969 -> client side only stuff disappears.
237.059 -> But the paragraph that is
238.216 -> not hydrated, which will be
239.972 -> inside of four point zero,
241.01 -> I believe, yeah. Right here.
242.406 -> Is not rendered. Notice that
243.963 -> we still have the five
244.761 -> zero zero d because it's
246.172 -> still in the end in
247.807 -> the Html, but the client
249.761 -> side content inside of it
251.395 -> has not rendered. And we
252.552 -> do see one of those
253.748 -> Html comments here. Sort of
255.958 -> indicating that there's a gap.
257.156 -> So we can re enable
257.995 -> Javascript and we see the
259.913 -> client come back and the
261.311 -> client element show up in
262.11 -> the dom. And this is
263.122 -> all well and good, but
263.879 -> I find the way that
265.034 -> it actually is den denoted
267.265 -> in the code, very interesting.
269.216 -> So We have our app
270.588 -> component, which has the same
271.705 -> function signature in S war
273.222 -> as we've been used to.
275.257 -> We have a view as
276.335 -> the return value, which we've
278.011 -> seen before. And then we
279.382 -> have the S web, no
281.177 -> hydrate and Ci more web,
282.653 -> no Ss sr components. So
285.285 -> this component or any of
286.521 -> the children of this component
287.717 -> won't render on the server
288.93 -> or won't be Ss. So
290.29 -> if we do a render
291.13 -> string, these won't be rendered
292.81 -> and in this case, these
294.13 -> will only be rendered on
295.17 -> the server. Now I don't
296.502 -> know how similar the functionality
298.655 -> that is indicated here is
300.25 -> to something like back server
301.685 -> components, but we'll get into
303.12 -> a little bit more of
303.958 -> that in a second. So
305.449 -> Tl r is s has
307.926 -> server side rendering. S has
309.923 -> client side hydration. S has
312.855 -> components that can render on
314.055 -> the server or the client
315.575 -> exclusively, and all of that
317.095 -> works without touching Perseus at
319.055 -> all. But you would have
320.668 -> to set up your own
321.665 -> server because Ci war doesn't
323.86 -> come with say a web
325.455 -> server kind of thing for
326.812 -> you to attach to. Another
328.662 -> example I found particularly in
330.098 -> lightning is this example here
332.251 -> that I had just his
333.647 -> page visit counter. So if
334.963 -> we refresh this, you can
336.04 -> see it flash right there
337.196 -> for a second. And if
338.21 -> I throttle the network to
339.53 -> slow 3g g, we should
341.17 -> be able to see it
342.61 -> happen a lot slower. So
344.05 -> we're seeing loading and then
345.33 -> we're seeing total visits pop
346.77 -> in. So I'll take that
347.864 -> t off, so I don't
349.022 -> forget leave it enabled for
350.661 -> my normal web browsing front
352.379 -> my normal web browsing. And
353.937 -> if we take a look
354.656 -> at the example here, I
356.589 -> find the example, super interesting.
358.227 -> So this is the example
359.546 -> of basically suspense if you
361.983 -> will. In like a react
364.5 -> term. In our world in
366.912 -> S world, all this means
368.709 -> is that we've got an
369.428 -> a component and we're using
371.186 -> this suspense str to or
373.638 -> the suspense component to fall
375.396 -> back to something else. So
376.875 -> we've got our fall back
377.794 -> specified here. Our fall back
379.112 -> is another component. So it's
380.551 -> another view basically. In this
382.203 -> case, we just have loading.
383.479 -> It could be as far
384.516 -> as I can tell anything.
385.991 -> And then we've got the
386.589 -> business count for when whatever
388.822 -> thing is happening inside of
390.098 -> this business component. Is done.
392.19 -> So in this case, we
393.83 -> have our regular component attribute
395.31 -> macro and all we need
396.59 -> to do to make this
397.95 -> an a component something that
399.59 -> will fetch basically on render
401.882 -> is call it an async
403.081 -> function. Once it's an async
404.679 -> function, the function signature changes
407.076 -> a little bit. We have
408.849 -> anonymous lifetime specified here for
410.883 -> scope, but otherwise, it's the
412.319 -> same function signature that we've
413.636 -> been used to with all
414.673 -> the other ci stuff. The
416.363 -> interesting part being, of course
417.839 -> that we can just run
419.116 -> any async code in here
420.632 -> in this case it's fetch
421.669 -> visits passed with an Id,
423.72 -> which just makes a request
424.92 -> to be rick w and
426.28 -> gets back some Json, which
428.04 -> is d serial decentralized into
429.2 -> a visits str, which we
430.88 -> can see up here as
431.52 -> just a value. So we
432.933 -> fetch visits, we await it,
434.688 -> and then we un or
435.805 -> default. So in this case,
437.64 -> if this function failed, we
440.009 -> would get that default value
441.008 -> of total visits zero because
443.165 -> zero is the default value
444.404 -> for a number. And we
445.283 -> just got a component to
446.002 -> render it. And all we
447.36 -> did was have this async
449.575 -> function just sitting here inside
451.535 -> of our async component, and
453.055 -> it kind of just pauses
454.215 -> for a second, falls back
456.135 -> and then renders. To me,
457.549 -> this is a really elegant
459.027 -> way of encoding this. We
461.904 -> haven't quite gotten to the
463.542 -> full suspense for in the
464.741 -> Javascript ecosystem. And since we
467.229 -> have these async functions in
468.942 -> rust, I really like this
470.575 -> approach for that use case
472.607 -> specifically. But all of that
474.138 -> together brings us to Perseus.
476.655 -> Now we didn't cover a
477.414 -> couple of things in s.
478.493 -> We didn't cover the second
479.451 -> war router, for example, because
481.463 -> Per has its own router.
483.379 -> And if we check the
484.497 -> documentation, there is quite a
486.293 -> bit of documentation here. Even
488.488 -> more when you consider that
490.7 -> this documentation that I'm scrolling
492.62 -> through on the side here
493.7 -> is on top of all
494.94 -> of the Sycamore documentation.
496.62 -> So Perseus is definitely a
498.993 -> framework built on top of
500.47 -> S. Perseus in their introduction
502.705 -> goes over a number of
504.301 -> different features that they support
505.539 -> a number of different rendering
506.816 -> paradigm from server side rendered
509.026 -> to static site generation to
511.381 -> how you implement caching if
512.618 -> you decide to run this
513.456 -> as a server, because if
514.813 -> you run this as a
515.532 -> server, you do then have
517.264 -> to worry about cashing the
518.662 -> actual results. And they say,
520.699 -> and I believe them from
521.778 -> what I've seen that they
523.855 -> support sort of a wider
525.785 -> breadth of these rendering options,
528.257 -> than pretty much any other
529.971 -> framework that currently exists. Including
532.683 -> the ones in Javascript. I
534.094 -> think it's worth going over
535.253 -> those in a separate video
536.451 -> though, so we'll have a
537.809 -> video on rendering strategies in
539.367 -> Per most likely. Today will
541.578 -> be covering the Perseus hello
543.014 -> world. So Perseus itself has
545.327 -> a Cli that they suggest
547.799 -> that you download to build
549.673 -> Per applications. I believe I
552.122 -> read somewhere that they they
553.399 -> do actually make it clear
554.316 -> that you could do this
555.474 -> without the Cli, but the
556.87 -> Cli is just something that
558.586 -> they officially support and suggest
560.836 -> that you use. The only
562.074 -> dependencies that you strictly need
563.67 -> to build a Perseus app
564.748 -> are Perseus itself and S
566.544 -> more? I'm not sure how
569.552 -> specifically these versions correlate. So
572.622 -> for something... In other frameworks
574.775 -> in the Javascript ecosystem, for
576.331 -> example, it can be common
577.806 -> to lock a major version
579.698 -> of a framework like next
581.335 -> to gasp beer or whatever.
582.693 -> To a specific version, a
584.091 -> major version of the underlying
586.223 -> framework react, but Perseus and
588.62 -> ci more both aren't at
590.298 -> one point zero yet. So
592.456 -> it may be that we
594.269 -> need to spend a little
595.068 -> bit more time tracking these
596.706 -> dependencies to make sure that
597.625 -> they stay in sync or
598.904 -> at least compatible. It is
600.542 -> interesting that the documentation specifies
603.234 -> rust twenty eighteen for Perseus
605.389 -> and that they specify six
606.945 -> zero dot seven. Because I
608.422 -> know that Si more currently
609.978 -> is on zero dot eight.
611.709 -> And S zero dot eight,
613.904 -> I believe only supports rest
615.501 -> edition twenty twenty one at
616.818 -> this point. So this hello
618.215 -> world example might be a
619.332 -> little bit behind but that
621.104 -> shouldn't materially affect what we're
622.781 -> going through today. They do
623.98 -> have a note here that
625.697 -> like the examples in S
627.415 -> war. In the past it's
628.507 -> been common to require an
630.062 -> index dot Html. But Perseus
632.974 -> now these days includes a
634.569 -> default index dot Html. So
636.044 -> you don't actually need to
637.041 -> stick one. In your application
638.89 -> if you don't want one.
640.007 -> And in fact, elsewhere in
641.522 -> the documentation, they let you
643.236 -> use Sycamore to generate
645.149 -> that index dot Html. Or
647.318 -> S morris Html generation capabilities,
650.232 -> which is kinda nice. I
651.19 -> like that a lot. So
652.108 -> this is our Perseus app.
653.505 -> We pull in Html Perseus
655.181 -> app template. And we use
656.673 -> the Perseus main macro to
659.306 -> sort of generate the root
660.743 -> of our application. In this
662.179 -> case, we call this function
663.216 -> name, but it can be
664.19 -> called anything because I believe
665.71 -> Per main will rewrite this
667.23 -> name. And the function signature
668.87 -> here looks very similar to
670.19 -> the s function signature. It's
672.524 -> the generic g that we
674.324 -> had before that has to
675.725 -> implement the Html trait. But
677.165 -> in this case, we're returning
678.165 -> a Perseus app with that
679.938 -> generic rather than a s
682.292 -> more view or something like
683.33 -> that. So the Perseus app
684.806 -> has a builder pattern that
686.043 -> we can use. So we
686.802 -> per us new then we
688.134 -> can add as many templates
689.413 -> as we want to. Templates
691.85 -> we'll probably get into more
692.929 -> when we talk about different
694.168 -> methods of rendering the different
696.125 -> ways to build a Perseus
697.94 -> application, but you can basically
699.46 -> think of them as, like
701.1 -> the templates for the pages
702.34 -> that you are going to
702.94 -> render out. In which case,
704.834 -> the template here makes a
705.792 -> lot sense because you've got
707.548 -> a paragraph that says hello
708.785 -> world. So if we go
709.703 -> do this ourselves, we do
710.82 -> cargo news let's call it
712.257 -> Per test. See the end
713.99 -> of that directory and open
715.47 -> a s code instance. I'm
716.95 -> going to completely swap out
718.79 -> the cargo dot and use
721.03 -> just what they gave me
722.23 -> to use. Minimize the counter
724.565 -> example that we had up
725.605 -> before as well since we
726.964 -> don't need to look at
727.605 -> that anymore. So we've got
728.805 -> our dependencies here. We've got
730.324 -> p at zero dot three
731.764 -> dot six. With the hydrate
733.457 -> feature, we got Sycamore
734.735 -> at zero dot seven. I've
736.172 -> got an extension in Vs
737.17 -> code telling me that we
738.208 -> could upgrade two zero dot
739.326 -> h dot two, but I'm
740.204 -> not going to do that
741.202 -> because the tutorial doesn't say
743.095 -> that that's okay yet. So
744.575 -> I can test that out.
746.215 -> Then, of course, in main
747.015 -> dot r, we have to
748.175 -> throw in our template. So
749.335 -> in this case, we don't
750.455 -> only need the Perseus Cli,
752.43 -> we also need W pack
754.03 -> installed. So I'm gonna cargo
755.31 -> install both of them. And
756.59 -> while that happens, I'm going
757.71 -> to fix a stake that
759.364 -> I made, this needs to
760.283 -> be l dot r s,
761.641 -> not main dot r s.
763.079 -> So it told me that
763.679 -> W pack failed because I
765.037 -> already have w back installed.
767.53 -> I'm just gonna leave it
768.29 -> like that and hope that
769.53 -> the version that I have
770.37 -> works. Let me use Perseus
772.09 -> serve instead of trunk serve.
774.384 -> And we can see in
776.258 -> parallel we're getting generating your
777.734 -> app, building your app to
778.93 -> w and building server. So
780.845 -> I believe generating your app
782.24 -> is the static site generation.
784.568 -> Building out to w is
786.043 -> building the client side w
787.398 -> bundle. And then bundle building
789.152 -> server would be building the
790.945 -> server side binary that we
792.101 -> would run. And, of course,
793.194 -> if we open this on
795.111 -> what is effectively local host
796.27 -> eighty eighty, we will see
797.907 -> hello world, which is our
799.505 -> template. Let's change this to
801.037 -> Hello Youtube and see if
802.154 -> it just automatically updates. So
804.27 -> you do need to run
805.946 -> with Perseus dash w to
807.861 -> watch your files so if
808.913 -> I wanted to change hello
810.586 -> world hello Youtube and save
812.259 -> it, that would have to
813.852 -> be with the dash w
815.366 -> flag. And then it is
817.136 -> not refreshing the page. I
818.533 -> have to refresh the page
819.65 -> manually. Although I thought I
821.326 -> saw something about live reload
822.962 -> in the docs. And yeah,
824.375 -> there is. On the left
825.055 -> hand side here, you can
825.855 -> see live reloading. So we'll
827.415 -> have to set that up.
828.535 -> I wonder why that's not
829.575 -> the default. So something that's
830.894 -> super interesting is that we
832.014 -> get this dot Perseus folder
833.829 -> this dot folder in the
835.662 -> name of the framework like
836.938 -> dot next or dot gasp
838.851 -> b or got cash or
840.326 -> whatever it is. Is pretty
841.881 -> common. There usually needs to
843.571 -> be a place for files
845.844 -> to be output. That can
847.24 -> then be used to run
848.596 -> a server or cert files
850.67 -> from disk or something like
852.065 -> that. So this is a
853.079 -> very very common pattern. But
855.079 -> it does usually end up
856.24 -> just being an additional caching
857.8 -> directory. So we can see
858.959 -> in here a bunch of,
859.759 -> like, generated cargo Tunnels. We
861.814 -> can see a lived dot
862.574 -> r in the root. We
864.494 -> can see the builder is
865.334 -> a project, the disc is
867.054 -> a bunch of static files.
868.709 -> In this case, it's the
869.868 -> index dot Html and stuff
871.067 -> like that. But just be
872.226 -> aware that that folder is
873.664 -> there. So they have a
876.181 -> Faq question in this tutorial
878.474 -> Why do I need to
879.113 -> c? Why do we need
880.032 -> per? And it's because that
882.069 -> directory is generating a bunch
884.346 -> of different projects. That then
886.4 -> get built in certain ways
888.08 -> and the Cli controls that
890.64 -> larger process. So it's not
892.839 -> just a cargo build or
894.415 -> a trunk serve. It is
896.575 -> generating and building multiple different,
898.575 -> like, rust projects effectively. It
900.55 -> does say the library reload
901.75 -> server should be running. So
903.51 -> I'm gonna do this again
904.75 -> and see if it pulls
906.07 -> down the new files. It
908.244 -> does say reloading, but it
909.882 -> never actually reload the page.
912.68 -> So maybe there's a bug
913.679 -> in it right now or
914.917 -> maybe there's an issue with
916.196 -> the browser I'm using. Let
918.049 -> me do this. To rule
920.287 -> out any shenanigans with arc
922.604 -> because I have had issues
923.763 -> with arc before on cashing
925.72 -> certain things. Gonna do Youtube
927.73 -> third and save that, which
929.445 -> also didn't work in chrome.
931.12 -> So there's something off about
932.396 -> the live reload because I
934.151 -> believe this is actually generated
936.519 -> So if I reload this,
937.953 -> then we get hello Youtube
939.667 -> third. And it says the
940.902 -> library load server is connected,
942.257 -> but it isn't actually running.
944.384 -> So... Or it isn't actually
945.82 -> working for me. But all
947.895 -> that said, I'm sure that
949.851 -> that is either user error
951.646 -> on my part or a
953.694 -> small bug that can be
954.61 -> easily fixed. So that's an
956.124 -> intro to Perseus There is
957.798 -> a lot to go over
959.312 -> here. So that's why this
961.123 -> video was exceptionally long. I
963.161 -> I think it will be
964.04 -> anyway. I haven't actually edited
965.319 -> it yet, obviously. But we've
967.316 -> got the server side rendering,
968.675 -> the static generation, the live
971.602 -> reload functionality we just saw
972.758 -> the client side Was bundle.
974.592 -> There's a couple of other
976.187 -> build techniques, like data imagination,
978.955 -> that I'm looking forward to
980.795 -> exploring, it seems like Perseus
982.795 -> adds quite a bit on
984.035 -> top of Stick more. So
985.315 -> you would probably not used
987.126 -> to come more by itself.
988.883 -> Although you could. I think
990.799 -> we've explored sick more enough
992.276 -> to note that if you
993.713 -> were building a client side
995.803 -> application that was pretty simple,
997.556 -> you could just use more
998.871 -> by itself to build that
1000.027 -> client side application. But once
1002.259 -> you get to the level
1004.429 -> of needing to do server
1005.827 -> side rendering or needing anything
1007.665 -> fancy like stale while validate
1010.302 -> or dealing with that caching
1012.42 -> or wanting multiple different rendering
1014.989 -> strategies between server side, static,
1017.622 -> and other techniques, then you
1019.138 -> would reach for Perseus. Fairly
1020.868 -> quickly. So I hope you
1021.944 -> enjoyed that video. There probably
1023.299 -> will be more Perseus content
1025.132 -> coming soon. And then on
1026.528 -> top of all of that,
1027.444 -> there's this interesting page that
1029.175 -> only has one plugin at
1030.335 -> the moment, but it's the
1031.895 -> size optimizations plugin and potentially,
1035.095 -> there could be reasons to
1036.615 -> write our own plug. So
1038.388 -> hopefully, we'll be able to
1040.026 -> upgrade second more to zero
1040.985 -> dot eight soon, and we'll
1042.423 -> continue with Perseus. I hope
1043.702 -> you have a great day.
Source: https://www.youtube.com/watch?v=-9zQgLwKJdU