Skip to main content

10-19

1 Babel

目的:

  • babel是什么?做什么?
  • babel原理?

一些重点:

  • babel是基于插件的,如果没有配置插件(预设),则babel不会进行转化

一些关联问题:

  • babel与corejs的关系是什么?babel的一个插件依赖corejs,详见问题二
  • BrowserList是什么?babel的一个插件依赖BrowserList,详见问题一
  • postcss插件又是干什么的?
  • js中的Reflect(反射)是什么?

介绍:babel是一个能够将es2015(es6)以上的js语法转换为es5的语法。

// Babel Input: ES2015 arrow function
[1, 2, 3].map(n => n + 1);

// Babel Output: ES5 equivalent
[1, 2, 3].map(function(n) {
return n + 1;
});

问题一:Browserlist

babel与browserlist的关系:

By default @babel/preset-env will use browserslist config sources unless either the targets or ignoreBrowserslistConfig options are set.

问题二:babel与corejs的关系是什么?

corejs 是一个现代填充库(Modular standard library for JavaScript.),支持 state>0 的Ecma-262的提案。

babel 是一个工具链,主要用于在当前和旧浏览器或环境中将 ECMAScript 2015+ 代码转换为向后兼容的 JavaScript 版本。

注意:babel能够进行两部分转化,语法转化和API转化。

babel本身不带有任何作用,都是依靠插件进行工作,例如:@babel/preset-env、@babel/polyfill等

@babel/preset-env本身只有语法转化的功能,如果配置了useBuiltIns,则可以利用@babel/polyfill进行API填充,而@babel/polyfill本身利用corejs进行填充,所以这就是它们俩的关系。

但babel v7.4.0以上不在建议使用@babel/polyfill ,而是使用core-js/stable、regenerator-runtime/runtime代替。

再来看看 @babel/core,它是babel的编译器,包含三个部分,@babel/paser、@babel/traverse、@babel/generator,也就是解析代码为AST、转化AST、生成代码

再来看看 @babel/preset-env,它是babel的一组插件的集合,它能够将es2015+的代码转化为目标代码(默认为es5)

[1] babel,babel-core是什么关系?分不清他们的职责?.https://www.zhihu.com/question/277409645

[2] 了解babel:polyfill、loader、 preset-env及 core之间的关系.https://zhuanlan.zhihu.com/p/138108118

2 safeTransferFrom is not a function

原因:abi文件有多个方法,它会优先访问第一个方法

✅ 解决方案:删除多余方法即可,此处为safeTransferFrom方法

3 styled-components的生态系统

生态系统:https://styled-components.com/ecosystem

里面包含很多在styled-components基础上实现的库

import { ApolloClient, HttpLink, ApolloLink, InMemoryCache, concat } from '@apollo/client';

const httpLink = new HttpLink({ uri: '/graphql' });

const authMiddleware = new ApolloLink((operation, forward) => {
// add the authorization to the headers
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
authorization: localStorage.getItem('token') || null,
}
}));

return forward(operation);
})

const client = new ApolloClient({
cache: new InMemoryCache(),
link: concat(authMiddleware, httpLink),
});

4 nodejs的官网好好看一下

nodejs官网文档14.8.1:https://nodejs.org/dist/latest-v14.x/docs/api/fs.html#fs_promise_example

5 在react中想渲染空格的方法

有两种方法

第一种:用{' '}

<Text>{' '}123</Text>

=>> 123

第二种:用html标记符

&nbsp;123
=>> 123

6 jsdelivr的CDN缓存

在github上面的公开项目,如果打了一个版本号,那么自动进入jsdelivr的CDN缓存

第一步:发布一个版本

第二步:引用网址

https://cdn.jsdelivr.net/gh/你的用户名/你的仓库名@发布的版本号/文件路径

//例如:加载 jQuery v3.2.1
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/dist/jquery.min.js

7 package.workspaces属性作用

介绍:它能够指定多个包,而用 yarn 之后可以安装多个项目的依赖

示例:在根目录下安装多个项目的依赖

//root下
package.json
packages
-- A
-- -- package.json
-- B
-- -- package.json

在root目录下的package.json内容如下:

{
"name": "root",
"private": true,
"npmClient": "yarn",
"usingWorkspances": true,
"workspaces": {
"packages": [
"packages/*" //重点
],
"nohoist": [
"**/*",
"**/**"
]
},
}

而A下的package.json

{
"name": "@test/admin",
"version": "0.0.1",
"private": true,
}

B下的package.json

{
"name": "@test/sever",
"version": "0.0.1",
"private": true,
}

那么如果在根目录运行 yarn ,则会安装三个package.json对应的依赖,并在根目录的node_modules下挂载A、B包的依赖路径

7 [科普]小白如何理解UniswapV3白皮书

v2和v3的核心公式

其实,它们的核心公式都是

x*y = k

只是在v3中引入了虚拟数量,导致x和y分成了两部分

(x + △x)(y + △y) = k

所以图就像左下角移动了,流动性范围利用率提高了(橙色部分),而斜率(价格)不变。

image-20211022111607701

添加流动性数量计算

区间内

L = delta x * (√p * √p_{upper}) / (√p_{upper} - √p)
L = delta y / (p - p_{lower})

L表示k=𝐿^2L=√k
p表示价格
delta x表示要添加的x数量
delta y表示要添加的y数量

高于区间

L = delta y / (p_{upper} - p_{lower})

低于区间

L = delta x * (√p_{upper} * √p_{lower}) / (√p_{upper} - √p_{lower})

[1] 如何计算导数?https://www.shuxuele.com/calculus/derivatives-introduction.html

[2][科普]小白如何理解UniswapV3白皮书.https://learnblockchain.cn/article/3055

[3][科普]由浅入深理解uniswapV3原理【视频】.https://www.bilibili.com/video/BV1uq4y1N7o6?from=search&seid=12157076229729745114&spm_id_from=333.337.0.0

8 Typescript接口命名规范

不用加I

9 GraphQL

问题一:GraphQL与SQL的区别?

SQL是Structured Query Language,GraphQL很显然,是Graph Query Language,它们的区别如下:

  • SQL的数据源是数据库,GraphQL的数据源可以是restful API,各种服务/微服务,或者数据库。
  • MySQL是SQL的实现,Apollo, Relay也是GraphQL规范的实现

[1] GraphQL入门&server搭建(一).https://juejin.cn/post/6978395879040516110

问题二:GraphQL如何以以太坊网络的数据为数据源?

这里需要知道三个库:

  • Graph Node – 一种服务器实现,用于对来自以太坊的数据进行索引、缓存和服务查询。
  • Graph CLI – 用于构建和编译部署到 Graph 节点的项目的 CLI。
  • Graph TypeScript Library – TypeScript/AssemblyScript 库,用于编写要部署到 The Graph 的子图映射。

大致流程为:程序员利用TS编写子图映射,通过CLI工具构建、编译和部署到Node上。Node会提供url以供GraphQL客户端查询(Apollo客户端,是GraphQL的实现)。

回到问题本身,我们可以看到是Node在帮我们操作,在获取以太坊网络的数据。

可以看以下图,表示前端Dapp应用和智能合约与整个以太坊网络的数据同步和检索的流程:

image-20211025095005983

[1] graph协议.https://github.com/graphprotocol

[2] graph协议入门.https://github.com/graphprotocol/graph-node/blob/master/docs/getting-started.md

[3] assemblyscript.https://github.com/AssemblyScript/assemblyscript

问题三:如何基于已有的 REST API 实现 GraphQL API?

dad-joke-dadabase项目(爸爸笑话):https://github.com/thawkin3/dad-joke-dadabase

[1] 如何基于已有的 REST API 实现 GraphQL API.https://juejin.cn/post/6930911717950947341

10 死活安装不上 sharp

解决:回家重新yarn,安装上了,公司网络问题

11 雷电模拟器3.0无法使用 指针位置 功能

解决方案:需要在模拟器所在的VMS文件夹新建一个debug的空TXT文本

问题一:为什么用3.0的版本?

因为3.0支持学习强国的视频播放

[1] 开发者模式的指针位置开启后不起作用.https://www.ldmnq.com/forum/72566.html

12 Lua基础语法

模拟类写法

第一种:

Person = {}

Person.speak = function (self)
...
end

-- 调用
Person:speak()

第二种:

function Person:speak()
...
end

-- 调用
Person:speak()

逻辑运算符

or and not

获取时间戳

os.time()
-- 获取秒级别时间戳

抛出错误

error(msg, [level])

[1] Lua 基础简明教程.https://www.cnblogs.com/xiand/p/6699964.html

13 Mac安装MongoDB

不要怕麻烦,两步,下载、解压-> 配置环境变量

第一步:下载社区版MongoDB

https://www.mongodb.com/try/download/community

第二步:放到自己喜欢的目录(等下要用),解压

第三步:设置环境变量,让mongo命令生效

#mongo
export PATH="/Users/jiangjin/Documents/static-app/mongodb-macos-x86_64-5.0.3/bin:$PATH"

注意软件路径

14 box.shadow(x,y,模糊半径,扩散半径,颜色)

如题

15 yarn global add的软件无法在全局访问(Mac)

.bash_profile 中添加

export PATH="$PATH:`yarn global bin`:$HOME/.config/yarn/global/node_modules/.bin" 

之后再source一下

source ~/.bash_profile

⚠️ 附,这样添加

export PATH="$PATH:`yarn global bin`"
export PATH="/Users/jiangjin/.yarn/bin:$PATH"

附,yarn查看全局安装路径

yarn global dir

[1][记录]解决MAC使用 yarn 安装全局包后找不到命令的问题.export PATH="$PATH:yarn global bin:$HOME/.config/yarn/global/node_modules/.bin"

16 重新审视GraphQL

总体上来讲GraphQL分为查询(变更)语言、类型系统、执行和内省

查询和变更Schema 和类型
字段(Fields)类型系统(Type System)
参数(Arguments)类型语言(Type Language)
别名(Aliases)对象类型和字段(Object Types and Fields)
片段(Fragments)参数(Arguments)
操作名称(Operation Name)查询和变更类型(The Query and Mutation Types)
变量(Variables)标量类型(Scalar Types)
指令(Directives)枚举类型(Enumeration Types)
变更(Mutations)列表和非空(Lists and Non-Null)
内联片段(Inline Fragments)接口(Interfaces)
联合类型(Union Types)
输入类型(Input Types)

还有验证、执行(resolver)、内省(查询支持类型)

查询语言

查询中又分为:别名、片段&内联片段、变量、指令、变更

变量

动态更改查询值

#JEDI是默认值
query HeroNameAndFriends($episode: Episode = "JEDI") {
hero(episode: $episode) {
name
friends {
name
}
}
}

指令

动态更改查询结构

query Hero($episode: Episode, $withFriends: Boolean!) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}
{
"episode": "JEDI",
"withFriends": false
}

GraphQL 的核心规范包含两个指令,其必须被任何规范兼容的 GraphQL 服务器实现所支持:

  • @include(if: Boolean) 仅在参数为 true 时,包含此字段。
  • @skip(if: Boolean) 如果参数为 true,跳过此字段。

变更

其实任何语句都可以实现变更,只是mutation语义上更加符合,具体实现要看resolver

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
#查询变量
{
"ep": "JEDI",
"review": {
"stars": 5,
"commentary": "This is a great movie!"
}
}

注意,在多个 字段 变更请求中,执行是继发的。查询字段时,是并行执行,而变更字段时,是线性执行,一个接着一个。

类型语言

称之为 “GraphQL schema language”

type Character {
name: String!
appearsIn: [Episode!]!
}

类型分为:标量类型和复杂类型,复杂类型以标量类型为基础堆叠起来的类型。例如:枚举、列表、接口、联合、输入类型

标量类型有

  • Int:有符号 32 位整数。
  • Float:有符号双精度浮点值。
  • String:UTF‐8 字符序列。
  • Booleantrue 或者 false
  • ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。

当然,还可以实现自定义标量类型

枚举类型

enum Episode {
NEWHOPE
EMPIRE
JEDI
}

列表和非空

type Character {
name: String!
appearsIn: [Episode]!
}

! 表示非空字段,如果它结果得到了一个空值,那么事实上将会触发一个 GraphQL 执行错误,以让客户端知道发生了错误。

myField: [String!]表示非空内容,内容不能为null

myField: [String]!表示非空列表,列表不能为null

接口

interface Character {
id: ID!
name: String!
friends: [Character]
}

实现接口

type Human implements Character {
id: ID!
name: String!
friends: [Character]

#其他类型
otherFiled1: Int
}

type Droid implements Character {
id: ID!
name: String!
friends: [Character]

otherFiled2: String!
}

联合类型

union SearchResult = Human | Droid | Starship

注意,联合类型的成员需要是具体对象类型;你不能使用接口或者其他联合类型来创造一个联合类型。

输入类型

从客户端传递复杂类型

input ReviewInput {
stars: Int!
commentary: String
}
#通过输入的$review去查询内容
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}

输入类型示例(示例来源[1]

type Account {
name: String
age: Int,
sex: String,
salary(city: String): Int
}

input AccountInput {
name: String
age: Int,
sex: String
}

type Mutation {
createAccount(input: AccountInput): Account
}

那如何传参呢?如下:

mutation {
createAccount(input: {
name: "李四"
age: 10
sex: "女"
}) {
name
}
}

其实这里和上述的传参方式没啥区别,唯一的不同就是类型的转变,这里变成了对象方式的传参。

@apollo/client 客户端中如何传递数据呢?下面是react中的实例代码(参考[2]):

import { ApolloClient, InMemoryCache } from '@apollo/client'
import { THEGRAPH_URL } from '../services/config'

export const client = function (url: string) {
return new ApolloClient({
uri: '...',

cache: new InMemoryCache({
typePolicies: {
Token: {
// Singleton types that have no identifying field can use an empty
// array for their keyFields.
keyFields: false,
},
Pool: {
// Singleton types that have no identifying field can use an empty
// array for their keyFields.
keyFields: false,
},
},
}),
queryDeduplication: true,
defaultOptions: {
watchQuery: {
fetchPolicy: 'no-cache',
},
query: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
},
})
}

const result = client(url).query({
query: graphSql,
variables: {}, //这里传参
})

[1] GraphQL从入门到起飞.https://juejin.cn/post/6897173001373483021#heading-33

[2] uniswap_v3项目

内省

内省能干啥?用于查询GraphQL支持哪些东西

询问哪些类型是可用的

#询问哪些类型是可用的
{
__schema {
types {
name
}
}
}
#回答
{
"data": {
"__schema": {
"types": [
{
"name": "Query"
},
{
"name": "String"
},
{
"name": "ID"
},

...

{
"name": "ReviewInput"
},
{
"name": "__Type"
},

...

{
"name": "__DirectiveLocation"
}
]
}
}
}

说明:__Directive - 这些有着两个下划线的类型是内省系统的一部分。

询问所有查询开始的地方

{
__schema {
queryType {
name
}
}
}
#回答
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
}
}
}
}

询问特定的类型

{
__type(name: "Droid") {
name
kind #更深入了解类型
}
}
#回答
{
"data": {
"__type": {
"name": "Droid",
"kind": "OBJECT"
}
}
}

询问它有哪些字段,列出它的 名称 以及 类型的名称类型的种类

{
__type(name: "Droid") {
name
fields {
name
type {
name
kind
}
}
}
}
#回答
{
"data": {
"__type": {
"name": "Droid",
"fields": [
{
"name": "id",
"type": {
"name": null,
"kind": "NON_NULL"
}
},
{
"name": "name",
"type": {
"name": null,
"kind": "NON_NULL"
}
},
{
"name": "friends",
"type": {
"name": null,
"kind": "LIST"
}
},
]
}
}
}

ofType可以查询包装类型

ofType {
name
kind
}
#回答
"ofType": {
"name": "String",
"kind": "SCALAR"
}

17 fetch使用方法

fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});

⚠️ 注意要从.json中拿到数据

const res = await fetch('http://example.com/movies.json')
const data = await res.json()
//要解析为json格式

18 Apollo客户端配置异步uri

总体思想为:利用 fetch 属性支持异步函数,来进行异步获取uri

const customFetch = async (uri, options) => {
//异步获取uri

const { operationName } = JSON.parse(options.body);
return fetch(`${uri}/graph/graphql?opname=${operationName}`, options);
};

const link = new HttpLink({ fetch: customFetch });

⚠️ 注意:customFetch每次请求都会进来,所以建议不要在customFetch内部进行请求,而是请求好,放入全局变量(或者状态管理器)中,在customFetch内部阻塞获取已请求好的uri即可

19 在nestjs中使用graphql

TODO

有一些问题:

1.在resolver中导入的类型,可以来自实体

import { Post } from './post.entity';

@Resolver((of) => Post)

2.@Qeury()装饰器

@Query(() => Post, { name: 'post' })

它一共有三个重载函数,第二个参数可以对该字段进行 描述 (字段名、描述、弃用原因、复杂的)

export interface QueryOptions extends BaseTypeOptions {
name?: string;
description?: string;
deprecationReason?: string;
complexity?: Complexity;
}

export declare function Query(): MethodDecorator;
export declare function Query(name: string): MethodDecorator;
export declare function Query(typeFunc: ReturnTypeFunc, options?: QueryOptions): MethodDecorator;

同理,mutation也有几个重载方法,MutationOptions选项与QueryOptions一致:

export declare function Mutation(): MethodDecorator;
export declare function Mutation(name: string): MethodDecorator;
export declare function Mutation(typeFunc: ReturnTypeFunc, options?: MutationOptions): MethodDecorator;