Shared Modules between Node and Browser

January 25, 2017 - Søren Alsbjerg Hørup

I am currently prototyping a game built using TypeScript + Node. Node will host some REST API’s + act as HTTP server + act as WebSocket server. The HTTP server part will host a React frontend also built using TypeScript.

What I want is the ability to share TypeScript code between the two parts of the application.Typically, I have always used outFile when working with React in the browser, because I find it very easy to embed into my index.html. This approach is however not feasable on the server side (it can be hacked, but is ugly as hell), since the server needs to import modules from node_modules using the ES6/TypeScript import syntax.

TypeScript supports the ability to emit ES5 JavaScript code using different module types, such as AMD, systemjs, etc. For this project I have experimented in using modules on both the server and the client portion of my code.

My structure is as follows:

  • /client contains all client related .ts files
  • /server contains all my server related .ts files
  • /library contains all my shared .ts files

This setup allows me to easily import modules from library in either client or server:

import someClass from "../library/someClass";

/client and /server has their own tsconfig.json file which tells the compiler on how to emit JavaScript code. On the /client, I have specified that I want to emit ‘AMD’ modules while on the /server I want to emit commonJS used by node.

When building, I invoke tsc on both /client and /server, which will emit more or less the same JavaScript output but where the module format differs. In the browser, I can easily include the AMD module loader and load all my stuff. I can even concatenate the output of the client (for my own modules) using outFile if I make sure to manually load the output in the browser before passing everything to the AMD module loader.

On the server, Node can use commonJS and require to load my modules without any issue, since I built the node part using commonJS as module loader.

The only con I have found is that /library directory gets compile twice, which is OK in my book since we are talking about different run-time environments (node vs the browser).

I need to test this setup a bit more, and see if it scales as well as I hope!