npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

igloo-code-compiler

v0.1.2

Published

Browser-side build SDK — compile frontend projects via a hosted iframe

Downloads

404

Readme

igloo-code-compiler

Browser-side frontend build SDK. Wraps the code-compiler service into a clean TypeScript API — no postMessage boilerplate required.


How it works

Your app
  └─ CodeCompiler SDK
       └─ Hidden iframe  ←postMessage→  code-compiler service
                                          └─ WebContainer (Node.js in Browser)
                                               └─ npm install + npm run build

The SDK creates an invisible <iframe> pointing to your deployed code-compiler instance. All postMessage communication (COMPILE_READY / COMPILE_REQUEST / COMPILE_SUCCESS, etc.) is handled automatically — you just call compile().


Installation

npm install igloo-code-compiler
# or
pnpm add igloo-code-compiler

Quick start

import { CodeCompiler } from 'igloo-code-compiler'

const compiler = new CodeCompiler({
  endpoint: 'https://compiler.example.com',
})

// Stream build logs
compiler.on('progress', (msg) => console.log('[Build]', msg))

// Compile and get output files
const outputFiles = await compiler.compile({
  files: {
    'package.json': JSON.stringify({
      name: 'my-app',
      scripts: { build: 'vite build' },
      dependencies: { react: '^18.0.0', 'react-dom': '^18.0.0' },
      devDependencies: { vite: '^5.0.0', '@vitejs/plugin-react': '^4.0.0' },
    }),
    'vite.config.js': `
      import { defineConfig } from 'vite'
      import react from '@vitejs/plugin-react'
      export default defineConfig({ plugins: [react()] })
    `,
    'index.html': `<!doctype html><html><body>
      <div id="root"></div>
      <script type="module" src="/src/main.jsx"></script>
    </body></html>`,
    'src/main.jsx': `
      import React from 'react'
      import ReactDOM from 'react-dom/client'
      ReactDOM.createRoot(document.getElementById('root')).render(<h1>Hello</h1>)
    `,
  },
})

// outputFiles: { 'index.html': '...', 'assets/index.js': '...', ... }
console.log('Build output:', Object.keys(outputFiles))

compiler.destroy()

API

new CodeCompiler(options)

| Option | Type | Required | Description | | -------------- | ------------------------------ | -------- | --------------------------------------------------------------------------------- | | endpoint | string | ✅ | URL of the deployed code-compiler service, e.g. 'https://compiler.example.com' | | container | HTMLElement | — | Mount the iframe into this element (default: hidden, appended to document.body) | | iframeStyle | Partial<CSSStyleDeclaration> | — | Custom iframe CSS (only applies when container is not set) | | readyTimeout | number | — | Timeout (ms) waiting for the compiler to become ready; default 180000 |


.compile(options): Promise<OutputFiles>

Triggers one compilation and returns a file map of the build output ({ [relativePath]: content }).

| Option | Type | Description | | -------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------- | | files | FileMap | Flat file map (mutually exclusive with zip). Keys are relative paths, values are file content strings. Must include package.json. | | zip | string | Base64-encoded zip (mutually exclusive with files). Accepts with or without a data: URL prefix. | | buildCommand | string | Build command; default 'npm run build' | | installCommand | string | Install command; default: auto-detected from lock file | | skipTsc | boolean | Strip tsc/vue-tsc from the build script; default true | | timeout | number | Compilation timeout (ms); default 600000 (10 minutes) | | autoUpload | boolean | Auto-publish to the server after a successful build; default false | | publishProjectName | string | Project name for publishing (required when autoUpload is true) | | publishAuthToken | string | Bearer token for the publish API (optional) |

When both files and zip are provided, zip takes priority.


.ready(): Promise<void>

Waits for the compiler iframe to initialize. compile() already calls this internally — you rarely need to call it manually.


.upload(options): Promise<UploadResult>

Uploads the output from the previous compilation without re-compiling. Must be called after a successful compile().

| Option | Type | Description | | -------------------- | -------- | ------------------------------------ | | publishProjectName | string | Project name (required) | | publishAuthToken | string | Bearer token (optional) | | timeout | number | Upload timeout (ms); default 60000 |


.on(event, listener) / .off(event, listener) / .once(event, listener)

| Event | Argument | Description | | ------------------- | ---------------------- | ------------------------ | | 'ready' | — | Compiler is ready | | 'progress' | message: string | Real-time build log line | | 'success' | files: OutputFiles | Build succeeded | | 'error' | error: Error | Build failed | | 'upload-progress' | message: string | Upload progress | | 'upload-success' | result: UploadResult | Upload succeeded | | 'upload-error' | error: Error | Upload failed |


.destroy()

Destroys the instance: removes the iframe and stops listening for messages. Any in-progress compile() call rejects immediately.


Properties

| Property | Type | Description | | -------------- | --------- | ------------------------------------------ | | .ready_state | boolean | Whether COMPILE_READY has been received | | .compiling | boolean | Whether a compilation is currently running | | .uploading | boolean | Whether an upload is currently running |


Publishing build output

Two ways to publish after a successful build:

Option 1 — Auto-publish (autoUpload)

const files = await compiler.compile({
  files: { ... },
  autoUpload: true,
  publishProjectName: 'my-app',
  publishAuthToken: 'Bearer xxx',   // optional
})

compiler.on('upload-progress', (msg) => console.log('[Upload]', msg))
compiler.on('upload-success', (result) => {
  console.log('Live URL:', result.url)      // e.g. 'my-app.example.com'
  console.log('HTML file:', result.s3Url)
})
compiler.on('upload-error', (err) => console.error('Upload failed:', err.message))

Option 2 — Manual upload (upload())

Use this when you want to inspect the output first, or let the user confirm before publishing.

import { CodeCompiler } from 'igloo-code-compiler'

const compiler = new CodeCompiler({ endpoint: 'https://compiler.example.com' })

// Step 1: compile
const files = await compiler.compile({ files: { ... } })
console.log('Build done, files:', Object.keys(files))

// Step 2: upload (reuses the same build output — no re-compilation)
compiler.on('upload-progress', (msg) => console.log('[Upload]', msg))
const result = await compiler.upload({ publishProjectName: 'my-app' })
console.log('Live URL:', result.url)

compiler.destroy()

Upload result

| Field | Type | Description | | ------------- | -------- | ---------------------------------------------------- | | projectName | string | Published project name | | url | string | Accessible project domain, e.g. my-app.example.com | | s3Url | string | Direct S3/CDN link to the HTML file |


Passing a ZIP archive

When the file count is large, or you already have a zip on hand:

// Fetch a zip from an API
const response = await fetch('/api/project/my-app.zip')
const buffer = await response.arrayBuffer()
const bytes = new Uint8Array(buffer)
let binary = ''
bytes.forEach(b => (binary += String.fromCharCode(b)))
const base64 = btoa(binary)

const files = await compiler.compile({ zip: base64 })

Error handling

import { CodeCompiler, CompileError, CompileTimeoutError } from 'igloo-code-compiler'

try {
  const files = await compiler.compile({ files: { ... } })
} catch (err) {
  if (err instanceof CompileTimeoutError) {
    console.error('Build timed out')
  } else if (err instanceof CompileError) {
    console.error('Build failed:', err.message)
  } else {
    throw err
  }
}

React hook example

import { useEffect, useRef, useState } from 'react'
import { CodeCompiler, type OutputFiles } from 'igloo-code-compiler'

export function useCompiler(endpoint: string) {
  const compilerRef = useRef<CodeCompiler | null>(null)
  const [logs, setLogs] = useState<string[]>([])

  useEffect(() => {
    const compiler = new CodeCompiler({ endpoint })
    compiler.on('progress', (msg) => setLogs((prev) => [...prev, msg]))
    compilerRef.current = compiler
    return () => compiler.destroy()
  }, [endpoint])

  const compile = async (files: Record<string, string>): Promise<OutputFiles> => {
    if (!compilerRef.current) throw new Error('Compiler not initialized')
    return compilerRef.current.compile({ files })
  }

  return { compile, logs }
}

Notes

  1. Browser-only: The SDK depends on window, document, and postMessage — it does not support SSR or Node.js environments.
  2. One compilation at a time: A single instance can only run one compile() call concurrently. Create multiple instances for parallel builds.
  3. COOP/COEP headers: The code-compiler service must serve with Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. The service handles this automatically via its built-in Service Worker — no configuration required on your parent page.
  4. First build is slower: The WebContainer runtime (~10 MB) is downloaded from CDN on first use. Call new CodeCompiler(...) or compiler.ready() early to warm up the instance.