The AKE-less General Purpose Build System with JavaScript DSL for Node.js platform.

Overview

JUKE build

The AKE-less General Purpose Build System with JavaScript DSL for Node.js platform. Inspired by NUKE.

This project is reaching a mature stage, although a lot of features are still in development. Take a look at our roadmap.

Project goals

Simplicity

Everything should be as simple as possible in all technical aspects. Builds are written in pure JavaScript and provide only the bare minimum for getting the job done. TypeScript is supported, but not required.

Currently it packs the following:

  • A robust dependency model between targets
  • File timestamp checker for inputs/outputs
  • Built-in CLI argument (and environment) parser with a strongly typed Parameter API.
  • Asynchronous execution of external programs via Juke.exec()

You can bring your own tools into the mix, e.g. the glorious google/zx, or native JavaScript tooling, e.g. webpack, with no restrictions imposed by our build framework.

Minimal dependencies

Build system should be native to JavaScript and Node.js, and require nothing but the Node.js executable, i.e. no dependency on npm/yarn or TypeScript compiler.

Strongly typed

Strongly typed API with fully instrospectible build scripts that are written in plain JavaScript, which allows us to parse the build script and generate definition files for tighter integration with other tooling (e.g. CI).

How to build

./build.mjs

General usage

Copy contents of the dist folder anywhere you want to use Juke (and rename it to juke), then create a javascript file for the build script with the following contents (pick one):

ES modules variant (recommended):

// build.mjs
import Juke from './juke/index.js';

Juke.setup({ file: import.meta.url });

// TODO: Declare targets here
export const MyTarget = new Juke.Target({
  // ...
});

CommonJS modules variant:

// build.cjs
const Juke = require('./juke');

Juke.setup({ file: __filename });

// TODO: Declare targets here
const MyTarget = new Juke.Target({
  // ...
});

// TODO: Export targets here
module.exports = {
  MyTarget,
};

We recommend using an ES module for the build script, because it allows exporting targets/parameters with a much shorter syntax.

Create targets

Target is a simple container for your build script that defines how it should be executed in relation to other targets. It may have dependencies on other targets, and may have various other conditions for executing the target.

export const Target = new Juke.Target({
  executes: async () => {
    console.log('Hello, world!');
  },
});

Notice: When referencing an unexported target, it must have a name property, which is used in CLI for specifying (and displaying) the target. If you forget to specify a name, it will be displayed as undefined during execution.

const Target = new Juke.Target({
  name: 'foo',
  // ...
});

Normally, name is derived from the name of the exported variable (minus the Target suffix).

Declare dependencies

export const Target = new Juke.Target({
  dependsOn: [OtherTarget],
  // ...
});

Set a default target

When no target is provided via CLI, Juke will execute the default target.

export const Target = new Juke.Target({
  // ...
});

export default Target;

Declare file inputs and outputs

If your target consumes and creates files, you can declare them on the target, so it would check whether it actually needs to rebuild.

If any input file is newer than the output file, target will be rebuilt, and skipped otherwise.

Supports globs.

export const Target = new Juke.Target({
  inputs: ['package.json', 'src/**/*.js'],
  outputs: ['dest/bundle.js'],
  // ...
});

Create parameters

Available parameter types are: string, number and boolean. You may add a [] suffix to the type to make it an array.

To provide a parameter via CLI, you can either specify it by name (e.g. --name), or its alias (e.g. -N). If parameter is not a boolean type, value will be expected, which you can provide via --name=value or -Nvalue.

To fetch the parameter's value, you can use the get helper, which is exposed on the target's context.

export const FileParameter = new Juke.Parameter({
  type: 'string[]',
  alias: 'f',
});

export const Target = new Juke.Target({
  executes: async ({ get }) => {
    const files = get(FileParameter);
    console.log('Parameter values:', files);
  },
  // ...
});

You can also dynamically set up target dependencies using binary expressions:

export const Target = new Juke.Target({
  dependsOn: ({ get }) => [
    get(FileParameter).includes('foo') && FooTarget,
  ],
  // ...
});

If you simply need access to arguments passed to the target, you can use the args context variable. Note, that you can only pass arguments that begin with - or --, because all other arguments are normally treated as targets to build.

export const Target = new Juke.Target({
  executes: async ({ args }) => {
    console.log('Passed arguments:', args);
  },
});

Context is available on these properties (when using a function syntax):

  • dependsOn
  • inputs
  • outputs
  • onlyWhen
  • executes

Notice: When referencing an unexported parameter, it must have a name, which is used in CLI for specifying the parameter.

const FileParameter = new Juke.Parameter({
  name: 'file',
});

Normally, name is derived from the name of the exported variable (minus the Parameter suffix, if it exists).

Conditionally run targets

If you need more control over when the target builds, you can provide a custom condition using onlyWhen. Target will build only when the condition is true.

Function can be async if it has to be, target will wait for all promises to resolve.

export const Target = new Juke.Target({
  onlyWhen: ({ get }) => get(BuildModeParameter) === BUILD_ALL,
  // ...
});

Execute an external program

Juke provides a handy Juke.exec helper.

export const Target = new Juke.Target({
  executes: async () => {
    await Juke.exec('yarn', ['install']);
  },
});

On program completion, you get its stdout and stderr. In case, when you need to run a program just to parse its output, you can set a silent option to stop it from piping its output to stdio.

const { stdout, stderr, combined } = await Juke.exec(command, ...args, {
  silent: true,
});

It throws by default if program has exited with a non-zero exit code (or was killed by a non-EXIT signal). If uncatched, error propagates through Juke and puts dependent targets into a failed state.

You can disable this behavior via:

const { code } = Juke.exec(command, ...args, {
  throw: false,
});

You can also simulate an exit code by rethrowing it yourself.

throw new Juke.ExitCode(1);

Run the build

You can build targets by specifying their names via CLI.

Every flag that you specify via CLI is transformed into parameters, and their names are canonically written in --kebab-case.

./build.js [globalFlags] task-1 [flagsLocalToTask1] task-2 [flagsLocalToTask2]

To specify an array of parameters, you can simply specify the same flag multiple times:

./build.js task-1 --foo=A --foo=B

You can also specify parameters via the environment. Environment variable names must be written in CONSTANT_CASE. If this parameter is an array, you can use a comma to separate the values.

FOO=A,B ./build.js task-1

Single target mode

You can specify that Juke CLI should only accept a single target to run.

Juke.setup({
  file: import.meta.url,
  singleTarget: true,
});

This mode means that all arguments after the first task name are considered as its arguments, regardless of whether they are flags or not.

./build.js [globalFlags] task [argsLocalToTask]

Various helpers

Juke.chdir(directory: string, relativeTo?: string)

Changes directory relative to another file or directory. Most commonly used as following:

Juke.chdir('..', import.meta.url);

Juke.rm(path: string, options = {})

Removes files and directories (synchronously). Supports a small subset of Node 16 options for fs.rmSync. Supports globs.

Juke.rm('**/node_modules', { recursive: true });

Juke.glob(pattern: string)

Unix style pathname pattern expansion.

Performs a search matching a specified pattern according to the rules of the glob npm package. Path can be either absolute or relative, and can contain shell-style wildcards. Broken symlinks are included in the results (as in the shell). Whether or not the results are sorted depends on the file system.

Returns a possibly empty list of file paths.

Examples

Our own build pipeline

/tg/station13 build pipeline

Screenshot image

License

Source code is available under the MIT license.

The Authors retain all copyright to their respective work here submitted.

You might also like...

A module containing utilities for osu!droid and osu! in general.

About This module is published for my own convenience so that I can use it across multiple projects of mine without having to manually transfer files,

Dec 23, 2022

NewsStation is a news app which can be used to grab daily news bites. If you are interested in news whether politics, business, entertainment, general, health, science, sports and technology news NewsStation is for you!

NewsStation is a news app which can be used to grab daily news bites. If you are interested in news whether politics, business, entertainment, general, health, science, sports and technology news NewsStation is for you!

This is a NewsStation WebApp Project Using News API NewsStation is a news app which can be used to grab daily news bites. If you are interested in new

Feb 7, 2022

An online multiplayer IO-like game that tests your general knowledge.

An online multiplayer IO-like game that tests your general knowledge.

Source code for insort.app Insort is a game where you sort a deck of cards by some attribute. It's main components are React, Socket.io, Express and P

Dec 10, 2022

PDF.js compiled for node-less, serverless enviroments.

Pdf.mjs PDF.js custom-compiled for nodeless, serverless enviroments, like Deno Deploy and Cloudflare Workers. Rocking in under 700kb uncompressed. Usa

Apr 16, 2022

GetOsLocalesCrossPlatform - A cross platform alternative to get locales used on the platform. Works on Node, Electron, NW.js and Browsers

getOsLocalesCrossPlatform A cross platform alternative to get locales used on the platform. Works on Node, Electron, NW.js and Browsers This script is

Jan 2, 2022

Leader Board is a simple project based on JavaScript programing language. The purpose of this project is to work with APIs and ASYNC & AWAIT methods. I have used vanilla JavaScript with web pack to implement this project

Leader Board is a simple project based on JavaScript programing language. The purpose of this project is to work with APIs and ASYNC & AWAIT methods. I have used vanilla JavaScript with web pack to implement this project

Leader Board - JavaScript Project Table of contents Overview The challenge Screenshot Links Project Setup commands My process Built with What I learne

Oct 21, 2022

A dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more

Glide.js is a dependency-free JavaScript ES6 slider and carousel. It’s lightweight, flexible and fast. Designed to slide. No less, no more What can co

Jan 3, 2023

EggyJS is a Javascript micro Library for simple, lightweight toast popups focused on being dependency-less, lightweight, quick and efficient.

EggyJS EggyJS is a Javascript micro Library for simple, lightweight toast popups. The goal of this library was to create something that meets the foll

Jan 8, 2023
Releases(v0.9.0)
  • v0.9.0(Aug 20, 2021)

    This release is planned to be reverted, because changes to Juke.exec have made build scripts randomly stall on Windows. Additionally, stdio passthrough also makes impossible to prefix the output with the target name (which is something we want to add).

    Changed

    • Juke.exec now spawns processes with inherited stdio by default.
      • This means that stdout/stderr will not be available in the return value by default, but can be changed via captureOutput: true.
      • This API might be changed in the future.
    Source code(tar.gz)
    Source code(zip)
  • v0.8.1(Aug 12, 2021)

  • v0.8.0(Aug 12, 2021)

    Added

    • new Juke.Target() and new Juke.Parameter() constructors, which work the same way as Juke.createTarget() and Juke.createParameter() respectively. Constructors are more direct than creator functions, so using them is preferred.
    • Juke.chdir() was added as an easy way to change directories relative to import.meta.url.
    • Juke.glob() is now generally available for unix-style pathname pattern expansion.
    • Juke.rm() was added as a common file removal tool. It has a subset of Node 16 API but is compatible with Node 12, and has an built-in support for globs.
    • Juke.setup() accepts a singleTarget mode setting, which reconfigures CLI to only accept one target and treat all the remaining arguments (not only flags) as this target's arguments.

    Changed

    • Compiled bundle was changed back to index.js from index.cjs, because the latter was not compatible with the default Node.js resolver and TypeScript could not import type definitions properly.
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Jul 23, 2021)

  • v0.6.3(Jul 23, 2021)

  • v0.6.2(Jul 23, 2021)

    BREAKING CHANGES

    Juke Build now supports ES modules as build scripts, but this also means that the whole thing was redesigned to support named exports. When target/parameter is exported, you may omit the name property completely, and it will be automatically picked up from the name of the exported variable.

    Targets are no longer automatically registered, and you must export them via export keyword in ES modules, or module.exports in CommonJS.

    You must now call Juke.setup() to point the executor to the build script that you want to parse/run.

    // ES modules variant
    Juke.setup({ file: import.meta.url });
    // CommonJS variant
    Juke.setup({ file: __filename });
    

    Other setup options were removed. Default target is specified by export default syntax.

    Source code(tar.gz)
    Source code(zip)
    index.cjs(154.30 KB)
    index.d.ts(7.78 KB)
  • v0.5.1(Jul 4, 2021)

    v0.5.0 was skipped because it was built on an out-of-date base.

    Added

    • Juke.exec now returns useful data on completion, like code, stdout, stderr and combined (which is stdout + stderr).
    • Juke.exec accepts two new options as the last argument:
      • silent - If true, disables piping of its output to stdout and stderr.
      • throw - If false, it won't throw an exception on a non-zero exit code. Useful if you want to analyze the exit code via it's code variable it returns.
    • Juke.ExitCode constructor is exposed in case if you want to throw a custom exit code in the executes function and fail the target.
      • It is thrown like this: throw new Juke.ExitCode(1)

    Changed

    With the help of dts-bundle-generator, Juke build is now only two files:

    • dist/index.js
    • dist/index.d.ts
    Source code(tar.gz)
    Source code(zip)
    index.d.ts(6.95 KB)
    index.js(197.35 KB)
  • v0.4.0(Jun 24, 2021)

    Added

    • dependsOn, inputs, outputs, and onlyWhen fields now all accept a function with an execution context (a function of format ({ get }) => ...), and all of them can be async. This means that you can easily parametrize every part of the build via CLI parameters.
    • Async dependsOn will block initialization of the task runner due to the way dependency resolution is currently implemented. Prefer sync functions over async, otherwise use carefully.

    Removed

    • Removed the ability to pass arrays of functions to executes and onlyWhen, because nobody will realistically use it, and it increases Juke's code complexity.
    Source code(tar.gz)
    Source code(zip)
    juke.zip(47.14 KB)
Owner
Aleksej Komarov
Javascript expert. Bash ninja. Lead developer of TGUI at /tg/station 13.
Aleksej Komarov
A general purpose, real-time visualization library.

Epoch By Ryan Sandor Richards Epoch is a general purpose charting library for application developers and visualization designers. It focuses on two di

Epoch 5k Dec 30, 2022
A jQuery-free general purpose library for building credit card forms, validating inputs and formatting numbers.

A jQuery-free general purpose library for building credit card forms, validating inputs and formatting numbers.

Jesse Pollak 528 Dec 30, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
A simple query builder, it will helps to develop DSL query for Elasticsearch

Elasticsearch Dynamic Query Builder A simple query builder, it will helps to develop DSL query for elasticsearch Installation You can start it from np

Hashemi Rafsan 4 Nov 20, 2022
The Frontend of Escobar's Inventory Management System, Employee Management System, Ordering System, and Income & Expense System

Usage Create an App # with npx $ npx create-nextron-app my-app --example with-javascript # with yarn $ yarn create nextron-app my-app --example with-

Viver Bungag 4 Jan 2, 2023
Agetos is a web-platform messaging service founded in 2022. It has no purpose. Just like the other applications.

Start with a simple idea ?? Turn it into an awesome app ?? About Agetos is a web-platform messaging service founded in 2022. It has no purpose. Just l

flash 4 Aug 4, 2022
It is a solo Project and In this repo I try to build a E-Commerce full-stack website with MERN stack technologies. For Practice purpose.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Alok Kumar 5 Aug 3, 2022