Clean Javascript modules for front-end development
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Tissevert 69a8184f10 Release 0.1.3.0 6 days ago
benchmark Release 0.1.3.0 5 days ago
demo Fix indentation typo 3 years ago
src Release 0.1.3.0 5 days ago
test Release 0.1.3.0 5 days ago
.gitignore First draft defining the structure of the program, needs to implement «imports» and the actual compilation 3 years ago
CHANGELOG.md Release 0.1.3.0 5 days ago
LICENSE Release 0.1.3.0 5 days ago
README.md Release 0.1.3.0 5 days ago
SJW.cabal Release 0.1.3.0 5 days ago
Setup.hs First draft defining the structure of the program, needs to implement «imports» and the actual compilation 3 years ago
guix.scm Release 0.1.3.0 5 days ago

README.md

SJW

The Simple Javascript Wrench is a tool made to "compile" a set of independant Javascript modules into a single "executable" Javascript file which can then be loaded and executed by a browser to animate your web pages. Since no conversion to a different language is performed in the process, "compile" is intended here with the meaning of "assembling together". We will keep using it with this meaning by convenience.

This allows one to write (relatively) clean Javascript and to design libraries to reuse code accross projects. SJW aims at maximal backwards compatibility and requires as little browser extensions as possible. In particular, SJW's modules are not related to ES6' ones. They provide isolation, hiding all the internals of a module from the others, except what the module exposes through the use of a global-scope return statement. The output SJW produces is a single pure-Javascript file wich code runs once the browser has finished loading the page (load event).

To achieve this, it slightly extends the syntax of Javascript to add import statements at the top of the modules to describe their relations. These statements disappear after the files are compiled by SJW and are completely invisible to the web browser eventually loading the script. In this regard, SJW can be thought as "yet another language-specific package manager".

However, SJW is not actually a package manager and only focuses on assembling the modules into one script. To handle packages and dependencies in themselves, it relies instead on guix. In addition to the benefit of not reinventing the proverbial wheel, this brings cool features like reproducibility, controlled environments (making sure your package isn't actually broken but only seems to work because of that file you have locally but forgot to version) and the ability to keep as many versions of the same library as your various projects need while keeping the packages database unduplicated. Finally, it makes it very simple to develop and deploy your own packages without needing to rely on a central repository.

Usage

Command-line arguments

The input expected by SJW is the path to a folder containing the modules of the web application to compile. For instance, the demo project distributed in this repository, which Javascript sources are found in the subfolder src/ can be assembled from the root of this repository with

sjw demo/src/

By default it prints the resulting Javascript code on its standard output.

window.addEventListener('load', function() {
	
});

This can be overridden as usual in compilers by using the -o (long form --output) option to set the path of the file to create.

sjw dome/src/ -o main.js

Since the web application SJW compiles is an executable script, it needs an entry point. By default SJW expects to find a module named Main at the root of the web application (as is the case in the demo project). The name of the main module can be set with the -m (--main-is) option like this:

sjw demo/src/ -m MyCustomMain.js

Libraries don't require any compilation, they are merely copied until being needed in a particular web application. Once they are properly made available to SJW as we will next discuss, they can be included into a project, as with most compilers, with the -I (--include) option:

sjw demo/src -I someAdditionalLib

Libraries

The arguments to the previous -I option can be any path to a folder where you have a SJW library installed. However, it is common to want to keep all your libraries in a single place and refer to them only by their relative path from this package database. By default, SJW will look for a folder named .sjw in your home folder and use it as the package database when it exists.

ls ~/.sjw
# prints: myLib/
sjw -I myLib src # will work

This can be overridden by setting the $SJW_PACKAGE_DB environment variable to the path of the folder where you keep your libraries. In both cases, the package database consists of only one folder where the librarie's subfolders are kept.

export SJW_PACKAGE_DB="somewhere/else"
ls $SJW_PACKAGE_DB
# prints: anotherLib/
sjw -I anotherLib src # will work
sjw -I myLib # no longer works because SJW_PACKAGE_DB hides ~/.sjw

Additionally you may keep your libraries in different, unrelated folders and set $SJW_PATH to the colon-separated (:) list of paths to search.

export SJW_PATH="somewhere/else:${HOME}/.sjw"
sjw -I anotherLib -I myLib src # will work

Note that these act as the roots of separate package databases, they do not point directly to the folders of each individual library. That is, in the previous example, setting SJW_PATH to "somewhere/else/anotherLib:${HOME}/.sjw/myLib" would not have worked. We will call folders like anotherLib and myLib the "name" folders of a library.

About modules and paths

Module names must contain only letters and digits and start with a letter which should by convention be uppercase.

A module defined in file A.js will be available for import from other source files from the symbolic path A (no .js extension). Within a folder named A, a file called B.js is available as the symbolic A.B module. Each subfolder level adds a new component to the module's path with the exact same name as the subfolder .

ls demo/src/Math/
# prints: Fibonacci.js
grep Fibonacci demo/src/Main.js
# prints: import get as nth from Math.Fibonacci;

The folder containing a library and used to include it with -I is not the first component of the modules' paths it defines. Going back to the first myLib example, assuming that this library defines a module MyLib.Utils it will have the following structure:

find ~/.sjw/myLib
# prints:
# ~/.sjw/myLib
# ~/.sjw/myLib/MyLib
# ~/.sjw/myLib/MyLib/Util.sh

By contrast with the "name" folder, we will call the first folder in the modules' path the "modules" folder. In the example right above, myLib is the name folder, and MyLib is its modules folder.

Install

How not to install

Thanks to the way guix works, you don't really need to have SJW installed in your system or user profile to use it. Instead, you need only to package your web application with guix and make sure to add SJW to the native-inputs field, along with the SJW libraries your project uses.

Until SJW makes it to the official guix packages, you'll still need to declare it locally in your file, for instance by wrapping your web application's package within a let block:

(let
  ((SJW (load "path/to/where/you/cloned/this/repos/guix.scm")))
	(package
	  …
		))

Then you can use absolutely any building software you like, and the sjw command will be available in the build's context (custom script, Makefile… SJW's purpose is not to tell you how to build your web application).

And since the guix package for SJW handles the $SJW_PATH variable, you do not even have to worry about your libraries and can simply add them to the native-inputs for them to be available to the -I option. All a library has to do to for this to work is to have its guix package install its name folder to the path lib/SJW in the resulting guix store folder.

Trying it

You may still want to interact directly with the sjw on your favorite shell's command line. It's useful when you're still discovering SJW and want to play with it while writing the building rules of your web application (for instance, a Makefile). You can simply test SJW from this repository with the command:

guix shell -f guix.scm

How to install

Putting SJW in your permanent guix profile

If you want SJW installed "once and for all" to have it available whenever you open a new shell, you can use the regular guix commands. You can use:

guix install -f guix.scm

for instance, or to retain a more declarative approach, use the load function as above to make the package available within a manifest or even an operating system declaration if you need it installed system-wide for some reason.

When guix is not an option

SJW can still be compiled and installed as a regular haskell package with cabal:

$ cabal new-update
$ cabal new-install SJW

In that case, since guix won't be there to handle your SJW libraries either, you have to handle your libraries yourself. Since no action is needed on them before compiling a web application, this can be done simply with the usual shell commands such as ls, cp or rm. Make sure you copy the name folder and not the modules folder to ~/.sjw (or $SJW_PACKAGE_DB). If for instance the myLib above was distributed in a repository with the following structure:

ls path/to/myLib
# prints: src/ README LICENSE CHANGELOG guix.scm
ls path/to/myLib/src
# prints: MyLib/

Then in this case myLib is simply installed by doing:

cp -R path/to/myLib/src ~/.sjw/myLib