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.

    Install

    npm i monic

    DownloadsWeekly Downloads

    283

    Version

    2.6.1

    License

    MIT

    Unpacked Size

    88.6 kB

    Total Files

    80

    Last publish

    Collaborators

    • xdan
    • kobezzza
    • exactlynosense
    • bonkalol
    • dmitrybrovka