- Notifications
You must be signed in to change notification settings - Fork4
以 🚀 速度创建零配置 TypeScript 库项目的命令行工具
License
sinoui/ts-lib-scripts
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
ts-lib-scripts,一个以 🚀 速度创建零配置 TypeScript 库项目的命令行工具。
尽管 TypeScript 最近很火爆,但是要设置一个 TypeScript 库仍然很困难。ts-lib-scripts 能让你轻松创建、构建、测试和发布 TypeScript 库。别再浪费一个下午时间来处理TypeScript、Rollup、Babel、ESLint、tsconfig.json、Yarn、Prettier和VSCode之间的和谐共处,用 ts-lib-scripts 来帮你节省出这些时间:
npx ts-lib-scripts create my-ts-lib
ts-lib-scripts 关注构建 TypeScript 库需要的元素,并提供一些开箱即用的特性:
- 🎯 使用Rollup打包你的代码,支持
CJS、UMD、ESM输出格式和development、production模式。当然,还有.d.ts 文件。 - 📦 支持 tree-shaking,内置 lodash 优化、babel helpers、代码压缩,节省代码大小。
- 💄 友好的日志输出。
- 💯 内置 ESLint 和 Prettier 支持,让代码错误无所遁形。
- 🏎️ 针对 Git、GitHub 和 VSCode 做调优,完美的编程体验。
- ✨ 内含非常智能的
Jest配置,yarn test即可享受美妙的单元测试。 - 🎣Babel 宏:轻松扩展 Babel 配置。
- 🎉 无须配置,只需一个命令行。
ts-lib-scripts 需要Node.js 10+和Yarn。
打开命令行,执行以下命令:
npx ts-lib-scripts create my-ts-libcd my-ts-libcode.yarn start
使用 VSCode 打开src/index.ts,开始构建你的 TypeScript 库吧。
项目结构:
my-ts-lib|__ .vscode|__ src|__ .editorconfig|__ .gitignore|__ package.json|__ README.md|__ tsconfig.json创建的my-ts-lib项目有很多有用的命令可用。如下介绍。
打包,并将打包文件放在dist文件夹中。使用 rollup 对代码做优化并打包成多种格式(Common JS,UMD和ES Module)。
yarn lint会检查整个项目是否有代码错误、风格错误。
开启 vscode 的 eslint、prettier 插件,在使用 vscode 编码时,就会自动修正风格错误、提示语法错误。
yarn format可以自动调整整个项目的代码风格问题。
yarn test以监听模式启动 jest,运行单元测试。
开启 vscode 的 jest 插件,会在文件变化时自动运行单元测试。
发布 npm 包。
从 0.3.0 开始,ts-lib-scripts支持生成 monorepo 结构的项目:
npx ts-lib-scripts create my-ts-lib --monorepo
生成的项目结构如下:
my-ts-lib|__ .vscode|__ pacakges|__ .editorconfig|__ .gitignore|__ lerna.json|__ package.json|__ README.md|__ tsconfig.json采用lerna管理模块的依赖和发布,所有模块都放在 pacakges 目录中。有以下几个命令行可用:
yarn build- 编译所有模块yarn lint- 检查所有模块的代码yarn test- 以监听者模式执行所有模块的单元测试yarn lerna publish- 发布yarn gen- 添加新模块。例如:yarn gen module-a。yarn lerna add- 添加依赖。
可以为所有模块添加依赖,如给所有模块添加ts-lib依赖:
yarn lerna add ts-lib
也可以为单个模块添加依赖:
yarn lerna add immer --scope=module-a
前端代码的大小是前端项目中至关重要的指标,但是压缩代码大小不能以牺牲开发者体验为代价。ts-lib-scripts 做代码优化就是本着这个原则来的。
我们在开发时需要很多日志来记录和展示代码的运行情况,但是这些日志又不想打包到生产环境中去。使用 ts-lib-scripts,可以实现这种愿望。
我们的代码如下:
functionsum(a:number,b:number){if(process.env.NODE_ENV!=='production'){console.log(`调用sum方法:${a} +${b} =${a+b}`);}returna+b;}
打包之后,在dist目录下生成下面三个文件:
index.js:
'use strict';if(process.env.NODE_ENV==='production'){module.exports=require('./ts-lib-scripts-example.cjs.production.js');}else{module.exports=require('./ts-lib-scripts-example.cjs.development.js');}
my-ts-lib.cjs.development.js:
'use strict';functionsum(a,b){{console.log('调用sum方法:'.concat(a,' + ').concat(b,' = ').concat(a+b),);}returna+b;}exports.sum=sum;
my-ts-lib.cjs.production.js:
'use strict';exports.sum=function(t,r){returnt+r;};
如你所见,ts-lib-scripts 在生成生产模式(production mode)包时是会剔除掉process.env.NODE_ENV !== 'production'而不会影响到开发模式(development mode)包。所以,你可以尽情地编写一些开发日志而不用担心加大生产包的大小。
warning是非常有用的产生开发日志的库。用法如下:
// some scriptvarwarning=require('warning');varShouldBeTrue=false;warning(ShouldBeTrue,'This thing should be true but you set to false. No soup for you!',);// 'This thing should be true but you set to false. No soup for you!'
ts-lib-scripts 会将warning代码转换成process.env.NODE_ENV !== 'production'代码,如下所示:
warning(condition,argument,argument);
会被替换成:
if('production'!==process.env.NODE_ENV){warning(condition,argument,argument);}
lodash是前端的瑞士军刀,在前端出现频次非常高,但是 lodash 库很大。ts-lib-scripts 内置了 lodash 打包优化。
要使用 lodash,你需要先安装 lodash:
yarn add lodash lodash-es @types/lodash
然后在你的代码中自由使用 lodash:
// ./src/index.tsimport{kebabCase}from'lodash';exportconstKebabLogger=(msg:string)=>{console.log(kebabCase(msg));};
ts-lib-scripts 会将上面的代码翻译成:
importofrom'lodash-es/kebabCase';conste=(e)=>{console.log(o(e));};export{easKebabLogger};
也就是说,ts-lib-scripts 将import kebabCase from 'lodash/kebabCase'转换成了import o from 'lodash-es/kebabCase'。这样这些 lodash 代码可以被 treeshaking 优化。
ts-lib-scripts 使用 Babel 编译 TypeScript,在转换 ES6 语法时,需要一些胶水代码才能转换成 ES5 语法。如类:
index.js:
exportclassPointer{construcor(privatex:number,privatey:number){}move(x:number,y:number){returnnewPoint(this.x+x,this.y+y);}}
不经过优化编译后的代码如下:
'use strict';function_classCallCheck(instance,Constructor){if(!(instanceinstanceofConstructor)){thrownewTypeError('Cannot call a class as a function');}}function_defineProperties(target,props){for(vari=0;i<props.length;i++){vardescriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if('value'indescriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}function_createClass(Constructor,protoProps,staticProps){if(protoProps)_defineProperties(Constructor.prototype,protoProps);if(staticProps)_defineProperties(Constructor,staticProps);returnConstructor;}/* eslint-disable import/prefer-default-export */varPointer=/*#__PURE__*/(function(){functionPointer(x,y){_classCallCheck(this,Pointer);this.x=x;this.y=y;}_createClass(Pointer,[{key:'move',value:functionmove(x,y){returnnewPointer(this.x+x,this.y+y);},},]);returnPointer;})();exports.Pointer=Pointer;//# sourceMappingURL=my-ts-lib.cjs.development.js.map
编译后的代码中有_classCallCheck、_createClass、_defineProperties三个函数,这三个函数就是为了支持 ES6 类语法的胶水代码,我们称之为 babel helpers。
如果我们的库代码中包含了这样的代码,那么被其他项目引用后,就很可能出现重复的这样的代码,这样就增加了应用的大小。
我们可以将胶水代码改成引用 babel helpers 相关的库。经过优化后,编译的代码如下:
'use strict';function_interopDefault(ex){returnex&&typeofex==='object'&&'default'inex ?ex['default'] :ex;}var_classCallCheck=_interopDefault(require('@babel/runtime/helpers/classCallCheck'),);var_createClass=_interopDefault(require('@babel/runtime/helpers/createClass'),);/* eslint-disable import/prefer-default-export */varPointer=/*#__PURE__*/(function(){functionPointer(x,y){_classCallCheck(this,Pointer);this.x=void0;this.y=void0;this.x=x;this.y=y;}_createClass(Pointer,[{key:'move',value:functionmove(x,y){returnnewPointer(this.x+x,this.y+y);},},]);returnPointer;})();exports.Pointer=Pointer;//# sourceMappingURL=my-ts-lib.cjs.development.js.map
这样的 ES6 语法胶水代码还很多,包括async/await语法。
实践证明,babel 现在在自动引入 polyfill 方面做得还不是特别好。所以 ts-lib-scripts 不会自动插入新 API 的补丁引用。当你的库使用到新的 API,但是又需要支持旧浏览器,你就需要在库的醒目位置(如 README.md 文档)提示使用者需要引入这些新 API 的 polyfill。
ts-lib-scripts 使用 rollup 做打包,所以支持 tree shaking。
tree-shaking 特性会将应用中没有使用到的代码在最终打包时剔除掉。
ts-lib-scripts 使用babel-plugin-annotate-pure-calls插件辅助产生#__PURE__注释,以使项目充分利用 tree shaking 剔除无用代码。
日常工作中经常需要创建 TypeScript 库,但是每次都需要从零开始设置配置。用惯create-react-app创建小应用后,创建一个类似的简单易用的工具的想法就变得非常强烈。偶然间遇到tsdx,哇喔,多简洁的工具呀。可惜跟我想要的还差一些距离,而所在的团队又急切需要这方面的工具,所以就出来了这样的一个轮子,满足日常需求。
ts-lib-scripts 只关注如何构建 TypeScript 库,不关注其他方面的需求。你如果想构建 React 应用,请使用create-react-app、Next.js等工具;如果你想构建 JavaScript 库,看看microbundle;如果想构建大型应用,您最好研究一下Webpack。
ts-lib-scripts 会围绕着 TypeScript 库的开发、构建、部署体验继续前进,与周边工具继续加强关联性,如 VSCode、Git、Github、CircleCI、Docker 等。
近期规划清单:
- 更易用的 ts-lib-scripts 文档
- 支持 React (0.2.0)
- 添加 demo 支持
- 文档支持:docusaurus(针对普通库)
- 文档支持:docz(针对 React 组件库) (0.2.0)
- TypeScript 编译缓存,提升 TypeScript 编译速度
- 默认启用 UMD(正在提升 UMD 打包体验)
- 文档:CircleCI 集成
- Git:提交前检查提交注释(git commit message)
- vscode:添加默认的 demo 调试配置
- vscode:推荐安装的插件清单
- npm:发布包命令(类似如
lerna publish) - eject
- 文档:迁移指南
- 其他类型的文件编译处理
中期规划清单:
- 使用 16 倍速的swc编译 TypeScript 代码(等着 swc 的成熟)
- 英文文档
- monorepo 支持
- 分离的 ES Module 支持(不合并文件,只针对单个文件进行编译处理)
About
以 🚀 速度创建零配置 TypeScript 库项目的命令行工具
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors4
Uh oh!
There was an error while loading.Please reload this page.