
Security News
Socket Security Analysis Is Now One Click Away on npm
npm now links to Socket's security analysis on every package page. Here's what you'll find when you click through.

Substrat is a powerful yet simple build system for HTML5 projects.
It's easy and quick to set up, configurable, extendable and built with for frontend heavy, single page applications.

Automatic monitoring and syncing our source and build directories
Supports complex file patterns for file filtering and ordering
Has task dependencies to re-build files when other files are changed (based on patterns)
Built in static web server with support for automatic page reload on each build
Comes with many built-in tasks for things like:
Easily set up proxies:
Is easy to extend with your own, custom tasks
Standalone, can be integrated with Grunt, Jake or any other task runner or existing build script
Get it via npm install substrat
var substrat = require('substrat');
Setup your patterns, these allow you to group and filter the files for your build
var patterns = {
js: {
// Match all source files of the application, and put app and config
// at the end when generating a array of the filenames from this pattern
app: substrat.pattern(/js\/.*\.js$/).last('js/config.js', 'js/app.js'),
// Match all the javascript source files of the libraries, but ignore any pre-minified ones
lib: substrat.pattern(/lib\/.*\.js$/).not(/\.min\.js$/)
},
compile: {
jade: substrat.pattern(/\.jade$/),
less: substrat.pattern(/\.less$/)
},
// Match all style sheets both generated and existing ones
// but put the generated ones at the end when generating a array of the
// filenames from this pattern
style: substrat.pattern(/(\.css|\.less)$/).last(/\.less$/),
// A matcher for everything else
all: substrat.pattern('*')
};
Define an environment for the use in your templates, you can also expose the patterns so you can include all your scripts and styles automatically
var env = {
title: 'Substrat',
version: 0.1,
patterns: patterns // Expose the patterns for later usage
};
Create a new instance of substrat with your specific configuration
var s = substrat.init({
// The source directory to watch
src: 'src',
// The destination directory for the build
dest: 'public',
// Whether or not to log build events, will still print general info
silent: false,
// Will disable all logging (sets silent to true)
quiet: false,
// If true, will produce lots of internal logging output
debug: false,
// Enable compression in tasks (e.g. strip whitespace, minify js etc.)
compress: false,
// Set up dependencies
depends: [
// Rebuild src/index.jade every time a js or less file changes
// This way, the template can automatically update the included
// scripts and styles
['index.jade', [patterns.js, patterns.style]]
],
// Define the tasks
// Tasks are run in order, each task will filter out the files it matched
// so they are not subject to any further tasks in the chain
tasks: [
// Compile all app specific scripts with uglify-js
substrat.task.compile(patterns.js.app, 'js'),
// Compile all jade files to html and supply them with the locals from "env"
substrat.task.compile(patterns.compile.jade, 'jade', env),
// Compile all less stylesheets to css
substrat.task.compile(patterns.compile.less, 'less'),
// Copy all other files which did not match any previous tasks
substrat.task.copy(patterns.all)
],
// Setup some proxies for testing and local database access
proxy: {
// Proxy the local couchdb instance to avoid messy CORS setup during
// development
'/couchdb': {
// URL is the target of the proxy
host: 'localhost',
port: 5984,
// Add 500 milliseconds of delay to each request
delay: 500
},
// Proxy the "public" directory itself but "mock" out a couple of
// files to inject test mocks / frameworks
'/test': {
// The directory to serve
root: 'public',
// Replace the main application file and include additional files
// for testing
mock: {
'js/app.js': [
'test/e2e/app.js',
'test/e2e/mocks.js'
]
}
}
}
});
Start your continous build that automatically reloads your browser while you're editing
s.listen('index.html', 4444);
Read on for more details on the configuration options and tasks.
src: String
The source directory which contains the file to build.
dest: String
The destination directory were the files produced by the build are to be found.
The contents of the directory are automatically synced with the source, meaning that files and folders which no longer exist in the source directory will automatically be removed.
silent: Boolean (false)
If true disables substrat logging (except for top level logs).
quiet: Boolean (false)
If true disables all substrat logging (enables silent).
debug: Boolean (false)
If true enables internal logging of substrat's components.
hidden: Boolean (true)
When true substrat will ingore any dotfiles.
excludePattern: RegExp (/..~$/)*
A additional regular expression which will be used to filter all files in
the source directory. Defaults to filter common backup files which end with
a ~ (tilde).
compress: Boolean(false)
A flag which indicates to tasks that the should compress / minify their output.
See the Tasks section for more details.
sourceMaps: Boolean(true)
Whether or not to generate source maps for CSS and JavaScript files when performing compression or concatenating tasks.
depends: Array[Array[Pattern, Pattern|Array[Patterns]]...]
A array containing arrays of patterns which specify which files should be rebuild once other files matching the specified patterns have changed.
See the Dependencies section for more details.
tasks: Array
A listing of tasks which will be executed in order once the contents of the
src directory change. Each successive tasks will filter out the files it
matched from the list of files that have changed.
See the Tasks section for more details.
proxy: Object
A mapping of paths to proxy configurations.
See the Proxies section for more details.
cssReload: Boolean(false)
Enables in-page reloading of CSS resources without reloading the full page.
run() -> this
Invokes the build once and then finishes.
Will emit the done event once the build has finished.
watch() -> this
Will continously monitor the source directory for changed and re-build automatically.
Triggers a build event after each completed build.
listen(indexUrl, port [, host]) -> this
Same as watch() but will also start a local web server on the specified
host and port and will patch the specified indexUrl HTML file to
automatically reload on every build.
To disable automatic reloading, simply pass null as the value of indexUrl.
stop() -> this
Stops substrat in case it is watching or listening.
Triggers the done event.
pattern(expr) -> Pattern
Creates a new substrat pattern from the given expression.
files(pattern) -> Array[String]
Returns a list of files for the destination directory which match the specified pattern(s).
Substrat makes heavy use of patterns for both file matching and listing.
Patterns can be created from a variety of sources and are converted to regular expressions internally. You can also create pass objects of patterns which will be merged, as well as arrays which will concatenate their matches.
Note: All paths and files within substrat are treated relative to either the
srcordestdirectories. E.g./home/user/project/src/js/app.jswill be treated asjs/app.js.
All strings are parsed via minimatch and
converted into regular expressions. This means that you can use standard glob
patterns like **/*.js and the like.
The only exception to this rule is the special string * which will get
converted to /^.*$/.
You can pass any valid regular expression as a pattern.
Patterns from objects are merged, they object's keys are sorted via the standard
sort() function and are then used to merge the object's values into a new
pattern.
Functions which are passed as pattern will get invoked with the filename they
should test for matching. They should return either true or false.
Arrays will create so called Pattern Groups. Pattern groups apply all included patterns in order and will preserve the ordering of the files returned by the individual sub patterns.
Patterns have the very useful pattern.first(patterns...) and
pattern.last(patterns...) methods which will move the files matching the
specified patterns either to the beginning or the end of the file list.
substrat.pattern(/js\/.*\.js$/).first('js/config.js').last('js/init.js', 'js/afterInit.js');
For example, this allows you to get a list of all JavaScript files in your application and then put the file that defines your namespaces and configuration and the beginning of the list and the file initializing your code at the very end.
In addition patterns can include one or more files via the
pattern.not(pattern...) method.
Substrat includes a minimal - but efficient - dependency management for files which is also based on pattern.
Dependencies are specified in the format of an array with two entries. The first one is a pattern which describes which files will be re-build and the second entry being a pattern which specifies which files will trigger the re-build.
['index.jade', [/*.js$/, /*.less$/]]
The above will rebuild index.jade every time that a .js or .less file has
been added, changed or removed from the source directory.
Of course it is also possibly to re-build multiple files, simply supply a more complex pattern as the first entry of the array:
[/template\/view\/controller\/*.jade$/, [/*.js$/, /*.less$/]]
Note: Every rebuild will trigger another check for dependencies. This allows for the creation of dependencies that depend on other dependencies.
Tasks in substrat are highly configurable and easy to extend.
Compile
substrat.task.compile(pattern, compiler[, config])
Compiles all the files matching the pattern from the src to the dest
using the specified compiler. Following compilers are available out of the box:
Note: The compile tasks by will only obfuscate and/or minify their output when the
substrat.compressoption is set.
js
Compiles JavaScript files using uglify-js, if the substrat.compress
option is enabled, otherwise it will simply copy the JS files.
Example: Minifying all applications JS files
substrat.task.compile('js/**/*.js', 'js')
less
Compiles less files into CSS, changing the file extension in the process.
If substrat.compress is set it will stip whitespace from the output files.
Example: Transforming less files into CSS
substrat.task.compile(/*\.less$/, 'less')
jade
Compiles jade files into HTML, changing the file extension in the process.
The config paramter should be an object and will be populate the locals
of the template.
Example: Converting all jade templates into HTML
substrat.task.compile(/*\.jade$/, 'jade', config)
Concat
substrat.task.compile(pattern, type, outputFile)
This task is pretty much the same as compile task but only supports js
and less at the moment and will merge all the files into the specified
outputFile.
Copy
substrat.task.compile(pattern)
Copies all the files matching the pattern from the src to the dest
directory. This task uses fs.stream interally for efficient copying and
will create directories in the destination as requried.
Example: Copying all outstanding files as the last task
substrat.task.copy('*')
Template
substrat.task.template(pattern, locals [, tags, virtual])
Compiles all files matching the pattern as mustache.js templates and
supplies them with locals. The files get rendered to a file with the same
name in the dest directory.
The optionaltags array can be used to replace the default tags used in
mustache templates with custom ones. e.g. ['<%', '%>'].
If virtual is set to true the tasks will not generate an actual file on
disk, but rather a virtual which essentially replaces the src for the
duration of the build. This allows templated files to be picked up by
concators and other tasks.
Example: Rendering configuration file with custom tags to keep it JSHint friendly
substrat.task.template('js/config.js', config, ['"{{', '}}"']),
New tasks can be created via the substrat.Task constructor:
new substrat.Task(taskName, filePattern, handler, config)
taskName: String
This simply is a internal name for the task which is used in debug logging.
filePattern: Pattern
A substrat pattern which describes all files for which the task should be executed.
Note: A
nullpattern will run the task on every build, not matter which files have changed.
handlerDescription: Object
A object which implements the actual logic of the task.
config: Object
Additional configuration which is available to the task logic during execution.
A task handler description consists of a number of properties and methods:
var handlerDescription = {
// Run the task independently for each file
mode: substrat.Task.Each,
// Automatically provide the file data to the task
data: true,
// Map the source files to html files in the output
map: function(e, file) {
return file.replace(/\.jade$/, '.html');
},
// The actual task logic
run: function(e, done) {
try {
// Use the custom configuration of the task as the locals
var locals = util.merge(e.config, {
pretty: !e.options.compress,
substrat: e.substrat
});
done(null, jade.render(e.data.toString(), locals));
} catch(err) {
done(err);
}
}
};
mode: Integer
One of the following:
Each
Run the task independently for each file, meaning that for five input files the task will be run five times.
All
Run the task once on all files, meaning that for five input files the task will be called exactly one time and will be provided with all the files and their data at once.
Single
Run the task once and don't care about the input. Useful for auto generation of files and other things.
data: Boolean|Function(e)
Whether or not to automatically read the input file(s) and supply their
buffers to the task. Can also be a function which gets passed the task
execution environment and should return a
boolean.
map: Function(e, file)
A function which maps the input filename to the respective outputs, can also return an array with multiple output names (e.g. a JS file and its corresponding source map file).
It's arguments consists of the task execution environment and the path of the file in source directory.
These mappings are used to create the output files of the task in the destination directory.
In addition, they also server to synchronize the destination directory and automatically remove files which are no longer exist in the source.
They are also available via substrat.files(patterns) and can be used to
automatically include files in HTML and other templates.
run: Function(e, done(err[, data]))
A function which performs the actual task logic.
It's arguments consists of the task execution environment and a callback function.
The done callback takes the following arguments:
err: Null|Error
The error value in case the task could failed. Pass null if the task
was successful.A
data: String|Array[String] (Optional)
The file data to be written into the files indicated by the return
value(s) of the handlers map() function.
If left out, no file be written. This can be used by tasks which handle
the writing on their own (e.g. the copy task which uses streams).
This "environment" argument is passed to all functions of a task handler description and has the following structure:
options: Object
A reference to the configuration object passed into substrat.init().
config: Object
A reference to the configuration object passed into the task constructor.
mapped: String|Array[String]
The filename(s) returned by the map() function of the task handler.
Only for tasks running with mode Task.Each or Task.All
source: String
The filename from the source directory.
Only for tasks running with mode Task.Each
data: Buffer
A Buffer object with the contents of the file reference by source.
Only for tasks running with mode Task.Each
path: String
The full path to the file in the source directory.
Only for tasks running with mode Task.Each
all: Array[Object]
A array of objects with source, data and path properties as described
above.
Only for tasks running with mode Task.All
Substrat can be used to quickly configure proxies to both http endpoints as well
as local directories, this is done via the substrat.proxy option which takes a
mapping of absolute paths to proxy configuration objects having the following
structure:
host: String
port: Integer
delay: Integer
root: String
mock: Object
Subfile.jsSubstrat is licenses under MIT.
FAQs
A powerful yet simple build system for HTML5 projects.
We found that substrat demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
npm now links to Socket's security analysis on every package page. Here's what you'll find when you click through.

Security News
A compromised npm publish token was used to push a malicious postinstall script in cline@2.3.0, affecting the popular AI coding agent CLI with 90k weekly downloads.

Product
Socket is now scanning AI agent skills across multiple languages and ecosystems, detecting malicious behavior before developers install, starting with skills.sh's 60,000+ skills.