There is a website, the front is written by ReactJS. For the correct operation of the CEO, SSR is used.
The algorithm is like:
1 page load
the browser opens / foo;
SSR checks if is in the cache /foo does not find it;
SSR renders on the server and executes the react application on request / foo;
SSR puts in the cache HTML, which turned out as a result of the render process / foo;
SSR gives to the browser an HTMLL, which was the result of the render process / foo;
The browser performs asynchronous requests, which are HTML, which is the result of the / foo render (CSS, JS, favicon ...);
the loaded application react "understands that the page has already been drawn and that it's not necessary to perform routing and so on";
The react processes the user's further actions (as in a regular SPA).
Subsequent Updates
the browser opens / foo;
SSR checks if is in the cache /foo does not find it;
SSR renders on the server and executes the react application on request / foo;
SSR puts in the cache HTML, which turned out as a result of the render process / foo;
gives to the browser an HTMLL, which was the result of the render process / foo;
The browser performs asynchronous requests, which are HTML, which is the result of the / foo render (CSS, JS, favicon ...);
the loaded application react "understands that the page has already been drawn and that it's not necessary to perform routing and so on";
The react processes the user's further actions (as in a regular SPA).
The problem is at the front that every time the page is refreshed, routing is started and the entire application is drawn anew, and thus “flicker” appears, that is point 7 does not work.
Question: Is it possible to stop this rendering at a certain moment? Tell the route that it’s not necessary to draw it right now. Maybe there is any popular solution?
You can use lifecycle method shouldComponentUpdate. You can set your own logic in the method for the component to be re-rendered or not. shouldComponentUpdate class method has access to the next props and state before running the re-rendering of a component. That's where you can decide to prevent the re-render by returning false from this method. If you return true, the component re-renders.
Related
So this is a fairly new topic, React Server Components has recently been released, comparing to SSR/Next.js, how does it affect SEO?
Since the component is rendered in the server dynamically when it is requested, it is not really as static as SSR like Next.js, will search engine fail to index those component if I use it?
A demo can found here
We can see that in api.server.js,
async function renderReactTree(res, props) {
await waitForWebpack();
const manifest = readFileSync(
path.resolve(__dirname, '../build/react-client-manifest.json'),
'utf8'
);
const moduleMap = JSON.parse(manifest);
pipeToNodeWritable(React.createElement(ReactApp, props), res, moduleMap);
}
function sendResponse(req, res, redirectToId) {
const location = JSON.parse(req.query.location);
if (redirectToId) {
location.selectedId = redirectToId;
}
res.set('X-Location', JSON.stringify(location));
renderReactTree(res, {
selectedId: location.selectedId,
isEditing: location.isEditing,
searchText: location.searchText,
});
}
I understand this can help to reduce the workload for client's device, since the component are rendered on the server and sent to the client, and that the component can be rendered with the secret stored in server as we can just pass it in as props rather we sending the secret to client.
But if SEO matters, is SSR preferred over React Server Component?
Server Components are complementary to rendering into HTML, not an alternative. The plan is to have both.
Server Components were not released. What was released is an early tech preview in the spirit of sharing our research. This preview doesn’t include an HTML renderer. The api.server.js file from the demo you mentioned contains a comment about this:
const html = readFileSync(
path.resolve(__dirname, '../build/index.html'),
'utf8'
);
// Note: this is sending an empty HTML shell, like a client-side-only app.
// However, the intended solution (which isn't built out yet) is to read
// from the Server endpoint and turn its response into an HTML stream.
res.send(html);
By the time Server Components are officially released, there will be a streaming HTML renderer for the first render.
It’s not built yet.
It should be same from SEO point of view as SPA.
What happens with classic React SPA is, it loads React components (which are essentially JS functions) as part of the JS bundle, and then it starts to request data from the backend in JSON format. After JSON is fetched, it is rendered via the React component functions and inserted into the DOM. Modern crawlers use V8 engine (or maybe smth else if it's Bing :D), they wait until page is fully loaded and all JSON data is loaded and all components are actually rendered - and then it crawls the resulting DOM.
GoogleBot is crawling SPAs that way for at least 3 years now, probably more - so if you were thinking that SSR is essential for SEO, no, it is not. There were plenty of investigations into this, random example: https://medium.com/#l.mugnaini/spa-and-seo-is-googlebot-able-to-render-a-single-page-application-1f74e706ab11
So essentially for crawler it doesn't really matter, how exactly React component is rendered. In case of React Server Components, component function resides on server and is never transferred to the client as part of the JS bundle. So instead of requesting JSON data, the application requests rendered component in some intermediate format (not HTML btw). Result of that is transferred to the client and is getting rendered to the DOM. So the end result is still the same - it's some DOM elements that the bot can crawl.
Do you know if it's possible to re-execute Gatsby page queries (normal queries) manually?
Note, This should happen in dev mode while gatsby develop runs.
Background info: I'm trying to set up a draft environment with Gatsby and a Headless CMS (Craft CMS in my case). I want gatsby develop to run on, say, heroku. The CMS requests a Gatsby page, passing a specific draft-token as an URL param, and then the page queries should be re-executed, using the token to re-fetch the draft content from the CMS rather than the published content.
I'm hooking into the token-request via a middleware defined in gatsby-config.js. This is all based on https://gist.github.com/monachilada/af7e92a86e0d27ba47a8597ac4e4b105
I tried
createSchemaCustomization({ refresh: true }).then(() => {
sourceNodes()
})
but this completely re-creates all pages. I really only want the page queries to be extracted/executed.
Probably you are looking for this. Basically, you need to set an environment variable (ENABLE_GATSBY_REFRESH_ENDPOINT) which opens and exposes a /__refresh webhook that is able to receive POST requests to refresh the sourced content. This exposed webhook can be triggered whenever remote data changes, which means you can update your data without re-launching the development server.
You can also trigger it manually using: curl -X POST http://localhost:8000/__refresh
If you need a detailed explanation of how to set .env variables in Gatsby just tell me and I will provide a detailed explanation. But you just need to create a .env file with your variables (ENABLE_GATSBY_REFRESH_ENDPOINT=true) and place this snippet in your gatsby-config.js:
require("dotenv").config({
path: `.env.${activeEnv}`,
})
Of course, it will only work under the development environment but in this case, it fits your requirements.
Rebuild for all is needed f.e. when you have indexing pages.
It looks like you need some logic to conditionally call createPage (with all data refetched) or even conditionally fetch data for selected pages only.
If amount (of pages) is relatively not so big I would fetch for all data to get page update times. Then in loop conditionally (time within a few minutes - no needs to pass parameter) call createPage.
If develop doesn't call 'createPage' on /__refresh ... dive deeper into gatsby code and find logic and way to modify redux touched nodes.
... or search for other optimization techniques you can use for this scenario (queried data cached into json files?).
I'm looking for web framework for interactive, real-time web apps without writing the Client (Browser), everything will be done by the Server.
There's such framework - LiveView in Phoenix (Elixir/Erlang), see demos below. I'm looking for something similar in JavaScript/TypeScript or Ruby.
How it works, it's better to demonstrate by example. Let's imagine we already have such framework in JavaScript and building an Autocomplete component. It would look almost like React.JS, but with the huge difference - it will be run on the Server:
class Autocomplete extends MagicServerSideReactComponent {
state = {
query: '',
suggestions: []
}
async search(e) {
const query = e.target.value
// This whole component runs on the Server, not in the Browser.
// So it has full access to the Server infrastructure and Database.
const suggestions = await db.find(`select like '${query}'`)
this.setState({ query, suggestions })
}
render() {
return <div>
<input value={this.state.query} onKeyPress={this.search}/>
{this.state.suggestions.map((name) => <div>{name}</div>)}
</div>
}
}
How it works:
When rendered first time:
- Autocomplete component get rendered on the Server and final HTML sent
to the Browser.
The Server remembers the `state` and the Virtual DOM - i.e. it's a
statefull Server, not usual Stateless node.js Server.
- Browser gets the HTML and renders it into DOM.
When user type something in the input:
- Browser serializes the Event and sends it to the Server,
something like `{ method: 'Autocomplete.search', event: '...' }`
- Server get the serialized Event and the previously stored Virtual DOM
for the given Web Page.
Then Server process the Event, and as a result the Virtual DOM
on the Server gets updated.
Then Server finds out the difference between the new and old Virtual DOM
and generates the DIFF.
Then Server sends the DOM DIFF to the Browser
- Browser gets the DOM DIFF and modify its DOM.
And the user see its Web Page updated with the search suggestions.
Do you know any such web frameworks in JavaScript or Ruby?
Please don't suggest frameworks that do something like that - but where you have to mutate DOM manually. Virtual DOM on the Server is important because it allows to update DOM automatically. It doesn't have to be exactly like React.JS but it should update DOM automatically, like React does.
P.S.
Why? Because of the first law of distributed systems - "Don't build distributed systems". It's simpler to build web app as one instead of distributing it into client and server.
Latency - yes, nothing is free, you have to pay for the simplicity and the latency will be the price. The interactions would be delayed - to travel to the server and back.
Performance - yes, Server is not stateless anymore, it's stateful, runs Virtual DOM and consume more resources.
You can take a look at marko by ebay (https://markojs.com/docs/server-side-rendering/) but I don't think you can find a framework/library with all your requirements.
Because of the first law of distributed systems - "Don't build distributed systems". It's simpler to build web app as one instead of distributing it into client and server.
The code you send to user with react or any other single page application framework is defining view. So you shouldn't consider it as a system. It's just html, css, js + user's data
Virtual DOM on the Server is important because it allows to update DOM
automatically.
Why the goal is to update DOM? DOM is just a view of your state/data. And your frontend application is just a mapper/hash function from your state to DOM. So if you only have your state in your server, you kind of have your DOM as well.
If you don't want to write both server and client, but still you want to have fancy frontend features with thousands of open source repos, you can try react + firebase.
I'm using Angular 5 for building a web application and would like to know if I can re-initialize the entire application OR use something like:
ApplicationRef.tick();
to execute all the changes that happens after a specific event. The event is my scenario is authentication token renewal, because for some reason my application's change detection starts breaking unless I run each action inside
NgZone.run()
(I'm using ADAL for authentication in case anybody is interested), but when the token is renewed (using a hidden iframe) the application change detection, routing, etc starts breaking. But when the page is refreshed it starts working perfectly fine till the next time token expires and ADAL has to create an iFrame to renew the token. So I was thinking if at least I could re-initialize the application after the token is renewed so that user doesn't have to refresh the application manually (till I find a more solid solution).
You can call the change detection explictly like below.
constructor(private changeDetector: ChangeDetectorRef) {
this.someEvents.subscribe((data) => {
this.changeDetector.detectChanges();
} );
}
https://angular.io/api/core/ChangeDetectorRef
It's mandatory, if you are calling any third party API or executing third party library Codes. We need to manually call ngzone.run(), which will internally call ApplicationRef.tick() to notify angular to perform change detection from Application root component to the child component (i.e whole application).
ngZone.run(()=>{
// Adal callback Function
});
If you are need to trigger change detection only to the current component and their childrens (not whole application). You can use any one option.
1) setTimeout(()=>{}, 0);
2) this.cdr.detectChanges();
3) For Components with OnPush Change Detection Stratergy, you can call this.cdr.markForCheck() inside setTimeout();
setTimeout(()=>{
this.cdr.markForCheck();
}, 0);
I'm using Meteor to create dynamic client-side interfaces to a server which is tightly coupled to an external hardware system (i.e., a robot). The server can be in one of three different states (A/B/C), but takes a while to transition between the three states. Depending on which state it is in, I want the client UIs to display a different screen.
I have approached this problem by storing the server state in a Meteor collection and publishing this state variable to all connected clients. A client can call a Meteor method to ask the server to change state (e.g., A->B). As a result, once the server has changed state, the new screen is displayed on the client. I'm using this state variable in client-side templates like this:
<template name="root">
{{#if equals server.state "A"}}
{{> UI_for_state_A}}
{{/if}}
{{#if equals server.state "B"}}
{{> UI_for_state_B}}
{{/if}}
etc.
</template>
However, the state transition on the server may take upwards of 10 seconds to complete. During this time, the client is still displaying the old screen. The client UI feels extremely unresponsive. I have also tried having the server update the state variable in the collection at the beginning of the state transition, but this causes the client to switch to the new screen before the server is ready, meaning none of the data is yet populated or available for the new screen.
What I would like to have is for the client to display a "loading" page while the server is in transition, so that a user knows something is going on, but isn't allowed to click any buttons during the transition.
What's the best practice in Meteor for doing this kind of UI synchronization?
Update: there can be multiple connected clients, which all must be synchronized with the server's state. In addition the server can change its state due to external factors, not necessarily on a client event. All these state updates need to be propagated to all clients.
It sounds like you just need to introduce a third, loading state. Set the value of the state in the server collection to this loading state before starting the state transition, and then set it to the final, changed state upon completion.
Note that your app might still feel a little sluggish on noticing the loading state - so you should define method stubs on the client that simply set the state:
if (Meteor.isClient) {
Meteor.methods({
yourMethodName: function() {
States.insert({state: "loading", timestamp: Date.now()}); // or however you would set the state on the server
}
});
}
This will allow your methods to use latency compensation, so the client will immediately enter the loading state rather than waiting for the server to send a publication update.
This is a typical example of a two-phase-commit strategy. It is often used in database transactions, but can be applied to any state machine.
Basically, you actually have the intermediate states and need to store and reference to those as well.
Please have a look at the mongodb two phase commit tutorial for an example.
There is also a third party meteor package on atmosphere that wraps a good state-machine library.