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 🙏

© 2024 – Pkg Stats / Ryan Hefner

stratum-framework

v0.6.3

Published

a framework for web application development

Downloads

30

Readme

Stratum

NPM version

A framework and component library for web application development.

Designed to provide a small modular basis upon which to build web applications.

To this end, the whole framework is built around a single core mechanism, the modular inclusion functionality, in require.js.

Contents

Modularity

The require function:

  • Is compatible with CommonJS Module/1.1
  • Works with the file: protocol, for rapid prototyping
  • Works with cross site urls
  • Retains correct file and line number mapping for debugging/error handling.
  • Is tested in a wide variety of browsers
  • Passes CommonJS module unit tests (though two are passed in error, see Gotchas for details)

The define function:

  • Is compatible with require.js AMD
  • Is probably best suited to providing mock modules for testing purposes!

Install

Either directly through git:

git clone https://github.com/jka6502/stratum.git

Or via npm:

npm install stratum-framework

Quickstart

To use Stratum, include the require script first:

	<script src='./stratum/lib/require.js'></script>

To include a component, require it, much as you would using node/CommonJS:

	var someModule = require('someModule');

Remember to leave off the '.js' suffix, this is a module path, not a file reference.

Relative paths can also be used, using the *nix style . (current) and .. (parent) prefixes for the module:

	var other = require('./some/other/module');

To export functionality from a module, assign it to module.exports:

	module.exports = { ... exported object/function ... };

or the global exports variable:

	exports = { ... exported object/function ... };

Requiring modules even works in inline script tags!

	<script>
		var something = require('../library/something');
	</script>

Production

This code is designed to facilitate faster building of applications. It is pretty thoroughly tested and works in a wide variety of environments, but it is not designed to be used in production.

In production environments, you can bake your scripts into a safe, universally compatible format, using Browserify.

Testing

To run the supplied test suite:

npm install
npm test

Testing with CommonJS

Open the CommonJS test suite page to run the tests. Remember to checkout the submodules required first in vendor.

The tests need printStackTrace to allow referencing exports or module.exports after the first load and execution of a module, due to the design of the CommonJS unit tests.

This practise is not recommended. Although possible in the browser, through some arcane trickery, this practise is rather unintuitive - it makes assumptions about a global variable reacting differently depending on the source file it is referenced in. It is better to wrap a module in a function scope (you are doing that anyway, aren't you?), use local variables to maintain internal relationships, then explicitly export any functions or objects required.

Gotchas

The browser is not the ideal environment for the CommonJS require approach, so there are some potential pitfalls with this implementation:

  • Requiring a module that is not yet loaded throws an exception.

This is the fundamental trickery that makes the require function possible in the browser, but it has implications.

Any try{ ... }catch{ ... } in the current stack will catch the dependency abort exception, that is used to halt script execution until dependencies have been resolved.

To avoid this, either filter any exceptions caught, by calling require.filter(exception); in your handler, or avoid catching exceptions from your require calls entirely.

Note: For this reason, two of the tests in the CommonJS module test suite pass in error. They catch the 'dependency abort' exception, rather than the 'file missing' exception they expect. However, those tests would actually pass, if they filtered out that exception.

  • Code preceeding require calls may be executed multiple times

The exception abort/re-execute cycle also means that any code before, or between require calls can be executed multiple times, if the script aborts to load a dependency.

Also, for the same reason, wrapping a require in a try{ ... }finally{ ... } handler may well invoke the finally clause one or more times...

  • Inline scripts are not necessarily sequenced

If a page contains multiple inline scripts, the order they are executed in will be indeterminate (well, determinate, but according to complex rules).

This is because any script containing one or more require calls may, or may not, cause execution of that script to be deferred, depending on whether its dependencies have already been satisfied.

Requiring in one inline script will not ensure dependencies are met before executing subsequent scripts.

So the following pattern should be avoided:

<script>
	var something = require('something');
</script>

<script>
	// Assume the above ensures availability...
	something.confabulate();
</script>
  • Global variables cannot be correctly supplied after module load

The module and exports global variables are guaranteed to be correct during the initial execution of a newly loaded module, but are not guaranteed to point to the same values in closures created within that module.

There is no way to automatically wrap a remotely loaded script in a new scope, which would be needed to implement this cleanly, so the best approach is to only set module.exports or exports in the initial execution of a script, and reference locally cached copies, to use any exported features internally.

  • Avoiding problems

All of the multi-execution issues can be overcome by just avoiding mixing logic with require calls, and requiring any dependencies at the top/start of any file - which is generally good advice anyway.

If you absolutely must mix logic and require calls, be careful to cache state globally to ensure the same path is taken if the logic is executed a second (or nth) time. Basically, any logic preceeding your require calls must be idempotent - or odd things will happen.

For inline scripts, each script tag has its own dependency chain, read it as the dictionary definition, if you require something in an inline script, you must actually require it in that script, don't assume it is available. Just don't add hard coupling between code in distinct inline script tags - its icky.

Global module and exports access issues can be alleviated by including printStackTrace before the require script in the page, but if possible, a simpler approach is to avoid reading from module or exports directly after initialisation.

In summary

GOOD

(function() {

	var something	= require('something'),
		other		= require('some/module/other');

	function Implementation() {}

	Implementation.prototype = {

		other: other

	};

	Implementation.staticMethod = function(param) {
		Implementation.blah(something(param));
	};

	module.exports = Implementation;

})();

BAD

console.log('Echo'); // Executed *at least* once... woo!

var something = require('something'); // Globalised!

try{
	exports = {
		other: require('some/other/module').feature,

		closure: function(param) {
			exports.other(something(param)); // Which 'exports' will this be?
		}
	};
}catch(e) {
	console.log('File missing: ' + e); // File missing: Dependency Abort
	// This will also prevent the 'next' file load being queued...
}

Just... why?

Why not use one of the existing module loaders that tackle browser dependency management, you ask?

Well, basically:

  • I enjoyed writing it
  • I hate the automagic and boilerplate required for mechanisms like AMD
  • I personally find this approach makes for simple, clean, readable code
  • I find that build steps/manual dependency management slow down prototyping, and by doing so, inhibit my creativity and demotivate me
  • The gotchas listed above are easily avoided
  • I've convinced myself that anything that falls foul of the above is, in fact, a code smell anyway :-P