GitHunt
OK

Semantically packaged standard solutions for everyday frontend tasks and syntax streamlining for those ugly dark corners of JavaScript. Unit-tested and with browser examples.

annex

annex

by Sebastian Schlapkohl

Unit-tested and semantically packaged standard solutions for everyday frontend tasks and syntax streamlining for
those ugly darks corners of JS.

NPM - no peer dependencies
JavaScript - ES6+
JavaScript - Module
JavaScript - Legacy ES5 Monolith
Ava - Unit Tested
Examples - Interactive Demonstrations
JSDOC - Fully Documented
GitHub Pages - Online Documentation & Examples
Docker - Docker Compose Dev Setup With Gulp and Rollup

A Word of Caution

This package has reached beta status. Everything included is tested with unit tests and/or browser examples. And the
contents include everything I aimed for in the first version. Although everything is finished from a technical
perspective, this package is not yet battle-proven.

The beta should be fine to use (cautiously), but I will delay the bump to version 1.0.0 stable until after I've used
this in a real-world project.

What is This?

After more than 15 years of web development I have gotten quite opinionated about JavaScript, its way of doing things,
the dark places of this language, what it is lacking and how I like to do things instead.

This package is a collection of helpers, solutions and best practices that have amassed over the years, providing
quality of life solutions, best practices (in my opinion) and additions, that I can't and don't want to live without
(especially some Python stuff).

Everything included here is strictly frontend-oriented and not meant for node or window-less or dom-less
environments. Think of it as lodash's little frontend brother.

Every single solution/helper/function is importable by itself using ES6 imports (and maybe a bundler),
documented with jsdoc, tested with Ava (unit tests can be found in test),
used in a live browser example (in case unit tests are not helpful; examples can be found in examples) and
semantically structured into modules concerning topics and aspects of development
(such as logging or strings).

So, the TL;DR is: annex is a battle-proven, tested pool of frontend js tools to solve reappearing tasks quickly and make
JavaScript more bearable by streamlining syntactical nonsense and providing functions other languages provide naturally.

Some of the Batteries Included

  • event helpers including a complete event system
  • variable normalization and type evaluation
  • DOM handling with element creation and manipulation
  • streamlined standard requests (basic requests & special versions for html/css/js/json)
  • url and navigation helpers
  • better logging
  • better randomization for numbers and ids
  • string generation and conversion tools like formatting and slugification
  • array tools like actually usable removal functionality based on values and flexible indices
  • dates, that actually make sense and offer helpful functions
  • browser capability checks and context evaluation
  • viewport information and functionality
  • interaction solutions like obfuscated mailto and tel links
  • better (& more precise) timers
  • polling
  • cookie handling
  • image and webfont availability callbacks
  • form helpers for data

Is This Documented Somewhere?

Yes, that as well.

Visit the documentation on GitHub or open
/docs/documentation/index.html locally after checking out the repo.

Is This Tested in Any Way?

Yes, it actually is!

The algorithmic core is tested via Ava and all tests are to be found in test.

Many features are not really well suited for unit testing but require a real browser as a context.
For all those cases I built example pages (to be found under examples, just opening index.hml from the file system
should work, at least for the es5 version). In these example pages you can browse all topics not covered by unit tests
and play around with the functionality.

How Can I Run the Examples?

Either view the examples on GitHub or open
/docs/examples/index.html locally after checking out the repo.

How Do I Install This?

Besides just downloading the zip file and dropping the package in your project (which I would not recommend doing), you
may easily use NPM or Yarn.

Currently, I'm publishing to Github packages and not the central NPM registry. If you want to directly install the
package, not using the repository URL, , you'll have to tell NPM/Yarn, that @oktarintentakel can be found at GitHub
packages and not at the central NPM registry and add an access token to use for installing. To do this, add or edit a
.npmrc file (either globally in your home folder or next to the package.json to your project) and add
@oktarintentakel:registry=https://npm.pkg.github.com to the file (following GitHub's
documentation).
After this, the defined namespace is installed from there automatically. Additionally, we also need a personal access
token by adding the line //npm.pkg.github.com/:_authToken=TOKEN (following GitHub's
documentation).

Hint: I am aware, that this is rather cumbersome currently, and therefore I currently suggest using the repository
URL, but I implemented the workflow anyway, awaiting an easier workflow in the future.

NPM

npm install @oktarintentakel/annex

or with a version

npm install @oktarintentakel/annex@X.X.X

or via GitHub repository

npm install oktarintentakel/annex

or via GitHub repository using a tag

npm install oktarintentakel/annex#vX.X.X

Yarn

yarn add @oktarintentakel/annex

or with a version

yarn add @oktarintentakel/annex@X.X.X

or via GitHub repository

yarn add oktarintentakel/annex

or via GitHub repository using a tag

yarn add oktarintentakel/annex#vX.X.X

Using an Alias Location

In many cases (especially when installing directly from Github repository) it makes sense to define an install alias,
to manually define a folder inside node_modules to install to.

Using NPM

npm install my-alias-location@:npm@oktarintentakel/annex@X.X.X

or using NPM with GitHub repository

npm install my-alias-location@oktarintentakel/annex#vX.X.X

or using Yarn

yarn add my-alias-location@:npm@oktarintentakel/annex@X.X.X

or using Yarn with GitHub repository

yarn add my-alias-location@oktarintentakel/annex#vX.X.X

or in package.json

{
  "dependencies": {
      "my-alias-location" : "npm:@oktarintentakel/annex@X.X.X"
  }
}

or with Github repository

{
  "dependencies": {
      "my-alias-location" : "oktarintentakel/annex#vX.X.X"
  }
}

@client Package Separation

It may be a good idea, to generally split node and client packages up. Why? Client packages are delivered directly to
the client and are executed and interpreted on the user's machine. So, these packages have a different set of rules
applying to them. For example: it is not really clever to give client packages an approximate version, like a normal
node dependency using ^ oder ~, because every minor change in a client package may affect all receiving clients
after a reevaluation of npm versions. This is a nightmare, because this means, that, at undetermined points in time, all
cross-browser testing you did may be invalid and since you are not seeing everything while developing all the time, your
app may fall apart on certain devices, without you knowing.

Another problem is sharing of packages between dev/build/hosting and frontend/client. Let's say both use lodash or q
promises: both have to agree on the exact same version, that should not be changed frequently because of the
aforementioned problems. That is very unpractical for both usages and each should be able to use the version fitting its
purpose, since they are used for different things on very different machines, even if it is the same package under the
hood.

So I generally propose separating all npm packages, that are delivered to the client directly in any way into a specific
@client package in node_modules using fixed versioning for these (I originally got the idea when I transitioned)
from bower to npm, reading the bower team's ideas about
this.

So, I propose to generally use an alias location for client packages, such as this
(see previous point, for all/other options):

{
  "dependencies": {
      "@client/annex" : "oktarintentakel/annex#vX.X.X"
  }
}

How Do I Include and Use This?

After installation, just include single functions/symbols from the semantic packages like this:

import {log} from 'annex/source/logging';

It might be a good idea, to set a path alias in your bundler, to skip the source path.

In Webpack a path alias would look like this (see documentation):

{
  resolve: {
    alias: {
      annex : path.resolve(__dirname, 'node_modules/@client/annex/source/')
    }
  }
}

Which would allow you an import like this:
import {log} from 'annex/logging';

If you want to serve packages without bundling, as they are, you can do so, by serving them as type module scripts.
For this purpose I included a dist dir, containing minified, ES6 scripts. Use these, you would do:

<script type="module" src="annex/dist/logging.js"></script>

In this case, make sure all dist file are publicly available and are in the same dir, so imports can work.

Of course, you can also import dist files via a bundler, but in that case you would lose the capability to jump to
readable source in your IDE and you would also lose all JSDOC strings.

Be aware, that all module source code is written in fairly up-to-date ES6, disregarding legacy concerns. So, whether
you are bundling the modules or using them verbatim, keep the browser support in mind and make sure to set up
transpilation during bundling, matching your browser matrix, if necessary. All features I'm using are transpilable
with Babel and polyfillable with core-js
(have a look at the gulpfile for a working webpack setup). Anything additionally necessary, I've included as a
polyfill function in the "polyfills" module (stuff like CustomEvents, which are not included in core-js).

If you need to use ES5, I also included a monolithic ES5 version in dist as a UMD. So you can easily load the script
with

<script src="public/annex/dist/es5-monolith.js"></script>

After which there should be window.annex, which has each package as a key, so for example

window.annex.logging.log('test')

should write something to the console.

ES5 is compiled with a target >= IE11.

Versioning

I'm using semver, so majors are definitely breaking, minors may be breaking and bugfixes should never break anything.

Is This Any Good, Why Should I Use This?

Well, since this package is not monolithic: Why not?

If anything catches your eye, just use this one thing and maybe you find other helpful things as well. Since ES6 we have
the luxurious situation of being able to pick and choose, without immediately bloating the bundle. And since annex has
no peer dependencies, you are not even bloating your node_modules.

On the other hand, you are also completely free to just scan the source and copy whatever you need, if you do not want
to add the dependency. You are completely free to just use the repo as reference as well!

OktarinTentakel/annex | GitHunt