将npm模块编译为单个文件,不包含依赖项

30
我试图将npm模块uncss编译成一个适合ExecJS编译的单一.js文件。例如,CoffeeScript的作者有这个。目标是创建一个简单的Ruby包装器,类似于ruby-coffee-script

我尝试过:

  1. 看到一个回答建议使用UglifyJS,但没有成功。
  2. 使用browserify,本应该解决问题,但它无法编译lib/uncss.js并显示以下错误消息:

    Error: ENOENT, open 'tls' while resolving "tls" from file /home/prajjwal/code/uncss/node_modules/request/node_modules/forever-agent/index.js
    
    我猜测这是因为browserify没有适当的适配器?我也担心browserify用来替换node模块的适配器是否完全安全?我将把它嵌入到一个Ruby gem中。我认为不应该使用browserify。是否有其他方法可以从npm模块生成独立的.js文件?
    任何帮助都会感激。

如果您正在寻找一种最小化CSS和JS的工具,可以使用yuicompressor,它是一个单独的Java文件,请查看此链接:http://yui.github.io/yuicompressor/。 - Rodrigo Polo
3个回答

18

Browserify有一个--standalone标志,可以在这里提供帮助。

在命令行上:

browserify -s moduleName --bare moduleName.js -o filename.js

在您的 Node 脚本中,您可以正常导入已经拼接好的模块:

var moduleName = require('./filename');

然而,您可能仍需要忽略和/或存根掉任何棘手的模块。


13
虽然看起来它似乎不是最适合这项工作的工具,但browserify可能是最接近你所需的东西。为了完整起见,以下是我使用的工具版本:Node v0.10.26browserify 3.38.0。我没有测试其他版本,因此他们可能会有问题。下面是我克隆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
    

在完成上述步骤后,文件uncss.js将包含uncss及其捆绑的依赖项。不幸的是,由于browserify将所有内容都包装在自己的require函数中,因此现在捆绑的模块最初并没有导出任何东西。

$ node
> require('./uncss')
{}
>

要解决这个问题,我必须将生成的捆绑包的初始行更改为以下内容:
(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){

转换为:

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){

注意:这不仅仅是添加module.exports - 中间还需要进行一些修改*。
之后,打包似乎可以正常工作了:
$ node
> require('./uncss')
[Function: init]
>

*: 实质上,browserify 定义了一个名为 function s(o, u) 的内部函数,其作用类似于 require。周围的代码开始通过循环遍历一系列看起来像是“主模块”的列表(在这个例子中只有一个),使用 require 去调用它们,但不存储结果。然后返回整个匿名函数的输出,即 s,这个类似于 require 的函数(我不确定为什么)。我所要做的就是添加一个变量来存储结果,然后将其 return 出去。

如果你给 browserify 加上 -r 选项,那么它会使文件可用于“require”。browserify -r lib/uncss.js:uncss --bare > uncss.bundle.js 命令将允许你通过执行 require('uncss') 来运行 uncss.js 的内容。 - yegodz
1
顺便提一下,当使用此方法创建“request”的静态副本时,我不得不手动替换存根 - 正如这里的注释所指出的那样,-r标志没有帮助。然后我尝试了@xer0x指出的-s标志,这样就不需要替换存根了。 - radicand

1
虽然不是不可能,但有点复杂,我不知道有什么工具可以自动完成,但可以手动完成。
因此,如果您以这种方式加载模块:
var async = require('async');

你可以将该模块的源代码包含在你的主脚本中,首先声明该模块实例:
var global_async = null;

接着,在匿名函数内包含模块代码,并将 "module.exports" 替换为之前声明的全局变量:

module.exports = async

带有

global_async = async;

问题在于"uncss"有很多依赖项,每个依赖项都有一些依赖关系,所以需要做很多工作,但并非不可能...但最终,该模块还需要一些外部二进制文件,如"phantomjs"。
如果要构建一个创建围绕"uncss"的gem包装器,您可以首先检查是否安装了node和uncss,如果没有,则安装两者,然后只需调用它们,就像uncss使用phantomjs一样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接