Reputation: 15032
I would like to use TypeScript in my NodeJS app. In order to do that I've thought it would be nice to use SystemJS to make it transpile my source files on the fly to JavaScript. I've managed to bypass most of the issues related to SystemJS configuration except the following:
How to make SystemJS to prevent processing certain imports and make it use original require
?
SystemJS via it's own require
implementation wraps everything in it's own module representation disrespecting the original type of the module. It makes such NodeJS module as express
an object rather than the function (the problem is in the code below)
'use strict';
console.log('In server.ts');
if ('production' === process.env.NODE_ENV)
require('newrelic');
let PORT = process.env.PORT || 3333;
import * as fs from 'fs';
import * as os from 'os';
import * as https from 'https';
import * as express from 'express'; // <------------- SystemJS makes express an object
import * as socketio from 'socket.io';
import { Routes } from './routes/index';
import { DBConfig } from './config/db.conf';
import { RoutesConfig } from './config/routes.conf';
import { SocketServer } from "./reflex/SocketServer";
const app = express(); // <------------ This is object, so no way to initialize
RoutesConfig.init(app);
DBConfig.init();
Routes.init(app, express.Router());
const opts = {
key: fs.readFileSync(__dirname + '/cert/server.key'),
cert: fs.readFileSync(__dirname + '/cert/server.crt')
};
let server = https.createServer(opts, <any>app);
let socket = socketio(server, { transports: ['websocket'] });
let socketServer = new SocketServer(100, socket);
server.listen(PORT, () => {
console.log(`Application is up and running @: ${os.hostname()} on port: ${PORT}`);
console.log(`enviroment: ${process.env.NODE_ENV}`);
});
Another problem is that by replacing original require, not only every module should be covered with SystemJS configuration but also every submodule which is an overkill.
Here's my SystemJS config:
SystemJS.config({
transpiler: 'typescript',
defaultJSExtensions: false,
map: {
// ------ system modules ------
"console": "@node/console",
"buffer": "@node/buffer",
"querystring": "@node/querystring",
"events": "@node/events",
"http": "@node/http",
"cluster": "@node/cluster",
"zlib": "@node/zlib",
"os": "@node/os",
"https": "@node/https",
"punycode": "@node/punycode",
"repl": "@node/repl",
"readline": "@node/readline",
"vm": "@node/vm",
"child_process": "@node/child_process",
"url": "@node/url",
"dns": "@node/dns",
"net": "@node/net",
"dgram": "@node/dgram",
"fs": "@node/fs",
"path": "@node/path",
"string_decoder": "@node/string_decoder",
"tls": "@node/tls",
"crypto": "@node/crypto",
"stream": "@node/stream",
"util": "@node/util",
"assert": "@node/assert",
"tty": "@node/tty",
"domain": "@node/domain",
"constants": "@node/constants",
// ------ common modules ------
'helmet': '@node/helmet',
'morgan': '@node/morgan',
'express': '@node/express',
'mongoose': '@node/mongoose',
'socket.io': '@node/socket.io',
'socket.io-client': '@node/socket.io-client', // <----- this module is being referenced by 'socket.io'
'body-parser': '@node/body-parser',
// ------ SystemJS configuration ------
json: './node_modules/systemjs-plugin-json/json.js'
},
meta: {
'*.json': {
loader: 'json'
}
},
paths: {
'typescript': './node_modules/typescript',
},
packages: {
'typescript': {
main: 'lib/typescript'
},
'server': {
defaultExtension: 'ts'
}
},
typescriptOptions: tsconfig
});
So the question is the following: how to make SystemJS ignore certain imports (via configuration) and bypass control to native NodeJS require
implementation?
Thank you in advance!
Upvotes: 2
Views: 1933
Reputation: 51629
If you take a look at how express.js exports things, you will see
exports = module.exports = createApplication;
and then
exports.application = proto;
exports.request = req;
exports.response = res;
When SystemJS converts this to a module, the function that you need, createApplication
, becomes a default export.
There is a shorthand syntax for importing only the default value
import express from 'express';
console.log(typeof express); // function
Of course all the properties assigned to it - application
, request
etc. - are still available.
Or, if you prefer your original form for import, you can access it as default
property
import * as express from 'express';
console.log(typeof express.default); // function
Now to your question
how to make SystemJS ignore certain imports (via configuration) and bypass control to native NodeJS require implementation?
There is no such option in the configuration AFAIK, but SystemJS provides original node require as System._nodeRequire
, so you can use this as fallback in the code:
var express = System._nodeRequire('express');
NOTE: as Lu4 noted in the comment, 'express': '@node/express'
mapping in SystemJS config is very important. Besides loading from node_modules
, @node
special notation tells SystemJS that all the packages required inside the module and its dependencies are to be loaded with node require
and not to be converted to modules. This is sometimes necesary because SystemJS module resolution algorithm is different from nodejs, as mentioned in CommonJS module format section in SystemJS docs.
Upvotes: 2