ESM 共有ライブラリの作成
42378 ワード
Alfons MoralesのUnsplashによる写真
monorepo の対象を探しているうちに、API を呼び出して何かを実行する基本的なアプリケーションを作成することにしました.そこで、 Public APIs を調べて、使用する交換 API を選択します.それらの API の中から、 Free Currency Rates API を選択します.
以前のルート リポジトリでは、共有ライブラリを
この ESM パッケージとして、
API 呼び出し用に
ルート
入力ファイルは
では、パッケージを作成しましょう.
まず、日付を扱うクラスを作成します.
入力からネイティブ
ES2019構文のprivateフィールドでネイティブオブジェクトをprivateに設定し、変更する必要がないのでTypeScriptの
次に、API を呼び出す関数を作成します.
API 呼び出しの型と定数を設定します.
APIを呼び出して通貨を計算する関数を作成します.
交換するデフォルトの通貨は
日付は基本的に
呼び出しに失敗した場合、関数は
呼び出しが成功した場合は、為替レートと計算された交換額を返します.
パッケージは
テスト パッケージには Jest を使用します.
パッケージ間でテスト環境を共有するには、ルート リポジトリに Babel config と Jest トランスフォームを設定します.
TypeScript ファイルは
次に、テストを書き留めます.
パッケージをテストします.
それはテストに合格します.
私はパッケージしか使っていなかったので、パッケージをビルドするのは初めてなので非常に興味深い時期です.今回は、パッケージのエクスポートとタイプについて考えるべきであり、Node.js パッケージの理解を深めることができました.
Jest、Mocha、Jasmine などの中で最も人気があると思われるため、テスト用に Jest を選択します.
次回は、
monorepo の対象を探しているうちに、API を呼び出して何かを実行する基本的なアプリケーションを作成することにしました.そこで、 Public APIs を調べて、使用する交換 API を選択します.それらの API の中から、 Free Currency Rates API を選択します.
パッケージの初期化
以前のルート リポジトリでは、共有ライブラリを
packages
フォルダーに保存するので、その下に exchange API を呼び出す exchange-api
パッケージを作成します.// packages/exchange-api/package.json
{
"name": "exchange-api",
...
"type": "module",
...
"exports": "./lib/index.js",
"types": "lib",
"files": [
"lib"
]
}
この ESM パッケージとして、
"type": "module"
を設定し、 exports
の代わりに main
を使用します. TypeScript でビルドされた出力は lib
に配置され、他のパッケージには types
と files
が追加されます.API 呼び出し用に
node-fetch
、日付形式用に date-fns
、および typescript
を追加します.yarn workspace exchange-api add date-fns node-fetch
yarn workspace exchange-api add -D typescript
tsconfig.json
を作成します.// packages/exchange-api/tsconfig.json
{
"extends": "../../tsconfig.json",
"include": [
"**/*.js",
"**/*.ts"
]
}
ルート
tsconfig.json
を参照します. TypeScript ビルド用のもう 1 つの構成ファイル.// packages/exchange-api/tsconfig.build.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "./lib",
"newLine": "lf",
"declaration": true
},
"include": [
"src"
]
}
入力ファイルは
src
に、出力ファイルは lib
に.型宣言も発行します.build
スクリプトを追加します.// packages/exchange-api/package.json
{
...
"scripts": {
"build": "tsc -p ./tsconfig.build.json"
},
...
}
では、パッケージを作成しましょう.
ビルド パッケージ
1.RateDate.ts
まず、日付を扱うクラスを作成します.
// packages/exchange-api/src/RateDate.ts
import { format } from 'date-fns';
class RateDate {
readonly #date: Date;
constructor(value: number | string | Date) {
this.#date = new Date(value);
}
toString(): string {
return format(this.#date, 'yyyy-MM-dd');
}
}
export default RateDate;
入力からネイティブ
Date
オブジェクトを作成し、日付を date-fns
で文字列にフォーマットします.ES2019構文のprivateフィールドでネイティブオブジェクトをprivateに設定し、変更する必要がないのでTypeScriptの
readonly
プロパティを利用する.次に、API を呼び出す関数を作成します.
2.exchange.ts
RateDate
クラスと node-fetch
をインポートします.// packages/exchange-api/src/exchange.ts
import fetch from 'node-fetch';
import RateDate from './RateDate.js';
API 呼び出しの型と定数を設定します.
// packages/exchange-api/src/exchange.ts
...
type ApiVersion = number;
type Currency = string;
type Extension = 'min.json' | 'json';
const apiEndpoint = 'https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api';
const apiVersion: ApiVersion = 1;
const extension: Extension = 'json';
APIを呼び出して通貨を計算する関数を作成します.
// packages/exchange-api/src/exchange.ts
...
async function exchange(
amount: number,
from: Currency = 'krw',
to: Currency = 'usd',
date: number | string | Date = 'latest',
): Promise<{
rate: number;
amount: number;
} | void> {
const dateStr = date !== 'latest' ? new RateDate(date).toString() : date;
const fromLowerCase = from.toLowerCase();
const toLowerCase = to.toLowerCase();
const apiURLString = `${apiEndpoint}@${apiVersion}/${dateStr}/currencies/${fromLowerCase}/${toLowerCase}.${extension}`;
const apiURL = new URL(apiURLString);
try {
const apiResponse = await fetch(apiURL.toString());
if (apiResponse.status !== 200) {
return {
rate: 0,
amount: 0,
};
} else {
const convertedResponse = (await apiResponse.json()) as { [key: string]: string | number };
const exchangeRate = convertedResponse[toLowerCase] as number;
return {
rate: exchangeRate,
amount: Number(amount) * exchangeRate,
};
}
} catch (error: unknown) {
console.log("Can't fetch API return.");
console.log((error as Error).toString());
}
}
export default exchange;
交換するデフォルトの通貨は
krw
から usd
です.日付は基本的に
latest
になり、それ以外の日付は toString
の RateDate
関数でフォーマットされます.これらの定数を構成して API エンドポイントの URI を構築し、それを呼び出します.async/await
で try/catch
を使用します.呼び出しに失敗した場合、関数は
void
を返し、エラーをログに記録します.呼び出しに成功し、応答コードが 200
でない場合、為替レートと金額は 0
になります.呼び出しが成功した場合は、為替レートと計算された交換額を返します.
// packages/exchange-api/src/exchange.ts
import fetch from 'node-fetch';
import RateDate from './RateDate.js';
type ApiVersion = number;
type Currency = string;
type Extension = 'min.json' | 'json';
const apiEndpoint = 'https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api';
const apiVersion: ApiVersion = 1;
const extension: Extension = 'json';
async function exchange(
amount: number,
from: Currency = 'krw',
to: Currency = 'usd',
date: number | string | Date = 'latest',
): Promise<{
rate: number;
amount: number;
} | void> {
const dateStr = date !== 'latest' ? new RateDate(date).toString() : date;
const fromLowerCase = from.toLowerCase();
const toLowerCase = to.toLowerCase();
const apiURLString = `${apiEndpoint}@${apiVersion}/${dateStr}/currencies/${fromLowerCase}/${toLowerCase}.${extension}`;
const apiURL = new URL(apiURLString);
try {
const apiResponse = await fetch(apiURL.toString());
if (apiResponse.status !== 200) {
return {
rate: 0,
amount: 0,
};
} else {
const convertedResponse = (await apiResponse.json()) as { [key: string]: string | number };
const exchangeRate = convertedResponse[toLowerCase] as number;
return {
rate: exchangeRate,
amount: Number(amount) * exchangeRate,
};
}
} catch (error: unknown) {
console.log("Can't fetch API return.");
console.log((error as Error).toString());
}
}
export default exchange;
exchange
関数を完了しました.3.index.ts
パッケージは
index.js
に設定されたエントリ ポイント package.json
で完了します// packages/exchange-api/src/index.ts
import exchange from './exchange.js';
export { exchange as default };
テスト パッケージ
1.構成
テスト パッケージには Jest を使用します.
yarn workspace exchange-api add -D @babel/core @babel/preset-env @babel/preset-typescript babel-jest jest
パッケージ間でテスト環境を共有するには、ルート リポジトリに Babel config と Jest トランスフォームを設定します.
// babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"@babel/preset-typescript"
]
}
// scripts/jest-transformer.js
module.exports = require('babel-jest').default.createTransformer({
rootMode: 'upward',
});
scripts/jest-transformer.js
は、ルート リポジトリで構成を検索するように Babel を設定します. Babel Config Files を参照してください.package.json
に Jest 構成を追加します.// packages/exchange-api/package.json
{
...
"scripts": {
"build": "tsc -p ./tsconfig.build.json",
"test": "yarn node --experimental-vm-modules --no-warnings $(yarn bin jest)",
"test:coverage": "yarn run test --coverage",
"test:watch": "yarn run test --watchAll"
},
...
"jest": {
"collectCoverageFrom": [
"src/**/*.{ts,tsx}"
],
"displayName": "EXCHANGE-API TEST",
"extensionsToTreatAsEsm": [
".ts"
],
"transform": {
"^.+\\.[t|j]s$": "../../scripts/jest-transformer.js"
},
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1"
}
}
}
TypeScript ファイルは
jest-transformer.js
によって変換され、.ts
によって extensionsToTreatAsEsm
ファイルが ESM に処理されます. test
スクリプトを設定して Jest を構成し、ESM をサポートします.構成とスクリプトについては、Jest ECMAScript Modules を参照してください.2.テストを書く
次に、テストを書き留めます.
// packages/exchange-api/__tests__/RateDate.spec.ts
import RateDate from '../src/RateDate';
describe('RateDate specification test', () => {
it('should return string format', () => {
const dataString = '2022-01-01';
const result = new RateDate(dataString);
expect(result.toString()).toEqual(dataString);
});
});
toString
クラスの RateDate
関数をテストして、正しくフォーマットします.// packages/exchange-api/__tests__/exchange.spec.ts
import exchange from '../src/exchange';
describe('Exchange function test', () => {
it('should exchange with default value', async () => {
const result = await exchange(1000);
expect(result).toHaveProperty('rate');
expect(result).toHaveProperty('amount');
expect(result.rate).not.toBeNaN();
expect(result.amount).not.toBeNaN();
});
it('should make currency lowercase', async () => {
const result = await exchange(1000, 'USD', 'KRW', '2022-01-01');
expect(result).toHaveProperty('rate');
expect(result).toHaveProperty('amount');
expect(result.rate).not.toBeNaN();
expect(result.amount).not.toBeNaN();
});
it('should return empty object when wrong input', async () => {
const result = await exchange(1000, 'test');
expect(result).toHaveProperty('rate');
expect(result).toHaveProperty('amount');
expect(result.rate).toEqual(0);
expect(result.amount).toEqual(0);
});
});
exchange
関数をテストして、デフォルト値と入力値でうまく機能し、間違った入力に対して 0
のオブジェクトを返します.3. テストを実行する
パッケージをテストします.
yarn workspace exchange-api test
それはテストに合格します.
PASS EXCHANGE-API TEST __tests__/RateDate.spec.ts
PASS EXCHANGE-API TEST __tests__/exchange.spec.ts
Test Suites: 2 passed, 2 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 3.687 s
Ran all test suites.
概要
私はパッケージしか使っていなかったので、パッケージをビルドするのは初めてなので非常に興味深い時期です.今回は、パッケージのエクスポートとタイプについて考えるべきであり、Node.js パッケージの理解を深めることができました.
RateDate
クラスを作成して、他の日付操作が必要になるかもしれませんが、書式設定なしでは何もないので、役に立たない可能性があり、削除できます.Jest、Mocha、Jasmine などの中で最も人気があると思われるため、テスト用に Jest を選択します.
次回は、
babel-jest
が機能するアプリケーションを作成しましょう.Reference
この問題について(ESM 共有ライブラリの作成), 我々は、より多くの情報をここで見つけました https://dev.to/ptcookie78/create-esm-shared-library-4702テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol