npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rockpack/ussr

v1.9.0

Published

USSR can help you to build Server Side Rendering for your react application.

Downloads

36

Readme

@rockpack/ussr (Universal Server-Side Rendering)

@rockpack/ussr A small library for building SSR applications. Universal in the name says that you can use it with any libraries and approaches for storing state - Redux (thunk, sagas), Mobx, Apollo...

@rockpack/ussr this module is part of the Rockpack project. See more details on the official site.

Articles

Getting Started

Modern JS applications are divided into 2 types:

  • CSR - Client-Side rendering. The application will be displayed only after downloading and executing all the necessary JS code. Until then, the user will see a blank page. It degrades the UX and is bad for SEO.
  • SSR - Server-Side rendering. The auxiliary server doesn't send a blank page, but a page with data. Thus, the user can immediately start working with the application, and the Secondary Server does not give a blank page but a page with data. The user can immediately start working with the application and SEO bots will index the page.

There are 2 problems when building SSR applications

Side effect's issue

For example, in a blog written in React, articles are loaded into the application via an asynchronous request to the server. Articles, in this case, are an important part of the application for the SEO bot to perform high-quality content indexing and for the user to immediately see the page content. This asynchronous piece of code must participate in the SSR. React out of the box can render an application on the server, but without considering asynchronous operations. @rockpack/ussr allows for asynchronous behavior during SSR.

Compilation issue

In production mode, we need to have an artifact for deployment. For these purposes, we need to compile both the client and the backend of the application.

Schematically it looks like this:

Rockpack USSR

  • SSR application consists of two sub-applications - frontend, backend with common logic.
  • NodeJS app runs React app.
  • @rockpack/ussr handles all asynchronous operations.
  • After receiving data from asynchronous operations, the React application is rendered.
  • NodeJS application serves HTML to the user.

The above application is compiled with @rockpack/compiler as minified NodeJS and React applications.

All of the above allows you to organize @rockpack/compiler and @rockpack/ussr.

Using

The simplest example of an SSR application using an asynchronous function via setState

Example: There is a simple application without SSR:

import React, { render, useState, useEffect } from 'react';

const asyncFn = () => new Promise((resolve) => setTimeout(() => resolve({ text: 'Hello world' }), 1000));

export const App = () => {
  const [state, setState] = useState({ text: 'text here' });

  useEffect(() => {
    asyncFn()
        .then(data => setState(data))
  }, []);

  return (
    <div>
      <h1>{state.text}</h1>
    </div>
  );
};

render(
  <App />,
  document.getElementById('root')
);

Let's change this app to SSR:

  1. Installation:

--> @rockpack/compiler is an optional module! If you have your own webpack.config or you want to build it from scratch you can use this approach.

# NPM
npm install @rockpack/ussr --save
npm install @rockpack/compiler --save-dev

# YARN
yarn add @rockpack/ussr
yarn add @rockpack/compiler --dev
  1. Make build.js in the root of project
const { isomorphicCompiler, backendCompiler, frontendCompiler } = require('@rockpack/compiler');

isomorphicCompiler(
  frontendCompiler({
    src: 'src/client.jsx',
    dist: 'public',
  }),
  backendCompiler({
    src: 'src/server.jsx',
    dist: 'dist',
  })
);

The main goal is to create 2 applications client and server with common logic.

  1. Let's separate the general logic from render. Let's create App.jsx, and take out the common part for both Frontend and Backend:
import React from 'react';
import { useUssrState, useUssrEffect } from '@rockpack/ussr';

const asyncFn = () => new Promise((resolve) => setTimeout(() => resolve({ text: 'Hello world' }), 1000));

export const App = () => {
  const [state, setState] = useUssrState({ text: 'text here' });

  useUssrEffect(async () => {
    const data = await asyncFn();
    setState(data);
  });

  return (
    <div>
      <h1>{state.text}</h1>
    </div>
  );
};

In this code, asyncFn is an asynchronous operation that emulates a call to the server.

  • useUssrState is analogue of useState only with SSR support

  • useUssrEffect is analogue useEffect (() => {}, []); for SSR. It works with async logic.

  1. client.jsx should contain part of the application for Frontend
import React from 'react';
import { hydrate } from 'react-dom';
import createUssr from '@rockpack/ussr';
import { App } from './App';

const [Ussr] = createUssr(window.USSR_DATA);

hydrate(
  <Ussr>
    <App />
  </Ussr>,
  document.getElementById('root')
);

The code:

const [Ussr] = createUssr(window.USSR_DATA);

Associates the state executed on the server with the application on the client. For correct work useUssrState on the client

  1. server.jsx should contain the logic of the NodeJS application, for this it is convenient to use the koa/express framework or similar:
import React from 'react';
import express from 'express';
import { serverRender } from '@rockpack/ussr';
import serialize from 'serialize-javascript';
import { App } from './App';

const app = express();

app.use(express.static('public'));

app.get('/*', async (req, res) => {
  const { html, state } = await serverRender(() => <App />);

  res.send(`
  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
      window.USSR_DATA = ${serialize(state, { isJSON: true })}
    </script>
</head>
<body>
    <div id="root">${html}</div>
    <script src="/index.js"></script>
</body>
</html>
`);
});

app.listen(4000, () => {
  console.log('Example app listening on port 4000!');
});

There are 2 important points in this code: 5.1

app.use(express.static('public'));

The server should serve the folder where the build frontendCompiler takes place

5.2

<script>
  window.USSR_DATA = ${serialize(state, { isJSON: true })}
</script>

This code saves the executed state on the server for later continuation of work with it on the client.


Please see "examples" folder - here


The MIT License

MIT