How to do it...

Let's perform the following steps to convert our Express.js main application file to use TypeScript so that we can use the same JavaScript syntax between our frontend and backend applications:

  1. First, we will want to create a new /src directory for all our application files; this makes compilation a bit more straightforward with our source TypeScript files taken from /src, while our compiled JavaScript output will be put into a generated /dist directory:
mkdir src
  1. Then, we will need to convert our app.js file into a new TypeScript-friendly class definition. We'll start with a new /src/App.ts class file, which will import all our needed libraries using the ES6 module style instead of Node.js's usual CommonJS (require) imports. We will also build the beginning of our App class and export a new application instance:
import * as express from 'express'
import * as morgan from 'morgan';
import * as cookieParser from 'cookie-parser';
import * as bodyParser from 'body-parser';
import * as session from 'express-session';
import * as jwt from 'jwt-express';
import * as helmet from 'helmet';
import * as auth from './middleware/auth';
import * as angular from './routes/angular';
import * as api from './routes/api';

import { Request, Response, Application } from 'express';
import { SessionOptions } from "express-session";

const env:string = process.env.NODE_ENV || 'development';
const secret:string = process.env.cookieSecret || 'secret';

class App {
public app:Application;

constructor() {
this.app = express();
}
}

export default new App().app
  1. Next, we will break apart the logical parts of our Express application configuration and make them individual methods that we will run in sequence in our constructor. Some of these setup methods will also require flags for whether we are building in production mode or not. We can simply provide these as options:
...

const isProduction = env === 'production';

class App {
public app:Application;

constructor() {
this.app = express();
this.enableLogging();
this.setupParsing();
this.setupCookies(isProduction);
this.enableSecurity(isProduction);
this.mountRoutes()
;
}

private enableLogging(): void {
this.app.use(morgan('short'));
this.app.use(auth.logger(morgan));
}


private setupParsing(): void {
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: false }));
}


private setupCookies(inProdMode:boolean): void {
this.app.use(cookieParser(process.env.cookieSecret));
this.app.use(jwt.init(process.env.jwtSecret, {

cookieOptions: { httpOnly: false }
}));

let sessionConfig:SessionOptions = {

secret: secret,
resave: false,
name: 'express-project-session',
saveUninitialized: true,
};

if (inProdMode) {

sessionConfig.cookie = {
secure: true,
httpOnly: true,
domain: 'localhost',
expires: new Date(Date.now() + 60 * 60 * 1000)

};
}


this.app.use(session(sessionConfig));
}


private enableSecurity(inProdMode:boolean): void {
if (inProdMode) {
this.app.use(helmet());
}

}

private mountRoutes(): void {
this.app.use('/', angular);
this.app.use('/api', api);
this.app.use(function(req:Request, res:Response) {

var error:Error = new Error('Not Found');
res.status(404).json({

status: 404,
message: error.message,
name: error.name
});
});
}

}

export default new App().app
  1. Our /src/App.ts file will need to import some of our legacy route configurations and middleware. The easiest way to fix this is to simply move those files from their current root location to inside our new /src directory. We can easily continue to use these legacy JavaScript files in conjunction with our new TypeScript versions:
mv ./routes ./src/routes
mv ./middleware ./src/middleware
mv ./models ./src/models
mv ./database.js ./src/database.js
mv ./mocks.js ./src/mocks.js
  1. Now that we have a new App class for our Express application and have moved all our other source files over, we will need to convert our /bin/www launcher script to initialize it. Instead of porting this file directly, we can make a simplified version for now that handles all the key parts required to launch our application. We will create this as a new /src/index.ts file in our source directory:
import app from './App'
import * as db from './database';

const port:number = Number(process.env.PORT) || 3000;

app.listen(port, (error:Error) => {
if (error) {
return console.log(error)
}

return console.log(`server is listening on ${port}`)
});
  1. Although many of our modules have defined type definitions from definitelyTyped, our jwt-express library does not. If we use strict type checking in TypeScript, this omission will throw an exception during compilation. We can remedy this by simply declaring this module to TypeScript to let the compiler know that we are aware of it. To do that, we will simple create a new declarations.d.ts TypeScript definition file in the root of our project, as follows:
declare module "jwt-express";
  1. The default TypeScript looks for a tsconfig.json file in the root of a project to configure how TypeScript should function. We can create a simple configuration to tell TypeScript where our project files are, that we want to compile for Node.js, and where our type definitions, including our custom definitions, are in our project:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"allowJs": true,
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"outDir": "./dist",
"strict": true
},
"typeRoots": [
"./node_modules/@types"
],
"files": [
"./declarations.d.ts"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}
  1. Now, to build our app, we can use the TypeScript command-line application, and then simply launch the built app from the /dist directory:
tsc
node ./dist
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.176.254