Frage

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:

  1. Came across an answer that suggested UglifyJS. Got nowhere with it.
  2. 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.

War es hilfreich?

Lösung 2

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:

  1. npm install, which downloads and sets up the proper packages
  2. Due 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
    
  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), requireing 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.

Andere Tipps

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.

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top