mrkeyoor.com_
Sun 09 Aug 06:57 UTC
npmWeb Frontendupdated 09 Aug 2026

node-ensure

node-ensure is a compatibility shim for the old require.ensure approach to asynchronous module loading. On Node, it ignores the requested module names and runs your callback on setImmediate, after which ordinary require calls load the modules. When a bundler honors the package's browser map, a second entry delegates the same call to the bundler's own require.ensure implementation so it can create and fetch a separate client bundle. It does not load modules itself, expose a CLI, return a Promise, or provide modern dynamic import behavior.

Verdict

Do not add node-ensure to new code. Keep it only as a pinned compatibility shim while an old custom bundler still requires its exact protocol, then migrate those split points to import().

API stability2/5The two-argument function has never changed, but the package is still version 0.0.0 and publishes no compatibility contract beyond a short README. Its browser behavior is not controlled by the package at all: it forwards arguments to whatever require.ensure a bundler injected. Stable source therefore does not guarantee stable behavior across loaders or generated bundles.
Docs2/5The README gives installation, both supported call shapes, and unusually important requirements for bundler authors. It also clearly warns that Browserify is incompatible. It has no migration guide, client error example, test matrix, TypeScript guidance, supported bundler list beyond an old dynapack link, or explanation that the Node implementation ignores module names.
Maintenance1/5The repository was last pushed in April 2015 and npm contains one 0.0.0 release. The package is not marked deprecated or archived, but its package.json test command is a placeholder that deliberately fails, and its development era predates standardized dynamic import. No releases, commits, CI, or current runtime support statement demonstrate active ownership.
Ecosystem2/5The package logged 3,436,284 downloads in the measured npm week, likely because old dependency trees still contain it, but the project itself names only node-raw and dynapack as use in the wild. Its custom protocol lost relevance once import() became standard, and current webpack, Vite, and Rollup workflows do not need this shim for ordinary code splitting.

Use it if

  • You maintain an old isomorphic CommonJS application whose bundler explicitly implements this node-ensure protocol
  • You need the exact server fallback expected by dynapack-era code: defer once, then use ordinary require
  • You are preserving a package that already publishes a browser replacement compatible with require.ensure
Skip it if

Setup reality

npm install node-ensure adds no dependencies, native builds, credentials, peer dependencies, or config files. It also does much less than the name suggests. On Node, ensure(moduleNames, callback) never resolves or checks moduleNames; it simply schedules callback with setImmediate. The require calls must remain literally inside that callback so an old compatible bundler can discover the split point. For browser builds, the package.json browser map replaces index.js with browser.js, which forwards to the require.ensure supplied by your loader. Your bundler must honor that browser map, inject a require function with an ensure property, accept the same array-and-callback arguments, and avoid per-module closure state in its implementation. The README explicitly excludes Browserify and names dynapack as the example, but both the package and that ecosystem come from 2015. The function returns undefined, supplies no Promise, timeout, cancellation, preload signal, chunk naming, retry, or fallback UI. Node errors from a later require happen inside your callback and are not passed as its err argument. There are no shipped types, exports map, ESM entry, tests, or declared Node engine range. If this protocol is already embedded in a legacy build, pin the exact version, test both server and produced browser chunks, and document the bundler dependency. For any new or actively migrated project, replace the split point with import() and let webpack, Vite, Rollup, or your runtime own module loading.

Patterns

Use the basic legacy split-point shapeload-commonjs-modules

const ensure = require('node-ensure');

ensure(['superagent', 'react'], (err) => {
  if (err) return handleClientLoadError(err);

  const request = require('superagent');
  const React = require('react');
  startApp({ request, React });
});

On Node, the module-name array is ignored and err is undefined. A compatible browser bundler is responsible for interpreting both.

Attach the shim to requireattach-require-ensure

require.ensure = require('node-ensure');

require.ensure(['./feature'], (err) => {
  if (err) throw err;
  const feature = require('./feature');
  feature.run();
});

This mutates the local CommonJS require function. It is for bundlers that look specifically for require.ensure syntax, not general Node module loading.

Keep dependency requests statically visiblekeep-static-require

ensure(['./reports/monthly'], (err) => {
  if (err) return showLoadFailure(err);
  const monthlyReport = require('./reports/monthly');
  monthlyReport.render();
});

Do not build the require path from a runtime variable. Old bundlers need a literal request to know what belongs in the split bundle.

Treat callback errors as client-loader errorshandle-client-error

ensure(['./account-panel'], (err) => {
  if (err) {
    showRetryButton(() => openAccountPanel());
    return;
  }
  require('./account-panel').mount();
});

The README says Node should never pass an error. Whether browser failures reach err depends on the injected bundler or loader.

Catch a missing module on Nodecatch-node-require-error

ensure(['./optional-feature'], () => {
  try {
    require('./optional-feature').start();
  } catch (error) {
    console.error('Feature could not start', error);
  }
});

A Node require failure is thrown inside the callback; node-ensure does not catch it or convert it into the callback's err argument.

Wrap the callback protocol in a Promisewrap-in-promise

function ensureAsync(modules) {
  return new Promise((resolve, reject) => {
    ensure(modules, (err) => err ? reject(err) : resolve());
  });
}

await ensureAsync(['./editor']);
const editor = require('./editor');

The wrapper only changes consumption. On Node it still does not preload or validate modules, and bundler recognition of the indirect call may fail.

Understand the actual Node timingdefer-server-work

console.log('before');
ensure(['anything'], () => console.log('callback'));
console.log('after');
// before, after, callback

The Node implementation is exactly setImmediate(callback). The dependency list does not influence timing or loading.

Pass context through a require.ensure callpreserve-callback-context

require.ensure = require('node-ensure');

require.ensure.call({ chunk: 'settings' }, ['./settings'], function (err) {
  if (!err) require('./settings').open(this.chunk);
});

The browser shim forwards this with apply. Whether the injected loader preserves it for the callback is loader-specific, so test the produced bundle.

Add a minimal local TypeScript declarationdeclare-types-locally

declare module 'node-ensure' {
  type EnsureCallback = (error?: Error) => void;
  function ensure(modules: string[], callback: EnsureCallback): void;
  export = ensure;
}

The npm package ships no declarations and has no types field. Keep this in your own .d.ts file if migration cannot happen yet.

Mirror the package's browser replacement conventionconfigure-browser-replacement

{
  "browser": {
    "./server-loader.js": "./browser-loader.js"
  }
}

node-ensure depends on the bundler honoring package.json browser mappings. This convention alone does not guarantee require.ensure support.

Replace a split point with dynamic importmigrate-dynamic-import

async function openEditor() {
  try {
    const { createEditor } = await import('./editor.js');
    return createEditor();
  } catch (error) {
    showLoadFailure(error);
  }
}

This is the preferred new-code shape. Current Node and bundlers understand import() without node-ensure or a custom callback protocol.

Preserve an explicit webpack chunk name during migrationname-webpack-chunk

const panelModule = await import(
  /* webpackChunkName: "account-panel" */
  './account-panel.js'
);
panelModule.mount();

The comment is webpack-specific. Other bundlers split dynamic imports but use their own output naming controls.

Alternatives

PackageRegistryPick it when
webpacknpmYou need a maintained bundler that turns dynamic import calls into on-demand chunks
vitenpmYou want an ESM-first development and production build around standard dynamic imports
@loadable/componentnpmYou need React-focused code splitting with loading components and server-rendering support