I'm converting an Express.js API to Typescript, that has a client server react-scripts counterpart. The Express.js API is reachable under port 5000 and the client via port 3000. To handle requests between the two servers, the project uses the cors package (https://www.npmjs.com/package/cors) as a middleware.
When I run my to JavaScript compiled files, the requests from the client are blocked by the CORS policy of my browser.
Access to fetch at 'http://localhost:5000/prs?username=mygithubuser' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
When I run the old code (pre-Typescript conversion, aka original JavaScript files), it works without problems. There are not many changes to the code (in api/index.ts), so I am clueless why it blocks the request.
This is the old api/index.js (working)
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const dotenv = require('dotenv');
const setupGithubApi = require('./setupHelpers/setupGithubApi');
const setupGitlabApi = require('./setupHelpers/setupGitlabApi');
const setupErrorHandling = require('./setupHelpers/setupErrorHandling');
const PrController = require('./controllers/pr');
const path = require('path');
const compression = require('compression');
const start = () => {
// Load environment variables from .env file
dotenv.config();
const app = express();
const shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
};
const githubApi = setupGithubApi();
const gitlabApi = setupGitlabApi();
const port = process.env.PORT || 5000;
app.set('port', port);
app.set('github', githubApi);
app.set('gitlab', gitlabApi);
setupErrorHandling(app);
app.use(express.static(path.join(__dirname, '../build')));
app.use(bodyParser.json());
const corsOptions = {
origin: process.env.REACT_APP_HOSTNAME,
};
app.use(cors(corsOptions));
app.use(
compression({
filter: shouldCompress,
})
);
app.get('/prs', PrController.index);
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
});
app.listen(port, () => {
console.log(`Express server listening on port ${port}`);
});
};
module.exports = start;
This is the Typescript version, api/index.ts (returning cors error)
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import dotenv from 'dotenv';
import path from 'path';
import compression from 'compression';
import setupGithubApi from './setupHelpers/setupGithubApi';
import setupGitlabApi from './setupHelpers/setupGitlabApi';
import setupErrorHandling from './setupHelpers/setupErrorHandling';
import PrController from './controllers/pr';
const start = () => {
// Load environment variables from .env file
dotenv.config();
const app = express();
const shouldCompress: compression.CompressionFilter = (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression.filter(req, res);
};
const githubApi = setupGithubApi();
const gitlabApi = setupGitlabApi();
const port = process.env.PORT || 5000;
app.set('port', port);
app.set('github', githubApi);
app.set('gitlab', gitlabApi);
setupErrorHandling(app);
app.use(express.static(path.join(__dirname, '../../build')));
app.use(bodyParser.json());
const corsOptions = {
origin: [process.env.REACT_APP_HOSTNAME],
};
app.use(cors(corsOptions));
app.options('*', cors(corsOptions));
app.use(
compression({
filter: shouldCompress,
})
);
app.get('/prs', PrController.index);
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../../build', 'index.html'));
});
app.listen(port, () => {
console.log(`Express server listening on port ${port}`);
});
};
module.exports = start;
When compiled into api/build/index.js (returning cors error)
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const body_parser_1 = __importDefault(require("body-parser"));
const cors_1 = __importDefault(require("cors"));
const dotenv_1 = __importDefault(require("dotenv"));
const path_1 = __importDefault(require("path"));
const compression_1 = __importDefault(require("compression"));
const setupGithubApi_1 = __importDefault(require("./setupHelpers/setupGithubApi"));
const setupGitlabApi_1 = __importDefault(require("./setupHelpers/setupGitlabApi"));
const setupErrorHandling_1 = __importDefault(require("./setupHelpers/setupErrorHandling"));
const pr_1 = __importDefault(require("./controllers/pr"));
const start = () => {
// Load environment variables from .env file
dotenv_1.default.config();
const app = (0, express_1.default)();
const shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
return false;
}
return compression_1.default.filter(req, res);
};
const githubApi = (0, setupGithubApi_1.default)();
const gitlabApi = (0, setupGitlabApi_1.default)();
const port = process.env.PORT || 5000;
app.set('port', port);
app.set('github', githubApi);
app.set('gitlab', gitlabApi);
(0, setupErrorHandling_1.default)(app);
app.use(express_1.default.static(path_1.default.join(__dirname, '../../build')));
app.use(body_parser_1.default.json());
const corsOptions = {
origin: [process.env.REACT_APP_HOSTNAME],
};
app.use((0, cors_1.default)(corsOptions));
app.options('*', (0, cors_1.default)(corsOptions));
app.use((0, compression_1.default)({
filter: shouldCompress,
}));
app.get('/prs', pr_1.default.index);
app.get('/*', (req, res) => {
res.sendFile(path_1.default.join(__dirname, '../../build', 'index.html'));
});
app.listen(port, () => {
console.log(`Express server listening on port ${port}`);
});
};
module.exports = start;
This is the tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"noUnusedLocals": false,
"outDir": "./build"
},
"include": [
"./**/*.ts"
]
}
I don't know what exactly causes this error, since cors seems to be imported correctly, when I log it out. Also the value of process.env.REACT_APP_HOSTNAME is set correctly, to 'http://localhost:3000', in the logs.
The full code is available here:
Typescript Version (https://github.com/vincentrohde/hacktoberfest-checker)
Original (https://github.com/jenkoian/hacktoberfest-checker)