10 分钟内构建您的第一个 Typescript 包
NPM 注册表
我们正在构建什么
设置
文件结构
切换组件
造型
组件道具
测试
发布
后续步骤
我已经推迟构建自己的 Typescript 包一段时间了。
不是因为缺乏想法,而是我知道现代的 Javascript/Typescript 开发一团糟。启动一个默认的 React 项目后,检查一下 node_modules 目录的大小,就能明白我的意思了:仅仅启动一个项目,依赖项就超过 200MB!或者更好的办法是,尝试启动一个没有依赖项的 React 项目create-react-app
。
我需要花几天时间才能用 Babel、Prettier、Rollup、ESLint、Jest 等工具按照我想要的方式配置我自己的 Typescript 包。更不用说这可能会让我失去理智。
然后我偶然发现了TSDX。
阅读完README后,我能够在一个晚上发布一个包含测试的完整 npm 包。
本指南是我发布第一个软件包时所学内容的简化版本。完成本教程后,你应该会在NPM 仓库中拥有一个已发布并测试过的 Typescript 软件包。
NPM 注册表
首先,您需要创建一个 NPM 帐户并将其配置为在命令行中使用。如果您还没有配置帐户并通过命令行登录,请先阅读本简短指南。npm login
我们正在构建什么
由于本教程面向初学者,因此我们将构建一些简单的东西。一个可复用的 React 组件,包含 Jest 测试、类型和 Github 操作:
我知道,这确实令人敬畏。
现场演示
最终源代码
设置
让我们从命令行引导我们的 TSDX 项目:
npx tsdx create toggle
安装依赖项后,让我们确保我们可以在开发/监视模式下启动项目:
cd toggle
npm start
您现在应该有一个可以运行的包!
文件结构
> tree -L 2 -I node_modules
.
├── LICENSE
├── README.md
├── dist
│ ├── index.d.ts
│ ├── index.js
│ ├── toggle.cjs.development.js
│ ├── toggle.cjs.development.js.map
│ ├── toggle.cjs.production.min.js
│ ├── toggle.cjs.production.min.js.map
│ ├── toggle.esm.js
│ └── toggle.esm.js.map
├── example
│ ├── index.html
│ ├── index.tsx
│ ├── package.json
│ └── tsconfig.json
├── package-lock.json
├── package.json
├── src
│ └── index.tsx
├── test
│ └── blah.test.tsx
└── tsconfig.json
默认项目非常精简。不过,有一些目录/文件需要了解。
目录
- src:这是所有将要实时构建的源文件的位置
- 示例:用于测试组件/包的示例游乐场
- dist:将被构建并发布到 npm 的内容。您实际上不需要修改此目录,并且它应该从源代码管理中排除。
- 测试:你的测试
文件
- src/index.tsx:将要构建的主要源文件。这需要导入所有其他源文件
- package.json:包的依赖项/所有配置
- example/package.json:你的游乐场的依赖项(这些不会发布到 npm)
- example/index.tsx:为游乐场加载包的文件
- test/blah.test.tsx:示例测试文件
- README.md:生成的 README 包含大量有用的信息以供参考。
切换组件
为了遵循 React 最佳实践,我们将为我们的组件创建一个单独的文件。
将以下代码复制并粘贴到src/Toggle.tsx
:
// Inside src/Toggle.tsx
import React, { FC } from 'react';
export const Toggle: FC = () => {
return (
<label className="switch">
<input type="checkbox" />
<span className="slider round"></span>
</label>
);
};
这里没什么特别的,只是一个默认的 HTML 复选框。让我们从我们的文件中导出组件index.tsx
,该文件是包中将要使用的主文件。
// src/index.tsx
export * from './Toggle';
TSDX 项目附带一个示例文件夹,可帮助您在浏览器中可视化组件。我们也将使用它作为组件的沙箱。由于我们更改了组件的名称,因此必须更新示例导入:
// example/index.tsx
import 'react-app-polyfill/ie11';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Toggle } from '../src/index'; // 👈 Change our import
const App = () => {
return (
<div>
<Toggle />{/* 👈 Change to use your new component*/}
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
现在让我们运行这个沙盒环境来看看我们有什么:
cd example
npm i
npm start
导航到http://localhost:1234。您应该会看到一个复选框!
造型
现在让我们为这个可爱的复选框添加一些样式。Toggle.css
在 src 目录中打开一个名为 的新文件,并将以下样式复制到其中:
/* src/Toggle.css */
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
让我们将这些样式导入到我们的Toggle.tsx
组件中。我们需要安装来rollup-plugin-postcss
告诉 Rollup 如何将 CSS 编译为我们包的一部分:
npm i -D rollup-plugin-postcss
现在在项目根目录中创建一个名为 tsdx.config.js 的文件并粘贴以下代码:
// tsdx.config.js
const postcss = require('rollup-plugin-postcss');
module.exports = {
rollup(config, options) {
config.plugins.push(
postcss({
plugins: [],
})
);
return config;
},
};
现在我们可以使用 ESM 导入来导入我们的样式:
// src/Toggle.tsx
import React, { FC } from 'react';
import './Toggle.css'; // 👈 Import our new styles
export const Toggle: FC = () => {
return (
<label className="switch">
<input type="checkbox" />
<span className="slider round"></span>
</label>
);
};
保存并刷新您的浏览器。
哒哒!
组件道具
但是如果我们真的想对切换组件的状态做些什么呢?它本身就没什么用。
让我们添加组件道具以便给我们更多的灵活性:
// src/Toggle.tsx
import React, { FC } from 'react';
require('./Toggle.css');
export type ToggleType = {
isOn: boolean;
handleChange: () => void;
};
export const Toggle: FC<ToggleType> = ({ isOn, handleChange }) => {
return (
<label className="switch">
<input checked={isOn} onChange={handleChange} type="checkbox" />
<span className="slider round"></span>
</label>
);
};
现在我们可以将 props 传递给组件并管理其状态。由于我们正在导出,我们的类型将自动构建并作为项目的一部分包含进来ToggleType
。
让我们更新我们的游乐场以包含此状态并确保切换仍然有效:
// example/index.tsx
import 'react-app-polyfill/ie11';
import React, { useState } from 'react';
import * as ReactDOM from 'react-dom';
import { Toggle } from '../src/index';
const App = () => {
const [isOn, setIsOn] = useState(false);
return (
<div>
<Toggle isOn={isOn} handleChange={() => setIsOn(!isOn)} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
现在我们在组件外部setIsOn(!isOn)
处理状态。这意味着我们只需调用 ,就可以在任何地方更改切换状态。
测试
我们已经准备好发布我们的软件包了,但首先需要确保它能正常运行。我们希望大家能为您的项目做出贡献,但我们不想每次提交新的 PR 时都在我们的沙盒中测试功能。
让我们将blah.test.tsx
文件重命名为toggle.test.tsx
并更新我们的react-dom
渲染方法:
// src/tests/blah.test.tsx -> src/tests/toggle.test.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Toggle } from '../src';
describe('it', () => {
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Toggle isOn={false} handleChange={() => {}} />, div);
ReactDOM.unmountComponentAtNode(div);
});
});
为了让 Jest 能够读取 CSS 文件,我们需要安装一个包来允许我们模拟这些文件:
npm i -D identity-obj-proxy
然后编辑我们的 package.json 来反映这一点:
// package.json
...
"jest": {
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
}
},
...
请参阅Jest 文档,了解更多关于此操作的必要性。现在,我们应该可以从根目录进行功能测试:
npm test
好极了!
唯一的问题是,这只是测试组件是否挂载,并且挂载过程中不会破坏应用。我们真正想测试的是 toggle 功能和isOn
prop 是否正常工作。
我们可以使用react-testing-library来测试我们的组件 prop 功能:
npm i -D @testing-library/react @testing-library/jest-dom
让我们更新测试文件以使用一些新的测试方法。我们将使用render
和fireEvent
方法:
// test/toggle.test.tsx
import * as React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { Toggle } from '../src';
it('Should render the toggle and be clickable between states', () => {
// mock onChange function
const onChange = jest.fn();
const { getByTestId, rerender } = render(
<Toggle isOn={false} handleChange={onChange} />
);
// checkbox and parent label components
const checkbox = getByTestId('Toggle');
const label = getByTestId('Toggle-label');
// isOn=false should mean it's unchecked
expect(checkbox).toHaveProperty('checked', false);
// Clicking from off -> on
fireEvent.click(label);
expect(onChange).toHaveBeenCalledTimes(1);
// isOn=true should mean it's checked
rerender(<Toggle isOn={true} handleChange={onChange} />);
expect(checkbox).toHaveProperty('checked', true);
// Clicking from on -> off
fireEvent.click(label);
expect(onChange).toHaveBeenCalledTimes(2);
});
如果你觉得有点困惑,或者你不熟悉 react-testing-library,没关系。我们实际上做的就是渲染组件,并确保它isOn
反映选中状态,并且handleChange
每次点击时都会调用我们的函数。
再次检查它是否仍然有效:
npm test
发布
您需要确保更新软件包的版本、作者和名称。名称应唯一,并且不会被 NPM 注册表占用。您需要在 package.json 中更改三个字段:
"author": "Frodo Baggins",
"name: "frodo-toggle",
"version": "1.0.0",
最后一步就是现在发布!
npm publish
如果出现错误,您可能需要 a) 通过 重新登录,或 b) 更改包名称以使其唯一。如果您想查看该包名称是否可用,请尝试在npm 注册表npm login
中搜索。
恭喜,您现在是一名 Typescript 包作者。😎
现在任何人都可以通过运行以下命令从命令行安装您的软件包:
npm i your-toggle-lib # replace this with your package name
后续步骤
您可以从现在开始做一些事情来改进这个包。如果您计划允许外部贡献者使用,您可能需要调整 TSDX 自带的默认Github 操作,以便在新的 PR 上运行测试套件。这将确保外部贡献者不会合并损坏的更改。
其他可能的后续步骤:
- 添加道具来改变颜色并向切换按钮添加标签。
- 添加
size
具有“小”、“中”和“大”选项的道具。 - 根据道具添加不同的过渡。
- 添加styled-components而不是 css
世界是你的牡蛎!
配置是任何项目中最痛苦的部分,但像 TSDX 和 create-react-app 这样的库却能出色地降低新手和懒人(比如我)的入门门槛。没有人喜欢花一整天时间与配置文件作斗争。希望本指南能让你更有信心编写自己的软件包。期待在 Github 和 npm 上看到你的项目!
文章来源:https://dev.to/g_abud/publish-a-typescript-package-in-under-10-minutes-4940