nicessr
Nicessr - ES6-based simple framework for server-side-rendering
Simple server-side-rendering framework for static HTML generation. It lets you render markup using JSX syntax using props provided from server.
Setup
- Create project:
npm init -y
- Install nicessr:
npm install nicessr
- Create
src/pages
directory - Create
index.js
inside, add some code from examples below - Run
npx nicessr start
- Open browser in
http://localhost:9000
Usage
Available commands
start
: Start development server with auto reloadingbuild
: Build production bundleserve
: Serve production bundle (note: You should runbuild
command beforeserve
)export
: Export static HTML and other assets (note: If you use app context, there will not bereq
andres
props)
Examples
You should create pages under src/pages
directory. Page file should look like this:
{ return <h1>Welcome to my home page!</h1>;} ;
Pages should always have default export: function returning html. You can also leverage server-side rendering by creating getInitialProps
exported function. It could be async, example:
{ return number: await resolve ;} { return <p>My favourite number is: $number</p>;} ;
You can also attach functional props to html. There is onMount
hook which will be called after DOM rendering and attaching event listeners. The only argument passed is element that has onMount
hook:
{ return <p = > Hi </p> ;} ;
When page is loaded, <p>
element will be printed in console.
Also you can attach event listeners to components. Event names are as like the names in addEventListener
function.
{ return <button =>Click me</button>;} ;
When you click this button, I'm clicked!
will be printed to console.
You can call useRef
hook provided by nicessr
package. Pass value returned by it to component, and its value will be set with rendered DOM node. Example:
import useRef from 'nicessr'; { let counter = 0; const textRef = ; return <> <p =>counter</p> <button => Click me! </button> </> ;} ;
In example below, textRef.current
value was set to <p>
element during initial render. You can also use ref callback:
<p =>
You can add <head>
tag to your page. Example:
{ return <> <head> <title>My home page</title> </head> <p>This is home page!</p> </> ;} ;
You can include css in your components! Example:
import useRef from 'nicessr'; const textStyles = css` color: red; font-size: 14px; background-color: white;`; { let counter = 0; const textRef = ; return <> <p = => counter </p> <button => Click me! </button> </> ;} ;
There is useForm
hook for convenient collecting form values. It accepts one argument, callback
, which will be called with form values object after successful validation. Example:
import useForm from 'nicessr'; { const formRef handleSubmit = ; // Pass formRef and handleSubmit functions to <form> tag <form = => <div> <label>Name</label> <div> <input ="name" ="text" /> </div> </div> <div> <label>Link</label> <div> <input ="link" ="url" /> </div> </div> <div> <input ="submit" ="Submit" /> </div> </form>;} ;
You can use css tagged template literal for styles. This will be rendered only on server side, and be included in <head>
tag of page. Classname will be as short as possible. Also you can pass array to class
prop of component:
const flexSpaceBetween = css` display: flex; justify-content: space-between;`; const redText = css` color: red;`; { return <div => <p>1</p> <p>2</p> </div> ;} ;
You can import CSS files using import
statements. They will be rendered as <link>
tags in the head of page. Example (you should install Bootstrap first: npm i bootstrap
):
import 'bootstrap/dist/css/bootstrap.min.css'; { return <div ="alert alert-primary" ="alert"> A simple primary alert—check it out! </div> ;} ;
Advanced
dangerouslySetInnerHTML
You can use dangerouslySetInnerHTML
prop of manual setting HTML for node. Note: node with dangerouslySetInnerHTML
must not have any children.
{ return <p ="Hello!" />;} ;
App context
Value returned from getInitialProps
function will be passed as first argument to page component.
There is appContext
instance passed to getInitialProps
function. It contains req
, res
props:
express Request
and Response
objects. You can also extend it by creating src/pages/_app.js
file:
src/pages/_app.js
:
import MongoClient from 'mongodb'; // Dispose is called when _app.js is updated, use it for cleanup.// For example: close connection to database, clearTimeouts, etc. { ctxclient;} // Default export is called only on start and when _app.js is updated.// It should return object that extends app context. { const client = await MongoClient; return client db: client ;}
src/pages/index.jsx
:
// There are { client, db, req, res } props passed to getInitialProps function.// { client, db } are created by init function in _app.js,// { req, res } are express request and response objects { return items: await db ;} { return <p>JSON</p>;} ;
Server-side functions
You can define server-side functions for your page. They will be passed as functions
prop to your page component. Example:
// Note that this function will not be available on client side as like getInitialProps. { // Return object with all functions. They accept application context extended with request and response objects as argument. Return value is sent back to the client. return add: number: a + b ;} { return <button = > Click me! </button> ;} ;
Compilator
There are extra babel plugins ran on builds (check src/compiler/babel/
):
strip-dev-code
: Removesif (process.env.NODE_ENV === 'development')
statements on production bundle (both SSR and client bundles)
Contributing
Check CONTRIBUTING.md
Under the hood
Webpack is used internally for build (check out src/compiler/index.ts
). Pages are built on-demand (only when are requested, look at src/compiler/bundler/entrypoints.ts
), called on server-side using dynamic require
(check out src/ssr/index.ts
).
Lifecycle
-
Init function for app context is called in
_app.js
-
Page component is being imported on server
-
getInitialProps
andserverSideFunctions
are called on server -
default
export of page module is being called on server -
Fibers are rendered to string and final markup is being sent to the client
-
Hydration is being performed on
default
export of page component -
Ref
s are being attached to corresponding DOM nodes -
Event listeners are being attached to DOM nodes
-
onMount
hooks are being called from queue