UNPKG

universal-emoji-parser

Version:

This tool allow parse unicode and emoji codes to html images using emojilib && Twemoji CDN

269 lines (175 loc) 12.2 kB
# Runtimes Per-environment reference for Universal Emoji Parser: where it runs, how it's loaded, and what consumers should know. The package is published as a single CommonJS bundle with TypeScript declarations and works in every JS environment that meets the Node engines constraint. ## Summary | Runtime | Loading | Notes | | ----------------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | Node.js (≥ 20.19) | `require('universal-emoji-parser')` or `import` | Primary target; CI runs on Node 24 | | Browsers (modern) | Bundled via webpack/rollup/vite/esbuild by the consumer | Catalog adds ~543 KB raw to consumer bundles see [Performance](PERFORMANCE.md#bundle-size) | | Deno | `npm:universal-emoji-parser` | Untested but expected to work Deno 1.28+ supports `npm:` specifiers | | Bun | `bun add universal-emoji-parser` | Untested but expected to work Bun is Node-compatible | | Edge runtimes (Cloudflare Workers, Vercel Edge) | Bundled by the framework | Catalog inlines fine; bundle size matters at the edge | The package is **environment-agnostic**: no `process`, no `fs`, no `Buffer`, no DOM APIs. It's a pure string transformer with a JSON catalog and a single `@twemoji/parser` call. --- ## Node.js ### Installing ```bash npm install universal-emoji-parser # or yarn add universal-emoji-parser # or pnpm add universal-emoji-parser ``` ### Importing The package supports both module systems out of the box: ```js // CommonJS Node default for .js files / .cjs const uEmojiParser = require('universal-emoji-parser') const { emojiLibJsonData, DEFAULT_EMOJI_CDN } = require('universal-emoji-parser') console.log(uEmojiParser.parse('hello :smile: 🚀')) ``` ```ts // ES modules .mjs files, "type": "module" packages, or TS with esModuleInterop import uEmojiParser, { emojiLibJsonData, DEFAULT_EMOJI_CDN } from 'universal-emoji-parser' console.log(uEmojiParser.parse('hello :smile: 🚀')) ``` The dual export shape is implemented in `src/index.ts`: ```ts export default uEmojiParser module.exports = uEmojiParser module.exports.emojiLibJsonData = emojiLibJsonData module.exports.DEFAULT_EMOJI_CDN = DEFAULT_EMOJI_CDN ``` This means **both** `require('universal-emoji-parser').parse(...)` and `import uEmojiParser from '...'` give you the same object see [Architecture CommonJS reattachment](ARCHITECTURE.md#commonjs-reattachment). ### Engines `package.json` sets `engines.node: ">=20.19.0"`. npm warns (does not error) when installing on older Node versions; the runtime will likely still work down to Node 18, but unsupported. CI runs on **Node 24**. If a Node version-specific bug surfaces, that's the reference version to debug against. ### Memory The catalog is a static `import emojiLibJson from './lib/emoji-lib.json'`. Node loads it once per process; it stays in memory for the lifetime of the process. ~5 MB resident (parsed JS objects expand the 543 KB JSON). If you're running this in a memory-constrained environment (Lambda with low memory, edge worker), this is the biggest cost there is no streaming-load mode. ### Threading The package is synchronous and stateless safe to call from worker threads (`worker_threads`). Each worker loads its own copy of the catalog (no shared memory). --- ## Browsers ### Bundling This package is **not** publishable as a static `<script>` import it relies on `require('@twemoji/parser')` to be resolved by a bundler. Consumers integrate it via: | Bundler | Integration | | ------- | -------------------------------------------------------------------------- | | webpack | `import uEmojiParser from 'universal-emoji-parser'` (works out of the box) | | Rollup | Add `@rollup/plugin-commonjs` and `@rollup/plugin-node-resolve` | | Vite | Works out of the box (Vite uses esbuild + Rollup internally) | | esbuild | Works out of the box | | Parcel | Works out of the box | The package's own bundle (`dist/index.js`) is `commonjs2` it expects `module.exports` to be writable. All modern bundlers handle this. ### Tree-shaking The catalog **cannot be tree-shaken**. The whole `emoji-lib.json` is reachable from the runtime (`getEmojiObjectByShortcode` enumerates all keys via `Object.keys(emojiLibJsonData)`). Even if the consumer only ever calls `parseToHtml('hello :smile:')`, the full ~543 KB ships. If a consumer cares deeply about bundle size, they have two options: 1. **Lazy-load** `const uEmojiParser = await import('universal-emoji-parser')` defers the catalog parse until first use 2. **Build a custom subset** fork or wrap the package, load only the emojis they actually use. Out of scope for this package; pattern documented in [Performance Bundle size](PERFORMANCE.md#bundle-size) ### Output rendering The HTML the package emits assumes: ```html <img class="emoji" alt="😎" src="https://cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets/svg/1f60e.svg" /> ``` Consumers typically style with: ```css img.emoji { height: 1em; width: 1em; margin: 0 0.05em 0 0.1em; vertical-align: -0.1em; } ``` (Recommended snippet from the README.) The `class="emoji"` selector is the contract. ### CDN considerations The default CDN is `cdn.jsdelivr.net/gh/jdecked/twemoji@latest`. For production, consumers should pin to a specific Twemoji version to avoid surprise changes: ```ts uEmojiParser.parseToHtml('hello 🚀', 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@17.0.1/assets/svg/') ``` See [Emoji Providers CDN selection](EMOJI_PROVIDERS.md#cdn-selection). ### CORS Twemoji CDN serves with permissive CORS (`Access-Control-Allow-Origin: *`). If a consumer hosts the SVG assets themselves, they must configure their CDN/server to send CORS headers otherwise SVGs render but cross-origin canvas access (`getImageData`) fails. Most consumers don't care. ### Image format Twemoji ships **SVG by default**. The CDN also has `/assets/72x72/` (PNG fallback). If a consumer wants PNGs, they pass: ```ts uEmojiParser.parseToHtml('🚀', 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets/72x72/') ``` …but the file extension would still be `.svg` because that's what `@twemoji/parser` returns. The package doesn't yet support automatic extension rewriting; if a consumer needs PNGs, they post-process the output. --- ## Deno Untested but expected to work via Deno's npm specifier: ```ts import uEmojiParser from 'npm:universal-emoji-parser@2' console.log(uEmojiParser.parse('hello :smile:')) ``` Caveats: - Deno's `npm:` resolver loads CommonJS via shim slower first call, fine afterwards - The catalog import (`import emojiLibJson from './lib/emoji-lib.json'`) is bundled into `dist/index.js`, so Deno doesn't need separate `--allow-read` permissions If a Deno-specific bug surfaces, file an issue. We don't actively test on Deno but accept fixes. --- ## Bun ```bash bun add universal-emoji-parser ``` Bun is Node-compatible and runs the package without modification. Bun's faster startup makes the catalog parse less noticeable. The Webpack bundle works as-is. --- ## Edge runtimes ### Cloudflare Workers ```ts import uEmojiParser from 'universal-emoji-parser' export default { fetch(request: Request): Response { const text = new URL(request.url).searchParams.get('text') ?? '' return new Response(uEmojiParser.parse(text), { headers: { 'content-type': 'text/html' }, }) }, } ``` Caveats: - Worker bundle size limit is 1 MB (Free plan) / 10 MB (Paid). The package alone is ~600 KB minified, so on Free plan you have ~400 KB of headroom for your code - No `fs`, no `Buffer` fine, this package doesn't need them - The Twemoji CDN is reachable from Workers; no proxy needed ### Vercel Edge / Netlify Edge Same characteristics as Cloudflare Workers. Both support npm packages out of the box. Bundle size is tracked by the platform; large catalogs eat into your edge function quota. ### AWS Lambda Standard Node Lambda works as a regular `npm install`. Catalog lives in memory across invocations within the same warm container. Cold-start cost is ~30ms for catalog parse on a 256MB Lambda. --- ## TypeScript users The package ships `.d.ts` files (built by `tsc --build`): ``` dist/ ├── index.js ├── index.d.ts types entry └── lib/ └── type.d.ts ``` `package.json` `types: "dist/index.d.ts"` is the entry. TypeScript users get full type inference: ```ts import uEmojiParser, { EmojiType, EmojiLibJsonType, EmojiParseOptionsType } from 'universal-emoji-parser' const opts: EmojiParseOptionsType = { parseToHtml: true, parseToShortcode: false } const result: string = uEmojiParser.parse('hello :smile:', opts) const emoji: EmojiType | undefined = uEmojiParser.getEmojiObjectByShortcode('smile') ``` The exported types are: - `EmojiType` one entry in the catalog - `EmojiLibJsonType` `{ [key: string]: EmojiType }` (the catalog itself) - `EmojiParseOptionsType` the options bag for `parse()` - `UEmojiParserType` the type of the default export - `TwemojiEntity` what `@twemoji/parser` returns (rarely needed by consumers) Removing or renaming any of these is a breaking change. --- ## Choosing a target to add We don't currently target React Native, NativeScript, or any non-V8 runtime. If a consumer asks for one: | Need | Likely fix | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | React Native | Should work RN's Metro bundler handles CommonJS. Catalog size matters; consider lazy-load | | NativeScript | Same as RN works through their CommonJS shim | | Browser-direct `<script>` (no bundler) | Need to ship a UMD bundle. Currently we don't. Adding one means a second `webpack.config.js` mode and a second `dist/` artifact | | ESM-only consumers (`"type": "module"` strict) | Already works `import` resolves through the `.d.ts` and Node's CommonJS interop | For each, the path is: open an issue describing the use case, add CI coverage for the new runtime if possible, document here. --- ## Gotchas across runtimes 1. **Catalog parse is synchronous and eager.** Every runtime pays the catalog parse cost at module load. This is fine for long-lived processes (Node servers, Lambdas), notable for cold-starting edge functions, irrelevant for browsers (the bundler precompiles the JSON into a JS object literal) 2. **The `@twemoji/parser` dependency is not optional.** It's `dependencies`, not `peerDependencies`. Consumers can't swap it out 3. **`require()` cache is shared.** If a Node app calls `require('universal-emoji-parser')` from multiple files, they all get the same `uEmojiParser` object. Don't mutate it 4. **`process.exit()` mid-`parse`** would leave the catalog parse incomplete; not a real risk because `parse()` is fast (microseconds) and synchronous, but worth knowing