Front-end utilities and patterns, plus components for use with Vue.
The package is organised by where the code can run. client needs a browser,
server needs Node, and isomorphic runs in both. Every area is a namespace of
smaller modules, so you can import the whole area or reach straight for the part
you need.
| Area | Runs in | Modules |
|---|---|---|
client |
Browser | animation, date, dom, loaders, printf, series, state, storage, string, utils, vue |
isomorphic |
Both | date, loaders, printf, state, string, utils |
server |
Node | date, loaders, printf, series, state, string, utils |
npm install @arijs/frontendBoth module systems are supported. ESM resolves to the original src/*.mjs
sources; CommonJS resolves to the UMD build in lib/, which is generated by
Babel at publish time.
// ESM
import { string, printf } from '@arijs/frontend/server/index';
// CommonJS
const { string, printf } = require('@arijs/frontend/server/index');Import a whole area, or a single subpath:
import { server } from '@arijs/frontend'; // everything
import { string } from '@arijs/frontend/server/index'; // one areacheckDigitMod11 computes the verifying digits for CPF and CNPJ, including the
alphanumeric CNPJ format:
import { string } from '@arijs/frontend/server/index';
const { getDigitsCPF, getDigitsCNPJ } = string.checkDigitMod11;
getDigitsCPF('350446208'); // '66'
getDigitsCNPJ('031722230001'); // '24'
getDigitsCNPJ('12ABC34501DE'); // '35' — alphanumeric CNPJprintfDict fills a template from two dictionaries: one of values, one of
modifier functions. A placeholder is written { modifier {params} : key }, and
the params are parsed as a query string.
import { printf, state, utils } from '@arijs/frontend/server/index';
const { printfDict } = printf;
const { DictionaryDynamic } = state;
const { numberString: { numberFormat }, queryString: { queryStringify } } = utils;
const store = new DictionaryDynamic({
labelMain: Math.PI * 1e6,
labelSub: { a: 1, b: 2 },
});
const mods = new DictionaryDynamic({
nr: (val, { dlen, dsep, gsep, glen } = { dlen: 2 }) =>
numberFormat(val, dlen, dsep, gsep, glen),
fn: queryStringify,
});
printfDict('{ nr {dlen=3&dsep=,&gsep=.&glen=3} : labelMain }', store, mods);
// '3.141.592,654'
printfDict('{ fn : labelSub }', store, mods);
// 'a=1&b=2'The vcomp/ folder ships plain HTML, CSS and JS component sources — a calendar
and a set of form fields (autocomplete, checkbox, select, select-button,
text and multiline text, date picker). They are shipped as sources rather than
as a built bundle, so you wire them into your own build.
Runnable examples live in examples/, including a Vue slides example under
examples/client/vue/use-slides.
Requires Node 22 or newer, as recorded in engines and .nvmrc.
npm install
npm test # builds first, then runs the ESM and CommonJS suites
npm run build # Babel: src/*.mjs -> lib/*.js (UMD)
npm run testSeries # the series demo: random input, prints, asserts nothing
npm run testClient # serve the repo and open the browser testsnpm test runs the same suite twice, once as ES modules against src/ and once
as CommonJS against lib/. That is why it builds first — the CommonJS half
imports the compiled output, and would fail on a clean checkout otherwise.
Every check in the suite asserts, and a mismatch exits non-zero. testSeries is
deliberately not part of it: it drives the series functions with random input
and prints the result for a human to look at. The deterministic half of that
work, test/*/series/parity.mjs, pins the same functions to frozen expected
values and does run under npm test.
CI runs npm ci && npm test on Node 22 and 24, on both Linux and Windows.
Windows is in the matrix on purpose — the problems this project has hit there
do not reproduce on Linux.
The build is driven by babel.config.mjs, which walks src/ with
dir-files to derive a UMD global name for
every module before Babel runs.
npm run build calls the Babel CLI by path rather than by name
(node ./node_modules/@babel/cli/bin/babel.js) because some Node version
managers on Windows fail to resolve binaries from node_modules/.bin inside
npm scripts. If you hit the same problem with another tool, call it the same way.
Publishing runs from GitHub Actions using npm's trusted publishing, so there is no npm token stored anywhere: Actions authenticates over OIDC with a short-lived credential and npm attaches provenance to the release. This works with 2FA on the account, which the older publish tokens are losing the ability to do.
Setting it up is a one-time step on npmjs.com, under the package's Trusted
Publishers: add a GitHub Actions publisher for arijs / front-end /
publish.yml.
To cut a release:
npm version patch # or minor — writes package.json and tags
git push --follow-tagsThen publish a GitHub Release on that tag. The workflow refuses to continue if
the tag disagrees with package.json, or if the version is already on npm, so a
release either matches what gets published or does not happen.
Run workflow on the Publish action does a dry run by default; untick it to
publish without cutting a Release. If a run fails, fix the problem and start a
fresh run — re-running a failed job replays the old commit.
The build depends on
@arijs/babel-plugin-module-resolver
rather than the upstream babel-plugin-module-resolver. Upstream's 5.0.x line
pulls in glob, and with it the minimatch → brace-expansion chain carrying
GHSA-mh99-v99m-4gvg, which
no downstream project can patch: the only remedy npm offers is a forced
downgrade of the plugin across a major version. The fork builds from upstream's
modernized tooling, which drops glob entirely, so npm audit here reports
nothing. Plugin behaviour is identical — the compiled output in lib/ is byte
for byte the same either way.
Switch back to the upstream package once it releases a version without glob.
MIT — see LICENSE.