Bundle Optimization

Reduce your bundle size with tree shaking and code splitting.

📘

This guide is specific to Web SDK 2.0. If you are still using 1.x, you can find documentation here. We strongly recommend upgrading - contact your Incode Representative for upgrade information.

Reduce your bundle size with tree shaking and code splitting.

Tree Shaking

Each module ships at its own subpath. Import only the subpaths you need — the SDK has no barrel re-exports that pull everything in.

✅ Good: Subpath imports

// Side-effect import: registers <incode-phone>, ships only the Phone UI bundle
import '@incodetech/web/phone';
import '@incodetech/web/phone/styles.css';

// Headless: only the Phone manager and its dependencies
import { createPhoneManager } from '@incodetech/core/phone';

❌ Avoid: importing more modules than you use

// Don't register every module if you only need one — each side-effect
// import bundles its UI. Import only what you mount.
import '@incodetech/web/phone';
import '@incodetech/web/email';
import '@incodetech/web/selfie';
import '@incodetech/web/id';

Code Splitting

Use dynamic imports to register modules on demand.

Lazy register a module

// Module registers itself only when this code runs
async function showPhone() {
  await import('@incodetech/web/phone');
  await import('@incodetech/web/phone/styles.css');
  document.body.insertAdjacentHTML('beforeend', '<incode-phone></incode-phone>');
  const phone = document.querySelector('incode-phone');
  phone.config = { otpVerification: true, otpExpirationInMinutes: 5, prefill: false };
  phone.onFinish = () => goToSelfie();
}

Prefetch the next module

Load the next step while the user interacts with the current one:

// Start prefetching as soon as the current step begins
const prefetchSelfie = () => import('@incodetech/web/selfie');

phone.onFinish = () => {
  // Selfie chunk is already in the cache by the time we mount it
  goToSelfie();
};

prefetchSelfie();

<incode-flow> optimization

<incode-flow> handles code splitting internally:

  • Lazy-loads each module's UI chunk only when the orchestrator advances to that step
  • Prefetches the next module while the user completes the current step
  • Loads WASM only when a selfie or ID-capture step is reached (unless preloaded via setup({ wasm }))

You don't need to manage code-splitting yourself when using <incode-flow>.

Bundle size reference

These numbers are a snapshot of the published @incodetech/web build. Your app's final cost depends on bundler, deduplication with framework dependencies, and which modules you actually import — measure with your bundler's built-in size analyzer for an accurate per-app breakdown.

Last measured: 2026-04-30 against @incodetech/[email protected]. Your bundler may produce slightly different numbers depending on minifier and tree-shaking settings.

Per-module entry chunks — what gets pulled in when you side-effect-import a single module:

SubpathEntry chunkGzipped
@incodetech/web/phone3.8 KB1.4 KB
@incodetech/web/email3.9 KB1.5 KB
@incodetech/web/selfie1.7 KB0.7 KB
@incodetech/web/id16.0 KB5.6 KB
@incodetech/web/flow19.3 KB4.5 KB
@incodetech/web/consent2.9 KB1.2 KB
@incodetech/web/curp-validation9.1 KB2.4 KB
@incodetech/web/document-capture34.4 KB8.9 KB
@incodetech/web/face-match65.9 KB45.5 KB
@incodetech/web/identity-reuse7.3 KB1.6 KB
@incodetech/web/redirect-to-mobile41.4 KB12.7 KB
@incodetech/web/signature24.7 KB7.2 KB
@incodetech/web/electronic-signature1454.8 KB470.3 KB
@incodetech/web/workflow6.2 KB2.3 KB
@incodetech/web/ekyc, /ekyb8.2 KB / 7.9 KB2.6 KB / 2.8 KB
@incodetech/web/geolocation118.8 KB32.5 KB

Shared chunks — loaded once and reused across modules. Most modules pull in some subset:

Shared chunkSizeGzipped
vendor-preact (Preact + signals)37.0 KB12.4 KB
i18n (translation runtime)79.1 KB22.3 KB
icons (shared icon set)17.4 KB5.6 KB
useModuleLoader (module-loading runtime)14.7 KB4.8 KB
homeScreen12.1 KB4.5 KB
verifiedByIncode13.7 KB5.6 KB
countries (phone module dependency)138.5 KB27.0 KB
AsYouType (phone formatter)82.6 KB16.3 KB
tutorial, ID tutorial Lotties, etc.100–230 KB each8–40 KB

Notes:

  • The phone module entry is tiny (~4 KB) but a real phone integration also pulls in countries (27 KB gzipped) and AsYouType (16 KB gzipped). Plan for 50–60 KB gzipped for a complete phone screen.
  • ID and selfie pull in WASM ML model files separately (loaded over the network when capture begins, not bundled). Use setup({ wasm: { pipelines: [...] } }) to preload them — see WASM Configuration.
  • The electronic-signature module includes a PDF rendering subsystem, which is why its entry chunk is so much larger. Lazy-load it.
  • Headless managers from @incodetech/core/<name> are typically 1–10 KB each, since they ship state machines and HTTP services without UI. Pair them with your own UI when bundle size is paramount.

If you need the precise number for your build, your bundler is the source of truth. Run vite build --mode analyze (Vite/Rollup), webpack-bundle-analyzer (Webpack), or esbuild --metafile=meta.json (esbuild) and inspect the resulting report.

Bundler Configuration

Vite

// vite.config.ts
export default {
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'incode-phone': ['@incodetech/web/phone'],
          'incode-selfie': ['@incodetech/web/selfie'],
        },
      },
    },
  },
};

Webpack

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        incode: {
          test: /[\\/]node_modules[\\/]@incodetech/,
          name: 'incode-sdk',
          chunks: 'async',
        },
      },
    },
  },
};

Best Practices

  1. Use subpath imports@incodetech/web/phone, never the package root.
  2. Defer registration until you need the module — wrap the side-effect import in await import('@incodetech/web/<module>') inside a click handler or route entry.
  3. Prefetch the next step — fire the dynamic import for the next module while the user is still completing the current one, so it's cached by the time you mount it.
  4. Analyze your bundle — use whatever size analyzer your bundler ships (webpack-bundle-analyzer, rollup-plugin-visualizer, esbuild --metafile, etc.).

See Also