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 相关文章推荐
jQuery之end()和pushStack()使用介绍
Feb 07 Javascript
JQuery实现表格中相同单元格合并示例代码
Jun 26 Javascript
JS获取网页属性包括宽、高等等
Apr 03 Javascript
javascript使用switch case实现动态改变超级链接文字及地址
Dec 16 Javascript
js实现最短的XML格式化工具实例
Mar 12 Javascript
js实现用户离开页面前提示是否离开此页面的方法(包括浏览器按钮事件)
Jul 18 Javascript
浅析Javascript中bind()方法的使用与实现
May 30 Javascript
详解JS构造函数中this和return
Sep 16 Javascript
vue项目中使用百度地图的方法
Jun 08 Javascript
详解Vue中watch的详细用法
Nov 28 Javascript
Vue开发中常见的套路和技巧总结
Nov 24 Vue.js
解决await在forEach中不起作用的问题
Feb 25 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 验证码(倾斜,正弦干扰线,黏贴,旋转)
2013/06/29 PHP
PHP函数分享之curl方式取得数据、模拟登陆、POST数据
2014/06/04 PHP
PHP的Trait机制原理与用法分析
2019/10/18 PHP
CLASS_CONFUSION JS混淆 全源码
2007/12/12 Javascript
js 数组操作代码集锦
2009/04/28 Javascript
JavaScript 页面编码与浏览器类型判断代码
2010/06/03 Javascript
JS对img进行操作(换图片/切图/轮换/停止)
2013/04/17 Javascript
JS控制一个DIV层在指定时间内消失的方法
2014/02/17 Javascript
JavaScript基于setTimeout实现计数的方法
2015/05/08 Javascript
jquery判断密码强度的验证代码
2020/04/22 Javascript
js判断文本框输入的内容是否为数字
2015/12/23 Javascript
详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
2017/06/01 jQuery
jQuery上传插件webupload使用方法
2017/08/01 jQuery
vue中子组件向父组件传递数据的实例代码(实现加减功能)
2018/04/20 Javascript
Vuex的actions属性的具体使用
2019/04/14 Javascript
在pycharm中开发vue的方法步骤
2020/03/04 Javascript
JavaScript indexOf()原理及使用方法详解
2020/07/09 Javascript
Js on及addEventListener原理用法区别解析
2020/07/11 Javascript
Python中for循环控制语句用法实例
2015/06/02 Python
使用Python的PIL模块来进行图片对比
2016/02/18 Python
python 实现自动远程登陆scp文件实例代码
2017/03/13 Python
PyQt5主窗口动态加载Widget实例代码
2018/02/07 Python
Python实现基于TCP UDP协议的IPv4 IPv6模式客户端和服务端功能示例
2018/03/22 Python
Windows系统Python直接调用C++ DLL的方法
2019/08/01 Python
Python 获取numpy.array索引值的实例
2019/12/06 Python
Python 在局部变量域中执行代码
2020/08/07 Python
创意广告词
2014/03/17 职场文书
《长相思》听课反思
2014/04/10 职场文书
党员批评与自我批评范文
2014/09/23 职场文书
基层党支部整改方案
2014/10/25 职场文书
2014党的群众路线教育实践活动总结材料
2014/10/31 职场文书
邀请函格式范文
2015/02/02 职场文书
导游词之山西-五老峰
2019/10/07 职场文书
win10+anaconda安装yolov5的方法及问题解决方案
2021/04/29 Python
react中的DOM操作实现
2021/06/30 Javascript
Java使用HttpClient实现文件下载
2022/08/14 Java/Android