Skip to content

phurytw/universal-react-redux-typescript-starter-kit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

universal-react-redux-typescript-starter-kit

A minimal starter kit with React, Redux, server side rendering, hot module replacement, and Webpack 2. 100% TypeScript.

Packages used

What you're here for:

What helps those things above:

What is actually not necessary but will most likely be used:

Tooling:

  • cross-env - allows to set NODE_ENV on all platforms

A bit of explanation

Most of the code is the React/Redux application. The action creators and reducers are located in the src/modules directory following the convention proposed here. The root reducer is located in src/reducer.ts.

Everything that is server side is located in src/server.tsx which has a single express application that is responsible for the Hot Module Replacement, the server side rendering, and is also itself a tiny API service for the client app.

npm scripts

ts-node allows TypeScript to be executed without compiling it in the file system. It is used to start the dev server, to compile the webpack bundle, and/or the server application.

TypeScript configurations

The tsconfig.json file is only used for the webpack bundle and debugging. The reason behind this is because we need to define different configurations when compiling webpack or the server or else the server code gets into the webpack bundle and vice versa. The server tsconfig can be found in scripts/build.ts:

let program = ts.createProgram(["./src/server.tsx"], { lib: ["lib.es6.d.ts"], jsx: ts.JsxEmit.React, noEmitOnError: true, noImplicitAny: true, noUnusedLocals: true, sourceMap: true, outDir: "./dist/server", target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS });

However, you may prefer to use a secondary tsconfig.json and run tsc in parralel.

Hot Module Replacement

In your webpack config you can see that when not in production the following entries are added: react-hot-loader/patch and webpack-hot-middleware/client. Because of webpack.optimize.CommonsChunkPlugin they'll be compiled into a separate JavaScript file that I named hot.js unless I'm mistaken...

In src/server.tsx, when not in production we have webpack-dev-middleware and webpack-hot-middleware used by the only express application. They're reponsible of compiling and sending the webpack bundle.

Then finally in src/index.tsx you will see:

if (module.hot) { module.hot.accept("./routes", () => { const App: any = require("./routes").default; render(App); }); }

This is what will be called whenever your webpack bundle is updated. This will re-render your application with the changes.

Server side rendering

In src/server.tsx, the final request handler is where server side rendering is done. First the match method of react-router will get the components to render according to the URL (req.originalUrl) and our defined routes.

In each of our components (i.e. src/components/Text.tsx) that require data to be fetched we have a fetchData static method. These methods will dispatch the necessary data to a newly created Redux store. This method must return a Promise so we can wait for data that needs to be fetched asynchronously with Promise.all.

After the data has been fetched we dispatch an action (setRendered)that will tell the client not to fetch data again (see componentWillMount method in src/components/Text.tsx).

The Helmet.rewind() call returns an object that we can use to write HTML tags with attributes that will be used by react-helmet. If react-helmet is used by any of our component the tags will be updated server side.

We can finally render our page using react-dom's renderToString with the help of react-router's RouterContext and react-redux's Provider. In the final page markup we add a polyfill.io script so we can use fetch client-side. And a script containing our Redux state that will be used when initializing the store client side. serialize-javascript is needed for safety purposes you can read more about it here.

Then finally in /src/index.tsx, we get our Redux state then we initialize our store with it.

Visual Studio Code (VSCode) debugging

You can debug in the VSCode editor by using the debug configurations in the .vscode directory. Start the application with npm debug and start the Node debugger VSCode. It will automatically attach the debugger to your application instance. In order to debug the client application you need to install the vscode-chrome-debug extension, then run Chrome with the --remote-debugging-port=9222 argument and open client application in http://localhost:3000, and then run the Chrome debugger in VSCode.

Now what

API Service

You may most likely want to get rid of the app.get("/api", [...]) in src/server.tsx and use your own API service.

Testing

There is no test in this package to let the choice up to you. If you wish to write tests I recommend that you use ts-node with your test framework CLI. Here's a simple example with mocha:

Install it:

npm i -D mocha 

Add a script with this command to your package.json:

mocha src/**/*.tests.* --compilers ts:ts-node/register,tsx:ts-node/register 

If you have multiple tsconfig.json files you can use them in mocha. First create a file (i.e. ts-node-register.js):

require("ts-node").register({ project: "your_ts_config.json", lazy: true });

Then you can change your test script with this:

mocha src/**/*.tests.* --compilers ts:./ts-node-register.js,tsx:./ts-node-register.js 

Babel

There is no any Babel insanity because it is not required if you have set target to es5 and jsx to react in your tsconfig.json. However, if you wish to use Babel this is what you can do:

Install Babel and friends:

npm i -S babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2 

Then add it after the awesome-typescript-loader like so:

 { test: /\.tsx?$/, use: ["babel-loader", "awesome-typescript-loader"], exclude: /node_modules/ }

You'll need to create a .babelrc file with this (more explanation here)

{ "presets": [ [ "es2015", { "modules": false } ], "stage-2", "react" ], "plugins": [ "react-hot-loader/babel" ] }

About

A minimal starter kit with React, Redux, server side rendering, hot reloading, and Webpack 2. 100% TypeScript.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published