从omit.js源码学习npm仓库知识并进行改造

651 阅读3分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,  点击了解详情一起参与。

这是源码共读的第36期 | 可能是历史上最简单的一期 omit.js 剔除对象中的属性

准备

omit.js 提供了删除对象属性的方法,它的作用和 delete差不多,不同的是它通过函数返回了一个新对象,不会对原对象进行操作,它没有副作用

https://github.com/benjycui/omit.js

解读package.json

基本信息

  "name": "omit.js", //包名
  "version": "2.0.2",  //迭代版本 参考Semver语义化版本号
  "description": "Utility function to create a shallow copy of an object which had dropped some fields.",  //描述
  "main": "lib/index.js",  //入口文件 如果没找到默认会去找目录下的index.js
  "module": "es/index.js",  //ESM规范声明入口文件 一般会用于rollup webpack 导出模块使用
  "types": "index.d.ts",  //TS类型声明入口文件

依赖相关

@umijs/fabric

``umijs```下 一个包含 prettier,eslint,stylelint 的配置文件合集 fabric

image.png

require.resolve 简化了 path.join+__dirname的这一写法,并且它本身对于不存在的文件还会抛出错误。 fabric用提前封装好的配置文件,非常简单的实现了 prettier eslint stylelint的配置

assert

assert是一个编写单元测试的断言模块,当然我们选择用更流行的jest

father

father是umijs下基于rollup、docz、storybook、jest、prettier和eslint的打包和文档工具

image.png

np

np 它的描述就是最好的npm发布工具

rc-tools

用于离线测试React组件的包,没看到在哪有用到

omit.js的实现

function omit(obj, fields) {
	// eslint-disable-next-line prefer-object-spread
	const shallowCopy = Object.assign({}, obj);
	for (let i = 0; i < fields.length; i += 1) {
		const key = fields[i];
		delete shallowCopy[key];
	}
	return shallowCopy;
}

export default omit;

//使用 const newObj = omit(targetObj,[keyName1,keyName2,..])
  1. 函数内部创建一个局部变量shallowCopy 通过Object.assign复制了obj创建一个新对象
  2. fields传入一个对象属性名数组,通过循环遍历将shallowCopy上对应数组的属性挨个删除
  3. 最后返回这个新对象

代码是浅拷贝实现,如果是复杂的嵌套对象则不起作用,同时这里也牵扯到了纯函数的一个知识点,也就是消除副作用,不对原来的对象产生任何影响。

TS支持以及单元测试

  1. 更换单元测试为Jest
npm i jest -D
npx jest --init //初始化jest并创建配置文件jest.config.js

1.1 安装完成后package.json内的 test会被重写为jest

1.2 引入babel解决 import语法编译错误

npm i babel-jest -D //支持jest的babel包
npm i @babel/core -D //babel核心编译包
npm i @babel/preset-env //babel预设的转换规则

1.3 修改tests下index.test.js

import omit from "../src";

describe("omit", () => {
	it("should create a shallow copy", () => {
		const benjy = { name: "Benjy", age: 18 };
		const copy = omit(benjy, ["name"]);
		expect(copy).toEqual({ age: 18 });
	});

	it("should drop fields which are passed in", () => {
		const benjy = { name: "Benjy", age: 18 };
		const target1 = omit(benjy, ["age"]);
		const target2 = omit(benjy, ["age", "name"]);
		expect(target1).toEqual({ name: "Benjy" });
		expect(target2).toEqual({});
	});
});

  1. 引入Typescript
npm i typescript -D
npx tsc --init //初始化 tsconfig文件
npm i ts-jest -D //jest typescript支持
npm i @types/jest //jest ts类型支持

2.1 修改jest.config.js

module.exports = {
  preset: "ts-jest",
  testEnvironment: "jest-environment-node"
};

2.2 修改index.js以及tests/index.test.js 改为ts后缀

//index.ts
function omit(obj: Object, fields: string[]) {
	// eslint-disable-next-line prefer-object-spread
	const shallowCopy = Object.assign({}, obj);
	for (let i = 0; i < fields.length; i += 1) {
		const key = fields[i];
		delete shallowCopy[key as keyof typeof obj];
	}
	return shallowCopy;
}
export default omit;
//index.test.ts
import omit from "../src";

describe("omit", () => {
	it("should create a shallow copy", () => {
		const benjy = { name: "Benjy", age: 18 };
		const copy = omit(benjy, ["name"]);
		expect(copy).toEqual({ age: 18 });
	});

	it("should drop fields which are passed in", () => {
		const benjy = { name: "Benjy", age: 18 };
		const target1 = omit(benjy, ["age"]);
		const target2 = omit(benjy, ["age", "name"]);
		expect(target1).toEqual({ name: "Benjy" });
		expect(target2).toEqual({});
	});
});

发布和钩子

npm的scripts中给了一下几个类似钩子的命令,允许你在安装发布时处理一些其他的操作:

  • prepublish: 当你要发布或者打包或者在本地安装的时候,出触发这个命令

  • prepare: 会在prepublish与prepublishOnly之间触发,以下几种情况会触发这个命令:

    • 打包或者发布之前
    • 安装git链接的dependencies
    • 本地包的npm install,并且不带任何参数
  • prepublishOnly: 在prepare和prepack之间触发,只有运行npm publish,才会触发这个命令

  • prepack: 在打包之前运行,触发条件:

    • npm pack
    • npm publish
    • 安装一个git链接的依赖
  • postpack: 打包完成之后触发

  • publish, postpublish: 发布成功之后触发

  • preinstall: 安装之前触发

  • install, postinstall: 安装之后触发

  • preuninstall, uninstall: 卸载之前触发

  • postuninstall: 卸载之后触发

更多具体的用法可以官方NPM文档 当我们执行npm publish发布时 就会触发这个钩子 执行cpmplie进行代码构建并执行np发包

 "compile": "father build",
 "prepublishOnly": "npm run compile && np --yolo --no-publish",

总结

  1. npm内置script钩子prepublishOnly 在运行npm publish触发
  2. omit函数的使用并进行 TS类型支持
  3. 学习使用Jest单元测试并进行 TS类型支持
  4. package.json字段属性学习 认识main入口和moudule入口