A Full Stack Javascript Setup that works for me

I like Javscript because it helps me make software that I can share with others easily. What I like about JS is writing software in it. What I don't like is configuring other tools to make javascript work. I would like to stay as far as possible from things like Babel, Webpack etc. What I want is to be able to set at my IDE and type javascript and see the changes on my adjoining browser window ad infinitum.

No or Zero config bundlers like parcel and vitejs come very close to creating this experience for me. Sadly they only enable this on the the frontend(browser).

I normally setup projects that look like this

┌───────────────────────┐
│ README.md             │
│ docker-compose.yml    │
│ docs/                 │
│ src/                  │
│   frontend/           │
│     node_modules      │
│     package.json      │
│     index.js          │
│   backend/            │
│     node_modules      │
│     package.json      │
│     index.js          │
└───────────────────────┘

Starting a project usually looks like this :

docker-compose up
npm run start // in the frontend dir
npm run start // in the backend dir

This was a recurring workflow in my projects to the point that I started observing the pain points that often come up when you repeat the same thing multilpe times.

  1. Confusing between CommonJS and ES6 syntax. While it is great to work on the frontend and backend together the subtle differences in the ES6 syntax I use in the browser code vs the CommonJS syntax I used in my node code would often waste some time. I found myself looking at my other code just to confirm if I was importing things the right way.
  2. Lack of reuse of data models. A big part of my apps client and server exchanging data. I do this by passing JSON around. In the absence of shared model, I find myself constructing requests objects on the client side and parsing them on the backend side without any guarantees from the compiler itself. I understand that I could use something like lerna or yarn workspace to create a directory of shared code and reuse. I got it working too but like I said, I would rather not keep up with these tools and debug when they break.

Digression

I consider myself a tech generalist and as such don't have strong opinions on the programming language I chose. I usually choose whatever will help me be productive on a platform. I have made android apps using Java and Dart, web apps using Javascript, Interactive installations using C++(OpenFrameworks), sound installations using PureData. So at some point I had considered using Elm for my frontend and GoLang for my backend. By the thought of maintaining different model files for the same data put me off. Maybe using ProtoBufs and gRPC in these languages would be worth trying some day.

Along came Deno

What I like about Deno was that it seemed to eradicate that unlike node it came with batteries included. Plus it didn't hurt that it seemed to have picked up a few good ideas from the Go Ecosystem.

  • It has a linter so, bye-bye ESLint
  • It supports tsx/jsx so. bye-bye babel(?)
  • It has an inbuilt watch mode so bye-bye nodemon
  • It has a test runner so bye-bye jest

What I like this time is that hte tooling is taken care of which means I can focus on programming (in Javascript) again.

One thing that I absolutely like is the module system. It uses URLs. Which technically means any publically hosted code can be imported. This has enabled me to setup a github repository with several packages for core functionality that I need. Each time I push my code to this repo, a Github Action kicks off and releases the changed code into modules I can them import in my deno code. Prety sweet.

An outcome of this along with deno being new and hence its ecosystem of packages not being as expansive as npm is that I find myself writing a lot of custom code for low level functionalities for which in the past I would have usually imported an npm module. After struggling to keep up with unusually high number of 3rd party modules over long time, I now default to limiting my imports.

Alright, enough raving for now. Lets wait for another year while I discover flaws in this current setup :)