monic
TypeScript icon, indicating that this package has built-in type declarations

2.6.1 • Public • Published

Monic

Monic is a JavaScript file builder (fork of Jossy) to one or several files. When used properly, Monic allows not only easy to build modules but also easy to rebuild when changing principles of the build.

Russian documentation

NPM version Build Status Coverage Status NPM dependencies NPM devDependencies

Install

npm install monic --global

Plugins

Using CLI

monic [options] [file ...]

options

-h, --help
-V, --version
-f, --file [src]             path to the source file (meta information)
-o, --output [src]           path to the output file
--eol [char]                 symbol that will be used as EOL
--flags [list]               list of flags separated by commas
--labels [list]              list of labels separated by commas
-s, --source-maps [val]      [true|false|inline]
--source-map-file [src]      path to the generated source map
--source-root [path]         root for all URLs inside the generated source map

Addition

The build result will be output to stdout. To save it to a file, you need to use your shell, e.g.,

monic file.js --flags ie --labels escapeHTML > _file.js

Or you can use --output

monic file.js --flags ie --labels escapeHTML -o _file.js

Examples

Builds a file and outputs to stdout

monic myFile.js

Builds a file and saves the result to a new file

monic myFile.js > myNewFile.js

Builds a file and saves the result to a new file with SourceMap

# SourceMap will be saved as "myFile-compiled.map.js"
monic myFile.js -s -o myFile-compiled.js

# SourceMap will be saved as "myFile-map.js"
monic myFile.js -s -o myFile-compiled.js --source-map myFile-map.js

# SourceMap will be saved into "myFile-compiled.js"
monic myFile.js -s inline -o myFile-compiled.js

Builds a text and outputs to stdout

monic '//#include foo/*.js' -f myFile.js

Over stdio

echo '//#include foo/*.js' | monic -f myFile.js

Using as a library

var monic = require('monic');
monic.compile(
  'myFile.js',

  {
    // A path to the working directory
    // (optional, by default `module.parent`)
    cwd: 'myDir/',

    // A symbol that will be used as EOL (optional, by default `\n`)
    eol: '\r\n',

    // A map of Monic labels (optional)
    labels: {
      escapeHTML: true
    },

    // A map of Monic flags (optional).
    // The flags can have different values, for instance
    flags: {
      ie: true,
      ieVersions: [7, 8, 9],
      needInclude({flags}) {
        return flags.ie && flags.ieVersions.includes(7);
      }
    },

    // If is `true`, then the generated files will be saved
    // (optional, by default false)
    saveFiles: true,

    // A path to the generated file (optional)
    file: 'myFiled-compiled.js',

    // If is `true` or `'inline'`, then will be generated a source map
    // (optional, by default `false`)
    sourceMaps: true,

    // A base source map object for the output source map
    // (optional)
    inputSourceMap: null,

    // A path to the generated source map (optional, by default `${file}.map`)
    sourceMapFile: 'myFiled.map',

    // A root for all URL-s within the generated source map (optional)
    sourceRoot: 'myDir/'
  },

  (err, result, {map, decl, url, isExternal}) => {
    if (err) {
      throw err;
    }

    console.log(result);
  }
);

Using Promise API

var monic = require('monic');
monic.compile('myFile.js')
  .then(({result, sourceMap: {map, decl, url, isExternal}}) => {
    // ...
  })

  .catch((err) => {
    // ...
  });

Building from a string

var monic = require('monic');
monic.compile(
  'myFile.js',

  {
    content: '...'
  },

  (err, result) => {
    // ...
  }
);

Using replacers

var monic = require('monic');
monic.compile(
  'myFile.js',

  {
    replacers: [
      // Replaces all require expressions to `#include` directives
      // ("this" refers to the compiler' instance)
      (text, file) => text.replace(/^\s*require\('(.*?)'\);/gm, '//#include $1')
    ]
  },

  (err, result) => {
    // ...
  }
);

The syntax and capabilities

Including files

To include an external file into the current need to use the #include directive.

//#include file.js

A file path is relative to the current file's location, but you can also use an absolute path. Within the path can also be used templates.

//#include lib/*.js

Technically, the line with the directive is simply replaced with a text of the attached file. However, if the specified file is already included in the current module, it won't be included again. For example:

f1.js

alert(1);

f2.js

//#include f1.js
alert(2);

f3.js

//#include f1.js
//#include f2.js

Build f3.js

monic f3.js > result.js

result.js

alert(1);
alert(2);

Excluding files

The #without indicates Monic exclude from the build all the files that are used in the specified (including specified, of course).

An example

Our project has several dozen widgets. The code for each widget is inside a separate file. Each widget indicated its dependence on the #include. Some widgets are used on most pages, and it is logical to place their code in a separate file, for example, common.js. Select frequently-used widgets, create the file common.js and write back:

//#include widget1.js
//#include widget2.js
//#include widget3.js

The widget is used on one of the pages, large enough not to include it in the common.js, let's call it big widget. In the file big-widget.js, its dependencies, many of those already in the common.js. If we build the big-widget.js, we will get a lot of duplicated code. Therefore, next to the common.js, create a file feature.js with the code:

//#without common.js
//#include big-widget.js

Now the code in the common.js misses the feature.js. Most importantly, don't forget to include to a page not only the feature.js, but the common.js too.

The path format in the directive is the same as in the #include.

Conditional build

In the build process can be defined special flags that determine whether or not to include selected code sections.

//#set flag

//#if flag
alert('flag');
//#endif

//#unset flag

//#unless flag
alert('not flag');
//#endunless

The flags can take values.

//#set ie 7

//#if ie = 7
alert('OMG!');
//#endif

//#unless ie = 7
alert('Cool!');
//#endunless

More examples

Different compare operators within the #if directives
//#set ie 7

//#if ie = 7
alert('ie = 7');
//#endif

//#if ie != 8
alert('ie != 8');
//#endif

//#if ie > 6
alert('ie > 6');
//#endif

//#if ie >= 7
alert('ie >= 7');
//#endif

//#if ie < 8
alert('ie < 8');
//#endif

//#if ie <= 7
alert('ie <= 7');
//#endif
Checking a value from a dictionary or array
//#set ie [7, 8]
//#if ie has 7
alert('ie = 7');
//#endif

// It's possible to add data to the existing array
//#set ie. 9

//#if ie has 9
alert('ie = 7');
//#endif

// It's possible to add or create nested fields within a dictionaries
//#set runtime.offlineMode

//#if runtime has offlineMode
alert('Offline mode enabled!');
//#endif
Testing a regular expression
//#set ie /[7-9]/

//#if ie like 7
alert('ie = 7');
//#endif
Invoking a functional flag
//#set ieVersions [7, 8, 9]
//#set ie function (o) { return o.flags.ieVersions.includes(o.value); }

//#if ie call 7
alert('ie = 7');
//#endif

//#if 7 callRight ie
alert('ie = 7');
//#endif

Flags

All the flags are declared globally. To set it in your code, you should use the directives #set and #unset, and also, you can specify it when you run Monic. For example:

file.js

//#if ie
alert('IE only');
//#endif

common.js

//#include file.js

common-ie.js

//#set ie
//#include file.js

Similarly, you can create a debug flag and write debugging code within //#if debug ... //#endif, that code never gets to the production server.

Using flags inside a path pattern

Flags that have been specified as build parameters or declared in the file' global scope can be used inside #include and #without with using a special syntax.

//#set lang en
//#include lang/${lang}.json

If the flag is a function, it will be executed. The result will be inserted into the template. If the flag doesn't exist, then will be inserted an empty string.

Including chunks of files

This functionality is handy to develop libraries and frameworks. For example, there is a file String.js in your library containing several dozens of functions for working with strings. Isolate each function in a separate file somehow wrong, but attach a few hundred lines of code for only one function is also not desirable. To solve this problem, Monic can mark the file String.js on specific areas. Names in areas can be arbitrary, but it is better to coincide with the names of functions.

var String = {};

//#label truncate
String.truncate = function () {

};
//#endlabel truncate

//#label escapeHTML
String.escapeHTML = function () {

};
//#endlabel escapeHTML

Now, if we only need the escapeHTML, when you include a file String.js write

//#include String.js::escapeHTML

As a result, the build will get only

var String = {};

String.escapeHTML = function () {

};

If you want to include several areas, you need to write something like this

//#include String.js::trim::truncate

If you want to include everything except the marked areas (for example, we need only String namespace), then

//#include String.js::

If some area needed another area of the current file, use the #include without specifying a file.

//#label truncate
//#include ::trim
String.truncate = function () {};
//#endlabel truncate

Please note that the marked-thus the area of the file inbuilt code can change the order between it and may receive another code.

For instance:

//#include String.js::escapeHTML
alert(1);
//#include String.js::truncate

After the build will receive

var String = {};

String.escapeHTML = function () {

};

alert(1);

String.truncate = function () {

};

Therefore, don't use #label inside functions and expressions because it can break your JavaScript.

In addition, #without also watching for these areas. So, for example, escapeHTML can get into common.js and truncate into feature.js.

License

The MIT License.

Package Sidebar

Install

npm i monic

Weekly Downloads

82

Version

2.6.1

License

MIT

Unpacked Size

88.6 kB

Total Files

80

Last publish

Collaborators

  • kobezzza
  • bonkalol
  • dmitrybrovka
  • gretzkiy