Migrate to NextJS
Opened this issue · 3 comments
Preface
There are a subset of features planned in OpenMinter's future which will either require or benefit from the project having server side capabilities.
Including, but not limited to:
- Indexing — facilitating filtering / allowlisting which contracts / NFTs are displayed on the site in a performant way (and decoupled from BCD).
- Site crawlability — enabling search engine indexing and metadata scraping (for social sharing, e.g., iMessage, Twitter, Slack, etc)
- Adding support for credit card payments (e.g., Stripe) and other legacy payment platforms
While there aren't many React SSR solutions to choose from, Next.js
is widely popular and generally the first choice for React SSR in the ecosystem.
Next.js is an opinionated React framework which bakes in server-side-rendering (SSR), client/server side routing, a simple API tier, and it is well documented. Not least, it is fairly easy to add to an existing React project without too much migration pain. As such, it is a fairly obvious choice as a solution to address the above use cases.
Migration considerations
State management (redux
)
This codebase uses redux
for state management. Given that the redux
store must be hydrated to render various bits of the application, it must necessarily be hydrated both server-side and client-side (and must be reconciled / kept in sync on both sides). Otherwise, we'll lose site crawlability for redux-connected pages and incur layout thrash (via irreconcilable server and client code rendering).
This is nontrivial, as redux
and Next.js
(or any SSR framework for that matter) do not implicitly interoperate. Fortunately, next-redux-wrapper
exists, and we can use this to simplify the integration. Again, given that redux
doesn't simply "plug in" to Next.js
, it will still be required for the migrator to thoughtfully write the glue-code bits for everything to reconcile correctly.
This will certainly be the most challenging bit of the migration.
Routing (wouter
)
This codebase uses wouter
as its routing solution. Next.js
ships with its own routing solution. The app's routing will need to be migrated over entirely to Next.js
's routing system to leverage all of the SSR goodies. The routing in this application is dead simple, which should make for a really straight-forward migration.
Styling (chakra-ui
)
Styling is handled via chakra-ui
. In any SSR app which employs a css-in-js solution (like chakra
), ensuring styles are extracted and injected into server-side render results is critical to avoiding flash of unstyled content (FOUS) issues. Fortunately, this is trivial to do so with chakra
and next.js
.
Potential lack of module universality
There is always a possibility that a dependency isn't written to support both node
and browser
APIs. However, it is fairly unlikely these days given the ubiquity of server-side-rendered javascript applications. This typically only arises in situations in which the relevant node
and browser
APIs for some set of functionality wildly diverge — quite common in networking (e.g., http clients) or system level operations. Again, the probability is fairly low, but be on the lookout.
wrouter replaced by @next/router
@zachrbrown why is the next-redux-wrapper
needed? I'm not sure I understand.
I've just been using the redux/provider
as an alternative. Seems like less work and cleaner in my opinion.
@maelswarm — redux/provider
and next-redux-wrapper
are solving different use-cases.
The last time I did an integration with Next.js
and redux
, and as far as I can tell from the current documentation, while including a <Provider>
at the pages
level will allow the server-side bits to interact with the redux store, it won't automatically keep the <Provider>
instances between the server and client in sync.
Note this section of the Server Rendering guide in Redux's docs.
The way Next.js
handles this client-server synchronization outside of a redux
context is through special internal treatment of their various data-fetching functions, getStaticProps
and getServerSideProps
. Because the framework controls the server and the client bits, it's able to automatically serialize the server generated props, embed them into the generated HTML as a global variable, and, finally, deserialize + inject these props into the client instance. Otherwise, state isn't implicitly shared between server and client code.
tldr; state that is managed outside of Next.js
's API (e.g., redux
) will not automatically be shared between the client and the server without the explicit handling of such. next-redux-wrapper
is facilitating this client-server synchronization of redux
state.
Again, it has been a little while since the last time I an integration of the two things, so please let me know if you have evidence to the contrary!