read-pkg 读取package.json文件

648 阅读3分钟

写在前面:

read-pkg

Read a package.json file

github地址:github.com/sindresorhu…

思考:es6 中如何导入 json 模块?

import 命令目前只能用于加载 ES 模块,现在有一个提案,允许加载 JSON 模块。

假定有一个 JSON 模块文件config.json。

{
  "appName": "My App"
}

目前,只能使用fetch()加载 JSON 模块。

const response = await fetch('./config.json');
const json = await response.json();

import 命令能够直接加载 JSON 模块以后,就可以像下面这样写。

import configData from './config.json' assert { type: "json" };
console.log(configData.appName);

import 命令导入 JSON 模块时,命令结尾的 assert {type: "json"} 不可缺少。这叫做导入断言,用来告诉 JavaScript 引擎,现在加载的是 JSON 模块。(经测试,不写 assert断言 会报错)

动态加载模块的 import() 函数也支持加载 JSON 模块。

import('./config.json', { assert: { type: 'json' } })

动手测试一下:用node执行文件,可行!

async function resolveJson() {
    const configData = await import("./config.json", { assert: { type: "json" } });
    return configData;
}

resolveJson().then((res) => {
    console.log(res.default); // {"appName": "My App"}
});

接下来看下read-pkg包

首先克隆源码,安装依赖

git clone https://github.com/sindresorhus/read-pkg.git

npm i -g yarn

cd read-pkg && yarn

用法

import {readPackage} from 'read-pkg';

console.log(await readPackage());
//=> {name: 'read-pkg', …}

console.log(await readPackage({cwd: 'some-other-directory'}));
//=> {name: 'unicorn', …}

API

readPackage(options?)

Returns a Promise with the parsed JSON.

readPackageSync(options?)

Returns the parsed JSON.

该库暴露了两个函数来读取 json 文件。传参options格式如下:

可选参数 cwd :默认当前工作目录

可选参数 normalize:默认true

index.d.ts文件中的 Options 定义如下:

export interface Options {
  /**
  Current working directory.
  @default process.cwd()
  */
  readonly cwd?: URL | string;

  /**
  [Normalize](https://github.com/npm/normalize-package-data#what-normalization-currently-entails) the package data.
  @default true
  */
  readonly normalize?: boolean;
}

接下来看下源码。

源码分析

首先看下 package.json 文件

"scripts": {
    "test": "xo && ava && tsd"
}

调试

在想看的地方打上断点。鼠标悬停在 “test”上方,点击 调试脚本。

啊哦,遇到了报错。。

image.png

错误信息:Path *** is not in cwd ***

一番搜索后发现:项目文件夹命名成了中文,就会遇到这个坑。改成英文名后成功了。

index.js

导出异步和同步的两个方法,支持传递参数对象,cwd 默认是 process.cwd(),normalize 默认标准化。

分别是用 fsPromises.readFilefs.readFileSync 读取 package.json 文件。

import process from 'node:process';
import fs, {promises as fsPromises} from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import parseJson from 'parse-json';
import normalizePackageData from 'normalize-package-data';

const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;

export async function readPackage({cwd, normalize = true} = {}) {
  cwd = toPath(cwd) || process.cwd();
  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, normalize = true} = {}) {
  cwd = toPath(cwd) || process.cwd();
  const filePath = path.resolve(cwd, 'package.json');
  const json = parseJson(fs.readFileSync(filePath, 'utf8'));

  if (normalize) {
    normalizePackageData(json);
  }

  return json;
}

process 进程模块

process 对象提供有关当前 Node.js 进程的信息并对其进行控制。 虽然它作为全局可用,但是建议通过 require 或 import 显式地访问它。

引用 node 原生库可以加 node: 前缀,比如 import util from 'node:util'

process.cwd()

process.cwd() 方法返回 Node.js 进程的当前工作目录。

测试文件test.js

import {fileURLToPath, pathToFileURL} 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);
});
// ...省略

import.meta.url

import.meta.url返回当前模块的 URL 路径。

注意,Node.js 环境中,import.meta.url返回的总是本地路径,即是file:URL协议的字符串,比如file:///home/user/foo.js。

fileURLToPath

返回: 完全解析的特定于平台的 Node.js 文件路径。 此函数可确保正确解码百分比编码字符,并确保跨平台有效的绝对路径字符串。

path.dirname

用法:path.dirname( path )

传入路径,返回该路径的目录字符串。

process.chdir

process.chdir() 方法更改 Node.js 进程的当前工作目录,如果失败则抛出异常(例如,如果指定的 directory不存在)。

小结

这个库内容比较简单,不过涵盖了node.js很多的知识点。