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

@zombieland/wichita

v0.1.2

Published

A resource module for running client side JS and resolving assets.

Readme

Wichita

A resource module for running client side JS and resolving assets.

JSDOM does run scripts quite well. It does however not provide a controlled way to execute scripts at a convenient time. A pattern when testing something is asserting an element original state, running the scripts then asserting the element's new state. JSDOM will, like a browser, run any client script as soon as it has loaded making it tricky to run assertions prior to script execution.

Custom script executor enables running code at any given time. Also it enables running source code over a built resource which is good for rapid retesting.

Resolver enables "binding" script tags to files making the test suite less verbose and less prone to mistakes.

Table of Contents

Basic usage

import assert from 'node:assert/strict';
import { JSDOM } from 'jsdom';
import { Script } from '@zombieland/wichita';

const dom = new JSDOM('<title>initial value</title>');
const script = new Script(`
  document.title += ', edit from script';
`);

await script.evaluate(dom.window);

assert.equal(dom.window.document.title, 'initial value, edit from script');

API

Script

A module for executing JavaScript code. A wrapper around the vm.SourceTextModule. Requires the use of the --experimental-vm-modules command flag.

import { Script } from '@zombieland/wichita';

Or if you're using the Script module without JSDOM:

import Script from '@zombieland/wichita/script.js';

new Script(filePath)

Creates a new Script instance from a file path.

  • filePath <string> Absolute path to a JavaScript file
const script = new Script(import.meta.dirname + '/my-script.js');

new Script(code)

Creates a new Script instance from source code.

  • code <string> JavaScript code to execute
const script = new Script(`
  document.title += ', edit from script';
`);

new Script(identifier, code)

Creates a new Script instance with a custom identifier from source code.

  • identifier <string> Script identifier. Used for resolving imports and stack traces.
  • code <string> JavaScript code to execute
const script = new Script('custom-script.js', `
	document.title += ', edit from named script';
`);

script.evaluate(context)

Executes the script in the provided context with ES module support.

  • context <Object> Context object to be used as the global scope for script execution
  • Returns: <Promise> Fulfills with exported values from the script (if any)
it('evaluates code in a given context', async () => {
  const dom = new JSDOM('<title>initial value</title>');
  const script = new Script(`
    document.title += ', edit from script';
  `);
  
  await script.evaluate(dom.window);

  assert.equal(dom.window.document.title, 'initial value, edit from script');
});

it('evaluates code with imports', async () => {
  const dom = new JSDOM('<title>initial value</title>');
  const script = new Script('./source-entry.js');
  
  await script.evaluate(dom.window);

  assert.equal(dom.window.document.title, 'initial value, edit from source entry, edit from source component');
});

it('evaluates code with exports', async () => {
  const dom = new JSDOM('<title>with exports</title>');
  const script = new Script(`
    export default document.title + '?';
    export const named = document.title + '!';
  `);
  
  const exports = await script.evaluate(dom.window);

  assert.equal(exports.default, 'with exports?');
  assert.equal(exports.named, 'with exports!');
});

it('evaluates code multiple times', async () => {
  const dom1 = new JSDOM('<title>once</title>');
  const dom2 = new JSDOM('<title>twice</title>');
  const script = new Script(`
    let i = 0;
    export default document.title + '!';
    export const times = ++i;
  `);

  const exports = await Promise.all([
    script.evaluate(dom1.window),
    script.evaluate(dom2.window),
  ]);
  
  assert.equal(exports[0].default, 'once!');
  assert.equal(exports[1].default, 'twice!');
  assert.equal(exports[1].times, 1);
});

ResourceLoader

An extension of the jsdom ResourceLoader with additional support for resolving DOM nodes into wichita scripts and script execution.

May be subject to change in the future. Keeping documentation breif. Take a look in the Source code resource example for more details.

import { ResourceLoader } from '@zombieland/wichita';

new ResourceLoader([options, ...args])

Creates a new ResourceLoader instance.

  • options <Object>
    • resolveTag Function to resolve a HTMLScriptElement into path to a local file to execute
  • args Arguments to forward to jsdom ResourceLoader constructor

resourceLoader.runScripts(dom[, options])

Iterates through document script tags and evaluates code with Script. Uses the resolveTag function to resolve script element into arguments for Script constructor.

  • dom <JSDOM> DOM to execute scripts in
  • options <Object>
    • noModule Boolean When set to true will skip script[module]. Default: false
  • Returns: <Promise> Resolves with undefined
it('runs document scripts', async () => {
	const resourceLoader = new ResourceLoader();
  const dom = new JSDOM(
	  '<script src="/scripts/main.js"></script>', 
	  { resources: resourceLoader, runScripts: "outside-only" }
  );
  await resourceLoader.runScripts();
});

it('runs local source code', async () => {
	const resourceLoader = new ResourceLoader({
		resolveTag (script) {
			if (script.src.endsWith('/scripts/main.js')) {
				const localSourceCodeFile = import.meta.resolve(path.join(import.meta.dirname, '../src/scripts/main.js'));
				return localSourceCodeFile;
			}
		}
	});
  const dom = new JSDOM(
	  '<script src="/scripts/main.js"></script>', 
	  { resources: resourceLoader, runScripts: "outside-only" }
  );
  await resourceLoader.runScripts();
});

Todo

  • [ ] Not using the ES module feature mustn't require the --experimental-vm-modules flag.
  • [ ] VM evaluation based on script type attribute.
  • [ ] Respecting nomodule like modern / legacy browser.
  • [ ] Support for importing CJS modules in Script
  • [x] Expose Script exports
  • [x] Cache for FS operations.
  • [x] Have not been able to make a working example using fetch along with the community recommended polyfill. Did make it with another polyfill though :fingers_crossed: