angular第三方包开发整理(小结)


Posted in Javascript onApril 19, 2018

近日笔者维护自己的几个无名小repo时,发觉想要创作一个第三方angular包,着实有一些不难但易乱的小问题,故作此文总结。本文将完成以下内容:

  1. 从空白开始搭建一个基于angular的第三方包
  2. 在本地测试待发布的包
  3. 在npm或yarn发布包中指定内容
  4. 在普通angular应用中引入并使用发布的包

基本项目搭建

一般的angular app使用angular-cli创建,直接ng new name搞定,生成的项目把webpack、AOT、dev server等细节都隐藏了,还支持各种参数来配置测试和sass等,使用起来直接npm run start、npm run build,可以说是非常傻瓜了,跳过了学习webpack等的许多大坑。

不过,如果是要搭建angular第三方包,预编译样式和打包部署这些一般就用不着了,取而代之的要熟悉npm(yarn)、tsconfig。

初始化

项目搭建命令如下:

mkdir my-ng-lib
cd my-ng-lib
yarn init

一路回车(实际情况中还是要编辑好包的基本信息)最终得到一个package.json,然后vscode打开:

angular第三方包开发整理(小结)

初始化npm包

依赖

作为angular的第三方包,首先需要安装如下依赖:

angular第三方包开发整理(小结)

依赖安装

其中typescript指定了版本是为了和当前angular-cli使用的版本保持一致,实际可能不必要这么做。

现在安装了开发时要用到的包,但这些包并不用在发布以后,实际上发布的时候我们想要的只是发布自己写的代码,而不是依赖的代码,这需要在package.json中配置peerDependencies作为前置依赖,但包本身不会实际安装这些依赖,实际的包应该由应用项目来安装。现在把peerDependencies添加进package.json:

"peerDependencies": {
  "@angular/common": ">=5.0.0",
  "@angular/core": ">=5.0.0",
  "rxjs": ">=5.0.0"
 }

项目编写

基本项目搭建好后,我们应该只有package.json、node_modules和一个lock文件在项目中,现在要加上真正的项目代码了。

无论这个包是用来实现什么目的的,作为一个第三方包,都应该要导出自己的功能以让其他项目引入使用,所以在项目根目录首先要有一个index.js文件,而我们要开发的是基于angular的TypeScript包,使用的自然是index.ts了,内容就是各种export导出类型、接口、方法等。作为示例这里只导出一个常量:

export const myNgLib: string = 'Hello, thie is my angular 3rd part lib';

为了支持TypeScript我们还需要一个tsconfig.json:

{
 "compilerOptions": {
  "baseUrl": ".", // 基于哪个目录编译ts
  "declaration": true, // 是否生成声明文件即*.d.ts文件,有了它才有TS的代码提示
  "experimentalDecorators": true, // 用于支持TS装饰器如angular中的 @NgModule({}) 之类
  "emitDecoratorMetadata": true, // 用于支持TS装饰器如angular中的 @NgModule({}) 之类
  "module": "commonjs", // 模块化形式
  "moduleResolution": "node", // 模块化形式
  "rootDir": ".", // 以哪个目录为根
  "lib": ["es2015", "dom"], // 支持编译的内置库
  "skipDefaultLibCheck": true, // 是否跳过内置库检查
  "skipLibCheck": true, // 跳过库检查
  "target": "es5", // 编译目标版本
  "suppressImplicitAnyIndexErrors": true, // 几个检查代码的规则
  "strictNullChecks": true, // 几个检查代码的规则
  "noImplicitAny": true, // 几个检查代码的规则
  "sourceMap": true, // 是否生成 .js.map
  "removeComments": true, // 移除注释
  "noFallthroughCasesInSwitch": true // 几个检查代码的规则
 },
 "exclude": [ // 编译时排除以下内容
  "node_modules",
  "*.d.ts",
  "**/*.d.ts"
 ]
}

其中的规则各有各效果,有些为了确定编译路径,有些为了语法检查,有些为了输出声明,还有排除规则等,现在可以tsc看看效果了,不过要先把tsc添加到package.json的scripts中:

"scripts": {
  "tsc": "tsc"
 }

angular第三方包开发整理(小结)

编译得到.js、js.map、.d.ts

发布

完美,这么厉害的包,接下来赶紧发布它。发布命令是

yarn publish

不过在此之前,要准备几件事:

npm账号

发布之前自然得先有npm账号,添加了就可以,最后用npm whoami确认身份。

包的基本信息

也就是要完善package.json,让全网知道这么厉害的包是我们开发的,包括开源许可、包名、作者、版本号等,最重要直接影响发布的是版本号。

选择性发布

基于angular的第三方包区别与普通的js包最大的地方就在于,不能直接把整个包都发布到npm,这样会导致奇怪错误,原因在于.ts文件,实际上需要发布的只是.js、.js.map、.d.ts这三种类型的文件就够了。

因为在其他项目中不一定会使用TypeScript,即使用了也不会刻意包含node_modules目录,也就是说其他项目只管使用,编译的活由我们得包自己来做,相反要是我们还发布多余的.ts文件,只会导致错误。

为了做到选择性发布,需要一个.npmignore文件,和.gitignore配合用来忽略上传的文件,一般这些编译输出我们会添加在.gitignore中,若项目不存在.npmignore,发布到npm时也会使用.gitignore,这不是我们想要的,所以需要再创建这个.npmignore来忽略.ts文件而包含编译输出:

node_modules
yarn-error.log
tsconfig.json
.gitignore
.npmignore
yarn.lock
*.ts
!*.d.ts

现在我们的项目看起来是这样的:

angular第三方包开发整理(小结)

待发布项目

使用yarn pack命令得到本地打包看看效果如何:

angular第三方包开发整理(小结)

本地打包

看起来非常完美,该有的都有了,不该有的都忽略了,那就可以发布了,不过这里就不发布这个没什么用处的包了 : )
打包至此完成,现在看看用起来怎么样。

本地测试

angular的第三方包要做本地测试的话,与普通的包比有一点不足,就是用不了npm link,这会导致错误,特别是在第三方包使用到依赖注入的情况下,原因是运行时实际是在两个angular环境下,再进一步说是因为第三方包依赖的是自己的node_modules,解决办法也很粗暴,删掉第三方包的node_modules即可,不过这代价显然有点大。找遍GitHub发现的另一个办法是配合--preserve-symlinks参数,不过可能是笔者使用姿势不对一直没效果。

最后笔者自己的曲线救国办法是手动写package.json的scripts,本地测试步骤是:

  1. 执行 yarn pack得到本地打包
  2. 解压到测试项目的node_modules中假装是安装的项目
  3. 测试项目中像使用普通安装包一样使用这个直接复制进来的包

参考脚本如下:

"scripts": {
  "prepublish": "npm run clean && tsc", // 清理并编译
  "clean": "rimraf index.js index.js.map index.d.ts src/**/*.js src/**/*.js.map src/**/*.d.ts linktest.tgz", // 清理编译文件
  "link": "npm run pack && tar -zxf linktest.tgz && rimraf ../lib-test-app/node_modules/my-ng-lib && mv package ../lib-test-app/node_modules/my-ng-lib", // 打包后解压并移动到测试项目node_modules中
  "pack": "npm run prepublish && yarn pack --filename linktest.tgz" // 执行编译并打包
 }

总结

  1. 发布基于angular的第三方包的两个难点:一是如何处理好TypeScript的编译,二是如何处理好angular运行上下文。
  2. 本文的命令均使用yarn完成,npm版本命令大同小异均有其对应命令,且发布的包都是在npm托管。
  3. 另外本文仅涉及发布最基本的基于angular的第三方包,包的实际功能方面没有做深入。其实对于不同功能的第三方包,仍有需要学习的内容。

参考资料:

How to create an Angular component library, and how to consume it using SystemJs or Webpack
stories linked library
npm link doesn't work with 1.5.4 version

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 参考教程
Dec 29 Javascript
javascript while语句和do while语句的区别分析
Dec 08 Javascript
使用JavaScript判断图片是否加载完成的三种实现方式
May 04 Javascript
javascript进行数组追加方法小结
Jun 16 Javascript
JavaScript字符串删除重复字符的方法
Dec 25 Javascript
javascript实现仿百度图片的瀑布流加载效果
Apr 20 Javascript
Jquery基础之事件操作详解
Jun 14 Javascript
angular框架实现全选与单选chekbox的自定义
Jul 06 Javascript
关于react中组件通信的几种方式详解
Dec 10 Javascript
一篇文章介绍redux、react-redux、redux-saga总结
May 23 Javascript
Vue watch响应数据实现方法解析
Jul 10 Javascript
Vue和React有哪些区别
Sep 12 Javascript
如何从零开始利用js手写一个Promise库详解
Apr 19 #Javascript
30分钟快速入门掌握ES6/ES2015的核心内容(下)
Apr 18 #Javascript
30分钟快速入门掌握ES6/ES2015的核心内容(上)
Apr 18 #Javascript
原生js实现拖拽功能基本思路详解
Apr 18 #Javascript
一个基于react的图片裁剪组件示例
Apr 18 #Javascript
JS实现对json对象排序并删除id相同项功能示例
Apr 18 #Javascript
Angular ng-animate和ng-cookies用法详解
Apr 18 #Javascript
You might like
深入探讨PHP中的内存管理问题
2011/08/31 PHP
php仿QQ验证码的实例分析
2013/07/01 PHP
php中preg_replace正则替换用法分析【一次替换多个值】
2017/01/17 PHP
PHP两种实现无级递归分类的方法
2017/03/02 PHP
PHP截取发动短信内容的方法
2017/07/04 PHP
IE6与IE7中,innerHTML获取param的区别
2009/03/15 Javascript
javascript 设置某DIV区域内的checkbox复选框
2009/11/30 Javascript
jQuery实现的立体文字渐变效果
2010/05/17 Javascript
使用jQuery轻松实现Ajax的实例代码
2010/08/16 Javascript
jquery下jstree简单应用 - v1.0
2011/04/14 Javascript
修复ie8&chrome下window的resize事件多次执行
2011/10/20 Javascript
jQuery 自定义函数写法分享
2012/03/30 Javascript
js修改原型的属性使用介绍
2014/01/26 Javascript
js实现一个链接打开两个链接地址的方法
2015/05/12 Javascript
jquery原理以及学习技巧介绍
2015/11/11 Javascript
BootStrap selectpicker
2016/06/20 Javascript
javascript 将共享属性迁移到原型中去的实现方法
2016/08/31 Javascript
JS中事件冒泡和事件捕获介绍
2016/12/13 Javascript
详解nodejs微信公众号开发——1.接入微信公众号
2017/04/10 NodeJs
Angular中ng-bind和ng-model的区别实例详解
2017/04/10 Javascript
微信小程序实现聊天室
2020/08/21 Javascript
OpenLayers3实现地图鹰眼以及地图比例尺的添加
2020/09/25 Javascript
[02:23]DOTA2英雄基础教程 幻影长矛手
2013/12/09 DOTA
[47:10]完美世界DOTA2联赛PWL S3 LBZS vs Rebirth 第二场 12.16
2020/12/18 DOTA
python使用pyhook监控键盘并实现切换歌曲的功能
2014/07/18 Python
Python在不同目录下导入模块的实现方法
2017/10/27 Python
解决pycharm运行时interpreter为空的问题
2018/10/29 Python
python导入坐标点的具体操作
2019/05/10 Python
使用pyqt 实现重复打开多个相同界面
2019/12/13 Python
Python生成器常见问题及解决方案
2020/03/21 Python
Gap英国官网:Gap UK
2018/07/18 全球购物
大学同学聚会邀请函
2014/01/29 职场文书
在职员工证明书
2014/09/19 职场文书
2015年高校就业工作总结
2015/05/04 职场文书
走进科学观后感
2015/06/18 职场文书
MySQL数据库配置信息查看与修改方法详解
2022/06/25 MySQL