NodeJS /浏览器交叉开发

时间:2014-03-19 16:38:47

标签: javascript node.js gruntjs amd commonjs

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

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

- 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端:EventEmitter来自require("events").EventEmitterevents是本地包,而不是本地文件或模块;

所以,我的问题是:如何在不进行大规模修改的情况下让Observable对象与NodeJS一起使用?我不确定如何使EventEmitter实现可用于我的模块,因为它不是本地模块(因此我不能写任何路径映射)而且它不是直接模块本身我们'我会使用它的“EventEmitter”属性......

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

1 个答案:

答案 0 :(得分:1)

uRequire使得使用runtimeInfo并在运行时选择性地加载替代依赖项变得微不足道(如果你不这样做,你总是可以选择在构建时使用替代版本和replace deps with alternative/mocks想写这样的选择性代码)。

Runtime info在所有模板中的工作方式相同,包括UMDcombined,因此,如果在以下位置执行:

  • nodejs

  • 带有requirejs

    等AMD加载程序的
  • 浏览器

  • 浏览器,内容为</script>标记,

您可以使用__isAMD__isNode&amp;运动来动态选择每种模块依赖关系在每种情况下的含义。 __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内嵌所有文件&amp;拥有自己的迷你加载器(almond),适用于nodejs,Web / AMD和Web / Script。从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

中查看测试项目