更新 : 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. Centos7编译安装zabbix-4.0.1

    架构组合:nginx1.9.10+php7.0.32+mysql5.7.22+zabbix4.0.1 nginx1.9.10 先装依赖 openssl-1.1.0f tar zxvf openssl- ...

  2. python简说(八)random

    import randomprint(random.randint(1,23))#随机整数l=[1,2,3,4]s='abcdefeg'print(random.choice(s))#随机选择一个元素 ...

  3. ARM 架构、ARM7、ARM9、STM32、Cortex M3 M4 、51、AVR 之间有什么区别和联系?(转载自知乎)

    ARM架构:  由英国ARM公司设计的一系列32位的RISC微处理器架构总称,现有ARMv1~ARMv8种类. ARM7:       一类采用ARMv3或ARMv4架构的,使用冯诺依曼结构的内核. ...

  4. 20165211 2017-2018-2 《Java程序设计》课程总结

    20165211 2017-2018-2 <Java程序设计>课程总结 一.每周作业及实验报告博客链接汇总 预备作业1:我期望的师生关系 预备作业2:学习基础和C语言调查 预备作业3:Li ...

  5. canvas-简单快速实现知乎登录页背景效果

    前言 打开知乎的登录页,就可以看到其背景有一个动效,看起来好像蛮不错的样子: 这个效果使用canvas是不难实现的,接下来就一步一步地讲解并实现这个效果. 分析 在动工之前先分析这个效果到底是如何运动 ...

  6. Codeforces 834D The Bakery - 动态规划 - 线段树

    Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredient ...

  7. Android studio 搭建测试环境 创建虚拟机

    1.打开android studio2.0 ,选择AVD Manger 2.选择Create Virtual Device 3.在左侧Category中选择Phone,然后选择自己喜欢的手机型号,点击 ...

  8. Android中EditText焦点问题

    https://www.jianshu.com/p/3d31d681f4bc 问题:当EditText失去焦点时做内容校验 场景:用户编辑EditText将内容清空,当点击空白地方时关闭软键盘,同时校 ...

  9. (zhuan) Paper Collection of Multi-Agent Reinforcement Learning (MARL)

    this blog from: https://github.com/LantaoYu/MARL-Papers Paper Collection of Multi-Agent Reinforcemen ...

  10. 给Ubuntu添加清华的软件源

    找到 sources.list 文件 cd /etc/apt/ 编辑 vim sources.list 在最后面加上下面这几条语句 # 默认注释了源码镜像以提高 apt update 速度,如有需要可 ...