javascript - 通过 SystemJS 用于 NodeJS 的 TypeScript

标签 javascript node.js typescript systemjs

我想在我的 NodeJS 应用程序中使用 TypeScript。为了做到这一点,我认为最好使用 SystemJS 将我的源文件即时转译为 JavaScript。我已经设法绕过了与 SystemJS 配置相关的大多数问题,除了以下问题:

如何让 SystemJS 阻止处理某些导入并使其使用原始 require

SystemJS 通过它自己的 require 实现将所有内容包装在它自己的模块表示中,不尊重模块的原始类型。它使 express 这样的 NodeJS 模块成为一个对象而不是函数(问题出在下面的代码中)

'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}`);
});

另一个问题是,通过替换原来的 require,不仅每个模块都应该被 SystemJS 配置覆盖,而且每个子模块都应该被覆盖,这是一个矫枉过正的行为。

这是我的 SystemJS 配置:

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
});

所以问题如下:如何让 SystemJS 忽略某些导入(通过配置)并绕过对原生 NodeJS require 实现的控制?

提前谢谢您!

最佳答案

如果你看看express.js如何导出东西,你会发现

exports = module.exports = createApplication;

然后

exports.application = proto;
exports.request = req;
exports.response = res;

当 SystemJS 将其转换为模块时,您需要的函数 createApplication 将变为 default export .

有一个仅导入默认值的简写语法

import express from 'express';

console.log(typeof express); // function

当然,分配给它的所有属性 - applicationrequest 等 - 仍然可用。

或者,如果您更喜欢导入原始表单,则可以将其作为默认属性进行访问

import * as express from 'express';

console.log(typeof express.default); // function

现在回答你的问题

how to make SystemJS ignore certain imports (via configuration) and bypass control to native NodeJS require implementation?

据我所知,配置中没有这样的选项,但 SystemJS 提供了原始 Node 需求为 System._nodeRequire,因此您可以在代码中使用它作为后备:

var express = System._nodeRequire('express');

注意:正如 Lu4 在评论中指出的那样,SystemJS 配置中的 'express': '@node/express' 映射非常重要。除了从 node_modules 加载之外,@node 特殊符号告诉 SystemJS 模块内所需的所有包及其依赖项都将通过 Node require 加载并且不转换为模块。这有时是必要的,因为 SystemJS 模块解析算法与 Nodejs 不同,如 CommonJS 中所述。 SystemJS 文档中的模块格式部分。

关于javascript - 通过 SystemJS 用于 NodeJS 的 TypeScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39301352/

相关文章:

javascript - 在 anchor 标记中包装路径元素

javascript - 函数返回未定义的、预期的 Promise 或值,而我返回新的 Promise

TypeScript 找不到模块 flatpickr,即使它包含 typescript 类型

javascript - 当 AngularJS jqlite 不存在损坏的 url 时,将损坏的 img url 替换为默认值

JavaScript - 检查这个(当前元素)是否有一个以结尾的类

javascript - 消失的 Javascript onClick Box,JS 新手

javascript - 使用 Redis 存储和获取 bool 值

node.js - 如何在弹性 beantalk 选项设置文件中设置 NODE_ENV 变量

node.js - Typescript - 无法扩充模块

html - Angular 2/4/6 组件方法如何用于另一个组件?