使用Typescript和ES模块发布Node模块的方法


Posted in Javascript onMay 25, 2020

本文主要介绍了使用Typescript和ES模块发布Node模块的方法,分享给大家,具体如下:

使用Typescript和ES模块发布Node模块的方法

TypeScript已经成为一种非常流行的JavaScript语言,这是有原因的。它的类型系统和编译器能够在您的软件运行之前的编译时捕获各种bug,并且附加的代码编辑器功能使它成为一个非常适合开发人员的高效环境。

但是,当你想用TypeScript编写一个库或包,同时又想用JavaScript来发布,这样你的最终用户就不必手动编译你的代码,会发生什么?我们如何使用现代的JavaScript功能(如ES模块)来编写,同时又能获得TypeScript的所有好处?

本文旨在解决所有这些问题,并为你提供一个设置,使你可以放心地编写和共享TypeScript库,并为包装的使用者提供轻松的体验。

入门

我们要做的第一件事是建立一个新项目。在本教程中,我们将创建一个基本的数学程序包——不是一个服务于任何实际目的的程序包——因为它将让我们演示所有我们需要的TypeScript,而不会偏离程序包的实际功能。

首先,创建一个空目录并运行 npm init -y 创建一个新项目。这将创建你的 package.json 并为你提供一个空项目以供处理:

$ mkdir maths-package
$ cd maths-package
$ npm init -y

现在,我们可以添加第一个也是最重要的依赖项:TypeScript!

$ npm install --save-dev typescript

安装TypeScript后,可以通过运行 tsc --init 初始化TypeScript项目。 tsc 是“ TypeScript编译器”的缩写,是TypeScript的命令行工具。

为确保你运行我们刚刚在本地安装的TypeScript编译器,应在命令前加上 npx。npx是个很棒的工具,它将在node_modules 文件夹中查找你提供的命令,因此,通过在命令前面加上前缀,可以确保我们使用的是本地版本,而不是你可能已安装的TypeScript的任何其他全局版本。

$ npx tsc --init

这将创建一个 tsconfig.json 文件,该文件负责配置我们的TypeScript项目。您会看到该文件具有数百个选项,其中大多数选项已被注释掉(TypeScript支持 tsconfig.json 文件中的注释)。我已将文件缩减为仅启用的设置,如下所示:

{
 "compilerOptions": {
  "target": "es5",
  "module": "commonjs",
  "strict": true,
  "esModuleInterop": true,
  "forceConsistentCasingInFileNames": true
 }
}

我们需要对此配置进行一些更改,以使我们能够使用ES模块发布程序包,因此,让我们现在来看一下这些选项。

配置tsconfig.json 选项

如果您正在寻找所有可能的 tsconfig 选项的完整列表,可以在TypeScript网站上找到此方便的参考。

让我们从 target 开始,这定义了你将在浏览器中提供代码的JavaScript支持级别。如果您必须使用一组较旧的浏览器,这些浏览器可能不具有所有最新和最强大的功能,则可以将其设置为 ES2015。如果您确实需要最大的浏览器覆盖范围,TypeScript甚至将支持 ES3

我们将在此处针对该模块使用 ES2015,但可以随时进行相应更改。例如,如果我为自己建立一个快速的辅助项目,并且只关心尖端的浏览器,那么我很高兴将其设置为 ES2020

选择模块系统

接下来,我们必须决定将用于该项目的模块系统。请注意,这不是我们要编写的模块系统,而是TypeScript的编译器在输出代码时将使用的模块系统。

发布模块时我喜欢做的事情是发布两个版本:

  • 带有ES模块的现代版本,以便捆绑工具可以巧妙地将未使用的代码tree?shake ,因此支持ES模块的浏览器只需导入文件
  • 使用CommonJS模块的版本(如果在Node中工作,你将习惯使用 require 代码),因此较早的构建工具和Node.js环境可以轻松运行该代码

稍后我们将介绍如何使用不同的选项捆绑两次,但是现在,让我们将TypeScript配置为输出ES模块。我们可以通过将 module 设置设置为 ES2020 来实现。

现在,你的 tsconfig.json 文件应如下所示:

{
 "compilerOptions": {
  "target": "ES2015",
  "module": "ES2020",
  "strict": true,
  "esModuleInterop": true,
  "forceConsistentCasingInFileNames": true
 }
}

编写一些代码

在讨论捆绑代码之前,我们需要写一些代码!让我们创建两个小模块,它们既导出函数,又为导出所有代码的模块提供一个主 entry 文件。

我喜欢将所有TypeScript代码放在 src 目录中,因为这意味着我们可以直接将TypeScript编译器指向它,因此,我将使用以下代码创建 src/add.ts

export const add = (x: number, y:number):number => {
 return x + y;
}

我也将创建 src/subtract.ts

export const subtract = (x: number, y:number):number => {
 return x - y;
}

最后,src/index.ts 将导入我们所有的API方法并再次导出它们:

import { add } from './add.js'
import { subtract } from './subtract.js'
export {
 add,
 subtract
}

这意味着,用户可以通过导入只需要的东西来获取我们的功能,也可以通过获取所有的东西来获取。

import { add } from 'maths-package';

import * as MathsPackage from 'maths-package';

请注意,在 src/index.ts 中,我的导入包含文件扩展名。如果只想支持Node.js和构建工具(例如webpack),则不需要这样做,但是如果要支持支持ES模块的浏览器,则需要文件扩展名。

使用TypeScript进行编译

让我们看看是否可以让TypeScript编译我们的代码。我们需要先对 tsconfig.json 文件进行一些调整,然后才能执行以下操作:

{
 "compilerOptions": {
  "target": "ES2015",
  "module": "ES2020",
  "strict": true,
  "esModuleInterop": true,
  "forceConsistentCasingInFileNames": true,
  "outDir": "./lib",
 },
 "include": [
  "./src"
 ]
}

我们进行了两项更改:

  • compilerOptions.outDir ——这告诉TypeScript将我们的代码编译到一个目录中。在这种情况下,我已经告诉它命名该目录 lib,但是您可以根据需要命名它。
  • include ——告诉TypeScript我们希望在编译过程中包含哪些文件。在我们的例子中,我们所有的代码都位于src 目录中,因此我将其传入。这就是为什么我喜欢将所有TS源文件保存在一个文件夹中的原因,这使配置变得非常容易

让我们来试一试,看看会发生什么吧! 我发现在调整我的TypeScript配置时,最适合我的方法是调整、编译、检查输出,然后再调整。不要害怕尝试这些设置,看看它们如何影响最终结果。

要编译TypeScript,我们将运行 tsc 并使用 -p 标志(“project”的缩写)告诉它 tsconfig.json 的位置:

npx tsc -p tsconfig.json

如果你有任何类型错误或配置问题,将在此处显示。如果没有,您应该什么也看不到——但是请注意,你有一个新的 lib 目录,其中有文件!TypeScript编译时不会将任何文件合并在一起,而是将每个模块转换成对应的JavaScript。

让我们看一下输出的三个文件:

使用Typescript和ES模块发布Node模块的方法

// lib/add.js
export const add = (x, y) => {
  return x + y;
};

// lib/subtract.js
export const subtract = (x, y) => {
  return x - y;
};

// lib/index.js
import { add } from './add.js';
import { subtract } from './subtract.js';
export { add, subtract };

它们看起来和我们的输入非常相似,但没有我们添加的类型注释。这是可以预期的:我们在ES模块中编写了我们的代码,并告诉TypeScript也要以这种形式输出。如果我们使用了比ES2015更新的任何JavaScript功能,TypeScript会将它们转换为ES2015友好的语法,但是在我们的案例中,我们没有使用它,因此TypeScript在很大程度上仅保留了所有内容。

该模块现在可以发布到npm上供其他用户使用,但是我们有两个问题需要解决:

  • 我们不会在代码中发布任何类型信息。这不会对我们的用户造成破坏,但这是一个错过的机会:如果我们也发布我们的类型信息,那么使用支持TypeScript的编辑器的人或用TypeScript编写应用程序的人将获得更好的体验。
  • Node还不支持开箱即用的ES模块。发布CommonJS版本也很好,所以Node不需要额外的工作。ES模块支持将出现在Node 13和更高的版本中,但是要赶上生态系统还需要一段时间。

发布类型定义

我们可以通过要求TypeScript在写代码的同时发出一个声明文件来解决类型信息问题。这个文件的结尾是 .d.ts,它将包含关于我们代码的类型信息。将它看作源代码,除了不包含类型和实现之外,它只包含类型。

让我们在 tsconfig.json 中添加 "declaration": true(在 "compilerOptions" 部分中),然后再次运行 npx tsc -p tsconfig.json

提示:我想在我的 package.json 文件中添加一个脚本来进行编译,因此无需输入以下内容:

"scripts": {
  "tsc": "tsc -p tsconfig.json"
 }

然后我可以运行 npm run tsc 来编译我的代码。

现在,您将看到每个JavaScript文件(例如 add.js )旁边都有一个等效的 add.d.ts 文件,如下所示:

使用Typescript和ES模块发布Node模块的方法

"scripts": {
  "tsc": "tsc -p tsconfig.json"
 }

因此,现在当用户使用我们的模块时,TypeScript编译器将能够选择所有这些类型。

发布到CommonJS

难题的最后一部分是还将TypeScript配置为输出使用CommonJS的代码版本。为此,我们可以制作两个 tsconfig.json 文件,一个针对ES模块,另一个针对CommonJS。不过,我们可以让CommonJS配置扩展我们的默认设置并覆盖 modules 设置,而不是复制所有配置。

让我们创建 tsconfig-cjs.json

{
 "extends": "./tsconfig.json",
 "compilerOptions": {
  "module": "CommonJS",
  "outDir": "./lib/cjs"
 },
}

重要的是第一行,这意味着此配置默认情况下会继承 tsconfig.json 的所有设置。这很重要,因为你不需要在多个JSON文件之间同步设置。

然后覆盖需要更改的设置。我相应地更新模块,然后将 outDir 设置更新到 lib/cjs ,这样我们就可以输出到lib 中的子文件夹。

此时,我还更新了 package.json 中的 tsc 脚本:

"scripts": {
 "tsc": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json"
}

现在,当我们运行 npm run tsc 时,我们将编译两次,并且我们的lib目录将如下所示:

使用Typescript和ES模块发布Node模块的方法

这个有点乱,让我们通过更新 tsconfig 中的 outDir 选项来将ESM输出更新到 lib/esm

接下来,我们将设置 module 属性。这是应该链接到我们软件包的ES模块版本的属性。支持此功能的工具将能够使用此版本的软件包。因此,应将其设置为 ./lib/esm/index.js

接下来,我们将 files entry 添加到 package.json 中。在这里,我们定义了发布模块时应包括的所有文件。我喜欢使用这种方法来明确定义要在最终模块中推送到npm的文件。

这样我们就可以减小模块的大小。例如,我们不会发布 src 文件,而是发布 lib 目录。如果你在 files entry 中提供目录,则默认情况下会包含其所有文件和子目录,因此你不必全部列出。

提示:如果要查看模块中将包含哪些文件,请运行 npx pkgfiles 以获得列表。

现在,我们的 package.json 中包含以下三个附加字段:

"main": "./lib/cjs/index.js",
 "module": "./lib/esm/index.js",
 "files": [
  "lib/"
 ],

还有最后一步。因为我们要发布 lib 目录,所以需要确保在运行 npm publishlib 目录是最新的。npm文档中有一节是关于如何做到这一点的——我们可以使用 prepublishOnly 脚本。当我们运行 npm publish 时,该脚本将自动为我们运行:

"scripts": {
 "tsc": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
 "prepublish": "npm run tsc"
},

注意,还有一个名为 prepublish 的脚本,这使选择哪个稍微有些混乱。npm文档提到了这一点:不推荐使用prepublish ,如果只想在发布时运行代码,则应使用prepublishOnly

这样,运行 npm publish 将运行我们的TypeScript编译器并在线发布模块!我将该软件包发布在 @ jackfranklin/maths-package-for-blog-post 下,虽然我不建议你使用它,但是你可以浏览文件并查看。我还将所有代码都上传到了CodeSandbox中,因此您可以根据需要下载或破解它。

结束

就是这样!我希望这篇教程已经告诉你,使用TypeScript上手和运行TypeScript并不像最初看起来那么困难,只要稍加调整,就可以让TypeScript输出你可能需要的多种格式,而不需要太多麻烦。

到此这篇关于使用Typescript和ES模块发布Node模块的方法的文章就介绍到这了,更多相关Typescript和ES发布Node模块内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
关于捕获用户何时点击window.onbeforeunload的取消事件
Mar 06 Javascript
javascript里模拟sleep(两种实现方式)
Jan 25 Javascript
HTML页面弹出居中可拖拽的自定义窗口层
May 07 Javascript
深入探究AngularJS框架中Scope对象的超级教程
Jan 04 Javascript
JavaScript+html5 canvas绘制缤纷多彩的三角形效果完整实例
Jan 26 Javascript
浅析jquery数组删除指定元素的方法:grep()
May 19 Javascript
判断输入的字符串是否是日期格式的简单方法
Jul 11 Javascript
jQuery多个版本和其他js库冲突的解决方法
Aug 11 Javascript
JavaScript实现格式化字符串函数String.format
Dec 16 Javascript
bootstrap表单示例代码分享
May 18 Javascript
MUI实现上拉加载和下拉刷新效果
Jun 30 Javascript
微信小程序实现点击返回顶层的方法
Jul 12 Javascript
js 动态校验开始结束时间的实现代码
May 25 #Javascript
使用 Opentype.js 生成字体子集的实例代码详解
May 25 #Javascript
Node.js API详解之 repl模块用法实例分析
May 25 #Javascript
微信小程序仿抖音视频之整屏上下切换功能的实现代码
May 24 #Javascript
如何使用vue slot创建一个模态框的实例代码
May 24 #Javascript
使用React代码动态生成栅格布局的方法
May 24 #Javascript
ES6对象操作实例详解
May 23 #Javascript
You might like
Zend Studio (eclipse)使用速度优化方法
2011/03/23 PHP
WebQQ最新登陆协议的用法
2014/12/22 PHP
合格的PHP程序员必备技能
2015/11/13 PHP
Gambit vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
JS 实现BASE64_ENCODE和BASE64_DECODE(实例代码)
2013/11/13 Javascript
JavaScript对象的property属性详解
2014/04/01 Javascript
jquery自定义下拉列表示例
2014/04/25 Javascript
node.js中的socket.io入门实例
2014/04/26 Javascript
CSS3,HTML5和jQuery搜索框集锦
2014/12/02 Javascript
AngularJS实现树形结构(ztree)菜单示例代码
2016/09/18 Javascript
移动端使用localStorage缓存Js和css文的方法(web开发)
2016/09/20 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
JavaScript高阶函数_动力节点Java学院整理
2017/06/28 Javascript
Vue.js devtool插件安装后无法使用的解决办法
2017/11/27 Javascript
详解vue2.0 不同屏幕适配及px与rem转换问题
2018/02/23 Javascript
解决layui中onchange失效以及form动态渲染失效的问题
2019/09/27 Javascript
详解JS函数防抖
2020/06/05 Javascript
[07:49]2014DOTA2国际邀请赛 Newbee夺冠后采访xiao8坦言奖金会上交
2014/07/23 DOTA
基于Python Shell获取hostname和fqdn释疑
2016/01/25 Python
Python和Perl绘制中国北京跑步地图的方法
2016/03/03 Python
Python 编码Basic Auth使用方法简单实例
2017/05/25 Python
对python中的pop函数和append函数详解
2018/05/04 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
Python3.7 新特性之dataclass装饰器
2019/05/27 Python
HTML实现代码雨源码及效果示例
2020/02/25 HTML / CSS
英国高档百货连锁店:John Lewis
2017/11/20 全球购物
日语专业个人的求职信
2013/12/03 职场文书
特色蛋糕店创业计划书
2014/01/28 职场文书
县级文明单位申报材料
2014/05/23 职场文书
花坛标语大全
2014/06/30 职场文书
2014年客房部工作总结
2014/11/22 职场文书
经费申请报告
2015/05/15 职场文书
iPhone13再次曝光
2021/04/15 数码科技
mysql在项目中怎么选事务隔离级别
2021/05/25 MySQL
Mysql 用户权限管理实现
2021/05/25 MySQL
css3带你实现3D转换效果
2022/02/24 HTML / CSS