更新 : 2018-10-28

不知道为什么在 ng 跑一直做不到 .d.ts

最后发现,如果有一个插件 propagating-hammerjs.ts

那么就在 root create 一个 propagating-hammerjs.d.ts ,名字要匹配到,这样就可以跑了。

暂时不管先呗..

refer :

https://blog.angularindepth.com/creating-a-library-in-angular-6-87799552e7e5

https://blog.angularindepth.com/creating-a-library-in-angular-6-87799552e7e5

https://blog.angularindepth.com/the-angular-library-series-publishing-ce24bb673275

https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/create-library.md#why-do-i-need-to-build-the-library-everytime-i-make-changes

https://github.com/leohxj/react-boilerplates/wiki/%E5%8C%BA%E5%88%AB%E4%B8%8B-%60dependencies%60,-%60devDependencies%60,-%60peerDependencies%60

https://stackoverflow.com/questions/38971984/how-to-add-custom-typings-in-typescript-2-0

https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html

https://www.typescriptlang.org/docs/handbook/declaration-files/library-structures.html

https://github.com/TypeStrong/grunt-ts#references

https://stackoverflow.com/questions/51565681/publishing-to-the-types-organaization-in-npm

在使用 Angular 开发项目的时候, 我们经常会遇到一种问题, 就是要引入一些老旧的 library 或者我们想开发一个自己的 library.

这篇会教大家

1. 把自己以前写的 js library, 模块化输出 + d.ts, 然后正规的在 Angular 上使用.

2. 为第三方 js library 加上 d.ts 然后 Angular 引用

3. 用 Angular cli 开发自己的 library, 直接写 typescript 啦.

先说说老旧 library 的问题, 主要就是 typesciprt , 还有 modular 机制.

因为 ng 要求使用 Typesciprt 而且所有代码都需要用模块化引入的概念, 然而老旧的代码怎么会有这些呢 ... ?

这里说的老旧 library 包括第三方的,也包括你自己曾经的呕心沥血创作.

来,

我们假设有个 add-to-cart 插件, 是很久以前的代码, 没有模块,没有 typescript, 没有 npm, 就只有一个能下载的 js file.

add-to-cart.js

window['add-to-cart'] = {
value : 'value',
method : function(value){
return value
}
}

代码长这样, 通过一个 window 把功能 "export" 出去, 使用的方式就是直接在 html 通过 <script> 引入, 然后就可以 window['add-to-cart'] 使用功能了.

在 ng 项目中,我们不可以直接 <script> 也尽量不要 append <script>

正确做法是这样的 :

1. 我们先写一个 .d.ts 给这个 add-to-cart.js

d.ts 是用来做借口类型定义的, 我们并不需要重写这个 js 代码, 我们只是把它公开的接口添加上类型就好了,这样调用起来就很自然了.

我们把这个 js 放入到 assets 里,并且创建一个 .d.ts 给它.

add-to-cart.d.ts

interface Window {
'add-to-cart': {
value: string;
method: (value: string) => string
}
}

我们只需要定义公开的接口类型就可以了. 然后像下面这样引入到我们的组件里使用.

import { Component, OnInit } from '@angular/core';
import '../assets/add-to-cart';
/// <reference path="../assets/add-to-cart.d.ts" /> @Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
ngOnInit() {
const g = window['add-to-cart'].value;
}
}

是不是挺简单的 ?

上面这个例子是最糟糕的情况了,如果这个插件还是有人维护, 或者你想帮忙继续维护它. 那下面是我们需要做的. ( note :自己的古老插件也可以这样做)

1. 把它添加上模块化 export, 然后发布到 npm 去

添加一个 package.json, 注意,这里我加了一个 prefix 'stooges', 防止命名冲突 (毕竟 add-to-cart 太热门了嘛 /.\)

{
"name": "stooges-add-to-cart",
"version": "0.0.1",
"private": false,
"main": "./stooges-add-to-cart.js",
"typings": "./stooges-add-to-cart.d.ts"
}

结构如上

stooges-add-to-cart.js 就是加入了一个 modular 包装同时把 window 'export' 改了.

;(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global['stooges-add-to-cart'] = factory()
}(this, (function () { return {
value : 'value',
method : function(value){
return value
}
} })));

stooges-add-to-cart.ts 把 window 定义改成了模块输出而已.

declare module 'stooges-add-to-cart' {
export var value: string;
export function method(value: string) : string
}

最后就 npm publish, 然后在项目中 yarn add 'stooges-add-to-cart' 就可以 import 使用了.

import { Component, OnInit } from '@angular/core';
import * as addToCart from 'stooges-add-to-cart'; @Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
ngOnInit() {
const da = addToCart.method('dada');
}
}

是不是挺简单的 ?

如果这项目不是你的,而是第三方项目,我们假设情况不要太糟糕,它有模块化并且有发布到 npm,只是这项目不支持 typescirpt 而已, 这情况很常见, 因为目前只有 Angular 一定要 Typescirpt, vue, react 并没有那么要求.

首先你要做的是先去 npm 找 @types/stooges-add-to-cart , @types/module_name 是规范, 所有为 non-typscirpt 项目的 d.ts 都被好心的开发者发布到了这里来.

找到就恭喜你啦, yarn add @types/stooges-add-to-cart --dev 把它下载了就可以用.

Angular 默认就帮我们设置好了, 通过 tsconfig typeroot 让 typescirpt 知道 .d.ts 都在哪里.

但...如果找不到呢 ... ?

那就只能自己写了... 一般上, 在写第三方插件时, 我们不会真的把所有接口类型都写进 .d.ts 里, 通常就写自己会用到的就好了... 如果你真的写到完. 那请你一定要发布到 @types 里头给大家用哦..

如果只是写一部分, 那我们的做法通常是这样..

开一个项目, 把所有我们要写的插件 .d.ts 全部放进去, 结构就是 folder with module name -> index.d.ts

package.json

{
"name": "stooges-types",
"version": "0.0.1",
"private": false,
"main": ""
}

然后 yarn add stooges-types --dev

tsconfig.json

{
"compilerOptions": {
"typeRoots": [
"node_modules/@types",
"node_modules/stooges-types"
]
}
}

这样就可以了, 当然你也不一定要发布到 npm, 直接放 local file 也是一样工作的.

这里还有一个小东西, 我们需要注意.

就是很多 js 都是 export function 的,function 还有 property

我们知道 ecma2015 (es6) import 的时候是一个对象, 比如 import * as stooges from 'stooges' or import { 'method' } from 'stooges';

export 必须是对象丫.

那我们需要特别一点点的写法.

add-to-cart.js

;
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global['add-to-cart'] = factory()
}(this, (function () {
'use strict' function method(value) {
return value + 'yeah';
} method.version = 1; return method; })));

add-to-cart.d.ts

declare namespace myFuncLib {
export var version: number
} declare function myFuncLib(value: string): string; export default myFuncLib;

然后 import stooges from 'stooges';   stooges('value'); 就可以了。

以上的 .d.ts 必须配搭在同一个项目里,或者在 @types 里面, 我没有搞明白为什么...

如果你是要写在 local 的话, 可以换一个写法.

declare namespace myFuncLib {
export var version : number
} declare function myFuncLib(value:string) : string; declare module 'add-to-cart'
{
export default myFuncLib;
}

或者返回 class, import * as Isotope from 'isotope-layout'

declare class Isotope {
constructor(selecter: string, options: {
itemSelector: string,
layoutMode: string
})
}
declare module Isotope { }
declare module "isotope-layout" {
export = Isotope;
}

有时间才去研究原理呗..tsconfig typeRoots 记得添加这个 .d.ts 哦.

以上就是比较正规的做法了. 不会费太大的功夫,但是结果又可以很稳定,是不是挺好的 ?

下面说说如果用 angular cli 做的一个 library, 这个就简单太多了.

首先 ng new Project

然后 ng g library stooges -prefix s   (stooges 是 lib 的名字, prefix 是 compoent 的 prefix selector, 比如这里是 s-datepicker)

这时候, 我们的 angular.json 会多一个 projects

还有我们的 tsconfig.json 会多了这个 path. 因为我们这个是 local library 没有要发布到 npm, 所以要特别告知 typescript import 时去哪里找 module, 如果是发布到 npm 那就可以像一般的 import 那样直接从 node_modules 获取了.

记得我们是不可以直接使用我们的 library 的, 每一次都需要 build. 所以

ng build stooges --watch (如果你是在做调试的话,加上自动 watch)

这样就可以了. 如果要发布, 就直接 cd dist/stooges -> npm publish 就好了.

最后说一下 peerDependencies, 如果我们回去看上面的图, projects/stooges 里面还有一个 package.json

{
"name": "stooges",
"version": "0.0.1",
"peerDependencies": {
"@angular/common": "^6.0.0-rc.0 || ^6.0.0",
"@angular/core": "^6.0.0-rc.0 || ^6.0.0"
}
}

这个是我们 library 的 package json, peerDependencies 的意思是, 如果最终的用户引入我们的这个 library, 它的项目必须也引入 peerDependencies 里面的模块.

一般上做 library 都是这样的, 为了不要让用户重复引入模块而这样做.

还有一个点也是要注意一下.

在 projects/stooges/src 里面有一个public_api.ts 我们必须把所有的 class 都在这里 export 出去. 虽然很麻烦... 虽然名字很容易撞...但是它就是这样设计的...我也懒得去理解了.

以上.

Angular 学习笔记 ( 创建 library, 转换老旧的 library )的更多相关文章

  1. Angular学习笔记—创建一个angular项目

    开始项目前,你需要先安装node和npm,然后执行npm install -g @angular/cli安装Angular CLI. 如何安装node.js和npm npm使用介绍 1.安装angul ...

  2. angular学习笔记(三十一)-$location(2)

    之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...

  3. angular学习笔记(三十一)-$location(1)

    本篇介绍angular中的$location服务的基本用法,下一篇介绍它的复杂的用法. $location服务的主要作用是用于获取当前url以及改变当前的url,并且存入历史记录. 一. 获取url的 ...

  4. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  5. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

  6. angular学习笔记(三十)-指令(1)-概述

    之前在 angular学习笔记(十九)-指令修改dom 里面已经简单的提到了angular中的指令,现在来详细的介绍 '指令' 一.指令的创建: dirAppModule.directive('dir ...

  7. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  8. angular学习笔记(三十)-指令(7)-compile和link(1)

    这篇主要讲解指令中的compile,以及它和link的微妙的关系. link函数在之前已经讲过了,而compile函数,它和link函数是不能共存的,如果定义了compile属性又定义link属性,那 ...

  9. angular学习笔记(三十)-指令(5)-link

    这篇主要介绍angular指令中的link属性: link:function(scope,iEle,iAttrs,ctrl,linker){ .... } link属性值为一个函数,这个函数有五个参数 ...

随机推荐

  1. 标准库 string

    1.func Fields(s string) []string,这个函数的作用是按照1:n个空格来分割字符串最后返回的是[]string的切片 package main import ( " ...

  2. HTTP小幺鸡接口管理工具安装与配置说明

    http://www.xiaoyaoji.cn/doc/TxybXPTdx 小幺鸡接口管理工具安装说明 使用可以参考:https://blog.csdn.net/qincidong/article/d ...

  3. bzoj 1419 Red is good - 动态规划 - 概率与期望

    Description 桌面上有R张红牌和B张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到1美元,黑牌则付出1美元.可以随时停止翻牌,在最优策略下平均能得到多少钱. Input 一 ...

  4. python脚本解析json文件

    python脚本解析json文件 没写完.但是有效果.初次尝试,写的比较不简洁... 比较烦的地方在于: 1,中文编码: pSpecs.decode('raw_unicode_escape') 2,花 ...

  5. git初学

    git在团队合作开发时是很有用的,SVN是集中式的代表,而git是分布式的代表,它分为代码区.暂存区.和本地库.在同一个团队中开发时,在代码存储中心(例如,码云.github)上创建一个库,用于储存和 ...

  6. topcoder srm 360 div1

    problem1 link (1)$n \neq m$时,假设$n<m$,那么同一行中的$m$个数字必定都相等. (2)$n=m$时,要满足任意的$i_{1},i_{2},j_{1},j_{2} ...

  7. Mac通过安装Go2Shell实现“在当前目录打开iTerm2”

    先上效果图: 1.从官网下载最新的版本,不要从苹果商店下载,因为苹果商店的版本比较旧,只支持Finders10.6~10.10,不支持最新的版本 http://zipzapmac.com/Go2She ...

  8. vscode Git:failed to execute git

    在vscoad中选择全部提交时候提示 Git:failed to execute git在git日志中会看到这么一行错误信息 empty ident name (for <XXXXXX.com& ...

  9. 终于明白vim 和 grep 中 的正则表达式的用法, vim 正则表达式 和grep基本正则表达式 几乎一样

    要搞清楚 vim中的正则和普通的Perl正则表达式的区别: 因为在perl中所有的元字符 都可以直接使用, 不需要在 元字符的前面加 反斜杠. 但是在vim, 包括grep中就有所区别, 同样是元字符 ...

  10. Elasticsearch-->Get Started-->Modifying Your Data

    https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-modify-data.html Mod ...