2014-03-19 41 views
1

我正在研究面向浏览器和NodeJS应用程序的库。模块使用AMD惯例,它在理论上足够灵活,足以映射今天的任何情况。源文件随后将被转换为工具,以便分发给不同的平台 - 再次是浏览器和NodeJS。 顺便说一句,有一个很棒的工具叫做uRequire来帮助解决这个问题,但我仍然不确定我的最佳选择是什么,所以我在这里要求相关经验。NodeJS /浏览器交叉开发

以下是文件的层次结构,我有:

- bower_components/ 
    - eventemitter2/ ... 
    - lodash/ ... 

- source/ 
    - library/ 
     - lodash.js -> ../../bower_components/lodash/dist/lodash.js 
     - EventEmitter.js -> ../../bower_components/eventemitter2/lib/eventemitter2.js 

    - Observable.js: 

     define(["lodash", "EventEmitter"], function(Utility, EventEmitter) { 
      function Observable(options) { ... }; 

      return Observable; 
     }); 

最后,浏览器和的NodeJS双方之间的最大区别在于:

  • 浏览器端:EventEmitter实现仅仅是eventemitter2浏览器被配置为“library/EventEmitter”的模块;
  • NodeJS端:EventEmitterrequire("events").EventEmitter获得,events是本地包,而不是本地文件或模块;

所以,我的问题是:我该如何使Observable对象与NodeJS一起工作,而无需大量修补?我不知道如何使EventEmitter实现可用于我的模块,因为它不是本地模块(因此我不能写任何路径映射),而且它不是直接使用我们将使用的模块,而是它的“EventEmitter”属性...

任何帮助/思想,将不胜感激。我相信很多人都遇到类似的情况,我很想知道他们要说些什么!

+1

考虑使用Browserify。它具有与Node.js模块兼容的浏览器模块。 – Brad

+1

这是一个很简短的答案...... :) 你如何处理不同的实现例如XMLHttpRequest在一方和“http”模块在另一方,例如? –

+0

这些情况非常棘手,需要在代码中处理。虽然没有银弹。 Browserify可以让你在那里找到大部分路径(在某些模块中,所有的路都在那里)。 – Brad

回答

1

uRequire可以轻松地将使用runtimeInfo和selectivelly在运行时加载替换的相依(你可以随时选择有替代构建和replace deps with alternative/mocks在编译的时候,如果你不想写这样选择的代码)。

Runtime info适用于所有的模板,包括UMDcombined一样的,所以无论是如果执行上:与AMD装载机像requirejs

  • 的NodeJS

  • 浏览器

  • 浏览器与普通</script>标签,

你可以选择每个模块的依赖性在每种情况下是指动态地,使用__isAMD__isNode & __isWeb运行时变量。

你需要的是:

- bower_components/ 
    - eventemitter2/ ... 
    - lodash/ ... 
    - requirejs/ ... 

- source/ 
    - library/ 
     - EventEmitter.js  
     - Observable.js: 

其中Observable.js是例如

define(["lodash", "EventEmitter"], function(_, EventEmitter) { 
    function Observable(options) { this.myOptions = options }; 

    Observable.EventEmitter = EventEmitter; 
    Observable._ = _; 
    return Observable; 
}); 

EventEmitter.js是:

define(function(){ 
    var EventEmitter2; 
    if (__isNode) { 
    return require("events").EventEmitter; 
    } else { 
    if (__isAMD) { 
     return EventEmitter2 = require("eventemitter2"); 
    } else if (__isWeb) { 
     return window.EventEmitter2; 
    } 
    } 
}); 

**说明**:

具有以下 grunt-urequire配置(在CoffeeScript中)

然后:

module.exports = gruntFunction = (grunt) -> 

    grunt.initConfig gruntConfig = 
    urequire: 
     library: 
     path: "source/library" 
     dstPath: "build/UMD" 
     runtimeInfo: ['EventEmitter'] # dont need it in other files 
     template: 'UMDplain' 

     combined: 
     derive: 'library' 
     main: 'Observable' 
     dependencies: exports: root: {'Observable': 'Obs'} 
     dstPath: "build/almond/Observable.js" 
     template: 'combined' 

    grunt.loadNpmTasks "grunt-urequire" 

你有两个版本:

A)library:有独立的UMD文件,在那里你可以运行,例如从source\test\load_node.js

var Observable = require("../../build/UMD/Observable"); 
console.log(Observable.EventEmitter); 

或来自浏览器(source/test/Loader_unoptimized_AMD.html):

<!DOCTYPE html> 
<html> 
    <head><title>test crossdev: RequireJs, UMD</title></head> 
    <body>Check console!</body> 

    <script src="../../bower_components/requirejs/require.js"></script> 
    <script> 
    require.config ({ 
     baseUrl: '../../build/almond', 
     paths: { 
     lodash: "../../bower_components/lodash/dist/lodash.min", 
     eventemitter2: "../../bower_components/eventemitter2/lib/eventemitter2" 
     } 
    }); 

    require(["Observable" ], function(Observable){ 
     console.log(Observable); 
     console.log(Observable.EventEmitter); 
    }); 

    </script> 
</html> 

B)combined所有文件内联&具有上的NodeJS,网络/ AMD和Web /脚本作品自身的小型装载机(almond)。从source/test/Loader_almondJs_plainScript.html运行:

<!DOCTYPE html> 
<html> 
    <head><title>test crossdev: plain script, combined/almond</title></head> 
    <body>Check console!</body> 

    <script src="../../bower_components/lodash/dist/lodash.min.js"></script> 
    <script src="../../bower_components/eventemitter2/lib/eventemitter2.js"></script> 
    <script src="../../build/almond/Observable.js"></script> 

    <script> 
    console.log(window.Obs); 
    console.log(window.Obs.EventEmitter); 
    </script> 
</html> 

或使用RequireJs作为AMD装载机(source/test/Loader_almondJs_AMD.html):

<!DOCTYPE html> 
<html> 
    <head><title>test crossdev: RequireJs, combined/almond</title></head> 
    <body>Check console!</body> 

    <script src="../../bower_components/requirejs/require.js"></script> 
    <script> 
    require.config ({ 
     baseUrl: '../../build/almond', 
     paths: { 
     lodash: "../../bower_components/lodash/dist/lodash.min", 
     eventemitter2: "../../bower_components/eventemitter2/lib/eventemitter2" 
     } 
    }); 

    require(["Observable" ], function(Observable){ 
     console.log(Observable); 
     console.log(Observable.EventEmitter); 
    }); 

    </script> 
</html> 

您可以看到测试项目https://github.com/anodynos/nodejs-browser-cross-development