【问题标题】:Using TypeScript transpiled code utilizing es6-style classes with imports in a browser without an additional transpilation step?在浏览器中使用带有导入的 es6 样式类的 TypeScript 转译代码,而无需额外的转译步骤?
【发布时间】:2018-10-28 01:27:26
【问题描述】:

如果我使用 target:"es5" 转译使用 es6 样式类和 React 的 TypeScript 代码,我的预期入口点(这里是一个名为 App.ts 的文件)具有如下所示的转译代码:

Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = require("react");
var react_router_1 = require("react-router");

当这个 sn-p 中的第一行被命中时,我得到一个 Uncaught ReferenceError: exports is not defined 错误。 TypeScript 的 GitHub 问题页面 here 中描述了类似的问题。

quick answerexports 将存在于支持类加载的环境中。

commonjs 表示有一个可用的导出变量。不能直接在浏览器中运行 commonjs 代码。

这是我的 html 包装器:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="./components/App.js"></script>
  </head>
  <body>
    <div id="root"></div>

    <script>
      ReactDOM.render(
        React.createElement('App', null),
        document.getElementById('root')
      );
    </script>
  </body>
</html>

看起来(123)通常的反应是在您的 TypeScript 和它在浏览器上发布到客户端之间放置一个额外的转换步骤。等等,什么?我需要转译转译的代码吗?这有点像那些“I thought the dishwasher washed the dishes”的广告之一。

另一个建议是使用模块加载库,如 RequireJS 或 SystemJS (1, 2)。这是有道理的,但我还没有看到将模块加载库添加到 TypeScript 编译代码以传递到浏览器的示例。而且,TypeScript 似乎可以智能地(如“使用最少重复的代码”)在编译时包含这样的库。

(看起来 RequireJS 至少通常与 different syntaxrequire 一起使用,而 require(['lib1', 'lib2', 'lib3'], function (lib1, lib2, lib3) {...}}) 而不是更简单的 var lib1 = require('lib1') TypeScript 正在生成,尽管 perhaps I'm missing something?)

所以这里至少有两个相关的问题:

  1. target="es5" TypeScript 转码代码的预期用例是什么?
  2. 如何将 es6 TypeScript 代码提供给浏览器,而不需要超出 TypeScript 所能做的转换步骤?
    • 也就是说,有没有我错过的platform:"browser" 风格的设置?
    • 如果不是,RequireJS 是否应该使用 TS 生成的代码?那应该如何“引导”/启动?

更新:(将我的 cmets 从@felixmosh 的答案移到问题中)

我尝试将 "module":"es2015" 添加到我的 tsconfig.json 中,但代码开始出现错误,如下所示:import Home from './pages/Home'; 读取为 error TS2307: Cannot find module './pages/Home'

我的印象是module 选项定义了在 TypeScript 中定义模块的方式,而不是在生成的 JavaScript 代码中转译的方式。也就是说,如果这个选项只影响输出,为什么我的未编译代码会在添加/更改模块设置后抛出错误,而不是简单地更改生成的 JavaScript 文件的语法?

@felixmosh 还 [有用地] 建议使用类似 RollUp.js 的东西,但这确实会在加载模块的过程中结束,嗯,它 编译,但它实际上只是 conglomerating “将小段代码变成更大更复杂的东西”。将所有模块放入一个文件是一种作弊。 (虽然为什么 TS 至少不做这个聚合?)

所以 +1 到 felix 并感谢您的帮助,但我仍然不明白为什么 TS 在它停止的地方停止 - 它生成的代码的用例是什么? TypeScript 是否真的需要在 TS 之外的一步才能在交付给浏览器的代码中使用 es6 样式的类?

我为什么要关心?我以前使用过基于 RequireJS 的代码库,很高兴能够以一种比单一代码库更容易调试的方式分解文件。但我也不明白为什么 TS 在这个用例中似乎无法生成可部署的代码。

【问题讨论】:

  • 只是一个小提示:以后你可以使用打字稿指导的create-react-appcreate-react-app my-app --scripts-version=react-scripts-ts跳过所有的BS设置

标签: javascript reactjs typescript


【解决方案1】:

如果你想保留 es6 的 import/export,你应该定义 module:"es2015",默认情况下,它将那些转换为在 node 中使用的 cjs 样式。

Modern browsers 不支持节点的cjs 样式但es2015 样式,因此您需要指定该模块类型,并在您的脚本标签上指定type="module" 的属性,类似这样:

<script type="module" src="entry-point.js"></script>

目前只有 chrome 对 modules 提供原生支持,因此现在最好的做法是从您使用 进口。

常见的绑定器是WebpackRollUp,您可以阅读它们的配置以生成在浏览器中运行的包。

typescript 和 webpack 配置的小参考:https://webpack.js.org/guides/typescript/

【讨论】:

  • 我已经更新了我的答案,看看吧,如果这不能解释我的想法,我很乐意进一步解释。
  • 浏览器不支持加载模块(Chrome 除外),因此 Babel / TS 无法转译需要浏览器支持的内容。
  • 想一想,你有 2 个文件,a.ts 依赖于 b.ts,没有可以生成的代码可以让浏览器从 a.ts 开始运行,明白它需要b.ts,先下载,执行,然后才执行a.ts...你必须有浏览器支持。
  • 但是没有加载依赖exactly what RequireJS does
  • RequireJS 是由 lib 实现的,您是在建议 TS 将 es6 导入语法转换为 requirejs... 然后您需要包含该 lib?
【解决方案2】:

我看到您正在开始构建 TypeScript Web 应用程序。如果是这样,这是我的建议:

TypeScript 转 JS 是不可避免的,

不要使用 RequireJS 或 SystemJS,而是使用打包工具,如 parcel、webpack、rollup、browserify。我特别推荐 parcel,因为它超级简单并且与 TypeScript 配合得很好

  • 使用捆绑器,摆脱所有那些定义() 需要() SystemJs.calls() 并仅使用标准 JavaScript 导入声明(导入 {foo} 形式 'bar')。我也强烈推荐这个

  • 顺便说一句,避免使用 require.js、AMD、UMD、SystemJS 或类似文件。开始使用这些不是一个好建议。仅在确实需要时才使用它们。

祝你好运

【讨论】:

    猜你喜欢
    • 2019-01-22
    • 1970-01-01
    • 2020-10-23
    • 1970-01-01
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多