Interactive web apps with react.js on the server - javascript

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.

Related

Update data without reloading [duplicate]

I'm very very new to node.js, but there's actually only one simple thing that I am trying to achieve by learning the language.
I'd like to create a webpage, where by the code in a specific "div" can be hotswapped on the fly to users currently looking at that page. (ie. the div contains some text, but then an image replaces it.)
Ideally, the swap would be executed manually by the the webpage's admin through the click of a button, or some code fired off on the server or something. Regular viewers to the webpage would not be able to do this - they only see the live changes on the page.
real-life example:
live internet broadcast is off-air, therefore the "div" contains "off-air" text.
live hotswap of code happens when broadcast goes on-air, and the viewers of the webpage now see the html5 broadcast player in the "div" instead.
What's the simplest way to go about doing this for a node.js newbie?
Many thanks :)
Take a look at Socket.IO http://socket.io/#how-to-use
when the server decides to broadcast a change use:
io.sockets.emit('update-msg', { data: 'this is the data'});
on the client first connect socket.io and then wait for the "update-msg" event and update your dom:
var socket = io.connect('http://localhost');
socket.on('update-msg', function (msg) {
console.log(msg);
$('#mydiv').html(msg.data)
});
I created a system/methodology to live update (hot reload) front-end code using RequireJS and Node.js. I made sure it worked with both React and Backbone. You can read about it here:
https://medium.com/#the1mills/hot-reloading-with-react-requirejs-7b2aa6cb06e1
the basic steps involved in doing this yourself:
gulp.js watchers listen for filesystem changes
socket.io server in gulpfile sends a message to all browser clients
with the path of the file that changed
client deletes cache representing that file/module, and re-requires
it (using AJAX to pull it from the server filesystem)
front-end app is configured / designed to re-evaluate all references
to the modules that it wishes to hot-reload, in this case, only JS
views, templates and CSS are available to hot reload - the router,
controllers, datastores (Backbone Collections and Models) are not
configured yet. I do suspect all files could be hot reloaded with
the only exception being data stores.

React Server Components Performance on SEO

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.

Gatsby: Re-execute page queries manually

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?).

Display Kafka messages on web page

I have a Java Spring Application with a Tomcat server that listen on kafka topic. I want to display all messages in a real-time mode on the web page. Therefore, when a kafka messages is arrived in the backend I want to see it on my web page. I don't know a good approach to push kafka message directly to the front-end and display it on web page. Is someone could help my with a solution and some examples that could help? Thanks!
I have implemented a system like this in Java for my last employer, albeit not with Spring/Tomcat. It was consuming messages from Kafka and serving them on a web socket to be displayed in the browser. The approach I followed was to use akka-stream-kafka and akka-http for web-socket support. The benefit of that is both are based on akka-streams which makes it an easy fit for streaming data.
While you can embed akka-http in your spring app running inside tomcat, it may not feel the most natural choice any more as spring framework already has its own support for both kafka and websockets. However, if you're not familiar with either, then jumping on the akka approach may be easiest and the core logic goes along these lines (I can't share the code from work so have just put this together from the examples in the docs, not tested):
public Route createRoute(ActorSystem system) {
return path("ws", () -> {
ConsumerSettings<byte[], String> consumerSettings = ConsumerSettings.create(system, new ByteArrayDeserializer(), new StringDeserializer())
.withBootstrapServers("localhost:9092")
.withGroupId(UUID.randomUUID().toString()) //this is so that each client gets all messages. To be able to resume from where a client left off in case of disconnects, you can generate in on the client side and pass in the request
.withProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest")
return handleWebSocketMessages(
Flow.fromSinkAndSourceCoupled(
Sink.ignore(),
Consumer.committableSource(consumerSettings, Subscriptions.topics("topic1"))
.map(msg -> TextMessage.create(msg.record().value()))
)
);
}
}
To expose this route you can follow the minimalistic example, the only difference being the route you define needs the ActorSystem:
final Http http = Http.get(system);
final ActorMaterializer materializer = ActorMaterializer.create(system);
final Flow<HttpRequest, HttpResponse, NotUsed> routeFlow = createRoute(system).flow(system, materializer);
final CompletionStage<ServerBinding> binding = http.bindAndHandle(routeFlow,
ConnectHttp.toHost("localhost", 8080), materializer);
Once you have your messages published to the websocket, the front end will code will of course depend on your UI framework of choice, the simplest code to consume ws messages from javascript is:
this.connection = new WebSocket('ws://url-to-your-ws-endpoint');
this.connection.onmessage = evt => {
// display the message
To easily display the message in the UI, you want the format to be something convenient, like JSON. If your Kafka messages are not JSON already, that's where the Deserializers in the first snippet come in, you can convert it to a convenient JSON string in the Deserializer or do it later on in the .map() called on the Source object.
Alternatively, if polling is an option you can also consider using the off-the-shelf Kafka Rest Proxy, then you only need to build the front-end.

node.js - how to make a simple live page update?

I'm very very new to node.js, but there's actually only one simple thing that I am trying to achieve by learning the language.
I'd like to create a webpage, where by the code in a specific "div" can be hotswapped on the fly to users currently looking at that page. (ie. the div contains some text, but then an image replaces it.)
Ideally, the swap would be executed manually by the the webpage's admin through the click of a button, or some code fired off on the server or something. Regular viewers to the webpage would not be able to do this - they only see the live changes on the page.
real-life example:
live internet broadcast is off-air, therefore the "div" contains "off-air" text.
live hotswap of code happens when broadcast goes on-air, and the viewers of the webpage now see the html5 broadcast player in the "div" instead.
What's the simplest way to go about doing this for a node.js newbie?
Many thanks :)
Take a look at Socket.IO http://socket.io/#how-to-use
when the server decides to broadcast a change use:
io.sockets.emit('update-msg', { data: 'this is the data'});
on the client first connect socket.io and then wait for the "update-msg" event and update your dom:
var socket = io.connect('http://localhost');
socket.on('update-msg', function (msg) {
console.log(msg);
$('#mydiv').html(msg.data)
});
I created a system/methodology to live update (hot reload) front-end code using RequireJS and Node.js. I made sure it worked with both React and Backbone. You can read about it here:
https://medium.com/#the1mills/hot-reloading-with-react-requirejs-7b2aa6cb06e1
the basic steps involved in doing this yourself:
gulp.js watchers listen for filesystem changes
socket.io server in gulpfile sends a message to all browser clients
with the path of the file that changed
client deletes cache representing that file/module, and re-requires
it (using AJAX to pull it from the server filesystem)
front-end app is configured / designed to re-evaluate all references
to the modules that it wishes to hot-reload, in this case, only JS
views, templates and CSS are available to hot reload - the router,
controllers, datastores (Backbone Collections and Models) are not
configured yet. I do suspect all files could be hot reloaded with
the only exception being data stores.

Categories