Product
Socket Now Supports uv.lock Files
Socket now supports uv.lock files to ensure consistent, secure dependency resolution for Python projects and enhance supply chain security.
Build CommonJS modules for the browser via a chainable API
new Glue()
.basepath('./lib') // output paths are relative to this
.include('./lib') // includes all files in the dir
.exclude(new RegExp('.+\\.test\\.js')) // excludes .test.js
.replace({
'jquery': 'window.$', // binds require('jquery') to window.$
'Chat': 'window.Chat'
})
.export('App') // the package is output as window.App
.render(function (err, txt) {
// send the package as a response to a HTTP request
res.setHeader('content-type', 'application/javascript');
res.end(txt);
// or write the result to a file
fs.writeFile('./app.js', txt);
});
To use the resulting file, just include the build result:
<script src="app.js"></script>
<script>
console.log(window.App); // single external interface to the package
</script>
The require() statements inside the package work just like under Node, yet none of the internals are leaked into the the global namespace.
gluejs does not export a global "require()" function in the browser; this means that it is compatible with other code since all details are hidden and only a single interface is exported (main file's module.exports
). The reasons behind this are documented in much more detail in my book, "Single page applications in depth".
An additional benefit is that you only need one HTTP request to load a package, and that the resulting files can be redistributed (e.g. to a non-Node web application) without worry.
.include(path)
: If the path is a file, include it. If the path is a directory, include all files in it recursively.
.exclude(regexp)
: excludes all files matching the regexp from the build. Evaluated just before rendering the build so it applies to all files.
gluejs can also include dependencies from npm. You have to first npm install
the packages, then gluejs reads, wraps and includes them in your build. This is done recursively, so the dependencies of dependencies are also packaged.
npm(name, [searchFrom])
: includes a single package from a directory. The package is searched from searchFrom+"/node_modules/"
- the default value for searchFrom is the basepath for the build. The dependency is then available via require(name).
npm(pathToPackageJson)
: includes all dependencies from the package.json file. Note that things under "devDependencies" are not included. The dependencies are searched starting from pathToPackageJson. Each dependency is accessible via its name.
Sub-dependencies are also automatically bundled, as long as they've been installed by npm. Since the require() semantics are the same as in Node, subdependencies can depend on different versions of the same module without conflicting with each other.
.defaults({
// all relative include() paths are resolved relative to this path
reqpath: '',
// strip this string from each path
// (e.g. /foo/bar/baz.js with '/foo' becomes 'bar/baz.js')
basepath: '',
// main file, preset default is index.js
main: 'index.js',
// name for the variable under window to which the package is exported
export: '',
// binds require('jquery') to window.$
replace: { 'jquery': 'window.$' }
})
.export(name)
: sets the export name (e.g. export('Foo') => window.Foo = require('index.js'); )
.render(function(err, text){ ...})
: renders the result
.watch(function(err, text){ ...})
: renders and adds file watchers on the files.
When a file in the build changes, the watch()
callback will be called again with the new build result.
Note that this API is a bit clunky:
But it works fine for automatically rebuilding e.g. when doing development locally.
Once you get past your first CommonJS-based build, you'll probably want to explore these features:
.replace(module, code)
: Meant for replacing a module with a single variable or expression. Examples:
// define require('jquery') as window.$
.replace('jquery', 'window.$');
// define require('debug') as the function below
.replace('debug', function debug() { return debug() });
Source URLs are additional annotations that make it possible to show the directory tree when looking at scripts (instead of just the one compiled file):
To enable source URLs, set the following option:
.set('debug', true)
Note that source URLs require that scripts are wrapped in a eval block, which is a bit ugly, so you probably don't want that in production mode.
By default, gluejs only handles files that end with ".js".
You can create custom handlers that handle other types of files, such as templates for your favorite templating language.
To specify a handler, call handler(regexp, function(opts, done) { ... })
Here is an example:
var Template = require('templating-library');
var extensionRe = new RegExp('(.+)\\.tpl$');
new Glue()
.include('./fixtures/mixed_content/')
.handler(extensionRe, function(opts, done) {
var wrap = opts.wrap, filename = opts.filename;
var out = Template.precompile(
fs.readFileSync(filename).toString()
);
done(filename.replace(extensionRe, '$1.js'), out);
})
.render(function(err, txt) {
console.log(txt);
done();
});
In fact, internally, the ".js" extension handler is just:
.handler(new RegExp('.*\.js$'), function(opts, done) {
return done(opts.filename, fs.readFileSync(opts.filename, 'utf8'));
});
Handler params:
The callback params:
Let's assume that your app consists of several internal packages. For example, within your app code you want to refer to the Foo model as require('model').Foo rather than require('../../model/foo.js').
One way to do this would be to simply have multiple packages, App and Models - where models exports window.model. If you prefer to avoid that extra global variable, do this instead:
.define('model', 'require("./model")');
Don't use require('model') in files inside the ./model directory, since that may introduce a circular dependency (e.g. model/a -> model/index -> model/a).
.define(module, code)
: Meant for writing a full module. The difference here is that while replace() code is not wrapped in a closure while define() code is.
.define('index.js', [ 'module.exports = {',
[ (hasBrowser ? " browser: require('./backends/browser_console.js')" : undefined ),
(hasLocalStorage ? " localstorage: require('./backends/browser_localstorage.js')" : undefined )
].filter(function(v) { return !!v; }).join(',\n'),
'};'].join('\n'));
The example above generates a index.js file depending on hasBrowser and hasLocalStorage.
Glue.concat([ package, package ], function(err, txt)). For example:
var packageA = new Glue()
.basepath('./fixtures/')
.export('Foo')
.include('./fixtures/lib/foo.js');
var packageB = new Glue()
.basepath('./fixtures/')
.export('Bar')
.include('./fixtures/lib/bar.js');
Glue.concat([packageA, packageB], function(err, txt) {
console.log(txt);
});
The main file is determined by looking at the "main" key in package.json and resolution follows the require() rules as documented in the Node API docs.
Only files ending with .js are included in the builds, since require() only works with .js, .json and .node files (the last one being for compiled native modules).
The .npmignore file is honored. It works like a .gitignore file. This is the preferred way of excluding files and directories from npm dependencies according to man npm developers
.
FAQs
Build CommonJS modules for the browser via a chainable API
The npm package gluejs receives a total of 85 weekly downloads. As such, gluejs popularity was classified as not popular.
We found that gluejs 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.
Product
Socket now supports uv.lock files to ensure consistent, secure dependency resolution for Python projects and enhance supply chain security.
Research
Security News
Socket researchers have discovered multiple malicious npm packages targeting Solana private keys, abusing Gmail to exfiltrate the data and drain Solana wallets.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.