Skip to content

Full stack javascript framework with support for typescript and react πŸš€

License

Notifications You must be signed in to change notification settings

mulekick/vittel

Repository files navigation

Vittel

GitHub package.json version GitHub License Last Commit Docker Image Size Docker Pulls

Full-stack unopinionated express powered javascript framework that :

Uses For
typescript tsx Static typing and on-demand compilation for the entire codebase
react Declarative and component-based user interface development
vite HMR and browser auto-reload on file change during development
nodemon Server auto-restart on file changes during development
dotenv Loading environment variables from configuration files
jose cookie-parser Managing stateless client-side sessions with JSON web tokens
formidable Handling file uploads and multipart form data
esbuild Bundling server-side code into builds that run on any modern node.js version
vite postcss Bundling client-side code into builds that run in any TLSv1.2+ compatible browser
jest Running unit tests for server-side business logic
testing-library Running unit tests for individual react components
puppeteer
jest-puppeteer
Running end to end tests through browser automation

Why this

I designed this project to acquire a basic understanding of how different things work together in a self-contained development solution.

βœ… The idea is to create a full-stack development framework following these principles :

  • πŸš€ Remain as generic as possible (no default integration of any framework or library except react).

  • πŸš€ Remain as manageable as possible by relying on a single package.json file.

  • πŸš€ Silo the back-end and frontend during development - vite server and express run in separate processes.

  • πŸš€ Provide extensive capabilities for writing tests (unit, components and e2e tests).

  • πŸš€ Provide typescript support across the entire codebase.

  • πŸš€ Create builds that can be seamlessly packed into a Docker image.

βœ… DX is guaranteed to be smooth and enjoyable.

βœ… All the dependencies included by default are the go-to modules of the ecosystem for their respective usages.

βœ… Scaffold your project and integrate any additional dependency you need in an incremental, controlled way.

Prerequisites

Required software Recommended version
Linux Debian 12 bookworm
GNU Bash shell 5.2.15
Openssl 3.0.11
Node.js 20.0.9
NPM 10.2.3
Docker 25.0.2
Puppeteer compatible browser google chrome / puppeteer defaults

πŸ‘€ Important notes :

  • ⚠️ Running puppeteer on linux requires dependencies usually shipped with any desktop environment.

  • ⚠️ Installing a desktop environment is therefore recommended (I use xfce).

Project scaffolding

  1. Use the following commands to scaffold a new project :
# clone the repository using degit
npx degit https://github.com/mulekick/vittel.git myproject
# cd into your project's folder
cd myproject
# clean install dependencies (important)
npm ci
  1. Optional : create a new key pair for the server (do not change the command arguments) :
# create a private key
openssl ecparam -param_enc named_curve -name prime256v1 -genkey -noout -outform PEM -out .server.key
# create a self-signed certificate
openssl req -x509 -key .server.key -new -outform PEM -out .server.crt -verbose
# use the newly created key pair in development or production :
#  - open a dotenv config file from the .env.files directory
#  - change the value of the APP_PRIVATE_KEY variable to the contents of .server.key.
#  - change the value of the APP_X509_CERT variable  to the contents of .server.crt. 
#  - save the dotenv config file 

πŸ‘€ Important notes :

  • ⚠️ The server uses the key pair to sign / verify the JWTs and for HTTPS (if enabled).

  • ⚠️ If you want to do step 2, I assume you are comfortable with TLS and key pairs management.

  • ⚠️ If you're not, dummy key pairs are provided in the .env files so HTTPS and JWTs work out of the box.

  • ⚠️ In those circumstances, seek assistance on the matter prior to pushing anything in production.

Project file system

.
β”œβ”€β”€ .env.files           
β”‚   β”œβ”€β”€ .env.development       # dotenv config file (development) 
β”‚   └── .env.production        # dotenv config file (production)
β”œβ”€β”€ .vscode                  
β”‚   └── launch.json            # vscode debug configurations (dev, build and tests)
β”œβ”€β”€ dist                      
β”‚   └── *.*                    # react app + express server build
β”œβ”€β”€ dist.test                 
β”‚   └── *.test.ts              # end to end tests files
β”œβ”€β”€ node_modules                     
β”‚   └── *.*                    # ...
β”œβ”€β”€ src  
β”‚   β”‚
β”‚   β”œβ”€β”€ client                 # ====== react app source files ======= 
β”‚   β”‚   β”œβ”€β”€ app
β”‚   β”‚   β”‚   β”œβ”€β”€ *.tsx          # react components
β”‚   β”‚   β”‚   β”œβ”€β”€ *.ts           # non react code (helpers etc) 
β”‚   β”‚   β”‚   └── *.test.ts      # unit / react components tests
β”‚   β”‚   β”œβ”€β”€ public             
β”‚   β”‚   β”‚   └── *.*            # statically served files (served from / in production mode)
β”‚   β”‚   β”œβ”€β”€ scss               
β”‚   β”‚   β”‚   └── *.scss         # scss files for the react app
β”‚   β”‚   β”œβ”€β”€ static
β”‚   β”‚   β”‚   └── *.*            # assets to include in the build (use named imports)
β”‚   β”‚   └── index.html         # main html page (rollup entrypoint) 
β”‚   β”‚
β”‚   β”œβ”€β”€ server                 # ==== express server source files ====
β”‚   β”‚   β”œβ”€β”€ helpers                    
β”‚   β”‚   β”‚   └── *.ts           # business agnostic code
β”‚   β”‚   β”œβ”€β”€ middlewares        
β”‚   β”‚   β”‚   β”œβ”€β”€ *.ts           # express middlewares (implement business logic)
β”‚   β”‚   β”‚   └── *.test.ts      # unit tests for the business logic
β”‚   β”‚   β”œβ”€β”€ routes             
β”‚   β”‚   β”‚   β”œβ”€β”€ routes.ts      # main express router (mounted on VITE_SRV_ENTRYPOINT)
β”‚   β”‚   β”‚   └── *.ts           # express routers to import in routes.ts
β”‚   β”‚   β”œβ”€β”€ uploads             
β”‚   β”‚   β”‚   └── *.*            # uploads folder
β”‚   β”‚   β”œβ”€β”€ config.ts          # express server config file
β”‚   β”‚   └── server.ts          # main express server file
β”‚   β”‚
β”‚   └── interfaces.ts          # === typescript types / interfaces ===
β”‚    
β”œβ”€β”€ .browserslistrc            # browserslist queries for babel, autoprefixer and vite
β”œβ”€β”€ .eslintrc.json             # eslint config for typescript and react / jsx support
β”œβ”€β”€ .postcssrc.json            # postcss plugins used for development and build
β”œβ”€β”€ babel.config.json          # react / typescript support for babel-jest
β”œβ”€β”€ Dockerfile                 # bundle the app and server into a docker image
β”œβ”€β”€ jest-puppeteer.config.json # puppeteer config for e2e tests
β”œβ”€β”€ jest.config.json           # transforms to apply before running tests
β”œβ”€β”€ nodemon.json               # nodemon config
β”œβ”€β”€ package.json               # dependencies for the react app and the express server
β”œβ”€β”€ tsconfig.json              # typescript config
└── vite.config.js             # vite config + entrypoints for the rollup build process

πŸ‘€ Important notes :

  • ⚠️ The build process packs all the react app code as well as its dependencies into a self-sufficient bundle.

  • ⚠️ As a result, it is important to install react app dependencies as dev dependencies.

  • ⚠️ The docker image will be optimized in that it will only embark dependencies needed by the express server.

Available commands

Command Usage
npm run dev Start the project in development mode
HMR and browser auto-reload are enabled
Vite proxies requests to express
npm run list List all files for the current typescript codebase
npm run typecheck Typecheck the entire project against the current typescript configuration
npm run lint Validate the entire project against the current eslint configuration
npm run test:unit Run unit tests and components tests
npm run test:cover Run unit tests and components tests and print coverage report
npm run build Build the react app and the express server
npm run test:e2e Start a puppeteer automated browser and run the end to end test suite
npm run prod Start the project in production mode
Express serves the app bundle
npm run docker:build Create a docker image and packs the build files and the production environment in it
npm run docker:up Start an interactive container from the image
Container's port APP_PORT is mapped to the corresponding host port
npm run docker:down Stop the container

πŸ‘€ Important notes :

  • ⚠️ HTTPS is disabled by default, it can be enabled by setting the APP_ENABLE_HTTPS variable to "true".

  • ⚠️ JWTs won't work in Firefox when starting the project with HTTPS disabled.

  • ⚠️ When starting in development mode, the vite dev server listens at ${ VITE_HOST }:${ VITE_PORT }.

  • ⚠️ When starting in production mode, the express server listens at ${ APP_HOST }:${ APP_PORT }.

Environment variables

  • All environment variables can be configured in the dotenv config files.
Variable Usage
VITE_HOST Vite dev server host
VITE_PORT Vite dev server port
VITE_SRV_ENTRYPOINT Server API root route
APP_HOST Express server host
APP_PORT Express server port
APP_ENABLE_HTTPS HTTPS enabled / disabled
APP_UPLOAD_DIR Server file upload directory
APP_MAX_UPLOAD_SIZE Max size allowed for uploads
APP_PRIVATE_KEY Server private key
APP_X509_CERT Server certificate
APP_COOKIE_NAME Cookie holding the JWT
APP_TOKEN_VALIDITY JWT validity duration in seconds

πŸ‘€ Important notes :

  • ⚠️ Do not touch any variable that's not in this list unless you really know what youre doing.

πŸ“ Dependencies

Module Usage
cookie-parser parse cookies from HTTP requests header
cors serve or reject cross origin requests
dotenv load server environment variables
express node.js web server framework
formidable handle multipart data and file uploads
helmet add security-related headers to HTTP responses
jose JSON web tokens javascript implementation
morgan HTTP logger for express.js

πŸ“ Dev dependencies

Module Usage
@babel/preset-react React and jsx syntax support for babel
@babel/preset-typescript Typescript support for babel
@fortawesome/fontawesome-free Fontawesome free icons package
@fortawesome/fontawesome-svg-core Core svg library for fontawesome
@fortawesome/free-brands-svg-icons Free fontawesome icons (brands family)
@fortawesome/free-regular-svg-icons Free fontawesome icons (regular family)
@fortawesome/free-solid-svg-icons Free fontawesome icons (solid family)
@fortawesome/react-fontawesome Fontawesome 5 react component using svg with js
@jest/globals Allow explicit imports for jest primitives
@mulekick/eslint-config-muleslint Mulekicks's base JS / Node ESLint configuration
@mulekick/pepe-ascii Used as an example of client-side module bundling
@testing-library/jest-dom Custom matchers for react components testing
@testing-library/react React DOM testing utilities
@testing-library/user-event Fire events the same way the user does
@types/(whatever) Typescript type definitions
@typescript-eslint/eslint-plugin Typescript specific linting rules for eslint
@typescript-eslint/parser Typescript support for eslint
@vitejs/plugin-legacy Enable legacy browsers support in vite.js builds
@vitejs/plugin-react The all-in-one Vite plugin for react projects
autoprefixer Postcss plugin that adds vendor-specific prefixes to CSS rules
babel-plugin-transform-import-meta Babel transforms import.meta into legacy code in node.js
eslint-plugin-react React specific linting rules for eslint
eslint-plugin-react-hooks Enforces the rules of hooks in react functions
jest Delightful javascript testing
jest-environment-jsdom DOM test environment for jest
jest-puppeteer Jest preset that enables end-to-end testing with puppeteer
nodemon Watch server files and auto restart on file change
postcss A tool for transforming CSS withΒ JavaScript
puppeteer High-level API to control Chrome/Chromium over the DevTools Protocol
react Javascript library for creating user interfaces
react-dom React entry point to the DOM and server renderers
sass Auto-compile SCSS files to CSS in vite.js builds
terser Required for minification during the vite.js build process
tsx TypeScript Execute: Node.js enhanced to run TypeScript & ESM
typescript Bring static typing to javascript code
vite Next generation froontend tooling
vite-plugin-webfont-dl Extracts, downloads and injects fonts during the build

Footnotes

  • This project is at its third major iteration (it started with plain javascript, then react, now typescript).
  • It is a case of having done this before the new react docs came out :

This is a alt text.