NextJS Server-only Render to Reduce Client Bundle Size - javascript

TLDR: Is there a way to signal to NextJS to render a component only on the server (and thus only show the pre-rendered HTML on the client)?
Motivation:
The reason I want to do this is because the render function inside of the component in question runs a lot of (synchronous) Javascript. I'd like for this Javascript to not be included in the client bundle. My desired behavior is that this component is rendered once on the server and the generated HTML is simply displayed on the client; it should never render on the client.
Things that I've tried / don't work:
getServerSideProps
It appears that, even when a page has getServerSideProps, it will still send the Javascript code to the client. My assumption is that this occurs because NextJS (incorrectly) assumes that some state update could possibly occur in the component on the client and therefore the client must have access to the Javascript code to render the component in such an event. Perhaps I'm doing something wrong here?
Static rendering
The page uses dynamic from the URL (imagine something like the delivery status page of a delivery website; there are hundreds of thousands of different deliveries and so it doesn't make sense for them all to be statically rendered)
Conditional Rendering based on typeof window
I don't think this helps with my particular issue as I'd like to skip rendering entirely on the client but still show the component as it was rendered on the server
Thanks so much for any and all help!

Related

Caching of ReactJS [duplicate]

I just have began to study ReactJS and found that it gives you 2 ways to render pages: server-side and client-side. But, I can't understand how to use it together. Is it 2 separate ways to build the application, or can they be used together?
If we can use it together, how to do it - do we need to duplicate the same elements on the server side and client side? Or, can we just build the static parts of our application on the server, and the dynamic parts on the client side, without any connection to the server side that was already pre-rendered?
For a given website / web-application, you can use react either client-side, server-side or both.
Client-Side
Over here, you are completely running ReactJS on the browser. This is the simplest setup and includes most examples (including the ones on http://reactjs.org). The initial HTML rendered by the server is a placeholder and the entire UI is rendered in the browser once all your scripts load.
Server-Side
Think of ReactJS as a server-side templating engine here (like jade, handlebars, etc...). The HTML rendered by the server contains the UI as it should be and you do not wait for any scripts to load. Your page can be indexed by a search engine (if one does not execute any javascript).
Since the UI is rendered on the server, none of your event handlers would work and there's no interactivity (you have a static page).
Both
Here, the initial render is on the server. Hence, the HTML received by the browser has the UI as it should be. Once the scripts are loaded, the virtual DOM is re-rendered once again to set up your components' event handlers.
Over here, you need to make sure that you re-render the exact same virtual DOM (root ReactJS component) with the same props that you used to render on the server. Otherwise, ReactJS will complain that the server-side and client-side virtual DOMs don't match.
Since ReactJS diffs the virtual DOMs between re-renders, the real DOM is not mutated. Only the event handlers are bound to the real DOM elements.
Image source: Walmart Labs Engineering Blog
NB: SSR (Server Side Rendering), CSR (Client Side Rendering).
The main difference being that with SSR, the servers response to the clients browser, includes the HTML of the page to be rendered.
It is also important to note that although, with SSR, the page renders quicker. The page will not be ready for user interaction until JS files have been downloaded and the browser has executed React.
One downside is that the SSR TTFB (Time to First Byte) can be slightly longer. Understandably so, because the server takes some time creating the HTML document, which in turn increases the servers response size.
I was actually wondering the same researching quite a bit and while the answer you are looking for was given in the comments but I feel it should be more prominent hence I'm writing this post (which I will update once I can come up with a better way as I find the solution architecturally at least questionable).
You would need to write your components with both ways in mind thus basically putting if switches everywhere to determine whether you are on the client or the server and then do either as DB query (or whatever appropriate on the server) or a REST call (on the client). Then you would have to write endpoints which generate your data and expose it to the client and there you go.
Again, happy to learn about a cleaner solution.
Is it 2 separate ways to build the application, or can they be used together?
They can be used together.
If we can use it together, how to do it - do we need to duplicate the
same elements on the server side and client side? Or, can we just
build the static parts of our application on the server, and the
dynamic parts on the client side, without any connection to the server
side that was already pre-rendered?
It's better to have the same layout being rendered to avoid reflow and repaint operations, less flicker / blinks, your page will be smoother. However, it's not a limitation. You could very well cache the SSR html (something Electrode does to cut down response time) / send a static html which gets overwritten by the CSR (client side render).
If you're just starting with SSR, I would recommend start simple, SSR can get very complex very quickly. To build html on the server means losing access to objects like window, document (you have these on the client), losing ability to incorporate async operations (out of the box), and generally lots of code edits to get your code SSR compatible (since you'll have to use webpack to pack your bundle.js). Things like CSS imports, require vs import suddenly start biting you (this is not the case in default React app without webpack).
The general pattern of SSR looks like this. An Express server serving requests:
const app = Express();
const port = 8092;
// This is fired every time the server side receives a request
app.use(handleRender);
function handleRender(req, res) {
const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
console.log('fullUrl: ', fullUrl);
console.log('req.url: ', req.url);
// Create a new Redux store instance
const store = createStore(reducerFn);
const urlToRender = req.url;
// Render the component to a string
const html = renderToString(
<Provider store={store}>
<StaticRouter location={urlToRender} context={{}}>
{routes}
</StaticRouter>
</Provider>
);
const helmet = Helmet.renderStatic();
// Grab the initial state from our Redux store
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(helmet, html, preloadedState));
}
My suggestion to folks starting out with SSR would be to serve out static html. You can get the static html by running the CSR SPA app:
document.getElementById('root').innerHTML
Don't forget, the only reasons to use SSR should be:
SEO
Faster loads (I would discount this)
Hack : https://medium.com/#gagan_goku/react-and-server-side-rendering-ssr-444d8c48abfc

Dynamically returning a sitemap with Vue.js

I am working on a vue js project which has multiple tenants. I am trying to find a solution where I can dynamically generate an xml file for each tenant. Tenants are identified by the url, so example.com/sitemap.xml would be one sitemap, tenant 2 would be example1.com/sitemap.xml and a different sitemap. Both of the urls hit the same server but load different data because of their domain. In turn I need to make the sitemap.xml dynamically generated as well.
I have been doing some research and I have used routes in my project but I'm not sure if I can set a route for an actual filename, and if so is it possible to return an xml response straight from vue through javascript. I previously tried something similar for generating html outside of my application. So I had a route call it /test, which would load a component called test, the component would then have javscript code that replaces the html document with some other html. Would this possibly be an approach to use?
https://www.npmjs.com/package/vue-router-middleware
I also found the package above and another similar one, that looks to do what I need by allowing me to intervene between route changes. However, I am not sure if this will allow me to return xml, the example seems to have logic and then end with next(), wondering if instead of calling next I can actually just return the xml document at that point.
Any help would be much appreciated.
Thank you.
If you have a regular Vue app, it is running on the client side not the server side. So for all routes, your webserver returns index.html. Once loaded, vue router initialises on the client and detects the route to show the appropriate view/components.
So a request to example.com/sitemap.xml returns index.html
I would guess that web crawlers are expecting the following header in the response, and the response body of an XML document for sitemaps.
content-type: text/xml;
You may be able to generate on the client side if crawlers run the javascript but I would suggest it is better to generate server side and return plain old XML. Your server side code should be able to generate this and switch based on the tenant.
Then in the server put a special route for /sitemap.xml to not return the vue app

"need" in a Reactjs component

Well, I'm using MERN stack to create a single-page app now. The Start MERN app that I clone from mern.io it contains a Posts example.
I don't know "need" What it is, It's used by PostDetailPage (at line 30) .
enter image description here
Just on a high level, need is generally used when you are doing server side rendering or isomorphic rendering.
One use is that it tells what data the component needs on mount.
So when doing SSR/ISR, the initial page that is rendered is setup by the server only.Whatever action defined in the
need is processed by the server.It is a way to tell the server that these are the things required to do before rendering the page.
May it be data fetching, updating reducers data.
Try to understand how Client Side/Server Side/Isomorphic rendering works.You will get better insight about it.

How can I redraw the ITHit Ajax File Browser in an Angular SPA when I've got all the instantiated parts?

For various reasons I will not go into, I have successfully wrapped the ITHit Ajax File browser inside of an Angular Controller, which itself is loaded and wrapped in an Angular-UI-Router UI-View.
All of the settings are configured through preceding service calls (to support a cloud environment with shifty urls), and I've even gotten through all of my CORS (Cross Origin Request) issues, and we've wired in a custom Oath2 implementation on the DAV server. All of this is successfully working with the ITHit File Browser as a pretty centerpiece for our content-browsing implementation.
As of now, when I navigate certain areas, the Angular-ui-router tweaks the Url, the view responds, and the Angular Controller wrapping ITHit responds to the view change, and (without reloading the view) re-fetches the appropriate DAV url with available IT Hit commands ( e.g. SetSelectedFolderAsync )
Here's my (hopefully simple) challenge: when I navigate to certain areas - Angular-UI-router simply reloads the containing UI-View with new content, but when I return - the ITHit Ajax File Browser does not redraw.
Here are some guidelines to my challenge (ignore-able if you offer something I can work with):
I'd prefer to avoid having to "hide" the ITHit container (because
it's irrelevant and I don't want to have to manage keeping it up to
date as state changes in the view. These changes affect DAV paths). Also I don't want to worry about unnecessary network traffic.
I'd really like to let Angular-UI-Router do its thing with the
ui-view in which the browser is resting.
I'd like to keep
whatever calls need to be made invokable to the Angular Controller
(it's managing authentication, path resolution, and contextual
settings config - which change as users navigate).
Everything (well most important things) generated by the ITHit solution is
stored in a Singleton ('DavBrowserService') - so when I return to
the file-browser view, I have everything stored from the initial
instantiation including:
an instance of ITHit Object
the produced instance of the ITHit.Loader
an instance of the previously produced AjaxFileBrowser.Controller Object (ITHit.oNS.Controller)
an instance of the previously produced WebDavSession Object ( ITHit.oNS.WebDavSession)
With the above in place - I'm hoping that I can simply re-wire these instances back on to the now-returned dom-node ('afb-content-div').
Any help is MUCH appreciated!
UPDATE: The below "answer" while appearing to be functional - indeed was NOT. However, I have worked around this issue by grabbing the DOM instance and storing it memory when the user navigates away, and re-attaching it after the user has navigated back to the appropriate area. This way all of the ITHit Magic is still tied to the right DOM node, and I don't have to worry about the partial re-instantiation weirdness. Seems to be pretty solid now.
I figured it out!!! It looks like if I re-instantiate the controller by calling:
var controllerInstance = new ITHit.oNS.Controller( originalSettingsObj );
Everything rewires magically! I've wrapped the above code with some detection for whether the 'afb-content-div' HTML DOM node has children.
After much digging in the code, it looks like this is the argument object returned to as a parameter to ITHitLoader.oninit callback (From the AjaxFileBrowserLoader instance).
Thanks for playing!

Best practise to give JS its initial dataset on page load

Imagine a page that shows a newsfeed. As soon as a user request said page, we go to the database (or whatever) and get the newsfeed. After the page is already loaded, we also have new news items added dynamically (through ajax/json). This means we effectively have two mechanisms to build a newsfeed. One with our server side language for the initial page request, and one with Javascript for any new items.
This is hard to maintain (because when something changes, we have to change both the JS mechanism and the Server side mechanism).
What is a good solution for this? And why? I've come up with the following scenarios:
Giving javascript an intial set, somewhere in the html, and let it build the initial view when document is ready;
Letting javascript do an ajax request on document ready to get the initial data; or
Keep it as described above, having a JS version and a SS version.
I'm leaning towards the first scenario, And for that I have a followup question: How do you give JS the dataset? in a hidden div or something?
Doing one more AJAX request to get the data isn't really costly and lets you have one simple architecture. This is a big benefit.
But another benefit you seem to forget is that by serving always the same static resources, you let them be cached.
It seems to me there's no benefit in integrating data in your initial page, use only one scheme, AJAX, and do an initial request.
Use a separate news provider to be loaded from page providing data as-is. This will keep things simple and make it load very quickly to be available nearly as fast as any embedded but hidden data set.

Categories

Resources