简体   繁体   English

将npm模块编译为单个文件,没有依赖项

[英]Compile an npm module into a single file, without dependencies

I'm trying to compile an the uncss npm module into a single .js file that is suitable for compilation by ExecJS. 我正在尝试将一个uncss npm模块编译成一个适合ExecJS编译的.js文件。 For example, the coffee script guy has this . 例如,咖啡脚本的人有这个 The goal is to create a simple ruby wrapper for it, similar to ruby-coffee-script . 目标是为它创建一个简单的ruby包装器,类似于ruby-coffee-script

What I have tried to far: 我试过的远:

  1. Came across an answer that suggested UglifyJS. 遇到了一个暗示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: 使用了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 

I suppose this is because browserify does not have a proper shim for it? 我想这是因为browserify没有适当的垫片吗? 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? 还有另一种方法我可以从npm模块生成一个独立的.js吗?

Any help appreciated. 任何帮助赞赏。

Browserify has a --standalone flag that can help here. Browserify有一个--standalone标志,可以在这里提供帮助。

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 . 要完成,以下是我使用的工具的版本: Node v0.10.26browserify 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 : 这里是我克隆后采取的步骤uncss

  1. npm install , which downloads and sets up the proper packages npm install ,下载并设置正确的软件包
  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的某种版本控制问题 ,我不得不从Github手动安装graceful-fs包(一个uncss的依赖项的依赖项)(它不能通过npm

     npm install https://github.com/isaacs/node-graceful-fs/tarball/v2.0.3 
  3. At this point, I ran browserify. 此时,我运行了browserify。 It turns out that browserify has a --bare flag, which does a couple of things: 事实证明,browserify有一个--bare标志,它做了几件事:

    Alias for both --no-builtins, --no-commondir, and sets --insert-global-vars to just "__filename,__dirname". 别名为--no-builtins, - no-commondir,并将--insert-global-vars设置为“__filename,__ dirname”。 This is handy if you want to run bundles in node. 如果要在节点中运行bundle,这很方便。

    With this flag, browserify doesn't inject its own shims for core modules. 使用此标志,browserify不会为核心模块注入自己的填充程序。 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. 完成上述操作后,文件uncss.js包含uncss及其捆绑的依赖项。 Unfortunately, since browserify wraps everything inside its own require function, the now-bundled modules doesn't export anything initially. 不幸的是,由于browserify将所有内容包装在自己的require函数中,因此现在捆绑的模块最初不会导出任何内容。

$ 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*. 注意:它只是module.exports另外-有在还需要*中间的一些修改。

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 . *:从本质上讲,browserify定义了一个内部function s(o, u) ,它的作用就像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. 周围的代码开始于循环看起来像“主要模块”的列表(在这种情况下,只有一个), require它们,但不存储结果。 It then returns s , the require -like function (why, I'm not sure) as the output of the entire anonymous function. 然后它返回s ,类似require的函数(为什么,我不确定)作为整个匿名函数的输出。 All I had to do was add a variable to store the results, and then return that instead. 我所要做的就是添加一个变量来存储结果,然后return它。

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”替换为您之前声明的全局变量:

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". 问题是“unss”存在很多依赖关系,每个都有一些依赖关系,所以要完成很多工作,但并非不可能......但最后,这个模块还需要一些外部二进制文件,如“ 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. 如果你想构建一个创建一个围绕“unss”包装的gem,你可以检查node和uncss是否安装在任何东西之前,如果没有,安装两者,然后只是调用它们,就像uncss与phantomjs一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM