Come rendere node.js necessario assoluto? (anziché relativo)


234

Vorrei richiedere i miei file sempre dalla radice del mio progetto e non rispetto al modulo corrente.

Ad esempio, se guardi https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js linea 6 vedrai

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

È davvero un cattivo IMO. Immagina che vorrei mettere tutti i miei esempi più vicini alla radice solo di un livello. Sarebbe impossibile, perché dovrei aggiornare più di 30 esempi e molte volte all'interno di ogni esempio. A questa:

express = require('../')

La mia soluzione sarebbe quella di avere un caso speciale per root: se una stringa inizia con $ allora è relativa alla cartella principale del progetto.

Qualsiasi aiuto è apprezzato, grazie

Aggiornamento 2

Ora sto usando request.js che ti permette di scrivere in un modo e funziona sia sul client che sul server. Require.js ti consente anche di creare percorsi personalizzati.

Aggiornamento 3

Ora sono passato a webpack + gulp e utilizzo un servizio avanzato per gestire i moduli sul lato server. Vedi qui la logica: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


Se decidi di usare una costante / variabile esplicita per il percorso di root, questa risposta funziona per questo . La soluzione utilizza un piccolo modulo github per determinare il percorso di root.
potenziato a vapore l'

Risposte:


162

E che mi dici di:

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

Richiede il file come se fosse richiesto dal file js principale, quindi funziona abbastanza bene fintanto che il tuo file js principale è alla radice del tuo progetto ... ed è qualcosa che apprezzo.


Non è una cattiva idea (: puoi quindi definire alcuni altri metodi per rimappare in qualche modo l'app nel tuo modulo request.main. Penso che potresti quindi richiedere.main.req ('client / someMod'). Bella idea, ma questo sarebbe essere più prolisso dei miei attuali requestjs. Inoltre non credo valga la pena perché non mi piace anche browserify perché le modifiche non sono istantanee e mancano le modifiche (perché il mio codice dovrebbe essere eseguito sia in browser che node.js).
Totty.js

4
Se lo trovi troppo dettagliato, usa semplicemente .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel

sì, questo può essere utile per qualcuno che vuole ancora usare browserify per il lato client. Per me non ce n'è più bisogno, ma grazie comunque per la risposta (:
Totty.js

6
SE PRINCIPALE È AL ROOT DEL TUO PROGETTO :)
Alexander Mills

12
Questa soluzione non funzionerà se il codice è coperto da test unitari come Mocha test
alx lark,

129

C'è una sezione davvero interessante nel Manuale di Browserify :

evitando ../../../../../../ ..

Non tutto in un'applicazione appartiene correttamente al npm pubblico e il sovraccarico di impostare un npm privato o un repository git è ancora piuttosto grande in molti casi. Ecco alcuni approcci per evitare il ../../../../../../../problema dei percorsi relativi.

node_modules

Le persone a volte si oppongono all'inserimento di moduli specifici dell'applicazione in node_modules perché non è ovvio come effettuare il check-in dei moduli interni senza controllare anche i moduli di terze parti da npm.

La risposta è abbastanza semplice! Se hai un .gitignorefile che ignora node_modules:

node_modules

Puoi semplicemente aggiungere un'eccezione con !per ciascuno dei tuoi moduli applicativi interni:

node_modules/*
!node_modules/foo
!node_modules/bar

Si noti che non è possibile annullare l'annullamento di una sottodirectory, se il genitore è già ignorato. Quindi, invece di ignorare node_modules, devi ignorare ogni directory all'interno node_modules con il node_modules/*trucco e quindi puoi aggiungere le tue eccezioni.

Ora, ovunque nella tua applicazione, sarai in grado require('foo') o require('bar')meno di avere un percorso relativo molto grande e fragile.

Se hai molti moduli e vuoi tenerli più separati dai moduli di terze parti installati da npm, puoi semplicemente metterli tutti in una directory node_modulescome node_modules/app:

node_modules/app/foo
node_modules/app/bar

Ora sarai in grado require('app/foo')o require('app/bar') da qualsiasi parte dell'applicazione.

Nel tuo .gitignore, aggiungi solo un'eccezione per node_modules/app:

node_modules/*
!node_modules/app

Se la tua applicazione aveva le trasformazioni configurate in package.json, dovrai creare un package.json separato con il suo campo di trasformazione nella directory del tuo componente node_modules/fooo node_modules/app/fooperché le trasformazioni non si applicano oltre i confini del modulo. Ciò renderà i tuoi moduli più robusti rispetto alle modifiche di configurazione nella tua applicazione e sarà più facile riutilizzare autonomamente i pacchetti al di fuori della tua applicazione.

link simbolico

Un altro trucco utile se si sta lavorando su un'applicazione in cui si possono fare link simbolici e non hanno bisogno di supporto per le finestre è quello di link simbolico di una lib/ o app/cartella in node_modules. Dalla radice del progetto, eseguire:

ln -s ../lib node_modules/app

e ora da qualsiasi parte del progetto sarai in grado di richiedere i file lib/facendo require('app/foo.js')per ottenere lib/foo.js.

percorsi personalizzati

Potresti vedere alcuni luoghi che parlano dell'utilizzo della $NODE_PATH variabile d'ambiente o opts.pathsdell'aggiunta di directory per il nodo e di browserify per cercare i moduli.

A differenza della maggior parte delle altre piattaforme, l'utilizzo di un array in stile shell di directory di percorso con $NODE_PATHnon è così favorevole nel nodo rispetto all'utilizzo efficace della node_modulesdirectory.

Questo perché l'applicazione è più strettamente accoppiata a una configurazione di ambiente di runtime, quindi ci sono più parti mobili e l'applicazione funzionerà solo quando l'ambiente è configurato correttamente.

nodo e browserify supportano entrambi ma scoraggiano l'uso di $NODE_PATH.


17
L'unico lato negativo di metterlo nella node_modulescartella è che rende più difficile nuke ( rm -rf node_modules) cartella
Michael

13
@Michael Non molto più difficile: git clean -dx node_modules
Peter Wilkinson

3
O nel caso in cui hai dimenticato la git cleansintassi, puoi sempre rm -rf node_modules && git checkout node_modules- assicurati che git stashci siano cambiamenti nelle node_modulessottodirectory.
derenio,

1
Mi piace l'idea di usare node_modules, ma non per memorizzare il codice sorgente considerando quanto possa essere volatile. Non avrebbe più senso pubblicare il modulo separato e salvarlo come dipendenza nel progetto originale? Fornisce una soluzione chiara alla volatilità della directory node_modules e si basa solo su npm, anziché su git, collegamenti simbolici o la soluzione $ NODE_PATH.
Kevin Koshiol,

1
NODE_PATH sembra la strada da percorrere. "la tua applicazione funzionerà solo quando il tuo ambiente è configurato correttamente" questo è sempre vero! Non è più facile ottenere la configurazione dell'ambiente (di solito in un file) piuttosto che cambiare ogni importazione in ogni file?
CpILL,

73

Mi piace creare una nuova node_modulescartella per il codice condiviso, quindi lasciare nodo e richiedere di fare ciò che fa meglio.

per esempio:

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

Ad esempio, se ci sei car/index.js, puoi require('helper')e il nodo lo troverà!

Come funzionano node_modules

Il nodo ha un algoritmo intelligente per la risoluzione dei moduli che è unico tra le piattaforme rivali.

Se vieni require('./foo.js')da/beep/boop/bar.js , il nodo cercherà ./foo.jsdentro /beep/boop/foo.js. I percorsi che iniziano con un ./o ../sono sempre locali al file che chiama require().

Se tuttavia si richiede un nome non relativo come require('xyz')from /beep/boop/foo.js, il nodo cerca questi percorsi in ordine, fermandosi alla prima corrispondenza e generando un errore se non viene trovato nulla:

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

Per ciascuno xyz directory esistente, il nodo cercherà innanzitutto a xyz/package.jsonper vedere se "main"esiste un campo. Il "main"campo definisce quale file dovrebbe prendere in carico se require()il percorso della directory.

Ad esempio, se /beep/node_modules/xyz è la prima corrispondenza e /beep/node_modules/xyz/package.jsonha:

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

quindi le esportazioni da /beep/node_modules/xyz/lib/abc.jsverranno restituite da require('xyz').

Se non è presente package.jsonalcun "main"campo o nessun campo, index.jssi presume:

/beep/node_modules/xyz/index.js

2
ottima spiegazione su come funziona quando si carica un modulo
inizio

2
Questa è una soluzione molto elegante, evita tutti i problemi nelle risposte sopra. Dovrebbe essere considerata la risposta, imho.
rodurico,

38

La grande immagine

Sembra "davvero brutto" ma dagli tempo. In effetti è davvero buono. Gli espliciti require()offrono una totale trasparenza e facilità di comprensione che è come una boccata d'aria fresca durante un ciclo di vita del progetto.

Pensala in questo modo: stai leggendo un esempio, immergendo le dita dei piedi in Node.js e hai deciso che è "davvero un cattivo IMO". Sei leader indiscusso della comunità Node.js, persone che hanno registrato più ore di scrittura e manutenzione delle applicazioni Node.js di chiunque altro. Qual è la possibilità che l'autore abbia fatto un simile errore da principiante? (E sono d'accordo, dal mio background di Ruby e Python, sembra inizialmente un disastro.)

C'è molto clamore e contro-hype che circonda Node.js. Ma quando la polvere si depositerà, riconosceremo che i moduli espliciti e i pacchetti "local first" sono stati un importante fattore di adozione.

Il caso comune

Naturalmente, node_modulesdalla directory corrente, viene cercato il genitore, quindi il nonno, il bisnonno, ecc. Quindi i pacchetti che hai installato funzionano già in questo modo. Di solito puoirequire("express") da qualsiasi parte del progetto e funziona benissimo.

Se ti ritrovi a caricare file comuni dalla radice del tuo progetto (forse perché sono funzioni di utilità comuni), allora è un grande indizio che è tempo di creare un pacchetto. I pacchetti sono molto semplici: sposta i tuoi file node_modules/e inseriscili package.json . Ecco! Tutto in quello spazio dei nomi è accessibile da tutto il tuo progetto. I pacchetti sono il modo corretto di inserire il codice in uno spazio dei nomi globale.

Altre soluzioni alternative

Personalmente non uso queste tecniche, ma rispondono alla tua domanda, e ovviamente conosci la tua situazione meglio di me.

È possibile impostare $NODE_PATHla radice del progetto. Quella directory verrà cercata quando tu require().

Successivamente, potresti scendere a compromessi e richiedere un file locale comune da tutti i tuoi esempi. Quel file comune riesporta semplicemente il file vero nella directory dei nonni.

esempi / download / app.js (e piace a molti altri)

var express = require('./express')

Esempi / download / express.js

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

Ora, quando si riposizionano quei file, il caso peggiore è riparare il modulo shim .


14
Sono d'accordo che i ragazzi di Node.js devono aver scelto i relativi requisiti per un motivo. Non riesco proprio a vedere i suoi vantaggi, né dalla tua risposta. Mi sembra ancora "cattivo";)
Adam Schmideg il

21
"Siete i leader della seconda ipotesi della comunità Node.js" - Gli stessi leader hanno deciso di utilizzare i callback al posto di future / promesse. La maggior parte della mia consulenza su nodejs implica maledire i "leader" e convincere le persone a trasferirsi in JVM. Il che è molto più semplice dopo alcuni mesi di utilizzo di nodejs :)
David Sergey,

8
@nirth, passare a JVM? Per l'amor di Dio, perché?
Ivancho,

31
"Siete i capi della seconda ipotesi della comunità Node.js", per favore, evitate questo tono scoraggiante.
atlex2

15
Accidenti, è il secondo indovinando i capi dei nodi. Ecco come procede l'industria. Se i ragazzi del nodo non indovinassero i leader che hanno sostenuto modelli di concorrenza basati su thread, non avremmo nodo.
d512,

20

Dai un'occhiata a node-rfr .

È semplice come questo:

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

penso che la seconda riga dovrebbe essere var myModule = rfr ('/ projectSubDir / myModule');
Sikorski,

1
Dai documenti: var module2 = rfr ('lib / module2'); // La barra iniziale può essere omessa.
igelineau,

L'ho provato e rfr funziona bene per eseguire con il nodo, ma interrompe la navigazione del codice con VS Code ... Non sono stato in grado di trovare una soluzione alternativa, per essere in grado di utilizzare il completamento automatico in VS ...
Alex Mantaut

13

Se stai usando un filato invece di npm puoi usare gli spazi di lavoro .

Diciamo che ho una cartella servicesche desidero richiedere più facilmente:

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

Per creare un'area di lavoro Yarn, creare un package.jsonfile all'interno di services folder:

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

Nel tuo pacchetto principale, aggiungi:

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

Esegui yarn installdalla radice del progetto.

Quindi, ovunque nel tuo codice, puoi fare:

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

invece di qualcosa come:

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

6
Forse è un'idea per chiarire che questo funziona solo per filati , non per npm? Ho pensato che probabilmente avrebbe funzionato anche per npm, quindi ho trascorso un po 'di tempo a chiedermi cosa avevo fatto di sbagliato fino a quando non ho provato a usare il filato. Potrebbe essere stato uno stupido presupposto, ma forse non sono l'unico.
ArneHugo,

2
Ho modificato un po 'per chiarire. Dispiace per la confusione.
Cyberwombat,

12

IMHO, il modo più semplice è definire la tua funzione come parte GLOBALdell'oggetto. Crea projRequire.jsnella radice del tuo progetto con i seguenti contenuti:

var projectDir = __dirname;

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

Nel tuo file principale prima di requireinserire uno qualsiasi dei moduli specifici del progetto:

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

Dopodiché funziona per me:

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

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


@Totty, ho trovato un'altra soluzione, che potrebbe funzionare nel caso descritto nei commenti. Descrizione sarà tl;dr, quindi farò meglio a mostrare un'immagine con la struttura del mio progetto di test .


bene, fino ad ora questo sembra il modo migliore per farlo. Faccio: GLOBAL.requires = require ('r'). R; nel mio file index.js. Ma ho un problema nei test dei voti, non eseguono index.js, quindi i miei test falliscono perché richiede che non sia definito. Comunque per ora posso aggiungere GLOBAL.requires = require ('r'). R; in cima ad ogni test. qualche idea migliore? github.com/totty90/production01_server/commit/…
Totty.js


il problema si verifica quando mi trovo in "pathes-test / node_modules / other.js" e ho bisogno di "pathes-test / node_modules / some.js". Dovrei richiedere ('./ some') invece di request ("prj / some"). E in questo modo tutta la mia app sarebbe nella directory node_modules?
Totty.js il

@Totty, non è un problema che richiede prj/someda prj/other(appena testato require('prj/some'). Tutti i moduli comuni della tua app possono andare lì (ad es. Livello di database). Non farà alcuna differenza dove i vostri, diciamo, libè. Prova a vedere se è adatto.
Aleksei Zabrodskii,

sì, l'ho aggiornato: github.com/totty90/production01_server/tree/master/node_modules/… che ha funzionato alla grande. Ma posso mettere tutti i miei file su un livello senza usare node_modules?
Totty.js il

12

Uso process.cwd()nei miei progetti. Per esempio:

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

Vale la pena notare che questo comporterà requireun percorso assoluto, anche se non ho ancora incontrato problemi con questo.


1
È una cattiva idea perché CWD non deve essere la stessa directory in cui è stata salvata l'applicazione.
jiwopene,

11

C'è una buona discussione di questo problema qui .

Mi sono imbattuto nello stesso problema architettonico: volevo un modo per dare alla mia applicazione più organizzazione e spazi dei nomi interni, senza:

  • mescolando i moduli dell'applicazione con dipendenze esterne o disturbando con repository npm privati ​​per codice specifico dell'applicazione
  • usare i parenti richiede, il che rende più difficile il refactoring e la comprensione
  • utilizzando i collegamenti simbolici o modificando il percorso del nodo, che può oscurare le posizioni delle fonti e non giocare bene con il controllo delle fonti

Alla fine, ho deciso di organizzare il mio codice usando le convenzioni di denominazione dei file piuttosto che le directory. Una struttura sarebbe simile a:

  • NPM-shrinkwrap.json
  • package.json
  • node_modules
    • ...
  • src
    • app.js
    • app.config.js
    • app.models.bar.js
    • app.models.foo.js
    • app.web.js
    • app.web.routes.js
    • ...

Quindi nel codice:

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

o solo

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

e le dipendenze esterne sono disponibili da node_modules come al solito:

var express = require('express');

In questo modo, tutto il codice dell'applicazione è organizzato gerarchicamente in moduli e disponibile per tutti gli altri codici relativi alla radice dell'applicazione.

Lo svantaggio principale è ovviamente che in un browser di file non è possibile espandere / comprimere l'albero come se fosse effettivamente organizzato in directory. Ma mi piace che sia molto esplicito da dove proviene tutto il codice, e non usa alcun "magico".


In sostanza, la soluzione n. 7, "The Wrapper", è abbastanza semplice e conveniente.
Pier-Luc Gendreau,

Vedo ancora una piccola comodità: "spostare" un file in una "cartella" diversa diventa un nuovo nome, il che è più facile che spostare un file. Inoltre tendo a notare che dopo mezz'ora di lavoro sul progetto, quasi tutto il mio albero delle app viene espanso comunque. L'aggiunta di 1 livello di spazio per le cartelle può rendere gestibile la codebase di grandi dimensioni e non introdurre troppo ../x/xche è già leggibile.
Sci

Stai reinventando le cartelle, usando punti anziché barre, per superare una chiara mancanza di nodejs.
Simone Gianni,

9

Supponendo che la radice del progetto sia la directory di lavoro corrente, dovrebbe funzionare:

// 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');è valido anche.
cespon,

7
@cespon no, è solo relativo al file richiesto.
protometa,

8

Ho provato molte di queste soluzioni. Ho finito per aggiungere questo nella parte superiore del mio file principale (ad esempio index.js):

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

Ciò aggiunge la radice del progetto a NODE_PATH quando viene caricato lo script. Mi permette di richiedere qualsiasi file nel mio progetto facendo riferimento al suo percorso relativo dalla radice del progetto come var User = require('models/user'). Questa soluzione dovrebbe funzionare finché si esegue uno script principale nella radice del progetto prima di eseguire qualsiasi altra cosa nel progetto.


8

Alcune delle risposte stanno dicendo che il modo migliore è quello di aggiungere il codice a node_module come pacchetto, sono d'accordo ed è probabilmente il modo migliore per perdere il ../../../ bisogno, ma nessuno di loro in realtà offre un modo per farlo.

dalla versione 2.0.0puoi installare un pacchetto da file locali, il che significa che puoi creare una cartella nella tua radice con tutti i pacchetti che desideri,

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

quindi in package.json è possibile aggiungere modules(o fooe bar) come pacchetto senza pubblicare o utilizzare server esterni in questo modo:

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

Fatto ciò npm install, puoi accedere al codice convar foo = require("foo") , proprio come fai con tutti gli altri pacchetti.

maggiori informazioni possono essere trovate qui:

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

e qui come creare un pacchetto:

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


1
"Questa funzione è utile per lo sviluppo offline locale e la creazione di test che richiedono l'installazione di npm dove non si desidera colpire un server esterno, ma non devono essere utilizzati quando si pubblicano pacchetti nel registro pubblico."
Ryan Smith,

7

Potresti usare un modulo che ho creato, Undot . Non è nulla di avanzato, solo un aiuto, quindi puoi evitare l'inferno con semplicità.

Esempio:

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

6

Puoi definire qualcosa del genere nel tuo app.js:

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

e poi ogni volta che vuoi richiedere qualcosa dalla radice, non importa dove ti trovi, devi solo utilizzare requestFromRoot invece di quanto richiesto dalla vaniglia. Finora funziona abbastanza bene per me.


Grazie! Penso che sia piuttosto intelligente e diretto.
Ryan,

Mi perdoni padre perché ho peccato. Ho portato questo per ES6 ed ha ottenuto la seguente: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Adori la soluzione, ma devi davvero associare __dirname in quel modo?
Nuck,

1
La mia memoria è un po 'confusa su questo, ma credo che __dirname cambi valore a seconda del file utilizzato. Ora può darsi che dal momento che la funzione è definita in un singolo posto ma usata in più posti, il valore rimarrebbe costante anche senza questo legame, ma l'ho fatto solo per assicurarmi che ciò fosse effettivamente il caso.
user1417684,

fatto molto tempo fa, provoca dolori nel test di envs e simili. non vale il sovraccarico. random new global rende nuove persone incerte bla bla
The Dembinski,

E come si fa a requirequesta funzione?
Darko Maksimovic,

5

Ecco come sto andando da più di 6 mesi. Uso una cartella denominata node_modules come cartella principale nel progetto, in questo modo cercherà sempre quella cartella da qualsiasi luogo che io chiami un requisito assoluto:

  • node_modules
    • il mio progetto
      • index.js Posso richiedere ("myProject / someFolder / hey.js") invece di require ("./ someFolder / hey.js")
      • someFolder che contiene hey.js

Ciò è più utile quando si è nidificati in cartelle ed è molto meno lavoro modificare un percorso di file se impostato in modo assoluto. Uso solo 2 i relativi requisiti in tutta la mia app .


4
Io uso approccio simile, se non che io aggiungo locale (progetto) node_modulesin /src, e lasciare /node_modulesper i venditori di tenere le cose separate. Quindi ho /src/node_modulesper il codice locale e /node_modulesper i fornitori.
Marius Balčytis

33
IMHO la cartella node_modules è solo per node_modules. Non è una buona pratica mettere l'intero progetto in quella cartella.
McSas,

2
@McSas cosa suggeriresti in alternativa per ottenere lo stesso effetto di cui sopra?
spieglio,

3
@cspiegl Puoi usare la NODE_PATHvariabile d'ambiente
Christopher Tarquini il

5

Imho il modo più semplice per raggiungere questo obiettivo è creare un collegamento simbolico all'avvio dell'app node_modules/app(o come lo chiami) a cui punta ../app. Quindi puoi semplicemente chiamarerequire("app/my/module") . I collegamenti simbolici sono disponibili su tutte le principali piattaforme.

Tuttavia, dovresti comunque dividere le tue cose in moduli più piccoli e gestibili che sono installati tramite npm. Puoi anche installare i tuoi moduli privati ​​tramite git-url, quindi non c'è motivo di avere una directory monolitica per le app.


Il supporto su Windows richiede una conoscenza più approfondita di Node e del sistema operativo. Può limitare l'uso diffuso di un progetto open source.
Steven Vachon,

Generalmente non userei questo modello per una libreria (che sono la maggior parte dei progetti open source). Tuttavia, è possibile creare questi symlink nell'hook build npm in modo che l'utente non abbia una conoscenza approfondita.
Johannes Ewald,

Certo, ma Node.js su Windows non supporta i collegamenti simbolici per impostazione predefinita.
Steven Vachon,

4

Nel proprio progetto è possibile modificare qualsiasi file .js utilizzato nella directory principale e aggiungere il suo percorso a una proprietà della process.envvariabile. Per esempio:

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

Successivamente puoi accedere alla proprietà ovunque:

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

4

Un'altra risposta:

Immagina questa struttura di cartelle:

  • node_modules
    • lodash
  • src
    • subdir
      • foo.js
      • bar.js
    • main.js
  • test

    • test.js

Quindi in test.js , devi richiedere file come questo:

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

e in main.js :

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

Ora puoi usare babel e babel-plugin-module-resolver con questo. file babelrc per configurare 2 cartelle root:

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

Ora puoi richiedere i file nello stesso modo nei test e in src :

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

e se vuoi usare la sintassi del modulo es6 :

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

quindi importare i file nei test e src in questo modo:

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


3

Non è possibile che la examplesdirectory contenga un node_modulescon un collegamento simbolico alla radice del progetto project -> ../../, consentendo così agli esempi di utilizzare require('project'), sebbene ciò non rimuova la mappatura, ma consente all'origine di utilizzare require('project')anzichérequire('../../') .

Ho provato questo, e funziona con v0.6.18.

Elenco della projectdirectory:

$ 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 -> ../../

Il contenuto di index.jsassegna un valore a una proprietà exportsdell'oggetto e lo richiama console.logcon un messaggio che indica che era richiesto. Il contenuto di test.jsè require('project').


puoi mostrare il codice sorgente del test per favore? bene, e funzionerebbe se dovessi richiedere ('project.a') in questo modo?
Totty.js il

Cosa intendi con require('project.a')? Penso che potrebbe significare require('project/a'), anche se require('project').aè anche possibile?
Dan D.

ma con il tuo esempio avrei bisogno di creare quelle cartelle in ogni cartella in cui è presente un modulo che richiede il metodo request. Ad ogni modo dovresti prenderti cura dei tempi di "../" a seconda della cartella.
Totty.js il

In realtà il collegamento dovrebbe essere solo in una node_modulesdirectory nel genitore più vicino di entrambi i file e il collegamento sarebbe quindi lo stesso per entrambi. Vedi nodejs.org/api/…
Dan D.

E sarebbe relativo da quella posizione. Ad esempio: project/node_modules/project -> ../.
Dan D.

2

Se qualcuno è alla ricerca di un altro modo per aggirare questo problema, ecco il mio contributo allo sforzo:

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

L'idea di base: crei un file JSON nella radice del progetto che associ i tuoi percorsi di file a nomi abbreviati (o ottieni use-automapper per farlo per te). Puoi quindi richiedere i tuoi file / moduli usando quei nomi. Così:

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

Quindi c'è quello.


2

Ciò che mi piace fare è sfruttare il modo in cui il nodo viene caricato dalla directory node_module per questo.

Se si tenta di caricare la "cosa" del modulo, si farebbe qualcosa del genere

require('thing');

Il nodo cercherà quindi la directory 'cosa' nella directory 'nodo_modulo'.

Dato che node_module è normalmente alla radice del progetto, possiamo sfruttare questa coerenza. (Se node_module non è alla radice, allora hai altri mal di testa autoindotti da affrontare.)

Se andiamo nella directory e poi torniamo indietro da essa, possiamo ottenere un percorso coerente alla radice del progetto del nodo.

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

Quindi se vogliamo accedere alla directory / happy, lo faremo.

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

Anche se è un po 'confuso, tuttavia sento che se cambia la funzionalità di come caricare node_modules, ci saranno problemi più grandi da affrontare. Questo comportamento dovrebbe rimanere coerente.

Per chiarire le cose, lo faccio, perché il nome del modulo non ha importanza.

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

L'ho usato di recente per angular2. Voglio caricare un servizio dalla radice.

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

Informazioni sul riferimento angolare, con un'applicazione CLI standard, è possibile semplicemente importare src/app/my.service, è inoltre possibile configurare VSC per utilizzare le importazioni non relative per i file dattiloscritti.
Ploppy,

2

Ho scritto questo piccolo pacchetto che consente di richiedere i pacchetti in base al loro percorso relativo dalla radice del progetto, senza introdurre variabili globali o ignorare le impostazioni predefinite dei nodi

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

Funziona così

// 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()

A volte ho dei pacchetti privati ​​nel progetto principale, questo script si romperà con quello. Inoltre, non sono sicuro che funzionerà bene con il webpack (nel caso in cui usi webpack con node.js come faccio io)
Totty.js,

Se si dispone di directory nidificate con file di pacchetto, ogni directory sarà in grado di richiedere solo file all'interno del proprio pacchetto. Non è questo il comportamento che desideri? Non ho ancora testato con il webpack.
gafi,

Questo ha funzionato perfettamente per un progetto semplice ed è molto più facile di qualsiasi altra risposta.
byxor,

2

Voglio solo dare seguito alla grande risposta di Paolo Moretti e Browserify. Se stai usando un transpiler (ad esempio, babel, dattiloscritto) e hai cartelle separate per codice sorgente e traspilato come src/edist/ , puoi usare una variante delle soluzioni come

node_modules

Con la seguente struttura di directory:

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

puoi quindi consentire a babel ecc. di traspilare la srcdirectory indist directory.

link simbolico

Usando il collegamento simbolico possiamo eliminare alcuni livelli di annidamento:

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

Un avvertimento con babel --copy-files La --copy-filesbandiera di babelnon tratta bene i collegamenti simbolici. Potrebbe continuare a navigare nel ..collegamento simbolico e vedere in modo ricusivo file infiniti. Una soluzione alternativa consiste nell'utilizzare la seguente struttura di directory:

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

In questo modo, il codice sotto srcsarà ancora apprisolto src, mentre babel non vedrà più i collegamenti simbolici.


Grazie, non consiglierei di fare questa magia. Per prima cosa perderai tutte le importazioni, non saranno calcolate dal tuo IDE. Se si utilizzano altri strumenti come il tipo di flusso, non funzionerà correttamente.
Totty.js il

In realtà il flusso sembra funzionare nel mio caso, il che non sorprende poiché le soluzioni dipendono dal modello di risoluzione del modulo nodo standard e dai collegamenti simbolici. Quindi non è davvero magico per strumenti come il flusso capire. Ma gli IDE sono diversi.
user716468,

2

Stavo cercando la stessa identica semplicità per richiedere file da qualsiasi livello e ho trovato l' alias del modulo .

Basta installare:

npm i --save module-alias

Apri il tuo file package.json, qui puoi aggiungere alias per i tuoi percorsi, ad es

"_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
}

E usa i tuoi alias semplicemente:

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


1

Stiamo per provare un nuovo modo di affrontare questo problema.

Prendendo esempi da altri progetti noti come spring e guice, definiremo un oggetto "contesto" che conterrà tutta l'istruzione "richiedono".

Questo oggetto verrà quindi passato a tutti gli altri moduli per l'uso.

Per esempio

var context = {}

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

Ciò richiede di scrivere ogni modulo come una funzione che riceve le operazioni, che ci sembra comunque una buona pratica.

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

e poi ti riferirai al contesto invece di richiedere cose.

var module1Ref = context.moduel1;

Se vuoi, puoi facilmente scrivere un ciclo per fare le istruzioni richieste

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

Ciò dovrebbe semplificarti la vita quando vuoi deridere (test) e anche risolvere il tuo problema lungo la strada rendendo il codice riutilizzabile come pacchetto.

È inoltre possibile riutilizzare il codice di inizializzazione del contesto separando la dichiarazione bean da esso. ad esempio, il tuo main.jsfile potrebbe apparire così

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

Questo metodo si applica anche alle librerie esterne, non è necessario codificare i loro nomi ogni volta che ne abbiamo bisogno, tuttavia richiederà un trattamento speciale poiché le loro esportazioni non sono funzioni che prevedono un contesto.

In seguito possiamo anche definire i bean come funzioni - che ci consentiranno di requiremoduli diversi in base all'ambiente - ma che non rientrano nell'ambito di questo thread.


1

Ho avuto problemi con questo stesso problema, quindi ho scritto un pacchetto chiamato include .

Includi handle per capire la cartella principale del tuo progetto mediante l'individuazione del file package.json, quindi passa l'argomento path che gli dai al requisito native () senza tutto il relativo disordine del percorso. Immagino questo non come un sostituto di require (), ma uno strumento per richiedere la gestione di file o librerie non pacchettizzate / non di terze parti. Qualcosa di simile a

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

Spero che questo possa essere utile.


1

Se il file js del punto di ingresso dell'app (ovvero quello su cui si esegue effettivamente "nodo") si trova nella directory principale del progetto, è possibile farlo facilmente con il modulo npm rootpath . Basta installarlo tramite

npm install --save rootpath

... quindi nella parte superiore del file js del punto di ingresso, aggiungi:

require('rootpath')();

Da quel momento in poi tutte le chiamate richieste sono ora relative alla radice del progetto, ad esempio require('../../../config/debugging/log'); diventa require('config/debugging/log');(dove la cartella di configurazione si trova nella radice del progetto).


1

In poche parole, puoi chiamare la tua cartella come modulo:

Per questo abbiamo bisogno di: modulo globale e app-module-path

qui "App-module-path" è il modulo, ti consente di aggiungere ulteriori directory al percorso di ricerca del modulo Node.js E "globale" è, tutto ciò che colleghi a questo oggetto sarà disponibile ovunque nella tua app.

Ora dai un'occhiata a questo frammento:

global.appBasePath = __dirname;

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

__dirname è la directory corrente del nodo corrente. Qui puoi dare il tuo percorso per cercare il percorso del modulo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.