I'm trying to compile an the uncss npm module into a single .js file that is suitable for compilation by ExecJS. For example, the coffee script guy has this. The goal is to create a simple ruby wrapper for it, similar to ruby-coffee-script.
What I have tried to far:
Used browserify, which should have done the trick, but it fails to compile lib/uncss.js with the following error message:
Error: ENOENT, open 'tls' while resolving "tls" from file /home/prajjwal/code/uncss/node_modules/request/node_modules/forever-agent/index.js
I suppose this is because browserify does not have a proper shim for it? I'm also concerned about the shims that browserify replaces node modules with. Are they completely safe to use? I'm going to be embedding this into a ruby gem. Don't think browserify is what I should be using. Is there another way I can generate a stand alone .js from an npm module?
Any help appreciated.
Whether or not the library will work without Node will depend on the library. If it presents itself as a Node module, then you'll probably have to modify it (or find a compatible module loader for browser-side JS).
NPM installs devDependencies within the package. json file. The 'npm install' command should add all the dependencies and devDependencies automatically during installation. If you need to add specific devDependencies to your project, you can use this command- 'npm install --save-dev'.
You don't need webpack nor babel to make an mpm module. Just put in any folder the files you want to distribute, specifying the main entry point and export elements on that file.
Browserify has a --standalone flag that can help here.
On the command line:
browserify -s moduleName --bare moduleName.js -o filename.js
In your node script you can import the concatenated module normally:
var moduleName = require('./filename');
However, you will may still need to ignore and/or stub out any tricky modules.
Although it doesn't quite seem like it would be the right tool for the job, it appears that browserify is the closest thing to what you're looking for.
To be complete, here are the versions of the tools I used: Node v0.10.26
and browserify 3.38.0
. I didn't test with other version, so they may have problems.
Here are the steps that I took after cloning uncss
:
npm install
, which downloads and sets up the proper packagesDue to some sort of versioning problem with NPM, I had to manually install the graceful-fs
package (a dependency of one of uncss
's dependencies) from Github (it wasn't available via npm
)
npm install https://github.com/isaacs/node-graceful-fs/tarball/v2.0.3
At this point, I ran browserify. It turns out that browserify has a --bare
flag, which does a couple of things:
Alias for both --no-builtins, --no-commondir, and sets --insert-global-vars to just "__filename,__dirname". This is handy if you want to run bundles in node.
With this flag, browserify doesn't inject its own shims for core modules. The full command I used was:
browserify lib/uncss.js --bare > uncss.js
After doing the above, the file uncss.js
contained uncss
along with its bundled dependencies. Unfortunately, since browserify wraps everything inside its own require
function, the now-bundled modules doesn't export anything initially.
$ node
> require('./uncss')
{}
>
To fix this, I had to change the initial line of the generated bundle from this:
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
to this:
module.exports = (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require,ex;for(var o=0;o<r.length;o++)ex=s(r[o]);return ex})({1:[function(require,module,exports){
Note: it's not just the module.exports
addition - there's some modification in the middle that was needed also*.
After that, the bundle seemed to work:
$ node
> require('./uncss')
[Function: init]
>
*: Essentially, browserify defines an inner function s(o, u)
that acts like require
. The surrounding code starts off by looping through what looks like a list of "main modules" (in this case, there's just one), require
ing them, but not storing the result. It then returns s
, the require
-like function (why, I'm not sure) as the output of the entire anonymous function. All I had to do was add a variable to store the results, and then return
that instead.
While it is not impossible, it is a bit complicated, there is no tool that I know to do it automatically, but it coulb be done manually.
So, if you load a module in this way:
var async = require('async');
You can include the source of that module, first, declaring the module instance in your main script:
var global_async = null;
Then, include the module code inside an anonymous function and replace the "module.exports" with the global var you declared before:
module.exports = async
With
global_async = async;
Problem is that there are a lot of dependencies for "uncss", each one with some dependencies, so it is to much work to be done, but not impossible... but at the end, this module also requires some external binaries like "phantomjs".
If you want to build a gem that create a wrapper around "uncss" you can check if node and uncss are installed before anything, if not, install both, and then just call them, just like uncss does with phantomjs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With