今天带 TypeScript 的 ES6 模块

今天带 TypeScript 的 ES6 模块

原文:https://medium.com/hackernoon/es6-modules-today-with-typescript-22969cd360f0

Two work horses represent both ESM and CJS builds

2017 年的今天,很多常青树浏览器都支持开箱即用的 ES6 模块。一些浏览器将它隐藏在一个标志后面,包括 Node.js。但是用同一个 npm 包支持新旧环境可能吗?是啊!

编者按:ES6 模块有时被称为 ES2015 模块,或 ESM,或 *module* 脚本,有时甚至被扩展名 *.mjs* 读作“迈克尔杰克逊脚本”。我们都在谈论同一件事,所以如果你听到不同的术语,不要混淆。

我不会讨论使用 ES6 模块的优点或者为什么 TypeScript 很棒,因为已经有很多博客文章详细描述了这些。相反,我将着重于向 npm 发布一个用 TypeScript 编写但部署为.mjs (ESM)和.js (CommonJS)的包,这样任何消费者都可以使用您的包!

入门指南

第一步是设置您的tsconfig.json文件,这样 TypeScript 将使用最新最棒的 JavaScript 特性,如下所示:

{
  "compilerOptions": {
    "module": "es2015",
    "target": "ES2017",
    "rootDir": "src",
    "outDir": "dist",
    "sourceMap": false,
    "strict": true
  }
}

显然,我们希望模块是es2015,因为它在本文的标题中,所以我们必须在某个时候解决它!让我们瞄准es2017,这样我们就可以像 JS 忍者一样使用asyncawait关键字。您可以将您的rootDiroutDir命名为您想要的任何名称,但是在 JS Land 中使用dist进行输出是一个惯例。源地图是可选的,但是我喜欢在需要的时候关闭它们。严格模式也是可选的,但是如果以后需要的话,从严格开始变得宽松一点更容易。我强烈建议启用它,因为默认情况下它是禁用的。

连接起来

现在我们可以讨论package.json文件了。这里有一个名为 copee 的包的例子:

{ 
  "name": "copee",
  "version": "1.0.0",
  "description": "Copy text from browser to clipboard...natively!",
  "repository": "styfle/copee",
  "files": [ "dist" ],
  "main": "dist/copee",
  "types": "dist/copee.d.ts",
  "scripts": {
    "mjs": "tsc -d && mv dist/copee.js dist/copee.mjs",
    "cjs": "tsc -m commonjs",
    "build": "npm run mjs && npm run cjs"
  },
  "devDependencies": {
    "typescript": "^2.5.3"
  }
}

前四行定义了包nameversiondescription和 GitHub repository,它们是自我解释的。

接下来,我们定义files,我们简单地将它定义为一个单独的文件夹dist。这些是将发布到 npm 的文件。

你的包的入口点被定义为main,这就是神奇发生的地方。请注意,没有像预期的那样有文件扩展名(比如.js)。这将允许 Node 根据用户导入软件包的方式选择文件——是旧的 CJS 还是新的 ESM。

接下来是types,这对于想要通过 TypeScript 导入的用户来说是必需的。如果你正在用 TypeScript 编写你的包,你应该明确地包含types以便你的 TS 用户获得类型安全!说真的,这样做是对的。

现在有趣的部分来了:scripts。这些是您可以通过npm run thenameofthescriptgoeshere运行的构建步骤。第一个构建步骤mjs使用 TypeScript 编译器(tsc)使用我们之前定义的tsconfig.json文件,加上一个发出我们的.d.ts类型定义的-d标志来构建我们的代码。还要注意将输出文件从.js移动到.mjsmv命令。这是我们的 ESM 输出。

我们的下一个脚本,cjs使用 TypeScript 编译器(tsc)构建相同的源代码,但是将输出作为 CommonJS 模块发出。这是 Node.js 的模块系统,由browserifywebpack等理解。

最后,我们有devDependencies是你的构建工具。在这种情况下,我们所需要的是包含上面使用的tsc命令的typescript

节点使用

我将向您展示如何编写一个导入上述包的消费者。如果您已经经常使用 Node,请跳到下一节了解 ESM 的用法。

首先,安装 copee 包:

npm install --save copee

然后,用以下内容创建一个index.js文件:

const { toClipboard } = require('copee'); console.log('CJS: We found a ', typeof toClipboard);

新程序可以这样执行:

node index.js

节点 ESM 使用情况

我将向您展示如何编写一个导入上面的 copee 包的消费者。

安装 copee 后,创建一个index.mjs文件。您必须使用迈克尔杰克逊脚本扩展(。mjs)。

import { toClipboard } from 'copee';
console.log('ESM: We found a ', typeof toClipboard);

新程序可以这样执行:

node --experimental-modules index.mjs

浏览器 ESM 使用

节点的使用并不那么引人注目,因为从一开始就有模块,但是 ESM 的美妙之处在于,在节点模块中执行的相同代码将在浏览器中不变地运行!是的,是真的!请尽情欣赏下面这段优雅的代码片段:

<script type="module">
  import {
    toClipboard
  } from 'https://cdn.jsdelivr.net/npm/copee/dist/copee.mjs'; $('#btn').on('click', () => {
    const win = toClipboard('Wow, "copee" works!');
      if (win) {
        // it worked, check your clipboard!
      }
  });
</script>

我们为module提供了一个新的脚本类型,我们使用 jsDelivr 在 CDN 上自动托管我们的代码。这使得编写一个单独的导入行并在全世界的浏览器中使用 copee 包变得很容易!

传统浏览器

你会说,传统浏览器呢?不是所有人都支持 ESM?这可以通过捆绑 UMD 和 T1 来解决。安装完rollup后,将它添加到你的package.json文件的scripts部分。

{
  "umd": "rollup -i dist/copee.mjs -o dist/copee.umd.js -f umd -n copee"
}

您可以在同一页面上包含 ESM 和 UMD 版本,而不会发生冲突。请参见下面的片段:

<script nomodule src="https://cdn.jsdelivr.net/npm/copee/dist/copee.umd.js"></script> <script type="module">
  import {
    toClipboard
  } from 'https://cdn.jsdelivr.net/npm/copee/dist/copee.mjs';
</script>

通过使用nomodule属性,您告诉新浏览器忽略 UMD 脚本。通过使用type=module,你是在告诉老浏览器忽略 ESM。现在大家都赢了!

您可以在演示页面上看到该解决方案的工作演示。

此外,请查看 GitHub repo 了解更多细节,当然还有工作源代码!

原载于 2017 年 10 月 16 日www.ceriously.com


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除