持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
简单讲launch-editor、vue3-shared、vue.js发布、co、koa-compose的作用、原理和亮点。
旨在总结、复习,温故知新。
1、launch-editor
作用
支持 dev-tools 直接跳转到编译器打开当前页面所属的组件文件
原理
1 在
dev-tools中点击跳转时,会发出网络请求http://10.20.191.44:8080/__open-in-editor?file=src/components/HelloWorld.vue2
vue项目启动的服务拦截到请求,传给launch-editor,解析到文件名,拼工作目录路径得到文件的绝对路径3 基于
powershell命令查当前正在运行的程序是否有编译器,不然找process.env.VISUAL或者process.env.EDITOR,再不然就失败了,报错4 找到后 用 命令行命令 用编译器 直接打开组件文件,
childProcess.spawn( 'cmd.exe', ['/C', "D:\\软件\\Microsoft VS Code\\Code.exe", "C:\\Users\\82454\\Desktop\\vue3\\vue3-project\\src\\components\\HelloWorld.vue"], { stdio: 'inherit' } )相当于
code C:\\Users\\82454\\Desktop\\vue3\\vue3-project\\src\\components\\HelloWorld.vue
我调试时由于编辑器安装在中文路径,打不开文件,为此改了源码,让powershell读取后,转码再解压避免中文乱码,pr后,没有回复。。
学到啥
1 用
code文件路径 可以用编译器打开项目2 搜索
node_modules下的文件 就是「排除的文件」右侧旁边有个设置图标「使用“排查设置”与“忽略文件”」,点击下。
3 高效终端工具-使用 ohmyzsh 打造 windows、ubuntu、mac 系统高效终端命令行工具
mp.weixin.qq.com/s/MHngeDABR…
4 window路径要
\\5 在插件源码里改代码和添加打印代码,需要重新启动,一般的热重载不监听
node_module的文件6 我是怎么在
powershell输出中文的const iconv = require('iconv-lite') const output = iconv.decode( new Buffer( childProcess.execSync( 'powershell -Command "Get-Process | Select-Object Path"', { stdio: ["pipe", "pipe", "ignore"], encoding: "binary", } ), "binary" ), "cp936" )
2、vue3-shared
作用
vue3的一个工具函数包,
图来源:www.yuque.com/ruochuan12/…
学到啥
- 缓存,这里得到闭包函数,驼峰转换过的字符会存到闭包里,第二次转可以直接获取
const cacheStringFunction$1 = (fn) => {
const cache = Object.create(null);
return ((str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
});
};
const camelizeRE = /-(\w)/g;//匹配 -加数字、大小写字母和下划线 如-a -B
const camelize = cacheStringFunction$1((str) => {
//'aa-a-a'.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));返回 "aaAA"
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
});
//'aaAaaA'.replace(/\B([A-Z])/g, '-$1').toLowerCase() "aa-aaa-a"
const hyphenateRE$1 = /\B([A-Z])/g;
const hyphenate$1 = cacheStringFunction$1((str) => str.replace(hyphenateRE$1, '-$1').toLowerCase());
有用
getGlobalThis 全局对象
像作用域链,也像原型链
const getGlobalThis = () => {
return (_globalThis ||
(_globalThis =
typeof globalThis !== 'undefined'
? globalThis
: typeof self !== 'undefined'
? self
: typeof window !== 'undefined'
? window
: typeof global !== 'undefined'
? global
: {}));
};
hasChanged
//检测值的变化
const hasChanged = (value, oldValue) => !Object.is(value, oldValue);
hasOwn 检测是否属性是否拥有
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (val, key) => hasOwnProperty.call(val, key);
// .call 则是函数里 this 显示指定以为第一个参数,并执行函数。
//Object.prototype.hasOwnProperty.call(x,y)
hasOwn({__proto__: { a: 1 }}, 'a') // false
hasOwn({ a: undefined }, 'a') // true
hasOwn({}, 'a') // false
hasOwn({}, 'hasOwnProperty') // false
hasOwn({}, 'toString') // false
// 是自己的本身拥有的属性,不是通过原型链向上查找的。
isMap 判断是不是 Map 对象
const objectToString$1 = Object.prototype.toString;
const toTypeString$1 = (value) => objectToString$1.call(value);
const isMap = (val) => toTypeString(val) === '[object Map]';
//Object.prototype.toString.call(new Map())
// 例子:
const map = new Map();
isMap(map); // true
isObject 是否对象
const isObject$1 = (val) => val !== null && typeof val === 'object';
// 例子:
isObject(null); // false
isObject({name: '若川'}); // true
// 判断不为 null 的原因是 typeof null 其实 是 object
isPromise
//判断是否是对象,是否有then和catch方法
const isPromise = (val) => {
return isObject$1(val) && isFunction(val.then) && isFunction(val.catch);
};
// 判断是不是Promise对象
const p1 = new Promise(function(resolve, reject){
resolve('若川');
});
isPromise(p1); // true
isSet
const isSet$1 = (val) => toTypeString$1(val) === '[object Set]';
isSymbol
const isSymbol = (val) => typeof val === 'symbol';
looseEqual 判断对象是否相同
不像Object.is要引用地址相同,属性和值相同即可
function looseCompareArrays(a, b) {
if (a.length !== b.length)
return false;
let equal = true;
for (let i = 0; equal && i < a.length; i++) {
equal = looseEqual(a[i], b[i]);
//这里高能,如果是我会if(!equal)return false,他这样写特别有逼格耶
}
return equal;
}
function looseEqual(a, b) {
//引用地址相同,值也没啥好比的了
if (a === b)
return true;
//若都是日期对象,比时间戳
let aValidType = isDate(a);
let bValidType = isDate(b);
if (aValidType || bValidType) {
return aValidType && bValidType ? a.getTime() === b.getTime() : false;
}
//若都是数组,比长度,再比值
aValidType = isArray(a);
bValidType = isArray(b);
if (aValidType || bValidType) {
return aValidType && bValidType ? looseCompareArrays(a, b) : false;
}
aValidType = isObject(a);
bValidType = isObject(b);
//若都是对象,比key数量,比key,比key值,key值比对跟深拷贝类似
if (aValidType || bValidType) {
/* istanbul ignore if: this if will probably never be called */
if (!aValidType || !bValidType) {
return false;
}
const aKeysCount = Object.keys(a).length;
const bKeysCount = Object.keys(b).length;
if (aKeysCount !== bKeysCount) {
return false;
}
for (const key in a) {
const aHasKey = a.hasOwnProperty(key);
const bHasKey = b.hasOwnProperty(key);
if ((aHasKey && !bHasKey) ||
(!aHasKey && bHasKey) ||
!looseEqual(a[key], b[key])) {
return false;
}
}
}
//比字符串,String(对象):[object Object]
return String(a) === String(b);
}
3、vue.js发布
作用
一行命令 自动版本号更新、测试、更新依赖、打包、changelog、提交、推送和发布
流程
- 确认要发布的版本
- 执行测试用例
- 更新依赖版本 3.1
updatePackage更新包package.json的version3.2updateDeps更新依赖版本号- 打包编译所有包
- 生成
changelog- 提交代码
add,commit- 发布包
publish- 推送到
githubtag,push tag,push
学到啥
对我来说基本都是好东西。
为公司项目写了个小型脚本,只推送
"scripts": {
"push": "node script/push.js"
},
const execa = require('execa')
const m = process.argv.slice(2)[0]
// 执行命令和只打印命令相关信息
const run = (bin, args, opts = {}) =>
execa(bin, args, { stdio: 'inherit', ...opts })
// const dryRun = (bin, args, opts = {}) =>
// console.log((`[dryrun] ${bin} ${args.join(' ')}`), opts)
async function main() {
await run('git', ['add', '.'])
await run('git', ['commit', '-m', m || 'update'])
await run('git', ['push'])
}
main()
4、co
作用
自执行generator
学到啥
#https://www.yuque.com/ruochuan12/bssbzg/ci77ui
const co = gen => new Promise((resolve, reject) => {
function next(data) {
let { value, done } = gen.next(data);
if (done) {
resolve(value);
} else {
Promise.resolve(value).then(next, reject);
}
}
next(); // 这里需要自执行一次,然后不断递归调用
})
5、koa-compose
作用
洋葱模型,中间件是指连贯整个 Koa 应用程序,并共享资源的独立插件,“连贯”对应“next”,“共享资源对应context”。
原理
1 利用
app.use存储中间件,用数组存2 从第一个中间件开始执行,执行中间件第二个参数
next可以跳转执行下一个中间件,中间件用promise包裹,所以有什么报错时可以携带错误返回上一个中间件去处理。
学到啥
1 为了防止同一个中间件里多次执行
next,通过闭包计数next 即 dispatch.bind(null, i + 1),同一个中间件中i相等,每次执行next,i会赋值给index,第二次执行next会导致i和index相等,报错。 index = -1 dispatch(0) function dispatch (i) { if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i }2
compose源码博大精深,koa源码值得深入挖掘,这一块单独看还是有点蒙的