Monday, August 22, 2022

Setting up Express and Typescript August 2022

To learn express and typescript, I wanted to convert the default express skeleton app into a typescript one. This uses the tutorial link below and only adds minimal changes to the express framework.

https://expressjs.com/en/starter/installing.html

and some help from this url too

https://blog.logrocket.com/how-to-set-up-node-typescript-express/

# sets up package.json
mkdir myexpress; cd myexpress
npm init -y

###
# express
npm install express

# creates an express project using pug templating instead of default jade
npx express-generator --view=pug

npm install

# to start http://localhost:3000/
DEBUG=myapp:* npm start

###
# typescript
# save-dev packages used only during dev and does not need to be deployed to prod
# ts-node is cli/repl for typescript
npm install typescript ts-node --save-dev

# https://devblogs.microsoft.com/typescript/writing-dts-files-for-types/
npm install @types/node @types/express --save-dev

npx tsc --init # creates tsconfig.json

###
# Problems
# 1. convert all the .js files into typescript
# 2. create new directory called dist or built to store the transpiled js
# 3. copy static files into dist
# 4. transpile ts into js
# 5. run the server using `node dist/index.js`
# 6. update package.json and tsconfig.json so that you can run `DEBUG=myapp:* npm start`

## 1. convert all the .js files into typescript

# adapt app.js into app.ts
npm install @types/http-errors @types/cookie-parser @types/morgan

# routes/index.ts

import express from "express";
const router = express.Router();

router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

export default router;

# app.js
import createError from "http-errors";
import express from "express";
import path from "path";
import cookieParser from "cookie-parser";
import logger from "morgan";

import indexRouter from  "./routes/index";
import usersRouter from "./routes/users";
import {NextFunction, Request, Response} from "express-serve-static-core";

const app = express();

// view engine setup
app.set('views', path.join(__dirname, '../views'));

//...

app.use(express.static(path.join(__dirname, '../public')));

//...

// error handler
app.use(function(err: any, req: Request, res: Response, next: NextFunction) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

app.listen(3000, '127.0.0.1');
export = app

## 3. Update the views/public paths used in app.js
#
views and public need to be updated to ../ as app.js will be in ./dist and these two dirs will be one level up. This has been done in the above code snippet.

## 4. transpile cli
# this will search all ts files from the root directory and store the js files into the dist directory with the same hierarchy
npx tsc --outDir dist

## 5. run the server using `node dist/app.js`
With the addition of the last line above app.listen(//...), we can run node server using the `node` command.

## 6. update package.json and tsconfig.json so that you can run `DEBUG=myapp:* npm start`
# tsconfig.json
"outDir": "./dist",                                  /* Specify an output folder for all emitted files. */

# package.json
# this exists
  "scripts": {
    "start": "node ./bin/www"
  },

# edit ./bin/www
var app = require('../dist/app');

# Remove the app.listen line in app.ts as it's not needed any more
app.listen(3000, '127.0.0.1');

# and now it will work using the express way of starting the server
DEBUG=myapp:* npm start

## Bonus
# You can add a build to "scripts" in package.json
"build": "npx tsc"
# or use the cli
`npx tsc --watch`