runtime-detector v1.2.1
Runtime Detector
A lightweight, type-safe runtime environment detector for JavaScript/TypeScript applications. Easily detect and handle code execution in Bun, Node.js, Deno, and Browser environments.
π Key Features
- Environment Callbacks: Execute code through environment-specific callback functions
- Return Values: Callback functions can return values for further processing
- Zero Dependencies: No external dependencies
- TypeScript Ready: Full TypeScript support with type definitions included
- Lightweight: Only ~7KB minified
- Universal Detection: Supports Bun, Node.js, Deno, and Browser environments
- Flexible API: Both synchronous and asynchronous operations
- Type Safety: Environment-specific code execution with TypeScript type checking
- Tree-Shakeable: Import only what you need
- Dual Package: Supports both ESM (MJS) and CommonJS (CJS)
π¦ Installation
# Using npm
npm install runtime-detector
# Using yarn
yarn add runtime-detector
# Using pnpm
pnpm add runtime-detector
# Using bun
bun add runtime-detector
π Module Support
runtime-detector supports both ESM (ECMAScript Modules) and CommonJS formats.
// ESM (MJS)
import { currentEnv, isNodejs } from "runtime-detector";
// CommonJS (CJS)
const { currentEnv, isNodejs } = require("runtime-detector");
π― Quick Start
Basic Environment Detection
import { currentEnv, isNodejs, isBrowser } from "runtime-detector";
// Configuration setup example
function setupConfig() {
const { name, version, browserName } = currentEnv;
// Set environment-specific logging levels
const config = {
logLevel: isNodejs ? 'verbose' : 'error',
maxRetries: isBrowser ? 3 : 5,
timeout: isBrowser ? 5000 : 10000,
features: {
cache: isNodejs || browserName === 'Chrome',
analytics: isBrowser && browserName !== 'Firefox',
ssr: !isBrowser
}
};
return config;
}
Environment-Specific Code Execution
import { onNodejs, onBrowser, onBun, onDeno } from "runtime-detector";
// File handling across different environments
function saveData(content: string) {
// Node.js: Use fs with proper error handling
onNodejs((env) => {
const fs = require('fs').promises;
return fs.writeFile('data.json', content)
.catch(err => console.error(`Failed to write file in Node.js ${env.version}:`, err));
});
// Browser: Use localStorage with size check
onBrowser((env) => {
try {
const maxSize = 5 * 1024 * 1024; // 5MB
if (content.length > maxSize) {
throw new Error('Content too large for localStorage');
}
localStorage.setItem('data', content);
console.log(`Data saved in ${env.browserName}`);
} catch (err) {
console.error('Storage failed:', err);
}
});
// Bun: Use fast native file API
onBun((env) => {
try {
Bun.write('data.json', content);
console.log(`File written using Bun ${env.version}`);
} catch (err) {
console.error('Bun write failed:', err);
}
});
// Deno: Use native APIs with permissions
onDeno((env) => {
try {
Deno.writeTextFileSync('data.json', content);
console.log(`File written in Deno ${env.version}`);
} catch (err) {
console.error('Deno write failed:', err);
}
});
}
Async Operations with Error Handling
import { onNodejsAsync, onBrowserAsync } from "runtime-detector";
// API client with environment-specific optimizations
class APIClient {
async fetchData(endpoint: string) {
// Browser: Use native fetch with timeout
const browserData = await onBrowserAsync(async (env) => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(endpoint, {
headers: {
'User-Agent': `WebApp/${env.browserName}`,
'Accept': 'application/json'
},
signal: controller.signal
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (err) {
console.error(`Browser fetch failed:`, err);
throw err;
} finally {
clearTimeout(timeoutId);
}
});
// Node.js: Use axios with retries
const nodeData = await onNodejsAsync(async (env) => {
const axios = require('axios');
let retries = 3;
while (retries > 0) {
try {
const response = await axios.get(endpoint, {
headers: {
'User-Agent': `NodeApp/${env.version}`,
'Accept': 'application/json'
},
timeout: 5000
});
return response.data;
} catch (err) {
retries--;
if (retries === 0) throw err;
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
});
return browserData || nodeData;
}
}
Feature Detection and Optimization
import { onNotNodejs, onNotBrowser } from "runtime-detector";
// Cache system optimization example
function setupCache(data: any) {
// Use Redis in server environments
onNotBrowser(async (env) => {
const Redis = require('redis');
const client = Redis.createClient();
try {
await client.connect();
await client.set('app:cache', JSON.stringify(data));
console.log(`Redis cache setup in ${env.name}`);
} catch (err) {
console.error(`Cache setup failed in ${env.name}:`, err);
// Fallback to in-memory cache
global.__cache = data;
}
});
// Use IndexedDB in browser
onBrowser((env) => {
const request = indexedDB.open('appCache', 1);
request.onerror = () => {
console.error(`IndexedDB failed in ${env.browserName}`);
// Fallback to sessionStorage
sessionStorage.setItem('cache', JSON.stringify(data));
};
request.onsuccess = (event: any) => {
const db = event.target.result;
const tx = db.transaction('cache', 'readwrite');
tx.objectStore('cache').put(data, 'appData');
};
});
}
π API Reference
Environment Information
currentEnv
: Current environment detailsname
: Runtime name (e.g., "Node.js", "Bun")version
: Runtime versionbrowserName
: Browser name (if applicable)
Environment Checks
import {
isBrowser, // true in browser environments
isNodejs, // true in Node.js
isBun, // true in Bun
isDeno // true in Deno
} from "runtime-detector";
Synchronous Execution APIs
Function | Description |
---|---|
onBrowser(callback) | Execute in browser |
onNodejs(callback) | Execute in Node.js |
onBun(callback) | Execute in Bun |
onDeno(callback) | Execute in Deno |
onNotBrowser(callback) | Execute in non-browser |
onNotNodejs(callback) | Execute in non-Node.js |
onNotBun(callback) | Execute in non-Bun |
onNotDeno(callback) | Execute in non-Deno |
Asynchronous Execution APIs
Function | Description |
---|---|
onBrowserAsync(callback) | Async execute in browser |
onNodejsAsync(callback) | Async execute in Node.js |
onBunAsync(callback) | Async execute in Bun |
onDenoAsync(callback) | Async execute in Deno |
onNotBrowserAsync(callback) | Async execute in non-browser |
onNotNodejsAsync(callback) | Async execute in non-Node.js |
onNotBunAsync(callback) | Async execute in non-Bun |
onNotDenoAsync(callback) | Async execute in non-Deno |
π Release Notes
1.2.0
- π Bug Fix: Fixed critical issue where
on*
functions could potentially execute in incorrect environments- Previously, code within environment-specific functions could sometimes run in unintended environments
- Now strictly enforces environment checks before executing any code
- Affects all environment-specific functions (
onNodejs
,onBrowser
,onBun
,onDeno
, etc.)
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
MIT License - feel free to use this project in your applications.
Runtime Detector (νκ΅μ΄)
JavaScript/TypeScript μ ν리μΌμ΄μ μ μν κ²½λ λ°νμ νκ²½ κ°μ§ λΌμ΄λΈλ¬λ¦¬μ λλ€. Bun, Node.js, Deno, λΈλΌμ°μ νκ²½μ μ½κ² κ°μ§νκ³ μ²λ¦¬ν μ μμ΅λλ€.
π μ£Όμ κΈ°λ₯
- νκ²½λ³ μ½λ°±: νκ²½λ³ μ½λ°± ν¨μλ₯Ό ν΅ν μ½λ μ€ν μ§μ
- λ°νκ° μ§μ: μ½λ°± ν¨μμμ κ°μ λ°ννμ¬ μΆκ° μ²λ¦¬ κ°λ₯
- μμ‘΄μ± μμ: μΈλΆ μμ‘΄μ±μ΄ μμ
- TypeScript μ§μ: νμ μ μκ° ν¬ν¨λ μλ²½ν TypeScript μ§μ
- κ²½λν: μ½ 7KB (μμΆ μ)
- λ€μν νκ²½ κ°μ§: Bun, Node.js, Deno, λΈλΌμ°μ νκ²½ μ§μ
- μ μ°ν API: λκΈ° λ° λΉλκΈ° μμ λͺ¨λ μ§μ
- νμ μμ μ±: TypeScript νμ 체ν¬μ ν¨κ» νκ²½λ³ μ½λ μ€ν
- νΈλ¦¬ μμ΄νΉ: νμν κΈ°λ₯λ§ μν¬νΈ κ°λ₯
- λμΌ ν¨ν€μ§: ESM(MJS)μ CommonJS(CJS) λͺ¨λ μ§μ
π¦ μ€μΉ
# npm μ¬μ©
npm install runtime-detector
# yarn μ¬μ©
yarn add runtime-detector
# pnpm μ¬μ©
pnpm add runtime-detector
# bun μ¬μ©
bun add runtime-detector
π λͺ¨λ μ§μ
runtime-detectorλ ESM(ECMAScript Modules)κ³Ό CommonJS νμμ λͺ¨λ μ§μν©λλ€.
// ESM (MJS)
import { currentEnv, isNodejs } from "runtime-detector";
// CommonJS (CJS)
const { currentEnv, isNodejs } = require("runtime-detector");
π― μμνκΈ°
κΈ°λ³Έ νκ²½ κ°μ§
import { currentEnv, isNodejs, isBrowser } from "runtime-detector";
// νκ²½λ³ μ€μ κ΅¬μ± μμ
function setupConfig() {
const { name, version, browserName } = currentEnv;
// νκ²½λ³ λ‘κΉ
λ 벨 λ° μ€μ μ§μ
const config = {
logLevel: isNodejs ? 'verbose' : 'error',
maxRetries: isBrowser ? 3 : 5,
timeout: isBrowser ? 5000 : 10000,
features: {
cache: isNodejs || browserName === 'Chrome',
analytics: isBrowser && browserName !== 'Firefox',
ssr: !isBrowser
}
};
return config;
}
νκ²½λ³ μ½λ μ€ν
import { onNodejs, onBrowser, onBun, onDeno } from "runtime-detector";
// λ€μν νκ²½μμμ νμΌ μ²λ¦¬
function saveData(content: string) {
// Node.js: fs λͺ¨λ μ¬μ© λ° μ€λ₯ μ²λ¦¬
onNodejs((env) => {
const fs = require('fs').promises;
return fs.writeFile('data.json', content)
.catch(err => console.error(`Node.js ${env.version}μμ νμΌ μ°κΈ° μ€ν¨:`, err));
});
// λΈλΌμ°μ : localStorage μ¬μ© λ° μ©λ νμΈ
onBrowser((env) => {
try {
const maxSize = 5 * 1024 * 1024; // 5MB
if (content.length > maxSize) {
throw new Error('localStorage μ©λ μ΄κ³Ό');
}
localStorage.setItem('data', content);
console.log(`${env.browserName}μμ λ°μ΄ν° μ μ₯ μλ£`);
} catch (err) {
console.error('μ μ₯ μ€ν¨:', err);
}
});
// Bun: λ€μ΄ν°λΈ νμΌ API νμ©
onBun((env) => {
try {
Bun.write('data.json', content);
console.log(`Bun ${env.version}μμ νμΌ μμ± μλ£`);
} catch (err) {
console.error('Bun μ°κΈ° μ€ν¨:', err);
}
});
// Deno: κΆν κ΄λ¦¬μ ν¨κ» λ€μ΄ν°λΈ API μ¬μ©
onDeno((env) => {
try {
Deno.writeTextFileSync('data.json', content);
console.log(`Deno ${env.version}μμ νμΌ μμ± μλ£`);
} catch (err) {
console.error('Deno μ°κΈ° μ€ν¨:', err);
}
});
μ€λ₯ μ²λ¦¬λ₯Ό ν¬ν¨ν λΉλκΈ° μμ
import { onNodejsAsync, onBrowserAsync } from "runtime-detector";
// νκ²½λ³ μ΅μ νλ API ν΄λΌμ΄μΈνΈ
class APIClient {
async fetchData(endpoint: string) {
// λΈλΌμ°μ : νμμμμ΄ μλ λ€μ΄ν°λΈ fetch μ¬μ©
const browserData = await onBrowserAsync(async (env) => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(endpoint, {
headers: {
'User-Agent': `WebApp/${env.browserName}`,
'Accept': 'application/json'
},
signal: controller.signal
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (err) {
console.error(`λΈλΌμ°μ fetch μ€ν¨:`, err);
throw err;
} finally {
clearTimeout(timeoutId);
}
});
// Node.js: axios μ¬μ© λ° μ¬μλ λ‘μ§ κ΅¬ν
const nodeData = await onNodejsAsync(async (env) => {
const axios = require('axios');
let retries = 3;
while (retries > 0) {
try {
const response = await axios.get(endpoint, {
headers: {
'User-Agent': `NodeApp/${env.version}`,
'Accept': 'application/json'
},
timeout: 5000
});
return response.data;
} catch (err) {
retries--;
if (retries === 0) throw err;
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
});
return browserData || nodeData;
}
}
κΈ°λ₯ κ°μ§ λ° μ΅μ ν
import { onNotNodejs, onNotBrowser } from "runtime-detector";
// μΊμ μμ€ν
μ΅μ ν μμ
function setupCache(data: any) {
// μλ² νκ²½μμ Redis μ¬μ©
onNotBrowser(async (env) => {
const Redis = require('redis');
const client = Redis.createClient();
try {
await client.connect();
await client.set('app:cache', JSON.stringify(data));
console.log(`Redis μΊμκ° ${env.name}μ μ€μ λ¨`);
} catch (err) {
console.error(`${env.name}μμ μΊμ μ€μ μ€ν¨:`, err);
// λ©λͺ¨λ¦¬ μΊμλ‘ λ체
global.__cache = data;
}
});
// λΈλΌμ°μ μμ IndexedDB μ¬μ©
onBrowser((env) => {
const request = indexedDB.open('appCache', 1);
request.onerror = () => {
console.error(`${env.browserName}μμ IndexedDB μ€ν¨`);
// sessionStorageλ‘ λ체
sessionStorage.setItem('cache', JSON.stringify(data));
};
request.onsuccess = (event: any) => {
const db = event.target.result;
const tx = db.transaction('cache', 'readwrite');
tx.objectStore('cache').put(data, 'appData');
};
});
}
π API λ νΌλ°μ€
νκ²½ μ 보
currentEnv
: νμ¬ νκ²½ μμΈ μ 보name
: λ°νμ μ΄λ¦ (μ: "Node.js", "Bun")version
: λ°νμ λ²μ browserName
: λΈλΌμ°μ μ΄λ¦ (ν΄λΉλλ κ²½μ°)
νκ²½ νμΈ
import {
isBrowser, // λΈλΌμ°μ νκ²½μμ true
isNodejs, // Node.jsμμ true
isBun, // Bunμμ true
isDeno // Denoμμ true
} from "runtime-detector";
λκΈ° μ€ν API
ν¨μ | μ€λͺ |
---|---|
onBrowser(callback) | λΈλΌμ°μ μμ μ€ν |
onNodejs(callback) | Node.jsμμ μ€ν |
onBun(callback) | Bunμμ μ€ν |
onDeno(callback) | Denoμμ μ€ν |
onNotBrowser(callback) | λΈλΌμ°μ κ° μλ νκ²½μμ μ€ν |
onNotNodejs(callback) | Node.jsκ° μλ νκ²½μμ μ€ν |
onNotBun(callback) | Bunμ΄ μλ νκ²½μμ μ€ν |
onNotDeno(callback) | Denoκ° μλ νκ²½μμ μ€ν |
λΉλκΈ° μ€ν API
ν¨μ | μ€λͺ |
---|---|
onBrowserAsync(callback) | λΈλΌμ°μ μμ λΉλκΈ° μ€ν |
onNodejsAsync(callback) | Node.jsμμ λΉλκΈ° μ€ν |
onBunAsync(callback) | Bunμμ λΉλκΈ° μ€ν |
onDenoAsync(callback) | Denoμμ λΉλκΈ° μ€ν |
onNotBrowserAsync(callback) | λΈλΌμ°μ κ° μλ νκ²½μμ λΉλκΈ° μ€ν |
onNotNodejsAsync(callback) | Node.jsκ° μλ νκ²½μμ λΉλκΈ° μ€ν |
onNotBunAsync(callback) | Bunμ΄ μλ νκ²½μμ λΉλκΈ° μ€ν |
onNotDenoAsync(callback) | Denoκ° μλ νκ²½μμ λΉλκΈ° μ€ν |
π λ¦΄λ¦¬μ€ λ ΈνΈ
1.2.0
- π λ²κ·Έ μμ :
on*
ν¨μλ€μ΄ μλͺ»λ νκ²½μμ μ€νλ μ μλ μ€μν λ¬Έμ ν΄κ²°- μ΄μ μλ νκ²½λ³ ν¨μ λ΄μ μ½λκ° μλνμ§ μμ νκ²½μμ μ€νλ μ μμμ
- μ΄μ μ½λ μ€ν μ μ νκ²½ κ²μ¬λ₯Ό μ격νκ² μν
- λͺ¨λ νκ²½λ³ ν¨μμ μ μ© (
onNodejs
,onBrowser
,onBun
,onDeno
λ±)
π€ κΈ°μ¬νκΈ°
κΈ°μ¬λ μΈμ λ νμν©λλ€! Pull Requestλ₯Ό μμ λ‘κ² μ μΆν΄ μ£ΌμΈμ.
π λΌμ΄μ μ€
MIT λΌμ΄μ μ€ - μ¬λ¬λΆμ μ ν리μΌμ΄μ μ μμ λ‘κ² μ¬μ©νμ€ μ μμ΅λλ€.