从 vue-cli 源码中,我发现了27行读取 json 文件有趣的 npm 包
1. 前言
大家好,我是若川。最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。已进行四个月了,很多小伙伴表示收获颇丰。
想学源码,极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。
本文仓库 https://github.com/lxchuan12/read-pkg-analysis.git,求个star^_^[1]
源码共读活动 每周一期,已进行到15期。源码群里有小伙伴提问,如何用 import
加载 json
文件。同时我之前看到了vue-cli 源码 里有 read-pkg 这个包。源码仅27行,非常值得我们学习。
阅读本文,你将学到:
1. 如何学习调试源码
2. 学会如何获取 package.json
3. 学到 import.meta
4. 学到引入 json 文件的提案
5. JSON.parse 更友好的错误提示
6. 规范化 package 元数据
7. 等等
2. 场景
优雅的获取 package.json
文件。
read-pkg[3]
vue-cli 源码[4]
const fs = require('fs')
const path = require('path')
const readPkg = require('read-pkg')exports.resolvePkg = function (context) {if (fs.existsSync(path.join(context, 'package.json'))) {return readPkg.sync({ cwd: context })}return {}
}
封装这个函数的commit 记录[5]
你也许会想直接 require('package.json');
不就可以了。但在ES模块
下,目前无法直接引入JSON文件。
在 stackoverflow 也有相关提问[6]
我们接着来看 阮一峰老师的 JSON 模块[7]
import 命令目前只能用于加载 ES 模块,现在有一个提案[8],允许加载 JSON 模块。import 命令能够直接加载 JSON 模块以后,就可以像下面这样写。
import configData from './config.json' assert { type: "json" };
console.log(configData.appName);
import
命令导入JSON
模块时,命令结尾的assert {type: "json"}
不可缺 少。这叫做导入断言,用来告诉JavaScript
引擎,现在加载的是JSON
模块。
接下来我们学习 read-pkg 源码[9]。
3. 环境准备
3.1 克隆
# 推荐克隆我的项目,保证与文章同步
git clone https://github.com/lxchuan12/read-pkg-analysis.git
# npm i -g yarn
cd read-pkg && yarn
# VSCode 直接打开当前项目
# code .# 或者克隆官方项目
git clone https://github.com/sindresorhus/read-pkg.git
# npm i -g yarn
cd read-pkg && yarn
# VSCode 直接打开当前项目
# code .
看源码一般先看 package.json
,再看 script
。
3.2 package.json
{"name": "scripts": {"test": "xo && ava && tsd"}
}
test命令有三个包,我们一一查阅了解。
xo[10]
JavaScript/TypeScript linter (ESLint wrapper) with great defaults JavaScript/TypeScript linter(ESLint 包装器)具有很好的默认值
tsd[11]
Check TypeScript type definitions 检查 TypeScript 类型定义
nodejs 测试工具 ava[12]
Node.js test runner that lets you develop with confidence
3.3 调试
提前在入口测试文件 test/test.js
和入口文件 index.js
打好断点。
用最新的VSCode
打开项目,找到 package.json
的 scripts
属性中的 test
命令。鼠标停留在test
命令上,会出现 运行命令
和 调试命令
的选项,选择 调试命令
即可。
调试如图所示:
更多调试细节可以看我的这篇文章:新手向:前端程序员必学基本技能——调试JS代码
我们跟着调试来看测试用例。
4. 测试用例
这个测试用例文件,主要就是主入口 index.js
导出的两个方法 readPackage
, readPackageSync
。异步和同步的方法。
判断读取的 package.json
的 name
属性与测试用例的 name
属性是否相等。
判断读取 package.json
的 _id
是否是真值。
同时支持指定目录。{ cwd }
// read-pkg/test/test.js
import {fileURLToPath} from 'url';
import path from 'path';
import test from 'ava';
import {readPackage, readPackageSync} from '../index.js';const dirname = path.dirname(fileURLToPath(import.meta.url));
process.chdir(dirname);
const rootCwd = path.join(dirname, '..');test('async', async t => {const package_ = await readPackage();t.is(package_.name, 'unicorn');t.truthy(package_._id);
});test('async - cwd option', async t => {const package_ = await readPackage({cwd: rootCwd});t.is(package_.name, 'read-pkg');
});test('sync', t => {const package_ = readPackageSync();t.is(package_.name, 'unicorn');t.truthy(package_._id);
});test('sync - cwd option', t => {const package_ = readPackageSync({cwd: rootCwd});t.is(package_.name, 'read-pkg');
});
这个测试用例文件,涉及到一些值得一提的知识点。接下来就简单讲述下。
4.1 url 模块
url 模块提供用于网址处理和解析的实用工具。
url 中文文档[13]
url.fileURLToPath(url)
url|要转换为路径的文件网址字符串或网址对象。返回:完全解析的特定于平台的 Node.js 文件路径。此函数可确保正确解码百分比编码字符,并确保跨平台有效的绝对路径字符串。
4.2 import.meta.url
import.meta.url[14]
(1)import.meta.url import.meta.url返回当前模块的 URL 路径。举例来说,当前模块主文件的路径是
https://foo.com/main.js
,import.meta.url就返回这个路径。如果模块里面还有一个数据文件data.txt
,那么就可以用下面的代码,获取这个数据文件的路径。new URL('data.txt', import.meta.url) 注意,Node.js 环境中,import.meta.url
返回的总是本地路径,即是file:URL协议的字符串,比如file:///home/user/foo.js
。
4.3 process.chdir
process.chdir()
方法更改 Node.js
进程的当前工作目录,如果失败则抛出异常(例如,如果指定的 directory
不存在)。
5. 27行主入口源码
导出异步和同步的两个方法,支持传递参数对象,cwd
默认是 process.cwd()
,normalize
默认标准化。
分别是用 fsPromises.readFile
fs.readFileSync
读取 package.json
文件。
用 parse-json[15] 解析 json 文件。
用 npm 官方库 normalize-package-data[16] 规范化 package
元数据。
import process from 'node:process';
import fs, {promises as fsPromises} from 'node:fs';
import path from 'node:path';
import parseJson from 'parse-json';
import normalizePackageData from 'normalize-package-data';export async function readPackage({cwd = process.cwd(), normalize = true} = {}) {const filePath = path.resolve(cwd, 'package.json');const json = parseJson(await fsPromises.readFile(filePath, 'utf8'));if (normalize) {normalizePackageData(json);}return json;
}export function readPackageSync({cwd = process.cwd(), normalize = true} = {}) {const filePath = path.resolve(cwd, 'package.json');const json = parseJson(fs.readFileSync(filePath, 'utf8'));if (normalize) {normalizePackageData(json);}return json;
}
5.1 process 进程模块
很常用的模块。
process 中文文档[17]
process 对象提供有关当前 Node.js 进程的信息并对其进行控制。虽然它作为全局可用,但是建议通过 require 或 import 显式地访问它:
import process from 'node:process';
Node 文档[18]
也就是说引用 node
原生库可以加 node:
前缀,比如 import util from 'node:util'
5.2 path 路径模块
很常用的模块。
path 中文文档[19]
path 模块提供了用于处理文件和目录的路径的实用工具。
5.3 fs 文件模块
很常用的模块。
fs 中文文档[20]
5.4 parseJson 解析 JSON
parse-json[21]
文档介绍:
Parse JSON with more helpful errors
更多有用的错误提示。
// 源码有删减
const fallback = require('json-parse-even-better-errors');
const parseJson = (string, reviver, filename) => {if (typeof reviver === 'string') {filename = reviver;reviver = null;}try {try {return JSON.parse(string, reviver);} catch (error) {fallback(string, reviver);throw error;}} catch (error) {// 省略}
}
5.5 normalizePackageData 规范化包元数据
npm 官方库 normalize-package-data[22]
normalizes package metadata, typically found in package.json file.
规范化包元数据
module.exports = normalize
function normalize (data, warn, strict) {// 省略若干代码data._id = data.name + '@' + data.version
}
这也就是为啥测试用例中用了t.truthy(package_._id);
来检测 _id
属性是否为真值。
6. 总结
最后总结下我们学到了如下知识:
1. 如何学习调试源码
2. 学会如何获取 package.json
3. 学到 import.meta
4. 学到引入 json 文件的提案
5. JSON.parse 更友好的错误提示
6. 规范化 package 元数据
7. 等等
read-pkg 源码[23] 整体而言相对比较简单,但是也有很多可以学习深挖的学习的知识点。
作为一个 npm 包,拥有完善的测试用例。
学 Node.js
可以多找找简单的 npm
包学习。比直接看官方文档有趣多了。不懂的就去查官方文档。查的多了,自然常用的就熟练了。
建议读者克隆 我的仓库[24] 动手实践调试源码学习。
最后可以持续关注我@若川。欢迎加我微信 ruochuan12 交流,参与 源码共读 活动,大家一起学习源码,共同进步。
参考资料
[1]
本文仓库 https://github.com/lxchuan12/read-pkg-analysis.git,求个star^_^: https://github.com/lxchuan12/read-pkg-analysis.git
[2]
read-pkg: https://npm.im/read-pkg
更多点击阅读原文查看
最近组建了一个江西人的前端交流群,如果你是江西人可以加我微信 ruochuan12 私信 江西 拉你进群。
推荐阅读
整整4个月了,尽全力组织了源码共读活动~
我历时3年才写了10余篇源码文章,但收获了100w+阅读
老姚浅谈:怎么学JavaScript?
我在阿里招前端,该怎么帮你(可进面试群)
················· 若川简介 ·················
你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》10余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,最近组织了源码共读活动,帮助1000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。
识别上方二维码加我微信、拉你进源码共读群
今日话题
略。分享、收藏、点赞、在看我的文章就是对我最大的支持~
从 vue-cli 源码中,我发现了27行读取 json 文件有趣的 npm 包相关推荐
- 从Vue.js源码中我学到的几个实用函数
大家好,我是若川.欢迎加我微信 ruochuan12,长期交流学习.今天推荐Vuejs源码中几个实用的方法. 如果想看Vuejs源码,不知道如何下手,一般推荐配置Sourcemap,针对单个问题调试来 ...
- 从template到DOM(Vue.js源码角度看内部运行机制)
写在前面 这篇文章算是对最近写的一系列Vue.js源码的文章(github.com/answershuto-)的总结吧,在阅读源码的过程中也确实受益匪浅,希望自己的这些产出也会对同样想要学习Vue.j ...
- vue cli3源码解析
vue-cli3 源码解析 脚手架代码入口点 从package.json文件中可以看到"vue-cli-service": "bin/vue-cli-service.js ...
- 外部数据源 之 Plugin 可插拔的方式整合到Spark中/Spark源码中
一:概念理解 Plugin 可插拔的方式整合到Spark中/Spark源码中 为了在用外部数据源读取文件的时候,本来读取是valui 使他变成一个带schema的df 有具体的信息 外部数据源就是把很 ...
- 「从源码中学习」面试官都不知道的Vue题目答案
前言 当回答面试官问及的Vue问题,我们除了照本宣科的回答外,其实还可以根据少量的源码来秀一把,来体现出你对Vue的深度了解. 本文会陆续更新,此次涉及以下问题: "new Vue()做了什 ...
- 深入解析 Vue 的热更新原理,尤大是如何巧用源码中的细节?
大家都用过 Vue-CLI 创建 vue 应用,在开发的时候我们修改了 vue 文件,保存了文件,浏览器上就自动更新出我们写的组件内容,非常的顺滑流畅,大大提高了开发效率.想知道这背后是怎么实现的吗, ...
- vue 二维数组_最近研究Vue源码时我发现的一些好玩函数
来源 | segmentfault.com/u/chinamasters 作者 | chinamasters 最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大 ...
- 什么是php的ast结构,什么是AST?Vue源码中AST语法树的解析
这篇文章给大家介绍的内容是关于什么是AST?Vue源码中AST语法树的解析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 什么是AST AST是指抽象语法树(abstract syn ...
- vue 拷贝 数组_vue源码中值得学习的方法
最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大家对深入学习js有所帮助.如果大家都能一眼看懂这些函数,说明技术还是不错的哦. 1. 数据类型判断 Objec ...
最新文章
- c++局部对象是什么_面向对象三大特征: 封装
- 常见的上传绕过以及解析漏洞
- 云计算设计模式(二)——断路器模式
- IT职业就业-学长有话说
- 爬楼梯 java_Leetcode 70.爬楼梯(Java)
- html判断坐标,js判断鼠标位置是否在某个div中的方法
- JQuery EasyUI-1.5.x-Of-Insdep-Theme后台模板
- 当快递员也学会了“跑路”,消费者如何捍卫自己的权益?
- 利用阿里云LAMP环境搭建搭建wiki知识库
- Java 异常Exception e中e的getMessage()和toString()以及 e.printStackTrace();方法的区别
- HashMap源码剖析(代码基于JDK11)
- FlashFXP、LeapFTP、CuteFTP 等FTP软件二进制上传或下载方法
- c++ 取模和求余运算
- java中的terminated_解决maven build 无反应,直接terminated的问题
- 收藏商品表设计_数据采集实战:商品详情页数据埋点
- 深入理解计算机系统----第五章优化程序性能
- oracle field怎么翻译,field是什么意思_field的翻译_音标_读音_用法_例句_爱词霸在线词典...
- 在html中通过使用css解决高度塌陷问题
- 名爵5显示服务器异常,名爵5危险警告灯异常闪烁
- 深度学习-AUC/PR计算
热门文章
- python图片识别验证码软件_python识别图片验证码
- 产品运行所需的信息检索失败_为服务业注入新活力,华北工控推出服务机器人专用计算机产品方案...
- python调用c#注意事项_Python调用C#编写的DLL
- [spring mvc]Hello World入门
- 嵌入式Linux下Qt的中文显示
- 【PHP】文件写入和读取详解
- 【随笔】Win7下GVIM的安装与配置
- 网页搜索怎么显示排名_深圳seo搜索排名优化效果怎么样
- DM9000网卡原理与基地址设置
- 潘多拉设置有线中继_避坑指南:购买无线中继器必看