持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
场景
由于es模块里无法直接require('package.json'),所以要用依赖
提案是有了:
import configData from './config.json' assert { type: "json" };
一些小知识点
- xo
可以认为是一个小型的eslint吧
Check TypeScript type definitions 检查 TypeScript 类型定义
要建什么test-d.ts里面搞检查类型输出
- ava
测试用的
- import.meta.url
developer.mozilla.org/zh-CN/docs/…
es6.ruanyifeng.com/#docs/propo…
指明模块的基本URL "file:///home/user/my-module.mjs"
- 虽然process是node的全局对象,但是建议引用一下
import process from 'node:process'; - url 中文文档
url.fileURLToPath(url)
url | 要转换为路径的文件网址字符串或网址对象。 返回: 完全解析的特定于平台的 Node.js 文件路径。 此函数可确保正确解码百分比编码字符,并确保跨平台有效的绝对路径字符串。 - process.chdir
process.chdir()方法更改Node.js进程的当前工作目录,如果失败则抛出异常(例如,如果指定的directory不存在)。 - fs
很常用的模块。
fs 中文文档
parse-json
Parse JSON with more helpful errors 更好的json化,错误时有提示
npm 官方库 normalize-package-data
normalizes package metadata, typically found in package.json file. 规范化包元数据,通常在 package.json 文件中找到。
module.exports = normalize
function normalize (data, warn, strict) {
// 省略若干代码
data._id = data.name + '@' + data.version
}
这也就是为啥测试用例中用了t.truthy(package_._id); 来检测 _id 属性是否为真值。
源码
倒是很容易就理解两者的区别,一个异步一个同步嘛
import process from 'node:process';
//promises: http://nodejs.cn/api/fs.html#fspromisesreadfilepath-options
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);//data._id = data.name + '@' + data.version
}
return json;
}
测试
// read-pkg/test/test.js
import {fileURLToPath} from 'url';
import path from 'path';
import test from 'ava';
import {readPackage, readPackageSync} from '../index.js';
// 在源码文件目录可以发现,测试用的文件是放在test文件夹下
// 获取测试文件的路径 test
const dirname = path.dirname(fileURLToPath(import.meta.url));
//read-pkg-analysis-main\read-pkg\test
// 更改当前工作文件目录到test下
process.chdir(dirname);
const rootCwd = path.join(dirname, '..');
//read-pkg-analysis-main\read-pkg\
test('async', async t => {
const package_ = await readPackage();
t.is(package_.name, 'unicorn');
// id 是那个规范化包赋予的
t.truthy(package_._id);
});
test('async - cwd option', async t => {
// 根目录的Package
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');
});
疑问与解读
vue-cli中
"read-pkg": "^5.1.1",
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 {}
}
- 疑问:readPkg.sync这个api?有这个api?我怎么没看到
- 果然,老版本的,现在7.0了,这个还用5.1,老版本是这么用的~
- github.com/sindresorhu…
总结
- 流程
用fs库的同步
fsPromises.readFile或异步fs.readFileSync读取package.json文件。用 parse-json 解析 json 文件。
用 npm 官方库 normalize-package-data 规范化
package元数据。返回
- import.meta.url :指明模块的基本url,这里用来测试环境下得到当前文件的路径 url.fileURLToPath(url) :确保正确解码百分比编码字符,并确保跨平台有效的绝对路径字符串。
normalize-package-data,校验package.json的数据是否合格parse-json解析成json,报错提示丰富
- 上面两个库我看了源码,其实也很复杂。