tqtezos / minter

OpenMinter is dApp framework for enabling the creation and collection of non-fungible tokens (NFTs) on Tezos.
MIT License
192 stars 91 forks source link

Migrate to NextJS #324

Open cpubot opened 3 years ago

cpubot commented 3 years ago

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:

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.

maelswarm commented 3 years ago

wrouter replaced by @next/router

maelswarm commented 3 years ago

@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.

cpubot commented 3 years ago

@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!