GithubHelp home page GithubHelp logo

maerzhase / ssr3000 Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 0.0 995 KB

react server side rendering

License: MIT License

JavaScript 100.00%
react webpack babeljs ssr isomorphic universal nodejs webpack-concepts server-side-rendering

ssr3000's Introduction

SSR3000

A simple framework for server-rendered react applications.

Build with express and webpack >= 4.0.0.


Getting started

  1. npm install --save ssr3000 react react-dom react-hot-loader express lodash.template

  2. add scripts to your package.json

{
  ...
  scripts: {
    "watch": "./node_modules/.bin/ssr3000-watch",
    "build": "./node_modules/.bin/ssr3000-build",
    "serve": "./node_modules/.bin/ssr3000-serve"
  },
  ...
}
  1. create src, src/serverMiddlware and src/components folders

  2. create client entry: src/main.js

import React from 'react';
import { hydrate } from 'react-dom';
import App from './components/App';

hydrate(
  <App />,
  document.getElementById('root'),
);
  1. create html template to serve: src/serverMiddleware/index.ejs
<html>
  <head>
    <title>SSR3000 App</title>
  </head>
  <body>
    <div id="root"><%= app %></div>
    <% chunks.js.forEach((chunk) => { %><script src="<%= chunk %>"></script><% }); %>
  </body>
</html>
  1. create server entry: src/serverMiddleware/index.js
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Router } from 'express';
import compile from 'lodash.template';
import templateContent from './index.ejs';
import App from '../components/App';

const template = compile(templateContent);

export default (chunks) => {
  const router = new Router();
  router.use((req, res) => {
    res.status(200);
    res.send(template({
      chunks,
      app: renderToString(<App />),
    }));
  });
  return router;
};
  1. create your app e.g. src/components/App.js
import React from 'react';
import { hot } from 'react-hot-loader';

const App = () => (
  <div>
    Hello World
  </div>
);

export default hot(module)(App);
SSR3000 uses hot reloading by default when watching your application. See react-hot-loader for more informations.
  1. npm run watch

Serving static assets

SSR3000 comes with a build in solution to serve your static files. Just create folder called static inside your project root directory. From within your components you can now reference those files with /static/ URLs.

<img src="/static/cat.jpg" />

ssr3000.config.js

In order to extends the webpack configuration you can define a ssr3000.config.js file that exports a function, which returns the modified webpack configuration.

Warning: this file is not going to be transpiled with babel. So you need to write it in vanilla JS and/or features that are supported by your Node.js version
const customConfig = (config, { isServer }) => {
  return {
    ...config,
  }
}

module.exports = customConfig;

Since we are always configuring webpack for the client and the server, this function will get called twice. Once for the server and once for the client. You can distinguish between them with the isServer parameter.

.ssr3000rc

Use the .ssr3000rc to configure SSR3000 for your project. The .ssr3000rc files must be a valid JSON file.

{
  "host": "localhost",
  "port": 8000
}

Options

Option Default Description
host "0.0.0.0" set the hostname for the server
port 9999 set the port for the server

The idea

SSR3000 is build around the principle of having two different entry files for your application:

  • The client entry, which usually calls React.render or React.hydrate
  • The server entry, that handles requests and serves a response to the client

SSR3000 comes with a default webpack configuration that takes away the pain of setting up webpack. If you need to customize the webpack configuration you can do that with the ssr3000.config.js.

ServerMiddleware

It's important to realize that you are responsible for what get's rendered to your client. Without your middleware the server is running but there is no default way of handling responses — therefore without your middleware you will see no output in the browser. It also gives you the greatest flexibilty, because you can provide additional logic e.g. handle routing, serialize inital data to the browser, etc.

Node.js API

ssr3000

ssr3000()

the default export of the SSR3000 module is an ssr3000 instance ready to be initialized.

import ssr3000 from 'ssr3000';

const SSR3000 = ssr3000();

watch

ssr3000.watch(host, port)

The watch function starts the SSR3000 server for development. When the first bundle is ready it will notify that a server has been started. If no host and/or port parameters are provided it will use the default values (0.0.0.0:9999) or use the values from the .ssr3000rc.

import ssr3000 from 'ssr3000';

const SSR3000 = ssr3000();

SSR3000.watch('0.0.0.0', 9999); 

build

ssr3000.build()

The build function will build your application for production.

import ssr3000 from 'ssr3000';

const SSR3000 = ssr3000();

SSR3000.build();

serve

ssr3000.serve(host, port)

The serve function will serve the production build of your application – make sure u have used ssr3000.build() before. If no host and/or port parameters are provided it will use the default values (0.0.0.0:9999) or use the values from the .ssr3000rc..

import ssr3000 from 'ssr3000';

const SSR3000 = ssr3000();

SSR3000.serve('0.0.0.0', 9999);

CLI

SSR3000 comes with a built-in CLI which can be used to watch, build and serve your application from the command line. There three are methods exported to the node_modules/.bin folder. You are free to add npm run scripts to your package.json or execute the cli tools with the relative path instead. You can configure SSR3000 with the .ssr3000rc.

watch

start development server

./node_modules/.bin/ssr3000-watch

build

create a production build

./node_modules/.bin/ssr3000-build

serve

run the production server

./node_modules/.bin/ssr3000-serve

Examples

see examples/simple/ for a simple react application setup. see examples/advanced/ for an example with modified webpack config and react-jss for (server-side) styles

Usage

run npm install from within the examples/simple folder

To demonstrate the usage of the .ssr3000rc the example comes with commands to use the Node.js API and the CLI (npm commands have cli: prefix). You could run both at the same time because CLI and Node.js API start on different ports.

Start development server

To start the dev server, run npm run watch or npm run cli:watch

Build for production

To create a production build run npm run build or npm run cli:build

Serve production build

To start the production server, run npm run serve or npm run cli:serve

A brief digression into webpack

SSR3000 uses weback in the background to bundle your application. You no longer need to provide your own webpack configuration. SSR3000 aims to have a fully functional configuration made for all purpose. If you want to customize the webpack configuration anyway you can do that with the ssr3000.config.js. This section is meant to give you an overview of the most important parts of a webpack configuration. If u want to undestand how webpack works in detail please visit the webpack-website.

Entry

Set the entry points of your application

For full documentation see Webpack Concepts: Entry
{
  target: 'web',
  entry: [
    './src/clientEntry.js',
  ],
  ...
}
{
  target: 'node',
  entry: [
    './src/serverEntry.js',
  ],
  ...
}

Output

Set the output settings for your appliation.

For full documentation see Webpack Concepts: Output
{
  target: 'web',
  output: {
    path: './build/client',
    filename: '[name].[hash:8].js',
    publicPath: '/assets/',
  },
  ...
}
{
  target: 'node',
  output: {
    path: './build/server',
    filename: 'bundle.js',
    publicPath: '/assets/',
    libraryTarget: 'commonjs2',
  },
  ...
}

Loaders

Decide how different file types should be loaded. This is done so u can require any file type in your code.

For full documentation see Webpack Concepts: Loaders
{
  ...
  module: {
    rules: [
      {
        test: /\.js$/,
        include: JS_INCLUDES,
        loader: 'babel-loader',
      },
    ],
  },
  ...
}

Plugins (optional)

While loaders are mandatory for all the file types that you use within your application, plugins are totally optional. "Plugins range from bundle optimization and minification all the way to defining environment-like variables", the webpack docs.

For full documentation see Webpack Concepts: Plugins
{
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
  ],
}
Target

Because our application is getting bundled for the client and for the server the webpack configs need to set the target option accordingly. target: 'node' or target: 'web'

For full documentation see Webpack Concepts: Target

ssr3000's People

Contributors

maerzhase avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

ssr3000's Issues

Make document customizable

Users should be able to add a custom _document.js component to the app. the lib then checks if this component exists and if not falls back to the default document.

Test how to customize babel config

currently babel-loader just receives a default set of presets and plugins. i have to test how it behaves with a project specific .babelrc and document it in the README.

Write tests

There is no single test in the project. I guess having tests would raise confidence into SSR3000

Cleanup Readme

The readme could be re-structured, starting with a table of contents…

Add static export script

Add an export command that exports the app as static html.
This would somehow require an API to specify a HTML template. we have no a document component which we need to make customizable.

Default serverMiddleware

As stated in the readme the user is responsible to have a serverMiddleware setup to serve the responses to the "client". For most simple setups would be nice to have a default middleware that makes it obsolete to specify a middleware by the user unless you really want to modify the default one.

make nice html template

i dont like using the ejs anymore would be nicer if the html template would be a react component aswell.

Inject page when navigating

The pages should only be inject when the user is navigating to another page. When we have this adding a prefetch property is very simple.

Think about multiple entries

It could be interesting to think about multiple entry points. currently we are always just server the application from one single entry point.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.