jscc
Featuring some of the C preprocessor characteristics through special, configurable comments, jscc can be used in any type of files to build multiple versions of your software from the same code base.
With jscc, you have:
- Conditional inclusion/exclusion of blocks, based on compile-time variables*
- Compile-time variables with all the power of JavaScript expressions
- Replacement of variables in the sources, by its value at compile-time
- Sourcemap support, useful for JavaScript sources.
- TypeScript v3 definitions
* This feature allows you the conditional declaration of ES6 imports (See the example).
jscc is derived on jspreproc, the tiny source file preprocessor in JavaScript, enhanced with sourcemap support but without the file importer nor the removal of comments (rollup with rollup-plugin-cleanup does it better).
jscc works in NodeJS 6 or later, with minimal dependencies and footprint. It was designed to operate on small to medium pieces of code (like most nowadays) and, since the whole process is done in memory, it is really fast.
jscc is not a minifier tool, but it does well what it does...
Install
Use the instructions of the plugin for your toolchain:
or install the jscc package from npm if you need direct access to its API:
npm i jscc -D
Direct Usage
const jscc = require('jscc');
const result = jscc(sourceCode, options);
jscc(sourceCode, options, (err, result) => {
if (err) {
console.error(err);
} else {
console.log(result.code);
console.log(result.map);
}
})
The result is a plain JS object with a property code
, a string with the processed source, and a property map
, with a raw sourcemap object, if required by the sourcemap
option (its default is true
).
If a callback is provided, jscc will operate asynchronously and call the callback with an error object, if any, or null
in the first parameter and the result in the second.
Please see the Wiki to know the supported options.
Directives
jscc works with directives inserted in the text and prefixed with configurable character sequences, that defaults to '/*'
, '//'
and '<!--'
.
This directives allows you set or get compile-time variables, and exclude code blocks based in its value.
Here, I will refer to the names of the compile-time variables as varnames, to distinguish them from the JavaScript run-time variables.
To be valid, a <varname>
must match the regular expression /^_[0-9A-Z][_0-9A-Z]*$/
.
That is, it must start with an underscore, followed by a digit or uppercase letter, and then zero or more underscores, digits or uppercase letters. The character $
has a special use in jscc and is not allowed for varnames.
#set <varname> = <value>
Defines or redefines a varname
.
The value
can be a literal value, another varname, or an expression. If you don't specify a value, it is set to undefined
.
#unset <varname>
Removes the definition of the given varname
.
Both the definition or removal of a varname take immediate effect.
#if <expression>
Remove the block of code that follows this #if
if expression
is falsy.
You can nest multiple #if
blocks.
#ifsef <varname>
Check the existence of a varname
.
The returned value is true
if the variable exists, even if its value is undefined
. Apart from this, the behavior of #ifset
is the same as #if
, so references to the latter will imply both.
#ifnsef <varname>
This is the opposite to #ifset
, it returns false
if the varname
does not exists.
#elif <expression>
The behavior of #elif
is similar to the JS else if
statement.
The expression
will be evaluated if the previous #if
or #elif
was falsy.
You can have zero or more #elif
directives following one #if
.
#else
Includes the block that follows if the previous #if
or #elif
expressions were falsy.
#endif
Closes the current conditional block.
#error <expression>
Generates an exception at compile time with the result of the given character expression
.
You can learn more about this in the Wiki.
Changes in This Version
- Closes #8 : Removel of trailing jscc comment is breaking the expression.
- Removed Codebeat tests.
- More unity tests.
See details in the Changelog.
Known Issues
- If you are using ESM imports with Typescript, you must enable
esModuleInterop
in your tsconfig.json or use import jscc = require("jscc")
. - jscc does not work in a browser, but it must work without issues on the back-end.
ES6 TL
Remember that jscc is language agnostic, the following block may or may not work as you think:
const template = `
//#if _DEBUG
console.log('debug mode is on.')
//#endif
`
fs.writeFile('code.js', template, 'utf8')
Directive searching knows nothing about ES6 TL, so the #if..#endif
within the template will be evaluated at compile-time, just like any other (code.js is written without directives).
TODO
Support my Work
I'm a full-stack developer with more than 20 year of experience and I try to share most of my work for free and help others, but this takes a significant amount of time, effort and coffee so, if you like my work, please consider...
Of course, feedback, PRs, and stars are also welcome 🙃
Thanks for your support!
License
The MIT License.
© 2018, Alberto Martínez