【问题标题】:Understanding TypeScript and SystemJS WITHOUT Angular在没有 Angular 的情况下理解 TypeScript 和 SystemJS
【发布时间】:2017-08-24 07:17:12
【问题描述】:

我最近一直在研究和使用 TypeScript 做简单的“hello worlds”。有些事情我觉得我无法理解,那就是如何将 System.js 与 TypeScript 一起使用。互联网上的每一个教程或演示都是关于 Angular2 的,我还不想参与 Angular 2。

例如,我的项目结构如下:

RootFolder
| 
| _lib
| ...... ts (where .ts files are)
|
| components (where compiled .js files are)
| libraries
| ......... systemjs (where system.js is)
|
| index.html
| tsconfig.json

我的 tsconfig.json 文件看起来像:

{
  "compileOnSave": true,
  "compilerOptions": {
    "noImplicitAny": true,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "outDir": "./components"
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ],
  "include": [
    "./_lib/ts/**/*"
  ]
}

TypeScript 编译按预期工作,没有任何问题。我创建了一个名为“Alerter”的简单类,其中包含以下代码:

//alerter.ts
class Alerter {
    showMessage(): void {
        alert("Message displayed.");
    }
}

export default Alerter

还有一个 app.ts(这是我的“主”应用程序文件),代码如下:

//app.ts
import Alerter from "./alerter";

console.log("app.js included & executed");

function test() {
    console.log("test called");
    const alt = new Alerter();
    alt.showMessage();
};

在我的 index.html 中,我只想用 System.js 导入这个 app.js,并且只想从控制台调用“test”函数。但它不起作用。无论我做什么,我都无法访问该功能。我看到第一行 console.log 正在执行,但是当我尝试从 chrome 控制台调用 test() 时,它是未定义的。

如果我从 main.ts 中删除“alerter”类依赖项,一切正常。因为编译后的 app.js 只包含 console.log 调用和函数定义。

这是我在 index.html 中的 System.js 调用

System.config({
    packages: {
        "components": {
            defaultExtension: "js"
        }
    }
});

System.import("components/app");

我现在真的很绝望,我想我应该回到 Jquery 时代。这很简单,但不能让它工作。

【问题讨论】:

  • 我为演示做了一个简单的 TS + SystemJS 项目设置,也许它会对你有所帮助。 github.com/Toskv/talk.timjs.typescript/tree/master/modules/live
  • @toskv 谢谢你到目前为止真的很有帮助。我仍在检查,但已经给了我很好的洞察力。
  • 如果你想从 index.html 访问函数,你必须加载导出它,这样你就可以在模块加载完成后使用它。 System.import 返回一个承诺,响应将包含您要求的模块。 :)
  • 这可能有助于理解我最后的评论。 stackoverflow.com/questions/36313093/…

标签: typescript module systemjs typescript2.0 es6-modules


【解决方案1】:

我明白这里发生了什么。这与正确使用 TypeScript export 关键字和 SystemJS 有关。

根据您的描述,您基本上希望使用 SystemJS 导入 JavaScript 文件,类似于仅使用 <script> 标记,然后使用其全局定义的函数。

但这意味着您需要了解 TypeScript 如何编译您的文件。 https://www.typescriptlang.org/docs/handbook/modules.html 的文档说:

在 TypeScript 中,就像在 ECMAScript 2015 中一样,任何包含顶级导入或导出的文件都被视为一个模块。

这就是你正在做的。 app.ts 文件有一个importalerter.ts 文件有一个export 语句,因此它们都将被编译为模块。然后从您的tsconfig.json 我看到您使用的是system 格式(但是,这并不重要)。

模块的一个主要好处是它们不会泄漏任何超出其范围的全局对象。因此,当您调用 System.import("components/app") 时,test() 函数仅存在于该模块中。但是你可以导出函数并在模块加载后调用它:

这意味着你需要先导出函数:

// app.ts
export function test() {
  ...
};

然后System.import() 返回一个通过模块导出对象解析的 Promise,因此我们可以在那里调用 test() 方法。

System.import("components/app").then(function(m) {
  m.test();
});

这确实如您所愿。

但是,您似乎想在全局范围内定义 test() 函数。在这种情况下,您需要自己在 window 全局对象上定义函数:

// app.ts
function test() {
  ...
}
declare const window;
window.test = test;

现在你可以在导入包后随时使用它:

System.import("components/app").then(function(m) {
  test();
});

SystemJS 有多种操作全局对象的方法,但我认为当您导入的包具有需要解决的依赖项时,没有任何更简单的方法可以使用它们(否则看看这个,但它不是你的用途-case https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#exports)。

【讨论】:

  • 很好的解释!导出我的 test() 函数解决了您所说的问题,并且由于您的回答,我了解了它的工作原理。但是有一件事,将我自己的“本地/内部”模块相互包含的最佳实践是什么?我是否应该始终实现“每个文件都是一个模块”并使用导入/导出或 就足够了?
  • @Alaminut 我认为<reference path="..."> 仅由编译器使用,不会生成导入语句,因此代码将无法工作。 <reference path="..."> 在旧版本的 TypeScript 中用于告诉编译器您的 *d.ts 文件。我认为我现在没有任何常用用法,所以我坚持只使用 importexport
猜你喜欢
  • 2019-09-30
  • 2016-05-15
  • 1970-01-01
  • 2016-06-28
  • 2018-10-01
  • 2019-10-31
  • 2019-03-21
  • 1970-01-01
  • 2017-11-05
相关资源
最近更新 更多