2016-04-07 13 views
0

Ich versuche, einige JS-Module zu schreiben, die sowohl in einem Browser als auch in der node.js-Umgebung verwendbar sein sollten.requirejs() gibt undefined zurück, wenn Knoten und AMD-Module gemischt werden

Um dies zu erleichtern schreibe ich diese Module als AMD modules, und mit requirejs in the Node.js environment, um die define() Funktion sowie die Möglichkeit, diese Module zu laden.

Allerdings habe ich einige Verhaltensweisen kennen gelernt, die ich nicht verstehe.

habe ich eine SSCCE, die das Problem veranschaulicht:

├── bar.js 
├── node_modules 
│   └── foo 
│    ├── foo.js 
│    ├── index.js 
│    ├── node_modules 
│    │   └── requirejs 
│    │    ├── bin 
│    │    │   └── r.js 
│    │    ├── package.json 
│    │    ├── README.md 
│    │    └── require.js 
│    └── package.json 
└── test.js 

foo Modul ist ein Knoten, der die AMD-Modul

node_modules/foo/foo.js

define([], function() { 
    return function() { 
     console.log("This is foo!"); 
    }; 
}); 
foo.js wickelt

node_modules/foo/index.js

var requirejs = require('requirejs'); 

requirejs.config({ 
    baseUrl: __dirname, 
    nodeRequire: require 
}); 

module.exports = requirejs('foo'); 

bar.js ist eine weitere AMD-Modul:

define([], function() { 
    return function() { 
     console.log("This is bar!"); 
    }; 
}); 

test.js ist ein Skript, das sowohl foo und bar nutzen will:

var requirejs=require('requirejs'); 

requirejs.config(
    { 
     baseUrl: __dirname, 
     nodeRequire: require 
    } 
); 

var foo=require("foo"); 

foo(); 

var bar=requirejs("bar"); 

console.log("bar is:",bar); 

Wenn ich test.js laufen, bekomme ich diese:

This is foo! 
bar is: undefined 
/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:393 
     throw err; 
      ^
Error: Mismatched anonymous define() module: function() { 
     return function() { 
       console.log("This is bar!"); 
     }; 
} 
http://requirejs.org/docs/errors.html#mismatch 
    at makeError (/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:418:17) 
    at intakeDefines (/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:1501:36) 
    at null._onTimeout (/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:1699:25) 
    at Timer.listOnTimeout (timers.js:119:15) 

Es gibt zwei Dinge, die mir hier keinen Sinn ergeben.

  1. In test.js, der Aufruf von requirejs("bar") kehrt undefiniert. Tatsächlich erscheint , dass das Laden des Moduls verzögert wird, als ob es eine zirkuläre Abhängigkeit gäbe, weil es erst nach der Rückkehr die Moduldefinition für die Bar ausgeführt wird.

  2. Warum denkt es, das ist eine anonyme define()? Mein Anwendungsfall erscheint nicht , um die Kriterien in der angegebenen URL zu erfüllen.

Um die zweite Ausgabe supress ich die in bar.js definieren Namensgebung versucht, wie folgt aus:

define('bar', [], function() { 
... 

die in dem Sinne wirkt, dass die Ausnahme ist weg, aber requirejs("bar") noch kehrt undefiniert.

Das Beispiel ist eine vereinfachte Version von dem, was ich zu tun versuchen - im Grunde will ich haben eine Reihe von Modulen, die einige gemeinsame Komponenten enthalten, die in Browser verwendet werden kann und in Knoten, und einige spezifische Knotenkomponenten das wird nur in Knoten verwendet werden. Es wird Abhängigkeiten zwischen den Modulen geben.

Wenn es einen besseren Weg gibt, dann bin ich auch offen dafür.

+0

requirejs ("foo") fordert ein bereits geladenes Modul an. Versuchen Sie requirejs (["foo", "bar"], (foo, bar) => {foo() + bar()}); –

+1

@CoreyAlix nach [die requirjs node docs] (http://requirejs.org/docs/node.html) heißt es, dass man unter Knoten Module synchron mit 'requirejs (" foo ")' anfordern kann. Dies ist eine wichtige Voraussetzung, wenn Sie AMD-Module zur Verwendung in Node einbinden, da Node 'require()' synchron ist. – harmic

+0

Wo befindet sich 'bar.js' relativ zu Ihren anderen Dateien? – Louis

Antwort

0

Am Ende habe ich keine befriedigende Antwort auf dieses Problem erhalten.

Ich habe es mit amdefine umgehen, wenn Sie diese Module in der Umgebung node.js verwenden, anstatt zu versuchen, Requirejs zu verwenden.

Der Hauptnachteil dieses Ansatzes besteht darin, dass Sie an der Vorderseite aller AMD-Module ein Boilerplate hinzufügen müssen, damit sie bei Bedarf amdefine laden können, aber ansonsten funktioniert amdefine für meinen Anwendungsfall zumindest.

Ich fand auch das UMD Projekt, das einige andere Alternativen bietet.

1

Ich habe lokal den Code und die Hierarchie neu erstellt, die Sie in der Frage zeigen, aber ich bin nicht in der Lage, die genaue Fehlermeldung zu erhalten, die Sie erhalten. Ich werde sagen, wenn ich mir anschaue, was Sie in der Frage zeigen, verstehe ich nicht, wie Ihr Code zu dieser Fehlermeldung führen könnte. Wenn ich Ihren Code ausführen, ist der Fehler ich tun:

This is foo! 
/tmp/t1/node_modules/requirejs/bin/r.js:2604 
        throw err; 
        ^

Error: Tried loading "bar" at /tmp/t1/node_modules/foo/bar.js then tried node's require("bar") and it failed with error: Error: Cannot find module 'bar' 
    at /tmp/t1/node_modules/requirejs/bin/r.js:2597:27 

das ist genau das, was ich erwarten würde: RequireJS in Knoten ausgeführt werden versuchen, Knoten zu verwenden, eigene require, wenn es nicht ein Modul durch seine eigenen Maschinen finden.

Nun, das Problem, das Sie in rannte, ist kein Problem beim Ausführen von RequireJS in Node, sondern ein Problem mit der Verwendung von RequireJS. Sie könnten genau das gleiche Problem in einem Browser finden. Das Problem ist, dass Sie requirejs.config zweimal ausführen, ohne Kontexte zu verwenden, so dass eine Konfiguration die andere überschreibt. (RequireJS ist in der Lage configs zu fusionieren, aber die configs Sie verwenden sind, so dass sie sich gegenseitig überschreiben werden.) Ich den Code von test.js Wechsel zu laufen bekommen kann, so dass:

  1. Die Konfiguration von RequireJS a verwendet context Wert.

  2. Ich speichere den Rückgabewert requirejs.config und verwende dieses, um Module zu erfordern.

Das Endergebnis ist:

var requirejs=require('requirejs'); 

var r = requirejs.config(
    { 
     context: "me", 
     baseUrl: __dirname, 
     nodeRequire: require 
    } 
); 

var foo=require("foo"); 

foo(); 

var bar= r("bar"); 

console.log("bar is:",bar); 

Idealerweise ist der Code in index.js auch einen Kontext verwendet werden soll.

Dies gesagt, ich habe Code geschrieben, der in Node und dem Browser als AMD-Module seit Jahren ausgeführt wird. Es ist selten, dass ich AMD-Module mit RequireJS in Node laden muss. Ein seltener Fall, wo ich es tun möchte, ist, wenn ich prüfe, wie ein Modul seine Konfiguration durch module.config bekommt. Ich habe nie die Notwendigkeit gefunden, amdefine zu verwenden. Was ich verwende, wenn ich AMD-Module in Node laden will, ist amd-loader (alias Node-Amd-Loader). Es wird einfach in die Modullademaschinerie von Node eingebunden, um AMD-Module laden zu können. Ich vermute, der Nachteil von amd-loader ist, dass Projekte, die Ihren Code verwenden möchten, darauf angewiesen sind, einen Loader wie amd-loader installiert zu haben.