Wie kann man node.js absolut machen? (anstelle von Verwandten)


234

Ich möchte meine Dateien immer am Stamm meines Projekts und nicht relativ zum aktuellen Modul benötigen.

Wenn Sie sich beispielsweise https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js Zeile 6 ansehen, sehen Sie

express = require('../../')

Das ist wirklich schlecht, IMO. Stellen Sie sich vor, ich möchte alle meine Beispiele nur um eine Ebene näher an die Wurzel bringen. Das wäre unmöglich, da ich mehr als 30 Beispiele und viele Male in jedem Beispiel aktualisieren müsste. Dazu:

express = require('../')

Meine Lösung wäre, einen Sonderfall für root zu haben: Wenn eine Zeichenfolge mit einem $ beginnt, ist sie relativ zum Stammordner des Projekts.

Jede Hilfe wird geschätzt, danke

Update 2

Jetzt verwende ich require.js, mit dem Sie auf eine Weise schreiben können und das sowohl auf dem Client als auch auf dem Server funktioniert. Mit Require.js können Sie auch benutzerdefinierte Pfade erstellen.

Update 3

Jetzt bin ich zu Webpack + Gulp gewechselt und verwende Enhanced-Require, um Module auf der Serverseite zu handhaben. Siehe hier die Begründung: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


Wenn Sie sich jemals für eine explizite Root-Pfad-Konstante / -Variable entscheiden, funktioniert diese Antwort dafür . Die Lösung verwendet ein winziges Github-Modul, um den Root-Pfad zu bestimmen.
Steampowered

Antworten:


162

Und was ist mit:

var myModule = require.main.require('./path/to/module');

Es erfordert die Datei so, als ob sie aus der Haupt-JS-Datei benötigt würde, also funktioniert es ziemlich gut, solange sich Ihre Haupt-JS-Datei im Stammverzeichnis Ihres Projekts befindet ... und das weiß ich zu schätzen.


Keine schlechte Idee (: Sie können dann einige andere Methoden definieren, um die App in Ihrem require.main-Modul irgendwie neu zuzuordnen. Ich denke, Sie könnten dann require.main.req ('client / someMod') tun. Gute Idee, aber das wäre Seien Sie ausführlicher als meine aktuellen Anforderungen. Ich denke auch nicht, dass es sich lohnt, weil ich browserify auch nicht mag, weil Änderungen nicht sofort erfolgen und Änderungen fehlen (weil mein Code sowohl in browser als auch in node.js ausgeführt werden sollte).
Totty.js

4
Wenn Sie es zu ausführlich finden, verwenden Sie einfach .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
Cronvel

Ja, dies kann für jemanden nützlich sein, der browserify weiterhin für die Clientseite verwenden möchte. Für mich gibt es keine Notwendigkeit mehr, aber trotzdem danke für Ihre Antwort (:
Totty.js

6
WENN MAIN AN DER WURZEL IHRES PROJEKTS IST :)
Alexander Mills

12
Diese Lösung funktioniert nicht, wenn Code mit Unit-Tests wie Mokka-Test
Alx Lark

129

Es gibt einen wirklich interessanten Abschnitt im Browserify-Handbuch :

Vermeiden ../../../../../../ ..

Nicht alles in einer Anwendung gehört ordnungsgemäß zur öffentlichen npm, und der Aufwand für die Einrichtung einer privaten npm oder eines Git-Repos ist in vielen Fällen immer noch recht hoch. Hier sind einige Ansätze zur Vermeidung des ../../../../../../../Problems der relativen Pfade.

Knotenmodule

Menschen lehnen es manchmal ab, anwendungsspezifische Module in node_modules einzufügen, da es nicht offensichtlich ist, wie Sie Ihre internen Module einchecken können, ohne auch Module von Drittanbietern ab npm einzuchecken.

Die Antwort ist ganz einfach! Wenn Sie eine .gitignoreDatei haben, die Folgendes ignoriert node_modules:

node_modules

Sie können !für jedes Ihrer internen Anwendungsmodule einfach eine Ausnahme hinzufügen :

node_modules/*
!node_modules/foo
!node_modules/bar

Bitte beachten Sie, dass Sie ein Unterverzeichnis nicht aufheben können , wenn das übergeordnete Verzeichnis bereits ignoriert wird. Also statt sie zu ignorieren node_modules, müssen Sie jedes Verzeichnis ignorieren innen node_modules mit dem node_modules/*Trick, und dann können Sie Ihre Ausnahmen hinzufügen.

Jetzt überall in Ihrer Anwendung werden Sie in der Lage sein, require('foo') oder require('bar')ohne einen sehr großen und fragilen relativen Pfad aufweist.

Wenn Sie viele Module haben und diese von den von npm installierten Modulen von Drittanbietern trennen möchten, können Sie sie einfach in einem Verzeichnis ablegen, node_modulesz. B node_modules/app.:

node_modules/app/foo
node_modules/app/bar

Jetzt können Sie von require('app/foo')oder zu require('app/bar') jedem Ort in Ihrer Anwendung.

Fügen Sie in Ihrem .gitignoreeinfach eine Ausnahme hinzu für node_modules/app:

node_modules/*
!node_modules/app

Wenn in Ihrer Anwendung Transformationen in package.json konfiguriert wurden, müssen Sie eine separate package.json mit einem eigenen Transformationsfeld in Ihrem node_modules/foooder node_modules/app/fooKomponentenverzeichnis erstellen, da Transformationen nicht über Modulgrenzen hinweg angewendet werden . Dadurch werden Ihre Module robuster gegen Konfigurationsänderungen in Ihrer Anwendung und es ist einfacher, die Pakete außerhalb Ihrer Anwendung unabhängig voneinander wiederzuverwenden.

symlink

Ein weiterer praktischer Trick, wenn Sie an einer Anwendung arbeiten, in der Sie Symlinks erstellen können und Windows nicht unterstützen müssen, ist das Symlinken eines lib/ oder eines app/Ordners node_modules. Führen Sie im Projektstamm Folgendes aus:

ln -s ../lib node_modules/app

und jetzt können Sie von überall in Ihrem Projekt Dateien lib/anfordern require('app/foo.js'), indem Sie dies tun , um sie abzurufen lib/foo.js.

benutzerdefinierte Pfade

Möglicherweise wird an einigen Stellen über die Verwendung der $NODE_PATH Umgebungsvariablen oder opts.pathsdas Hinzufügen von Verzeichnissen für Node und Browserify gesprochen, um nach Modulen zu suchen.

Im Gegensatz zu den meisten anderen Plattformen ist die Verwendung eines Array von Pfadverzeichnissen im Shell-Stil mit $NODE_PATHim Knoten nicht so günstig wie die effektive Nutzung des node_modulesVerzeichnisses.

Dies liegt daran, dass Ihre Anwendung enger an eine Laufzeitumgebungskonfiguration gekoppelt ist, sodass mehr bewegliche Teile vorhanden sind und Ihre Anwendung nur funktioniert, wenn Ihre Umgebung korrekt eingerichtet ist.

Node und Browserify unterstützen beide, raten jedoch von der Verwendung von ab $NODE_PATH.


17
Der einzige Nachteil beim Einlegen in den node_modulesOrdner ist, dass es schwieriger ist, den Ordner nuke ( rm -rf node_modules) zu erstellen
Michael

13
@ Michael Nicht viel schwieriger: git clean -dx node_modules
Peter Wilkinson

3
Oder falls Sie die git cleanSyntax vergessen haben , können Sie immer rm -rf node_modules && git checkout node_modules- seien Sie sicher, git stashfalls sich Änderungen an den node_modulesUnterverzeichnissen ergeben.
Ihrio

1
Ich mag die Idee, node_modules zu verwenden, aber nicht, um den Quellcode zu speichern, wenn man bedenkt, wie flüchtig er sein kann. Wäre es nicht sinnvoller, das getrennte Modul zu veröffentlichen und als Abhängigkeit im ursprünglichen Projekt zu speichern? Es bietet eine klare Lösung für die Volatilität des Verzeichnisses node_modules und stützt sich nur auf npm, anstatt auf git, symbolische Links oder die $ NODE_PATH-Lösung.
Kevin Koshiol

1
NODE_PATH scheint der richtige Weg zu sein. "Ihre Anwendung funktioniert nur, wenn Ihre Umgebung korrekt eingerichtet ist" Dies ist immer wahr! Ist es nicht einfacher, die Umgebung einzurichten (normalerweise in einer Datei), als jeden Import in jeder Datei zu ändern?
CpILL

73

Ich mag es, einen neuen node_modulesOrdner für gemeinsam genutzten Code zu erstellen, dann Knoten und Anforderung das tun zu lassen, was er am besten kann.

beispielsweise:

- node_modules // => these are loaded from your package.json
- app
  - node_modules // => add node-style modules
    - helper.js
  - models
    - user
    - car
- package.json
- .gitignore

Zum Beispiel, wenn Sie in sind car/index.js, können Sie require('helper')und Knoten wird es finden!

Funktionsweise von node_modules

Der Knoten verfügt über einen cleveren Algorithmus zum Auflösen von Modulen, der unter den Konkurrenzplattformen einzigartig ist.

Wenn Sie require('./foo.js')von kommen /beep/boop/bar.js, sucht der Knoten nach ./foo.jsin /beep/boop/foo.js. Pfade, die mit einem ./oder beginnen, ../sind immer lokal für die aufrufende Datei require().

Wenn Sie jedoch einen nicht relativen Namen wie require('xyz')from benötigen /beep/boop/foo.js, durchsucht der Knoten diese Pfade der Reihe nach, stoppt bei der ersten Übereinstimmung und löst einen Fehler aus, wenn nichts gefunden wird:

/beep/boop/node_modules/xyz
/beep/node_modules/xyz
/node_modules/xyz

Für jedes vorhandene xyzVerzeichnis sucht der Knoten zuerst nach a, xyz/package.jsonum festzustellen, ob ein "main"Feld vorhanden ist. Das "main"Feld definiert, welche Datei die Verantwortung übernehmen soll, wenn Sie require()den Verzeichnispfad angeben.

Zum Beispiel, wenn /beep/node_modules/xyzes das erste Spiel ist und /beep/node_modules/xyz/package.jsonhat:

{
  "name": "xyz",
  "version": "1.2.3",
  "main": "lib/abc.js"
}

dann werden die Exporte von /beep/node_modules/xyz/lib/abc.jszurückgegeben von require('xyz').

Wenn kein package.jsonoder kein "main"Feld vorhanden ist, index.jswird angenommen:

/beep/node_modules/xyz/index.js

2
Tolle Erklärung, wie es beim Laden eines Moduls
funktioniert

2
Dies ist eine sehr elegante Lösung, die alle Probleme in den obigen Antworten vermeidet. Sollte die Antwort in Betracht ziehen, imho.
Rodurico

38

Das große Bild

Es scheint "wirklich schlecht", aber gib ihm Zeit. Es ist in der Tat wirklich gut. Die expliziten require()s bieten eine vollständige Transparenz und ein leichtes Verständnis, das wie ein Hauch frischer Luft während eines Projektlebenszyklus ist.

Stellen Sie sich das so vor: Sie lesen ein Beispiel, tauchen Ihre Zehen in Node.js ein und haben entschieden, dass es "wirklich schlechte IMO" ist. Sie sind zweitwichtigste Anführer der Node.js-Community, Leute, die mehr Stunden als jeder andere protokolliert haben, um Node.js-Anwendungen zu schreiben und zu warten. Wie groß ist die Chance, dass der Autor einen solchen Anfängerfehler gemacht hat? (Und ich stimme zu, aus meinem Ruby- und Python-Hintergrund scheint es zunächst eine Katastrophe zu sein.)

Es gibt viel Hype und Gegenhype um Node.js. Wenn sich der Staub gelegt hat, werden wir anerkennen, dass explizite Module und "local first" -Pakete ein wesentlicher Treiber für die Einführung waren.

Der häufige Fall

Natürlich wird node_modulesaus dem aktuellen Verzeichnis nach dem Elternteil, dann nach dem Großelternteil, dem Urgroßelternteil usw. gesucht. Von Ihnen installierte Pakete funktionieren also bereits auf diese Weise. Normalerweise können Sie require("express")von überall in Ihrem Projekt und es funktioniert gut.

Wenn Sie häufig verwendete Dateien aus dem Stammverzeichnis Ihres Projekts laden (möglicherweise, weil es sich um allgemeine Dienstprogrammfunktionen handelt), ist dies ein wichtiger Hinweis darauf, dass es Zeit ist, ein Paket zu erstellen. Pakete sind sehr einfach: Verschieben Sie Ihre Dateien in node_modules/und legen Sie eine package.json dort ab. Voila! Auf alles in diesem Namespace kann von Ihrem gesamten Projekt aus zugegriffen werden. Pakete sind der richtige Weg, um Ihren Code in einen globalen Namespace zu bringen.

Andere Problemumgehungen

Ich persönlich benutze diese Techniken nicht, aber sie beantworten Ihre Frage, und natürlich kennen Sie Ihre eigene Situation besser als ich.

Sie können $NODE_PATHIhr Projektstammverzeichnis festlegen . Dieses Verzeichnis wird bei Ihnen durchsucht require().

Als nächstes könnten Sie eine gemeinsame lokale Datei für alle Ihre Beispiele kompromittieren und benötigen. Diese allgemeine Datei exportiert einfach die wahre Datei im Großelternverzeichnis erneut.

Beispiele / Downloads / app.js (und viele andere mögen es)

var express = require('./express')

Beispiele / Downloads / express.js

module.exports = require('../../')

Wenn Sie diese Dateien verschieben, wird im schlimmsten Fall das eine Shim- Modul repariert .


14
Ich bin damit einverstanden, dass die Jungs von Node.js aus einem bestimmten Grund einen relativen Bedarf gewählt haben müssen. Ich kann seine Vorteile einfach nicht erkennen, auch nicht aus Ihrer Antwort. Es fühlt sich immer noch "schlecht" für mich an;)
Adam Schmideg

21
„Sie sind zweitrangige Anführer der Node.js-Community“ - Dieselben Führungskräfte haben beschlossen, Rückrufe anstelle von Futures / Versprechungen zu verwenden. Die Mehrheit meiner Nodejs-Beratung besteht darin, die "Führer" zu verfluchen und die Leute davon zu überzeugen, zu JVM zu wechseln. Was nach ein paar Monaten mit nodejs viel einfacher ist :)
David Sergey

8
@nirth, zu JVM wechseln? Um Gottes willen, warum?
Ivancho

31
"Sie sind zweitrangige Anführer der Node.js-Community", vermeiden Sie bitte diesen gedankenentmutigenden Ton.
Atlex2

15
Verdammt richtig, er ist der zweite erratende Knotenführer. So entwickelt sich die Branche. Wenn die Node-Jungs die Anführer, die threadbasierte Parallelitätsmodelle gestützt haben, nicht erraten hätten, hätten wir keinen Node.
d512

20

Schauen Sie sich node-rfr an .

So einfach ist das:

var rfr = require('rfr');
var myModule = rfr('projectSubDir/myModule');

Ich denke, die zweite Zeile sollte var myModule = rfr ('/ projectSubDir / myModule') sein.
Sikorski

1
Aus den Dokumenten: var module2 = rfr ('lib / module2'); // Führender Schrägstrich kann weggelassen werden.
igelineau

Ich habe es versucht und es funktioniert in Ordnung, um es mit dem Knoten auszuführen, aber es unterbricht die Code-Navigation mit VS-Code ... Ich konnte keine
Problemumgehung

13

Wenn Sie Garn anstelle von npm verwenden , können Sie Arbeitsbereiche verwenden .

Angenommen, ich habe einen Ordner, den servicesich einfacher benötigen möchte:

.
├── app.js
├── node_modules
├── test
├── services
   ├── foo
   └── bar
└── package.json

Um einen Garnarbeitsbereich zu erstellen, erstellen Sie eine package.jsonDatei in services folder:

{
  "name": "myservices",
  "version": "1.0.0"
}

Fügen Sie in Ihrem Hauptpaket.json Folgendes hinzu:

"private": true,
"workspaces": ["myservices"]

Führen Sie yarn installvom Stammverzeichnis des Projekts aus.

Dann können Sie überall in Ihrem Code Folgendes tun:

const { myFunc } = require('myservices/foo')

statt so etwas wie:

const { myFunc } = require('../../../../../../services/foo')

6
Vielleicht ist es eine Idee zu klären, dass dies nur für Garn funktioniert , nicht für npm? Ich rechnete damit, dass es wahrscheinlich auch für npm funktionieren würde, also fragte ich mich ein wenig, was ich falsch gemacht hatte, bis ich versuchte, stattdessen Garn zu verwenden. Könnte eine dumme Annahme gewesen sein, aber vielleicht bin ich nicht der einzige.
ArneHugo

2
Ich habe ein bisschen bearbeitet, um zu klären. Entschuldigung für die Verwirrung.
Cyberwombat

12

IMHO ist der einfachste Weg, Ihre eigene Funktion als Teil des GLOBALObjekts zu definieren . Erstellen Sie projRequire.jsim Stammverzeichnis Ihres Projekts den folgenden Inhalt:

var projectDir = __dirname;

module.exports = GLOBAL.projRequire = function(module) {
  return require(projectDir + module);
}

In Ihrer Hauptdatei, bevor requireSie eines der projektspezifischen Module verwenden:

// init projRequire
require('./projRequire');

Danach funktioniert folgendes für mich:

// main file
projRequire('/lib/lol');

// index.js at projectDir/lib/lol/index.js
console.log('Ok');


@Totty, ich habe mir eine andere Lösung ausgedacht, die für den Fall funktionieren könnte, dass Sie in den Kommentaren beschrieben haben. Die Beschreibung wird sein tl;dr, also zeige ich besser ein Bild mit der Struktur meines Testprojekts .


Nun, bis jetzt scheint dies der beste Weg zu sein. Ich mache: GLOBAL.requires = require ('r'). R; in meiner index.js Datei. Aber ich habe ein Problem mit meinen Gelübde-Tests. Sie führen index.js nicht aus, sodass meine Tests fehlschlagen, weil es undefiniert ist. Jedenfalls kann ich jetzt GLOBAL.requires = require ('r') hinzufügen. R; an der Spitze jedes Tests. eine bessere Idee? github.com/totty90/production01_server/commit/…
Totty.js


Das Problem tritt auf, wenn ich mich in "pathes-test / node_modules / other.js" befinde und den "pathes-test / node_modules / some.js" benötige. Ich sollte ('./ some') anstelle von ("prj / some") benötigen. Und auf diese Weise wäre meine gesamte App im Verzeichnis node_modules?
Totty.js

@Totty, kein Problem erforderlich prj/somevon prj/other(nur getestet require('prj/some'). Alle gängigen Module Ihrer App können dorthin gehen (z. B. Datenbankebene). Wird keinen Unterschied machen, wo Ihr, sagen wir, libist. Versuchen Sie zu sehen, ob es passt.
Aleksei Zabrodskii

yest, ich habe es aktualisiert: github.com/totty90/production01_server/tree/master/node_modules/… das hat super funktioniert. Aber ich kann alle meine Dateien auf eine Ebene bringen, ohne die node_modules zu verwenden?
Totty.js

12

Ich benutze process.cwd()in meinen Projekten. Beispielsweise:

var Foo = require(process.cwd() + '/common/foo.js');

Es könnte erwähnenswert sein, dass dies zu requireeinem absoluten Weg führen wird, obwohl ich noch keine Probleme damit habe.


1
Das ist eine schlechte Idee, da CWD nicht dasselbe Verzeichnis sein muss, in dem die Anwendung gespeichert ist.
Jiwopene

11

Es gibt eine gute Diskussion zu diesem Thema hier .

Ich hatte das gleiche Architekturproblem: Ich wollte meiner Anwendung mehr Organisation und interne Namespaces geben, ohne:

  • Anwendungsmodule mit externen Abhängigkeiten mischen oder sich mit privaten npm-Repos für anwendungsspezifischen Code beschäftigen
  • Die Verwendung relativer Anforderungen erschwert das Refactoring und das Verständnis
  • Verwenden von Symlinks oder Ändern des Knotenpfads, wodurch die Quellpositionen verdeckt werden und die Quellcodeverwaltung nicht gut funktioniert

Am Ende habe ich beschlossen, meinen Code mithilfe von Dateinamenkonventionen anstelle von Verzeichnissen zu organisieren. Eine Struktur würde ungefähr so ​​aussehen:

  • npm-shrinkwrap.json
  • package.json
  • Knotenmodule
    • ...
  • src
    • app.js.
    • app.config.js
    • app.models.bar.js
    • app.models.foo.js
    • app.web.js
    • app.web.routes.js
    • ...

Dann im Code:

var app_config = require('./app.config');
var app_models_foo = require('./app.models.foo');

oder nur

var config = require('./app.config');
var foo = require('./app.models.foo');

und externe Abhängigkeiten sind wie gewohnt von node_modules verfügbar:

var express = require('express');

Auf diese Weise wird der gesamte Anwendungscode hierarchisch in Modulen organisiert und steht allen anderen Codes relativ zum Anwendungsstamm zur Verfügung.

Der Hauptnachteil ist natürlich, dass Sie in einem Dateibrowser den Baum nicht so erweitern / reduzieren können, als ob er tatsächlich in Verzeichnissen organisiert wäre. Aber ich mag es, dass es sehr explizit ist, woher der gesamte Code kommt, und dass es keine "Magie" verwendet.


Nach dem Kern, den Sie verlinkt haben, ist Lösung Nr. 7, "The Wrapper", recht einfach und bequem.
Pier-Luc Gendreau

Ich sehe noch eine kleine Bequemlichkeit - das "Verschieben" einer Datei in einen anderen "Ordner" wird zum Umbenennen - was einfacher ist als das Verschieben von Dateien. Außerdem fällt mir auf, dass nach einer halben Stunde Projektarbeit fast mein gesamter App-Baum ohnehin erweitert wird. Durch Hinzufügen von 1 Ebene Ordnerbereich kann eine große Codebasis verwaltet werden, und es wird nicht zu viel eingeführt, ../x/xwas bereits lesbar ist.
Ski

Sie erfinden Ordner neu, indem Sie Punkte anstelle von Schrägstrichen verwenden, um einen deutlichen Mangel an NodeJs zu beheben.
Simone Gianni

9

Angenommen, Ihr Projektstamm ist das aktuelle Arbeitsverzeichnis, sollte dies funktionieren:

// require built-in path module
path = require('path');

// require file relative to current working directory
config = require( path.resolve('.','config.js') );

config = require('./config.js');ist auch gültig.
Cespon

7
@cespon nein, das ist nur relativ zu der Datei, die benötigt wird.
Protometa

8

Ich habe viele dieser Lösungen ausprobiert. Am Ende habe ich dies oben in meiner Hauptdatei hinzugefügt (z. B. index.js):

process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();

Dadurch wird der Projektstamm zum NODE_PATH hinzugefügt, wenn das Skript geladen wird. Dadurch kann ich jede Datei in meinem Projekt anfordern, indem ich auf ihren relativen Pfad vom Projektstamm verweise, z var User = require('models/user'). Diese Lösung sollte funktionieren, solange Sie ein Hauptskript im Projektstamm ausführen, bevor Sie etwas anderes in Ihrem Projekt ausführen.


8

Einige der Antworten besagen, dass der beste Weg darin besteht, den Code als Paket zum node_module hinzuzufügen. Ich stimme zu und es ist wahrscheinlich der beste Weg, die Anforderungen zu verlieren ../../../, aber keiner von ihnen gibt tatsächlich einen Weg dazu.

Ab Version können 2.0.0Sie ein Paket aus lokalen Dateien installieren. Dies bedeutet, dass Sie in Ihrem Stammverzeichnis einen Ordner mit allen gewünschten Paketen erstellen können.

-modules
 --foo
 --bar 
-app.js
-package.json

In package.json können Sie das modules(oder foound bar) als Paket hinzufügen , ohne einen externen Server wie folgt zu veröffentlichen oder zu verwenden:

{
  "name": "baz",
  "dependencies": {
    "bar": "file: ./modules/bar",
    "foo": "file: ./modules/foo"
  }
}

Danach npm installkönnen Sie auf den Code zugreifen var foo = require("foo"), genau wie bei allen anderen Paketen.

Weitere Infos finden Sie hier:

https://docs.npmjs.com/files/package.json#local-paths

und hier, wie man ein Paket erstellt:

https://docs.npmjs.com/getting-started/creating-node-modules


1
"Diese Funktion ist hilfreich für die lokale Offline-Entwicklung und das Erstellen von Tests, für die eine npm-Installation erforderlich ist, bei der Sie keinen externen Server erreichen möchten, die jedoch nicht zum Veröffentlichen von Paketen in der öffentlichen Registrierung verwendet werden sollte."
Ryan Smith

7

Sie könnten ein Modul verwenden, das ich erstellt habe, Undot . Es ist nichts Fortgeschrittenes, nur ein Helfer, damit Sie diese Punkthölle mit Einfachheit vermeiden können.

Beispiel:

var undot = require('undot');
var User = undot('models/user');
var config = undot('config');
var test = undot('test/api/user/auth');

6

Sie könnten so etwas in Ihrer app.js definieren:

requireFromRoot = (function(root) {
    return function(resource) {
        return require(root+"/"+resource);
    }
})(__dirname);

und wann immer Sie etwas von der Wurzel benötigen möchten, egal wo Sie sich befinden, verwenden Sie einfach requireFromRoot anstelle der Vanille-Anforderung. Funktioniert bisher ziemlich gut für mich.


Vielen Dank! Ich finde das ziemlich schlau und unkompliziert.
Ryan

Vergib mir Vater, denn ich habe gesündigt. Ich habe dies auf ES6 portiert und Folgendes erhalten : requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Ich liebe die Lösung, aber müssen Sie wirklich __dirname so binden?
Nuck

1
Mein Gedächtnis ist diesbezüglich etwas verschwommen, aber ich glaube, __dirname ändert den Wert abhängig davon, in welcher Datei er verwendet wird. Nun mag es sein, dass, da die Funktion an einer einzelnen Stelle definiert ist, aber an mehreren Stellen verwendet wird, der Wert auch ohne diese Bindung konstant bleibt, aber ich habe dies nur getan, um sicherzustellen, dass dies tatsächlich der Fall ist.
user1417684

tat dies vor langer Zeit, verursacht Schmerzen beim Testen von Envs und dergleichen. den Aufwand nicht wert. zufällige neue globale macht neue Leute unsicher bla bla
The Dembinski

Und wie funktioniert requirediese Funktion?
Darko Maksimovic

5

Hier ist die tatsächliche Art und Weise, wie ich es seit mehr als 6 Monaten mache. Ich verwende einen Ordner mit dem Namen node_modules als Stammordner im Projekt. Auf diese Weise sucht er immer von überall nach diesem Ordner, den ich als absolut erforderlich bezeichne:

  • Knotenmodule
    • Mein Projekt
      • index.js kann ich benötigen ("myProject / someFolder / hey.js") anstatt erfordern ("./ someFolder / hey.js")
      • someFolder, der hey.js enthält

Dies ist nützlicher, wenn Sie in Ordnern verschachtelt sind und das Ändern eines Dateispeicherorts viel weniger Arbeit erfordert, wenn dies absolut festgelegt ist. Ich verwende in meiner gesamten App nur 2 der relativen Anforderungen .


4
Ich benutze ähnlichen Ansatz, mit der Ausnahme , dass ich lokal (Projekt) hinzufügen node_modulesin /srcund lasse /node_modulesfür Anbieter Dinge getrennt zu halten. Also habe ich /src/node_modulesfür lokalen Code und /node_modulesfür Anbieter.
Marius Balčytis

33
IMHO ist der Ordner node_modules nur für node_modules. Es ist keine gute Praxis, Ihr gesamtes Projekt in diesem Ordner abzulegen.
McSas

2
@ McSas, was würden Sie als Alternative vorschlagen, um den gleichen Effekt wie oben zu erzielen?
Spieglio

3
@cspiegl Sie können die NODE_PATHUmgebungsvariable
Christopher Tarquini

5

Imho ist der einfachste Weg, dies zu erreichen, indem node_modules/appSie beim Start der App unter (oder wie auch immer Sie es nennen) einen symbolischen Link erstellen, der darauf verweist ../app. Dann können Sie einfach anrufen require("app/my/module"). Symbolische Links sind auf allen wichtigen Plattformen verfügbar.

Sie sollten Ihre Daten jedoch weiterhin in kleinere, wartbare Module aufteilen, die über npm installiert werden. Sie können Ihre privaten Module auch über git-url installieren, sodass es keinen Grund gibt, ein monolithisches App-Verzeichnis zu haben.


Die Unterstützung unter Windows erfordert genauere Kenntnisse über Node und das Betriebssystem. Dies kann die weit verbreitete Verwendung eines Open Source-Projekts einschränken.
Steven Vachon

Im Allgemeinen würde ich dieses Muster nicht für eine Bibliothek verwenden (was die meisten Open Source-Projekte sind). Es ist jedoch möglich, diese Symlinks im npm-Build-Hook zu erstellen, sodass der Benutzer keine detaillierten Kenntnisse benötigt.
Johannes Ewald

Sicher, aber Node.js unter Windows unterstützt standardmäßig keine Symlinks.
Steven Vachon

4

In Ihrem eigenen Projekt können Sie jede im Stammverzeichnis verwendete .js-Datei ändern und ihren Pfad zu einer Eigenschaft der process.envVariablen hinzufügen . Beispielsweise:

// in index.js
process.env.root = __dirname;

Danach können Sie überall auf die Unterkunft zugreifen:

// in app.js
express = require(process.env.root);

4

Eine andere Antwort:

Stellen Sie sich diese Ordnerstruktur vor:

  • Knotenmodule
    • lodash
  • src
    • Unterverzeichnis
      • foo.js
      • bar.js
    • main.js
  • Tests

    • test.js

Dann müssen Sie in test.js Dateien wie diese benötigen:

const foo = require("../src/subdir/foo");
const bar = require("../src/subdir/bar");
const main = require("../src/main");
const _ = require("lodash");

und in main.js :

const foo = require("./subdir/foo");
const bar = require("./subdir/bar");
const _ = require("lodash");

Jetzt können Sie damit babel und den babel-plugin-module-resolver verwenden . babelrc- Datei zum Konfigurieren von 2 Stammordnern :

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }]
    ]
}

Jetzt können Sie Dateien in Tests und in src auf dieselbe Weise anfordern :

const foo = require("foo");
const bar = require("bar");
const main = require("main");
const _ = require("lodash");

und wenn Sie die Syntax des es6-Moduls verwenden möchten :

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }],
        "transform-es2015-modules-commonjs"
    ]
}

dann importieren Sie Dateien in Tests und src wie folgt :

import foo from "foo"
import bar from "bar"
import _ from "lodash"


3

Konnte das examplesVerzeichnis nicht node_modulesein Symbol mit einem symbolischen Link zum Stammverzeichnis des Projekts enthalten, project -> ../../sodass die Beispiele verwendet werden können require('project'), obwohl dies die Zuordnung nicht entfernt, sondern die Verwendung der Quelle require('project')anstelle von ermöglicht require('../../').

Ich habe dies getestet und es funktioniert mit v0.6.18.

Auflistung des projectVerzeichnisses:

$ ls -lR project
project:
drwxr-xr-x 3 user user 4096 2012-06-02 03:51 examples
-rw-r--r-- 1 user user   49 2012-06-02 03:51 index.js

project/examples:
drwxr-xr-x 2 user user 4096 2012-06-02 03:50 node_modules
-rw-r--r-- 1 user user   20 2012-06-02 03:51 test.js

project/examples/node_modules:
lrwxrwxrwx 1 user user 6 2012-06-02 03:50 project -> ../../

Der Inhalt von index.jsweist einer Eigenschaft des exportsObjekts einen Wert zu und ruft console.logmit einer Nachricht auf, die angibt, dass dies erforderlich war. Der Inhalt von test.jsist require('project').


Können Sie bitte den Quellcode Ihres Tests anzeigen? gut, und es würde funktionieren, wenn ich auf diese Weise ('project.a') benötigen müsste?
Totty.js

Was meinst du damit require('project.a')? Ich denke das könnte bedeuten require('project/a'), obwohl require('project').aes auch möglich ist?
Dan D.

Aber mit Ihrem Beispiel müsste ich diese Ordner in jedem Ordner erstellen, in dem es ein Modul gibt, das die Methode require benötigt. Auf jeden Fall müssten Sie sich je nach Ordner um die Zeiten von "../" kümmern.
Totty.js

Tatsächlich müsste sich der Link nur in einem node_modulesVerzeichnis im nächstgelegenen übergeordneten Element der Datei befinden, und der Link wäre dann für beide gleich. Siehe nodejs.org/api/…
Dan D.

Und wäre relativ von diesem Ort. Zum Beispiel : project/node_modules/project -> ../.
Dan D.

2

Wenn jemand nach einem anderen Weg sucht, um dieses Problem zu umgehen, ist hier mein eigener Beitrag zu den Bemühungen:

https://www.npmjs.com/package/use-import

Die Grundidee: Sie erstellen eine JSON-Datei im Stammverzeichnis des Projekts, die Ihre Dateipfade Kurznamen zuordnet (oder lassen Sie use-automapper dies für Sie tun). Sie können dann Ihre Dateien / Module unter diesen Namen anfordern. Wie so:

var use = require('use-import');
var MyClass = use('MyClass');

Da ist also das.


2

Was ich gerne mache, ist zu nutzen, wie Knoten aus dem Verzeichnis node_module geladen werden.

Wenn man versucht, das Modul "Ding" zu laden, würde man so etwas tun

require('thing');

Der Knoten sucht dann im Verzeichnis 'node_module' nach dem Verzeichnis 'thing'.

Da sich das node_module normalerweise im Stammverzeichnis des Projekts befindet, können wir diese Konsistenz nutzen. (Wenn sich node_module nicht an der Wurzel befindet, müssen Sie mit anderen selbst verursachten Kopfschmerzen umgehen.)

Wenn wir in das Verzeichnis gehen und es dann wieder verlassen, können wir einen konsistenten Pfad zum Stammverzeichnis des Knotenprojekts erhalten.

require('thing/../../');

Wenn wir dann auf das Verzeichnis / happy zugreifen möchten, würden wir dies tun.

require('thing/../../happy');

Obwohl es ziemlich hackig ist, denke ich, dass es größere Probleme geben wird, wenn sich die Funktionalität des Ladens von node_modules ändert. Dieses Verhalten sollte konsistent bleiben.

Um die Dinge klar zu machen, mache ich das, weil der Name des Moduls keine Rolle spielt.

require('root/../../happy');

Ich habe es kürzlich für angle2 verwendet. Ich möchte einen Dienst aus dem Stammverzeichnis laden.

import {MyService} from 'root/../../app/services/http/my.service';

Über Ihre Angular-Referenz können Sie mit einer Standard-CLI-Anwendung einfach importieren src/app/my.serviceund VSC so konfigurieren, dass nicht relative Importe für Typoskriptdateien verwendet werden.
Ploppy

2

Ich habe dieses kleine Paket geschrieben, mit dem Sie Pakete anhand ihres relativen Pfads vom Projektstamm anfordern können, ohne globale Variablen einzuführen oder Knotenstandards zu überschreiben

https://github.com/Gaafar/pkg-require

Es funktioniert so

// create an instance that will find the nearest parent dir containing package.json from your __dirname
const pkgRequire = require('pkg-require')(__dirname);

// require a file relative to the your package.json directory 
const foo = pkgRequire('foo/foo')

// get the absolute path for a file
const absolutePathToFoo = pkgRequire.resolve('foo/foo')

// get the absolute path to your root directory
const packageRootPath = pkgRequire.root()

Manchmal habe ich private Pakete im Hauptprojekt, dieses Skript bricht damit. Darüber hinaus bin ich mir nicht sicher, ob es mit Webpack gut funktioniert (falls Sie Webpack mit node.js wie ich verwenden)
Totty.js

Wenn Sie verschachtelte Verzeichnisse mit Paketdateien haben, kann jedes Verzeichnis nur Dateien in seinem Paket benötigen. Ist das nicht das Verhalten, das Sie wollen? Ich habe nicht mit Webpack getestet.
Gafi

Dies funktionierte perfekt für ein einfaches Projekt und ist weitaus einfacher als alle anderen Antworten.
Byxor

2

Ich möchte nur die großartige Antwort von Paolo Moretti und Browserify weiterverfolgen. Wenn Sie einen Transpiler (z. B. Babel, Typoskript) verwenden und separate Ordner für Quellcode und transpilierten Code wie src/und haben dist/, können Sie eine Variation der Lösungen als verwenden

Knotenmodule

Mit folgender Verzeichnisstruktur:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app
        ... // source code
  dist
    node_modules
      app
        ... // transpiled code

Sie können dann babel etc srcVerzeichnis zu distVerzeichnis transpilieren lassen .

symlink

Mit symlink können wir einige Verschachtelungsebenen beseitigen:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app // symlinks to '..'
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

Eine Einschränkung mit babel --copy-files Die --copy-filesFlagge von babelgeht nicht gut mit Symlinks um. Möglicherweise navigiert es weiter in den ..Symlink und sieht wiederholt endlose Dateien. Eine Problemumgehung besteht darin, die folgende Verzeichnisstruktur zu verwenden:

app
  node_modules
    app // symlink to '../src'
    ... // normal npm dependencies for app
  src
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

Auf diese Weise wurde der Code unter srcweiterhin appaufgelöst src, während babel keine Symlinks mehr sehen würde.


Danke, aber ich würde diese Magie nicht empfehlen. Zuerst verlieren Sie alle Importe, sie werden von Ihrer IDE nicht berechnet. Wenn Sie andere Tools wie den Flusstyp verwenden, funktioniert dies auch nicht richtig.
Totty.js

Tatsächlich scheint der Fluss in meinem Fall zu funktionieren, was nicht überraschend ist, da die Lösungen vom Standardmodell der Knotenmodulauflösung und von Symlinks abhängen. Es ist also nicht wirklich magisch, Werkzeuge wie Flow zu verstehen. IDEs sind jedoch unterschiedlich.
user716468

2

Ich suchte nach genau der gleichen Einfachheit, um Dateien von jeder Ebene zu benötigen, und fand einen Modul-Alias .

Einfach installieren:

npm i --save module-alias

Öffnen Sie Ihre package.json-Datei. Hier können Sie Aliase für Ihre Pfade hinzufügen, z

"_moduleAliases": {
 "@root"      : ".", // Application's root
 "@deep"      : "src/some/very/deep/directory/or/file",
 "@my_module" : "lib/some-file.js",
 "something"  : "src/foo", // Or without @. Actually, it could be any string
}

Und verwenden Sie Ihre Aliase einfach durch:

require('module-alias/register')
const deep = require('@deep')
const module = require('something')


1

Wir sind dabei, einen neuen Weg zu finden, um dieses Problem anzugehen.

Anhand von Beispielen aus anderen bekannten Projekten wie Spring und Guice definieren wir ein "Kontext" -Objekt, das alle "require" -Anweisungen enthält.

Dieses Objekt wird dann zur Verwendung an alle anderen Module übergeben.

Beispielsweise

var context = {}

context.module1 = require("./module1")( { "context" : context } )
context.module2 = require("./module2")( { "context" : context } )

Dies erfordert, dass wir jedes Modul als eine Funktion schreiben, die Optionen empfängt, was für uns ohnehin eine bewährte Methode ist.

module.exports = function(context){ ... }

und dann werden Sie sich auf den Kontext beziehen, anstatt Dinge zu benötigen.

var module1Ref = context.moduel1;

Wenn Sie möchten, können Sie einfach eine Schleife schreiben, um die erforderlichen Anweisungen auszuführen

var context = {};
var beans = {"module1" : "./module1","module2" : "./module2" }; 
for ( var i in beans ){
    if ( beans.hasOwnProperty(i)){
         context[i] = require(beans[i])(context);
    }
};

Dies sollte das Leben erleichtern, wenn Sie verspotten möchten (Tests), und Ihr Problem auf dem Weg lösen, während Ihr Code als Paket wiederverwendbar wird.

Sie können den Kontextinitialisierungscode auch wiederverwenden, indem Sie die Beans-Deklaration davon trennen. Zum Beispiel main.jskönnte Ihre Datei so aussehen

var beans = { ... }; // like before
var context = require("context")(beans); // this example assumes context is a node_module since it is reused.. 

Diese Methode gilt auch für externe Bibliotheken. Sie müssen ihre Namen nicht jedes Mal fest codieren, wenn wir sie benötigen. Sie müssen jedoch speziell behandelt werden, da ihre Exporte keine Funktionen sind, die einen Kontext erwarten.

Später können wir Beans auch als Funktionen definieren, die es uns ermöglichen, requireje nach Umgebung unterschiedliche Module zu verwenden, die jedoch außerhalb des Bereichs dieses Threads liegen.


1

Ich hatte Probleme mit demselben Problem und schrieb ein Paket namens include .

Fügen Sie Handles ein, die den Stammordner Ihres Projekts ermitteln, indem Sie Ihre Datei package.json suchen, und übergeben Sie dann das von Ihnen angegebene Pfadargument an das native require (), ohne das gesamte relative Pfadproblem. Ich stelle mir dies nicht als Ersatz für require () vor, sondern als Tool für die Verarbeitung nicht gepackter Dateien oder Bibliotheken von Drittanbietern. Etwas wie

var async = require('async'),
    foo   = include('lib/path/to/foo')

Ich hoffe das kann nützlich sein.


1

Wenn sich die js-Einstiegspunktdatei Ihrer App (dh die, auf der Sie tatsächlich "node" ausführen) in Ihrem Projektstammverzeichnis befindet, können Sie dies ganz einfach mit dem rootpath npm-Modul tun . Einfach über installieren

npm install --save rootpath

... dann ganz oben in der js-Datei des Einstiegspunkts hinzufügen:

require('rootpath')();

Ab diesem Zeitpunkt sind alle erforderlichen Aufrufe nun relativ zum Projektstamm - z. B. require('../../../config/debugging/log'); wird require('config/debugging/log');(wo sich der Konfigurationsordner im Projektstamm befindet).


1

In einfachen Zeilen können Sie Ihren eigenen Ordner als Modul aufrufen:

Dafür benötigen wir: globales und App-Modul-Pfad-Modul

Hier ist "App-Modul-Pfad" das Modul, mit dem Sie dem Suchpfad des Node.js-Moduls zusätzliche Verzeichnisse hinzufügen können. Und "global" ist, dass alles, was Sie an dieses Objekt anhängen, überall in Ihrer App verfügbar ist.

Schauen Sie sich jetzt diesen Ausschnitt an:

global.appBasePath = __dirname;

require('app-module-path').addPath(appBasePath);

__dirname ist das aktuell laufende Verzeichnis des Knotens. Sie können hier Ihren eigenen Pfad angeben, um den Pfad nach dem Modul zu durchsuchen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.