Express with TypeScript
npm install typescript -s
Inside our package.json
we will put a script called tsc
:
"scripts": { "tsc": "tsc" },
npm run tsc -- --init
npm install typescript -s
Inside our package.json
we will put a script called tsc
:
"scripts": { "tsc": "tsc" },
npm run tsc -- --init
Adding the service worker module
ng add @angular/pwa
Generating a VAPID key-pair
yarn global add web-push
web-push generate-vapid-keys --json
Subscribing to push notifications
src/app/app.component.ts
import { Component } from '@angular/core' import { SwPush } from '@angular/service-worker' import { PushNotificationService } from './pushNotification.service' const VAPID_PUBLIC = 'BNOJyTgwrEwK9lbetRcougxkRgLpPs1DX0YCfA5ZzXu4z9p_Et5EnvMja7MGfCqyFCY4FnFnJVICM4bMUcnrxWg' @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) class AppComponent { title = 'angular-push-notifications' constructor(swPush: SwPush, pushService: PushNotificationService) { if (swPush.isEnabled) { swPush .requestSubscription({ serverPublicKey: VAPID_PUBLIC, }) .then(subscription => { pushService.sendSubscriptionToTheServer(subscription).subscribe() }) .catch(console.error) } } }
src/app/pushNotification.service.ts
import { Injectable } from '@angular/core' import { HttpClient } from '@angular/common/http' const SERVER_URL = 'http://localhost:3000/subscription' @Injectable() class PushNotificationService { constructor(private http: HttpClient) {} public sendSubscriptionToTheServer(subscription: PushSubscription) { return this.http.post(SERVER_URL, subscription) } }
Setting up a new Express project
Installing dependencies
yarn add body-parser cors express web-push
Creating an Express server
const express = require('express') const webpush = require('web-push') const cors = require('cors') const bodyParser = require('body-parser') const PUBLIC_VAPID = 'BNOJyTgwrEwK9lbetRcougxkRgLpPs1DX0YCfA5ZzXu4z9p_Et5EnvMja7MGfCqyFCY4FnFnJVICM4bMUcnrxWg' const PRIVATE_VAPID = '_kRzHiscHBIGftfA7IehH9EA3RvBl8SBYhXBAMz6GrI' const fakeDatabase = [] const app = express() app.use(cors()) app.use(bodyParser.json()) webpush.setVapidDetails('mailto:[email protected]', PUBLIC_VAPID, PRIVATE_VAPID) app.post('/subscription', (req, res) => { const subscription = req.body fakeDatabase.push(subscription) }) app.post('/sendNotification', (req, res) => { const notificationPayload = { notification: { title: 'New Notification', body: 'This is the body of the notification', icon: 'assets/icons/icon-512x512.png', }, } const promises = [] fakeDatabase.forEach(subscription => { promises.push( webpush.sendNotification( subscription, JSON.stringify(notificationPayload) ) ) }) Promise.all(promises).then(() => res.sendStatus(200)) }) app.listen(3000, () => { console.log('Server started on port 3000') })
References
https://malcoded.com/posts/angular-push-notifications/
https://blog.angular-university.io/angular-push-notifications/
https://medium.com/@a.adendrata/push-notifications-with-angular-6-firebase-cloud-massaging-dbfb5fbc0eeb
https://developers.google.com/web/fundamentals/push-notifications/display-a-notification
var mime = require('mime-types') var serveStatic = require('serve-static') app.use(serveStatic(__dirname + '/public', { maxAge: '1y', setHeaders: function (res, path) { if (mime.lookup(path) === 'text/html') { res.setHeader('Cache-Control', 'public, max-age=0') } } }))
app.use(function (req, res, next) { console.log(req.url); if (req.url !== '/app/index.html') { res.header('Cache-Control', 'public, max-age=600s') } next(); }); app.use('/app', express.static(path.resolve(__dirname, './app')));
References
https://stackoverflow.com/questions/45076710/can-i-ignore-few-static-files-in-express-static
https://github.com/expressjs/serve-static/issues/32
res.set('Cache-Control', 'public, max-age=31557600'); // one year
References
https://stackoverflow.com/questions/25462717/cache-control-for-dynamic-data-express-js
npm install express-static-gzip
var expressStaticGzip = require("express-static-gzip"); app.use("/", expressStaticGzip(path.join(__dirname, 'public')));
app.use("/", expressStaticGzip(path.join(__dirname, 'public'), {maxAge : "365d"}));
References
https://www.npmjs.com/package/express-static-gzip
Angular
ng build --prod --aot
app.js in express
var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var compression = require('compression'); var app = express(); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({extended: false})); app.use(cookieParser()); app.use(compression()); app.use(express.static(path.join(__dirname, 'public'), {maxAge: 31536000})); app.get('*', function (req, res, next) { var file = path.join(__dirname, 'public', 'index.html'); res.sendFile(file); }); module.exports = app;
npm install cors
var express = require('express') var cors = require('cors') var app = express() app.use(cors()) app.get('/products/:id', function (req, res, next) { res.json({msg: 'This is CORS-enabled for all origins!'}) }) app.listen(80, function () { console.log('CORS-enabled web server listening on port 80') })
Use gzip compression
var compression = require('compression') var express = require('express') var app = express() app.use(compression())
Cache Assets for a long Time
app.use(express.static(path.join(__dirname, 'public'), { maxAge: '30 days' }));
References
https://expressjs.com/en/advanced/best-practice-performance.html
https://matthewsmith.io/blog/how-to-set-up-cache-busting-in-express
https://varvy.com/pagespeed/cache-control.html
var helmet = require('helmet');
app.use(helmet());
References
https://expressjs.com/en/advanced/best-practice-security.html
var session = require('express-session'); const MongoStore = require('connect-mongo')(session);
app.use(session({ key: 'ERP.Session', secret: '310E56DD8E7C', resave:true, saveUninitialized:true, store: new MongoStore({ url: 'mongodb://localhost/ERP' }) }));
Setting Session Variables
req.session.name = 'Napoleon'; req.session['primary skill'] = 'Dancing';
Reading Session Variables
var name = req.session.name; var primary_skill = req.session['primary skill'];
Updating Session Variables
req.session.skills.push('Baking'); req.session.name = 'Pedro';
Deleting Session Variables
delete req.session.name delete req.session['primary skill'];
Deleting a Session
req.session.destroy();
req.session.destroy(function() { res.send('Session deleted'); });
References
http://expressjs-book.com/index.html%3Fp=128.html
https://github.com/expressjs/session
https://github.com/jdesboeufs/connect-mongo