Loading resources...
If the screen stays blank, please try refreshing.
프론트엔드 프로젝트를 진행하며 자주 반복되는 데이터 가공 로직(날짜 포맷팅, 유효성 검사, 금액 표기 등)을 매번 새로 구현하는 번거로움 및 의존성 관리를 해결하고자 했습니다.
프로젝트 간의 일관성을 유지하고, 검증된 로직을 재사용함으로써 전체적인 개발 생산성을 높이기 위해 라이브러리화를 진행했습니다.
꾸준히 지속적으로 유지 보수 중입니다.
Jest 기반의 단위 테스트를 작성하였고, 이를 통해 로직의 신뢰도를 높였습니다.package.json 설정을 통해 모듈의 진입점을 관리하고, npm 생태계를 통해 다른 프로젝트에서 쉽게 설치하여 사용할 수 있도록 구성했습니다.A set of JavaScript utilities for use in the browser.
npm install isa-util
yarn add isa-util
import {
isArray,
getQuery,
encryptData,
decryptData,
generateSalt,
generatePassword,
generatePasswordWithSaltAndEncrypt,
decryptPasswordWithSalt
} from 'isa-util';
async function demoEncryption() {
const message = 'Secret message';
const { password, salt, encryptedData } = await generatePasswordWithSaltAndEncrypt(16, message);
const decrypted = await decryptPasswordWithSalt(
encryptedData.encryptedData,
encryptedData.iv,
password,
salt
);
console.log(decrypted); // 'Secret message'
}
demoEncryption();
---
isArray([1, 2, 3]); // true
isString('hello'); // true
isObject({ a: 1 }); // true
const query = getQuery();
console.log(query.get('page')); // e.g. '1'
query.set('page', '2');
setQuery(query); // URL 업데이트
addComma(1234567); // '1,234,567'
camelCase('@#@assd-wsd_asd fkfk'); // assdWsdAsdFkfk
formatClass(
'a',
{ b: true, c: false },
['d', { e: true, f: 0 }, ['g', ['', null]]],
0,
undefined,
); //a b d e g 0
loadCDN('jquery', 'https://code.jquery.com/jquery-3.6.0.min.js');
const blob = new Blob(['Hello world'], { type: 'text/plain' });
download(blob, 'hello.txt', 'text/plain');
const debounced = debounce(() => console.log('called'), 300);
debounced();
debounced(); // 마지막 호출만 실행됨
const throttled = throttle(() => console.log('tick'), 1000);
throttled();
throttled(); // 1초에 한 번만 실행됨
getPlatform(); // { os: 'iOS', browser: 'Safari', mobile: true }
isMobile(); // true/false
isDarkMode(); // true/false
const salt = generateSalt();
const password = generatePassword(16);
const encrypted = await encryptData('secret', password, salt);
const decrypted = await decryptData(
encrypted.encryptedData,
encrypted.iv,
password,
salt,
);
formatDate(new Date(), 'YYYY-MM-DD'); // '2025-05-13'
timeAgo(new Date(Date.now() - 60000)); // '1 minute ago'
isToday(new Date()); // true
setLocalStorage('key', { name: 'isa' });
getLocalStorage('key'); // { name: 'isa' }
removeLocalStorage('key');
const db = await idb.open('my-db', {
version: 1,
schema: {
users: { keyPath: 'id', autoIncrement: true },
},
});
console.log(db.objectStoreNames); // ["users"]
addClass(document.body, 'dark');
hasClass(document.body, 'dark'); // true
toggleClass(document.body, 'dark'); // toggle
// FlushQueue
const fq = new FlushQueue();
fq.add('job1', async () => console.log('job 1'));
fq.add('job2', async () => console.log('job 2'));
await fq.flush(); // 병렬 실행
// JobQueue
const jq = new JobQueue<string>(async (job) => {
console.log('processing', job);
await new Promise((r) => setTimeout(r, 300));
});
jq.enqueue('task A');
jq.enqueue('task B'); // 순차 실행
isArray(arg: any): boolean
Checks if the argument is an array.
Usage Example:
isArray([1, 2, 3]); // true
isArray('hello'); // false
isFunction(arg: any): boolean
Checks if the argument is a function.
Usage Example:
isFunction(() => {}); // true
isFunction(123); // false
isObject(arg: any): boolean
Checks if the argument is an object.
Usage Example:
isObject({ key: 'value' }); // true
isObject([1, 2, 3]); // false
isString(arg: any): boolean
Checks if the argument is a string.
Usage Example:
isString('Hello, world!'); // true
isString(123); // false
isNumber(arg: any): boolean
Checks if the argument is a number.
Usage Example:
isNumber(42); // true
isNumber('Hello'); // false
isSymbol(arg: any): boolean
Checks if the argument is a symbol.
Usage Example:
isSymbol(Symbol('test')); // true
isSymbol('not a symbol'); // false
isBlob(arg: any): boolean
Checks if the argument is a Blob.
Usage Example:
isBlob(new Blob()); // true
isBlob('not a blob'); // false
isUndefined(arg: any): boolean
Checks if the argument is undefined.
Usage Example:
isUndefined(undefined); // true
isUndefined(null); // false
isFalsy(arg: any): boolean
Checks if the argument is falsy (false, 0, "", null, undefined, NaN).
isUndefined(undefined); // true
isUndefined(null); // false
isFalsy(arg: any): boolean
Checks if the argument is falsy (false, 0, "", null, undefined, NaN).
Usage Example:
isFalsy(null); // true
isFalsy(0); // true
isFalsy('hello'); // false
isTruthy(arg: any): boolean
Checks if the argument is truthy (not falsy).
Usage Example:
isTruthy(1); // true
isTruthy(''); // false
getQuery(): URLSearchParams
Retrieves the current URL query parameters as a URLSearchParams object.
Usage Example:
const queryParams = getQuery();
console.log(queryParams.get('user')); // prints the value of 'user' query parameter
setQuery(arg: URLSearchParams): void
Sets the URL query parameters using a URLSearchParams object.
Usage Example:
const params = new URLSearchParams();
params.append('page', '1');
setQuery(params); // Updates the URL's query params to ?page=1
addComma(arg: number): string
Formats a number by adding commas as thousand separators.
Usage Example:
addComma(1000000); // "1,000,000"
camelCase(input: string): string
Formats a string by camelCase.
Usage Example:
camelCase('@#@assd-wsd_asd fkfk'); // assdWsdAsdFkfk
pascalCase(input: string): string
Formats a string by pascalCase.
Usage Example:
pascalCase('@#@assd-wsd_asd fkfk'); // AssdWsdAsdFkfk
snakeCase(input: string): string
Formats a string by snakeCase.
Usage Example:
snakeCase('@#@assd-wsd_asd fkfk'); // assd_wsd_asd_fkfk
formatClass(...args: any): string | cx(...args): string
Formats args by className.
Usage Example:
formatClass('a', 0, 1); // 'a 0 1'
loadCDN(id: string, src: string, options?: ScriptAttribute): Promise<void>
Dynamically loads a script from a CDN with optional attributes.
Usage Example:
loadCDN(
'lodash',
'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js',
);
download(data: Blob, name: string, type: string): void
Triggers a download for a given Blob with the specified filename and MIME type.
Usage Example:
const blob = new Blob(['Hello, world!'], { type: 'text/plain' });
download(blob, 'hello.txt', 'text/plain');
debounce(func: Function, wait: number): Function & { cancel: () => void; pending: () => boolean; }
Creates a debounced function that delays invoking func until after wait milliseconds have passed. Returns a function with cancel and pending methods.
Usage Example:
const handler = debounce(() => console.log('called!'), 300);
handler();
handler(); // Only the last call within 300ms will be executed
throttle<T extends any[], R>(func: FuncType<T, R>, wait: number): (...args: T) => R | void
Creates a throttled function that only invokes func at most once per wait milliseconds.
Usage Example:
const throttledLog = throttle(() => console.log('Logged!'), 1000);
throttledLog();
throttledLog(); // Will log only once per 1000ms
getPlatform(): { os: string, browser: string, mobile: boolean } | null
Returns an object containing the user's platform information, including the operating system, browser, and whether the user is on a mobile device.
Usage Example:
const platform = getPlatform();
console.log(platform.os, platform.browser); // logs current platform info
JobQueue<T>(processJob: (job: T) => Promise<void>): enqueue(job: T)
A class that manages a queue of asynchronous jobs and processes them one at a time. Jobs are added to the queue using enqueue, and the class ensures they are processed sequentially.
Usage Example:
const queue = new JobQueue<string>(async (job) => {
console.log(`Processing job: ${job}`);
await new Promise((resolve) => setTimeout(resolve, 1000)); // 1초 대기
});
queue.enqueue('Job 1');
queue.enqueue('Job 2');
queue.enqueue('Job 3');
FlushQueue(options: FlushQueueOptions): add(id: string, job: AsyncJob)
A class that manages a queue of asynchronous jobs with optional debounce and custom start/finish handlers. Jobs can be added, canceled, and flushed either in parallel or sequentially.
Usage Example:
const queue = new FlushQueue({
debounceMs: 300, // Debounce for 300ms before flushing
onStart: (id) => console.log(`Starting job ${id}`),
onFinish: (id, error) => {
if (error) {
console.error(`Job ${id} failed`, error);
} else {
console.log(`Job ${id} finished`);
}
},
});
const job1: AsyncJob = async () => {
console.log('Processing Job 1');
await new Promise((resolve) => setTimeout(resolve, 1000));
};
const job2: AsyncJob = async () => {
console.log('Processing Job 2');
await new Promise((resolve) => setTimeout(resolve, 1000));
};
queue.add('job1', job1);
queue.add('job2', job2);
// Force flush all jobs sequentially
queue.flush(false);
sleep(ms: number): Promise<void>
A utility function that pauses the execution for the specified number of milliseconds by returning a Promise that resolves after the given delay.
Usage Example:
async function example() {
console.log('Start');
await sleep(1000); // Sleep for 1 second
console.log('End after 1 second');
}
example();
Note: Encryption uses AES-GCM with 256-bit keys derived via PBKDF2 (SHA-256, 100,000 iterations).
encryptData(data: string, password: string, salt: string): Promise<{ iv: number[], encryptedData: number[] }>
Encrypts a string using AES-GCM with a password-derived key and returns the IV and encrypted data.Usage Example:
const { iv, encryptedData } = await encryptData('Hello', 'password', 'salt');
console.log(encryptedData);
decryptData(encryptedData: number[], iv: number[], password: string, salt: string): Promise<string>
Decrypts AES-GCM encrypted data using the provided IV, password, and salt.
Usage Example:
const decrypted = await decryptData(encryptedData, iv, 'password', 'salt');
console.log(decrypted); // 'Hello'
generateSalt(): string
Generates a 16-byte random salt string.
generatePassword(length: number): string
Generates a random password of the specified length.
generatePasswordWithSalt(length: number): { password: string, salt: string }
Generates a random password and salt.
generatePasswordWithSaltAndEncrypt(length: number, data: string): Promise<{ password: string, salt: string, encryptedData: { iv: number[], encryptedData: number[] } }>
Generates a password and salt, encrypts the provided data, and returns all components.
decryptPasswordWithSalt(encryptedData: number[], iv: number[], password: string, salt: string): Promise<string>
Decrypts data using the given encryptedData, IV, password, and salt.
decryptPasswordWithSaltAndEncrypt(encryptedData: number[], iv: number[], password: string, salt: string, data: string): Promise<string>
Decrypts and verifies that the decrypted data matches the original input.
formatDate(date: Date, format: string): string
Formats a JavaScript Date object into a custom string format like 'YYYY-MM-DD HH:mm:ss'.
Usage Example:
formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'); // "2025-05-13 12:34:56"
timeAgo(date: Date | string): string
Returns a human-readable time difference string like "5 minutes ago" or "2 days ago".
Usage Example:
timeAgo(new Date('2025-05-12')); // "1 day ago"
isToday(date: Date): boolean
Returns true if the given date is today.
Usage Example:
isToday(new Date('2005-05-12')); // "false"
isMobile(): boolean
Detects whether the current device is a mobile device.
isDarkMode(): boolean
Detects whether the user's system prefers dark mode.
isTouchDevice(): boolean
Checks if the current device supports touch interactions.
setLocalStorage(key: string, value: any): void
Sets a value in localStorage.
Usage Example:
setLocalStorage('user', { name: 'Alice' });
getLocalStorage(key: string): any
Retrieves a value from localStorage.
Usage Example:
const user = getLocalStorage('user');
console.log(user.name); // "Alice"
removeLocalStorage(key: string): void
Removes a value from localStorage.
interface IDBOpenOptions: {
version?: number;
schema?: Record<string, IDBObjectStoreParameters>;
}
interface CursorOptions<T = any> {
range?: IDBKeyRange | null;
offset?: number;
limit?: number;
filter?: (value: T, key: IDBValidKey) => boolean;
sort?: (a: T, b: T) => number;
}
idb.open(name: string, options?: IDBOpenOptions): Promise<IDBDatabase>
Opens an IndexedDB database, creating object stores if they don’t exist.
Usage Example:
const db = await idb.open('my-db', {
version: 1,
schema: {
users: { keyPath: 'id', autoIncrement: true },
},
});
console.log(db.objectStoreNames); // ["users"]
idb.get<T>(dbName: string, store: string, key: IDBValidKey): Promise<T | undefined>
Retrieves a single item from the specified object store by key.
Usage Example:
const user = await idb.get('my-db', 'users', 1);
console.log(user?.name); // "Alice"
idb.put<T>(dbName: string, store: string, value: T): Promise<IDBValidKey>
Inserts or updates an item in the object store.
Usage Example:
const key = await idb.put('my-db', 'users', { name: 'Alice' });
console.log(key); // 1
idb.clear(dbName: string, store: string): Promise<void>
Removes all items from the specified object store.
Usage Example:
await idb.clear('my-db', 'users');
idb.deleteDB(name: string): Promise<void>
Deletes the entire database.
Usage Example:
await idb.deleteDB('my-db');
idb.cursor.each<T>(dbName: string, store: string, callback: (value: T, key: IDBValidKey, cursor: IDBCursorWithValue) => void): Promise<void>
Iterates over all items in the store and executes the callback for each.
Usage Example:
await idb.cursor.each('my-db', 'users', (value, key) => {
console.log(key, value.name);
});
idb.cursor.query<T>(dbName: string, store: string, options?: CursorOptions<T>): Promise<T[]>
Advanced cursor query with optional filter, sort, offset, and limit.
Usage Example:
const users = await idb.cursor.query('my-db', 'users', {
filter: (user) => user.age >= 18,
sort: (a, b) => a.age - b.age,
offset: 1,
limit: 2,
});
console.log(users);
hasClass(el: Element, className: string): boolean
Checks if an element contains a class.
Usage Example:
hasClass(document.body, 'dark-mode'); // true/false
addClass(el: Element, className: string): void
Adds a class to an element.
Usage Example:
addClass(document.body, 'dark-mode');
removeClass(el: Element, className: string): void
Removes a class from an element.
Usage Example:
removeClass(document.body, 'dark-mode');
toggleClass(el: Element, className: string): void
Toggles a class on an element.
This project is licensed under the MIT License. For more details, see the LICENSE.