【问题标题】:Build package for both node and browser environment为节点和浏览器环境构建包
【发布时间】:2013-05-06 15:10:09
【问题描述】:

我为特定的 JSON API 开发了一个 node NPM 包,它主要是一个包装器(使用 node 的 httphttpsquerystring 模块)。它在 Coffeescript 中构建,使 Node.js 服务器能够与此 API 进行通信。 Api 主要是 REST。

现在我希望这个库也可用于浏览器。这意味着对http 模块的调用需要替换为XMLHttpRequest(异步)。在我看来,我会为适配器制作一个包装器。对于 Node 环境,此适配器会将所有调用传递给 http 模块,对于浏览器环境,将传递给 XMLHttpRequest 对象。

有没有一种很好的方法来构建构建系统,以便 npm 包包含两个版本,并且我也可以在 Github 上发布普通的“浏览器版本”?节点包随后可以通过require('package-name') 获得,并且应该将一个 JS 文件(用于浏览器)放在一个目录中。

我查看了Component,它非常适合客户端包管理,但问题仍然是如何创建不同的构建环境。

【问题讨论】:

  • 如果你正在研究组件,也可以看看bower.io
  • 好的,谢谢。我也已经找到了鲍尔。看起来还不错。尽管如此,困难似乎还是要创造某种建筑环境。

标签: javascript node.js npm


【解决方案1】:

您可以使用node-browser-resolvebrowser 部分添加到package.json

{
  "browser": {
    "./index.js": "./browser.js"
  }
}

https://nolanlawson.com/2017/01/09/how-to-write-a-javascript-package-for-both-node-and-the-browser/

【讨论】:

    【解决方案2】:

    使用 browserify 对 node.js 和浏览器进行交叉开发的示例解决方案:https://github.com/amitayd/grunt-browserify-jasmine-node-example (and discussion at my blog post)。

    特别是对于浏览器/Node.js 的不同实现,请检查PersistentReaderWriter.js

    一旦您有一些模板开始使用 browserify,并且您意识到了一些陷阱,您可能会发现您也想将它用于小型库。

    编辑:请注意,如果您浏览模块,则 isBrowser() 检查不应该通过检查模块和 module.exports 是否已定义,因为 Browserify 的包装器将在模块上下文中定义它们。相反,在我的示例中,我检查要定义的窗口。

    【讨论】:

    • 谢谢。它认为var Utils = require('./Utils'); if (Utils.isBrowser) {...} else { ...} 是我真正想要的部分。虽然我仍然不是 Browserify 的真正粉丝,但我确实喜欢你的解决方案。
    • 我同意,如果它是单个模块(单个文件)库并且它适用于您,则可能没有理由切换到节点。诸如下划线的库在单个文件中同时满足节点和浏览器的需求。在我的回答中添加关于 isBrowser 的小注释。
    【解决方案3】:

    将此添加到模块的末尾。并像这样导出您的模块。

    if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
      module.exports = YourModule;
    }
    else {
      if (typeof define === 'function' && define.amd) {
        define([], function() {
          return YourModule;
        });
      }
      else {
        window['YourModule'] = YourModule;
      }
    }
    

    【讨论】:

      【解决方案4】:

      我找到了一个解决方案,虽然它不是最初想到的,但具有不同的构建环境。

      就我而言,我有一个非常小的库,它使用 Node 的 httphttpsquerystringurl 包。我不想使用 Browserify 之类的东西,因为将所有这些包捆绑到一个小型 api 库中似乎不合适。相反,我用XMLHttpRequest 包替换了httphttps 功能。 querystringurl 提供的小功能很容易被重写。

      在我的库中,我在运行时检查window.XMLHttpRequest 对象是否可用。如果是这样,请使用该(本机)对象。否则,它使用包提供的那个。因此:

      _getRequestObject: () ->
        if window? and window.XMLHttpRequest?
          return new window.XMLHttpRequest()
      
        if window? and window.ActiveXObject?
          try
            request = new ActiveXObject('Msxml2.XMLHTTP')
          catch e
            try
              request = new ActiveXObject('Microsoft.XMLHTTP')
            catch e
      
        XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
        return new XMLHttpRequest()
      

      另一个问题是exports 没有在浏览器中定义。有一些包可以模拟这种行为,但同样,它不想让库膨胀。因此,我再次检查运行时是否设置了 module 变量。如果是这样,我定义的对象设置为那个,否则设置为window对象:

      if typeof module is 'undefined'
        window['My-module'] = My_module_object
      else
        module.exports = exports = My_module_object
      

      这一切都对我有用,因为我没有真正需要的 Node.js 依赖项,这些依赖项在浏览器环境中不存在。恐怕对于较大的项目,确实需要像 Browserify 这样的解决方案,但我仍然很好奇是否还有其他解决方案,例如在为 Node.js 打包库或为(例如)Bower 时创建不同的构建环境。

      【讨论】:

      • 因为煮咖啡的方法不止一种(脚本):unless module?.
      猜你喜欢
      • 1970-01-01
      • 2020-12-12
      • 1970-01-01
      • 2014-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多