Comment rendre node.js absolu? (au lieu de relatif)


234

Je voudrais exiger mes fichiers toujours par la racine de mon projet et non par rapport au module actuel.

Par exemple, si vous regardez https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js ligne 6, vous verrez

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

C'est vraiment mauvais OMI. Imaginez que je souhaite rapprocher tous mes exemples de la racine d'un seul niveau. Ce serait impossible, car je devrais mettre à jour plus de 30 exemples et plusieurs fois dans chaque exemple. Pour ça:

express = require('../')

Ma solution serait d'avoir un cas particulier pour root: si une chaîne commence par un $ alors elle est relative au dossier racine du projet.

Toute aide est la bienvenue, merci

Update 2

Maintenant, j'utilise require.js qui vous permet d'écrire dans un sens et fonctionne à la fois sur le client et sur le serveur. Require.js vous permet également de créer des chemins personnalisés.

Mise à jour 3

Maintenant, je suis passé à webpack + gulp et j'utilise Enhanced-require pour gérer les modules côté serveur. Voir ici la justification: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


Si vous décidez d'utiliser une constante / variable de chemin racine explicite, cette réponse fonctionne pour cela . La solution utilise un minuscule module github pour déterminer le chemin racine.
Steam Powered

Réponses:


162

Et à propos de:

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

Il nécessite le fichier comme s'il était requis à partir du fichier js principal, donc cela fonctionne assez bien tant que votre fichier js principal est à la racine de votre projet ... et c'est quelque chose que j'apprécie.


Pas une mauvaise idée (: Vous pouvez ensuite définir d'autres méthodes pour remapper l'application dans votre module require.main. Je pense que vous pourriez alors faire require.main.req ('client / someMod'). Belle idée, mais ce serait être plus verbeux que mes requirejs actuels. Je ne pense pas non plus que cela vaille la peine parce que je n'aime pas browserify parce que les changements ne sont pas instantanés et manquent les changements (parce que mon code devrait fonctionner à la fois dans browser et node.js).
Totty.js

4
Si vous le trouvez trop verbeux, utilisez simplement .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel

oui, cela peut être utile pour quelqu'un qui souhaite toujours utiliser browserify pour le côté client. Pour moi, il n'y a plus besoin, mais merci quand même pour votre réponse (:
Totty.js

6
SI LE PRINCIPAL EST AU RACINE DE VOTRE PROJET :)
Alexander Mills

12
Cette solution ne fonctionnera pas si le code est couvert de tests unitaires comme le test Mocha
alx lark

129

Il y a une section vraiment intéressante dans le manuel Browserify :

éviter ../../../../../../ ..

Tout dans une application n'appartient pas correctement au npm public et la surcharge de mise en place d'un npm privé ou d'un dépôt git est encore assez importante dans de nombreux cas. Voici quelques approches pour éviter le ../../../../../../../problème des chemins relatifs.

node_modules

Les gens s'opposent parfois à mettre des modules spécifiques à l'application dans node_modules car il n'est pas évident de vérifier vos modules internes sans également archiver des modules tiers à partir de npm.

La réponse est assez simple! Si vous avez un .gitignorefichier qui ignore node_modules:

node_modules

Vous pouvez simplement ajouter une exception avec !pour chacun de vos modules d'application internes:

node_modules/*
!node_modules/foo
!node_modules/bar

Veuillez noter que vous ne pouvez pas ignorer un sous-répertoire, si le parent est déjà ignoré. Donc, au lieu d'ignorer node_modules, vous devez ignorer tous les répertoires intérieur node_modules avec l' node_modules/*astuce, puis vous pouvez ajouter vos exceptions.

Maintenant, n'importe où dans votre application, vous pourrez require('foo') ou require('bar')non avoir un chemin relatif très grand et fragile.

Si vous avez beaucoup de modules et que vous souhaitez les garder plus séparés des modules tiers installés par npm, vous pouvez simplement les mettre tous dans un répertoire node_modulestel que node_modules/app:

node_modules/app/foo
node_modules/app/bar

Maintenant, vous pourrez require('app/foo')ou require('app/bar') depuis n'importe où dans votre application.

Dans votre .gitignore, ajoutez simplement une exception pour node_modules/app:

node_modules/*
!node_modules/app

Si votre application a configuré package.json transforme, vous devrez créer une package.json séparée avec sa propre transformation dans votre domaine node_modules/fooou node_modules/app/foorépertoire composants , car les transformations ne sont pas applicables à travers les frontières du module. Cela rendra vos modules plus robustes contre les changements de configuration dans votre application et il sera plus facile de réutiliser indépendamment les packages en dehors de votre application.

lien symbolique

Une autre astuce pratique si vous travaillez sur une application dans laquelle vous pouvez créer des liens symboliques et n'avez pas besoin de prendre en charge Windows est de créer un lien symbolique vers un dossier lib/ ou . Depuis la racine du projet, faites:app/node_modules

ln -s ../lib node_modules/app

et maintenant de n'importe où dans votre projet, vous serez en mesure d'exiger des fichiers en lib/faisant require('app/foo.js')pour obtenirlib/foo.js .

chemins personnalisés

Vous pourriez voir certains endroits parler de l'utilisation de la $NODE_PATH variable d'environnement ouopts.paths d'ajouter des répertoires pour le nœud et browserify pour rechercher des modules.

Contrairement à la plupart des autres plates-formes, l'utilisation d'un tableau de répertoires de chemin d'accès de style shell avec $NODE_PATHn'est pas aussi favorable dans le nœud que l'utilisation efficace du node_modulesrépertoire.

Cela est dû au fait que votre application est plus étroitement couplée à une configuration d'environnement d'exécution, donc il y a plus de pièces mobiles et votre application ne fonctionnera que lorsque votre environnement sera correctement configuré.

node et browserify supportent tous les deux mais découragent l'utilisation de $NODE_PATH.


17
Le seul inconvénient de le mettre dans le node_modulesdossier est qu'il rend plus difficile le rm -rf node_modulesdossier nuke ( )
Michael

13
@Michael Pas beaucoup plus difficile: git clean -dx node_modules
Peter Wilkinson

3
Ou au cas où vous auriez oublié la git cleansyntaxe, on peut toujours rm -rf node_modules && git checkout node_modules- assurez-vous au git stashcas où il y aurait des changements dans les node_modulessous - répertoires.
derenio

1
J'aime l'idée d'utiliser node_modules, mais pas pour stocker le code source compte tenu de sa volatilité. Ne serait-il pas plus judicieux de publier le module séparé et de l'enregistrer en tant que dépendance dans le projet d'origine? Il fournit une solution claire à la volatilité du répertoire node_modules et ne s'appuie que sur npm, plutôt que de s'appuyer sur git, des liens symboliques ou la solution $ NODE_PATH.
Kevin Koshiol

1
NODE_PATH ressemble à la voie à suivre. "votre application ne fonctionnera que si votre environnement est correctement configuré" c'est toujours vrai! N'est-il pas plus facile d'obtenir la configuration de l'environnement (généralement dans un fichier) que de changer chaque importation dans chaque fichier?
CpILL

73

J'aime créer un nouveau node_modulesdossier pour le code partagé, puis laisser le nœud et exiger faire ce qu'il fait le mieux.

par exemple:

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

Par exemple, si vous y êtes, car/index.jsvous le pouvez require('helper')et le nœud le trouvera!

Fonctionnement de node_modules

Le nœud possède un algorithme intelligent pour résoudre les modules qui est unique parmi les plates-formes rivales.

Si vous venez require('./foo.js')de /beep/boop/bar.js, node cherchera ./foo.jsdans /beep/boop/foo.js. Les chemins commençant par ./ou ../sont toujours locaux vers le fichier qui appelle require().

Si toutefois vous avez besoin d'un nom non relatif tel que require('xyz')from /beep/boop/foo.js, le nœud recherche ces chemins dans l'ordre, s'arrêtant à la première correspondance et générant une erreur si rien n'est trouvé:

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

Pour chaque xyzrépertoire existant, le nœud recherchera d'abord un xyz/package.jsonpour voir si un "main"champ existe. Le "main"champ définit quel fichier doit prendre en charge si vousrequire() le chemin du répertoire.

Par exemple, si /beep/node_modules/xyzest la première correspondance et /beep/node_modules/xyz/package.jsona:

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

alors les exportations de /beep/node_modules/xyz/lib/abc.jsseront retournées par require('xyz') .

S'il n'y a pas package.jsonou pas de "main"champ, index.json suppose:

/beep/node_modules/xyz/index.js

2
grande explication sur la façon dont cela fonctionne lors du chargement d'un module
goenning

2
Ceci est une solution très élégante, évite tous les problèmes dans les réponses ci-dessus. Devrait être considérer LA réponse, à mon humble avis.
rodurico

38

La grande image

Cela semble "vraiment mauvais" mais donnez-lui du temps. C'est, en fait, vraiment bon. Les explicites require()donnent une transparence totale et une facilité de compréhension qui est comme une bouffée d'air frais pendant le cycle de vie d'un projet.

Pensez-y de cette façon: vous lisez un exemple, trempez vos orteils dans Node.js et vous avez décidé que c'était "vraiment mauvais IMO". Vous êtes les leaders de la communauté Node.js, ceux qui ont passé plus d'heures à écrire et à maintenir des applications Node.js que quiconque. Quelle est la chance que l'auteur ait fait une telle erreur de débutant? (Et je suis d'accord, de mon expérience Ruby et Python, cela semble d'abord comme un désastre.)

Il y a beaucoup de battage médiatique et de contre-battage publicitaire autour de Node.js. Mais lorsque la poussière retombera, nous reconnaîtrons que les modules explicites et les packages «local first» ont été un moteur majeur de l'adoption.

Le cas commun

Bien sûr, à node_modulespartir du répertoire actuel, la recherche du parent, puis des grands-parents, des arrière-grands-parents, etc. Les packages que vous avez installés fonctionnent donc déjà de cette façon. Habituellement, vous pouvez le faire require("express")n'importe où dans votre projet et cela fonctionne bien.

Si vous vous trouvez en train de charger des fichiers communs à partir de la racine de votre projet (peut-être parce que ce sont des fonctions utilitaires communes), c'est un indice important qu'il est temps de créer un package. Les packages sont très simples: déplacez vos fichiers dans node_modules/et mettez- package.json y un . Voila! Tout dans cet espace de noms est accessible à partir de l'ensemble de votre projet. Les packages sont la bonne façon de placer votre code dans un espace de noms global.

Autres solutions de contournement

Personnellement, je n'utilise pas ces techniques, mais elles répondent à votre question, et bien sûr vous connaissez mieux votre situation que moi.

Vous pouvez définir $NODE_PATHla racine de votre projet. Ce répertoire sera recherché lorsque vous require().

Ensuite, vous pourriez compromettre et exiger un fichier local commun de tous vos exemples. Ce fichier commun réexporte simplement le vrai fichier dans le répertoire des grands-parents.

exemples / téléchargements / app.js (et beaucoup d'autres comme ça)

var express = require('./express')

exemples / téléchargements / express.js

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

Maintenant, lorsque vous déplacez ces fichiers, le pire des cas est de réparer le module à une seule cale .


14
Je suis d'accord que les gars de Node.js doivent avoir choisi la relation relative pour une raison. Je ne vois tout simplement pas ses avantages, ni d'après votre réponse. Ça me fait toujours "mal";)
Adam Schmideg

21
«Vous êtes des leaders de second rang dans la communauté Node.js» - Les mêmes leaders ont décidé d'utiliser des rappels au lieu de futurs / promesses. La majorité de mes consultations nodejs impliquent de maudire les «leaders» et de convaincre les gens de passer à la JVM. Ce qui est beaucoup plus facile après quelques mois d'utilisation de nodejs :)
David Sergey

8
@nirth, passer à JVM? Pour l'amour de Dieu, pourquoi?
Ivancho

31
"Vous êtes les leaders de la communauté Node.js", veuillez éviter ce ton décourageant.
atlex2

15
Bon sang, il est le second leader des nœuds. C'est ainsi que l'industrie progresse. Si les gars du nœud n'ont pas deviné les leaders qui ont soutenu les modèles de concurrence basés sur les threads, nous n'aurions pas de nœud.
d512

20

Jetez un œil à node-rfr .

C'est aussi simple que ça:

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

je pense que la deuxième ligne devrait être var myModule = rfr ('/ projectSubDir / myModule');
Sikorski

1
À partir des documents: var module2 = rfr ('lib / module2'); // La barre oblique peut être omise.
igelineau

Je l'ai essayé et cela fonctionne correctement pour s'exécuter avec le noeud, mais il rompt la navigation avec VS Code ... Je n'ai pas pu trouver de solution de contournement, pour pouvoir utiliser la saisie semi-automatique dans VS ...
Alex Mantaut

13

Si vous utilisez du fil au lieu de npm, vous pouvez utiliser des espaces de travail .

Disons que j'ai un dossier dont servicesje souhaite avoir plus facilement besoin:

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

Pour créer un espace de travail Yarn, créez un package.jsonfichier dans services folder:

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

Dans votre package.json principal, ajoutez:

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

Exécutez à yarn installpartir de la racine du projet.

Ensuite, n'importe où dans votre code, vous pouvez faire:

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

au lieu de quelque chose comme:

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

6
C'est peut-être une idée de clarifier que cela ne fonctionne que pour le fil , pas pour npm? J'ai pensé que cela fonctionnerait probablement aussi pour npm, alors j'ai passé un peu de temps à me demander ce que j'avais fait de mal jusqu'à ce que j'essaie d'utiliser du fil à la place. Cela a peut-être été une supposition stupide, mais je ne suis peut-être pas le seul.
ArneHugo

2
J'ai édité un peu pour clarifier. Désolé pour la confusion.
cyberwombat

12

À mon humble avis, la façon la plus simple est de définir votre propre fonction en tant que partie d'un GLOBALobjet. Créez projRequire.jsà la racine de votre projet avec le contenu suivant:

var projectDir = __dirname;

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

Dans votre fichier principal avant requiretout module spécifique au projet:

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

Après cela, cela fonctionne pour moi:

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

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


@Totty, j'ai trouvé une autre solution, qui pourrait fonctionner pour le cas que vous avez décrit dans les commentaires. La description va être tl;dr, donc je ferais mieux de montrer une image avec la structure de mon projet de test .


Eh bien, jusqu'à présent, cela semble être la meilleure façon de le faire. Je fais: GLOBAL.requires = require ('r'). R; dans mon fichier index.js. Mais j'ai un problème dans mes tests de vœux, ils n'exécutent pas index.js donc mes tests échouent parce que requireS n'est pas défini. Quoi qu'il en soit pour l'instant, je peux ajouter GLOBAL.requires = require ('r'). R; au sommet de chaque test. une meilleure idée? github.com/totty90/production01_server/commit/…
Totty.js


le problème se produit lorsque je suis dans "pathes-test / node_modules / other.js" et que j'ai besoin de "pathes-test / node_modules / some.js". Je devrais exiger ('./ some') au lieu de require ("prj / some"). Et de cette façon, toute mon application serait dans le répertoire node_modules?
Totty.js

@Totty, aucun problème nécessitant prj/somede prj/other(vient d'être testé require('prj/some'). Tous les modules communs de votre application peuvent y aller (par exemple, la couche de base de données). Ne fera aucune différence là où, disons, se libtrouve. Essayez de voir si cela convient.
Aleksei Zabrodskii

oui, je l'ai mis à jour: github.com/totty90/production01_server/tree/master/node_modules/… qui fonctionnait très bien. Mais je peux mettre tous mes fichiers d'un niveau sans utiliser les node_modules?
Totty.js

12

J'utilise process.cwd()dans mes projets. Par exemple:

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

Il convient peut-être de noter que cela entraînera requireun chemin absolu, même si je n'ai pas encore rencontré de problèmes avec cela.


1
C'est une mauvaise idée car CWD n'a pas besoin d'être le même répertoire où l'application est enregistrée.
jiwopene

11

Il y a une bonne discussion de cette question ici .

Je suis tombé sur le même problème architectural: vouloir un moyen de donner à mon application plus d'organisation et d'espaces de noms internes, sans:

  • mélange de modules d'application avec des dépendances externes ou dérangement avec des dépôts npm privés pour du code spécifique à l'application
  • utiliser des exigences relatives, ce qui rend la refactorisation et la compréhension plus difficiles
  • en utilisant des liens symboliques ou en changeant le chemin du nœud, ce qui peut masquer les emplacements des sources et ne pas bien jouer avec le contrôle des sources

À la fin, j'ai décidé d'organiser mon code en utilisant des conventions de dénomination de fichiers plutôt que des répertoires. Une structure ressemblerait à quelque chose comme:

  • 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
    • ...

Puis en code:

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

ou juste

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

et les dépendances externes sont disponibles à partir de node_modules comme d'habitude:

var express = require('express');

De cette façon, tout le code d'application est hiérarchiquement organisé en modules et disponible pour tout autre code relatif à la racine de l'application.

Le principal inconvénient est bien sûr que dans un navigateur de fichiers, vous ne pouvez pas développer / réduire l'arborescence comme si elle était réellement organisée en répertoires. Mais j'aime que cela soit très explicite sur la provenance de tout le code, et qu'il n'utilise aucune «magie».


De l'essentiel que vous avez lié, la solution # 7, "The Wrapper", est assez simple et pratique.
Pier-Luc Gendreau

Je vois une autre petite commodité - "déplacer" un fichier vers un "dossier" différent devient un renommage - ce qui est plus facile que de déplacer un fichier. De plus, j'ai tendance à remarquer qu'après une demi-heure de travail sur le projet, la quasi-totalité de mon arborescence d'applications est de toute façon développée. L'ajout d'un niveau d'espace de dossier peut rendre la grande base de code gérable et ne pas en introduire trop ../x/xqui est déjà lisible.
Ski le

Vous réinventez des dossiers, en utilisant des points au lieu de barres obliques, pour surmonter un manque évident de nodejs.
Simone Gianni

9

En supposant que la racine de votre projet est le répertoire de travail actuel, cela devrait fonctionner:

// 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');est également valable.
cespon

7
@cespon non, c'est juste par rapport au fichier requis.
protometa

8

J'ai essayé plusieurs de ces solutions. J'ai fini par ajouter ceci en haut de mon fichier principal (par exemple index.js):

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

Cela ajoute la racine du projet à NODE_PATH lorsque le script est chargé. Le me permet d'exiger n'importe quel fichier dans mon projet en référençant son chemin relatif à partir de la racine du projet tel que var User = require('models/user'). Cette solution devrait fonctionner tant que vous exécutez un script principal dans la racine du projet avant d'exécuter quoi que ce soit d'autre dans votre projet.


8

Certaines des réponses disent que la meilleure façon est d'ajouter le code au node_module en tant que package, je suis d'accord et c'est probablement la meilleure façon de perdre le ../../../in require mais aucun d'entre eux ne donne réellement un moyen de le faire.

à partir de la version, 2.0.0vous pouvez installer un package à partir de fichiers locaux, ce qui signifie que vous pouvez créer un dossier dans votre racine avec tous les packages que vous souhaitez,

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

donc dans package.json, vous pouvez ajouter le modules(ou fooet bar) en tant que package sans publier ni utiliser de serveur externe comme ceci:

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

Après cela npm install, vous pouvez accéder au code avec var foo = require("foo"), comme vous le faites avec tous les autres packages.

plus d'informations peuvent être trouvées ici:

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

et voici comment créer un package:

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


1
"Cette fonctionnalité est utile pour le développement local hors ligne et la création de tests qui nécessitent l'installation de npm là où vous ne voulez pas toucher un serveur externe, mais ne doit pas être utilisée lors de la publication de packages dans le registre public."
Ryan Smith

7

Vous pouvez utiliser un module que j'ai créé, Undot . Ce n'est rien de avancé, juste une aide pour éviter ces enfers de points avec simplicité.

Exemple:

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

6

Vous pouvez définir quelque chose comme ça dans votre app.js:

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

puis à chaque fois que vous souhaitez exiger quelque chose de la racine, peu importe où vous êtes, vous utilisez simplement requireFromRoot au lieu de vanilla require. Fonctionne assez bien pour moi jusqu'à présent.


Merci! Je pense que c'est assez intelligent et simple.
Ryan

Pardonne-moi père, car j'ai péché. Je Ported cela ES6 et a obtenu ce qui suit: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. J'adore la solution, mais devez-vous vraiment lier __dirname comme ça?
Nuck

1
Ma mémoire est un peu floue à ce sujet, mais je pense que __dirname change de valeur en fonction du fichier dans lequel il est utilisé. Maintenant, il se peut que puisque la fonction est définie à un seul endroit mais utilisée à plusieurs endroits, la valeur resterait constante même sans cette liaison, mais je viens de le faire pour m'assurer que c'est bien le cas.
user1417684

a fait cela il y a longtemps, provoque des difficultés à tester les envs et similaires. ne vaut pas les frais généraux. aléatoire nouveau global rend de nouvelles personnes incertaines bla bla
The Dembinski

Et comment faites-vous requirecette fonction?
Darko Maksimovic

5

Voici la façon dont je fais depuis plus de 6 mois. J'utilise un dossier nommé node_modules comme dossier racine dans le projet, de cette façon, il recherchera toujours ce dossier partout où j'appelle un besoin absolu:

  • node_modules
    • mon projet
      • index.js je peux exiger ("myProject / someFolder / hey.js") au lieu de require ("./ someFolder / hey.js")
      • someFolder qui contient hey.js

Ceci est plus utile lorsque vous êtes imbriqué dans des dossiers et qu'il est beaucoup moins fastidieux de modifier l'emplacement d'un fichier s'il est défini de manière absolue. J'utilise seulement 2 le parent requis dans toute mon application .


4
J'utilise approche similaire, sauf que j'ajouter locale (projet de) node_modulesdans /src, et laisser /node_modulesaux fournisseurs de garder les choses séparées. J'ai donc /src/node_modulespour le code local et /node_modulespour les fournisseurs.
Marius Balčytis

33
À mon humble avis, le dossier node_modules est juste pour node_modules. Ce n'est pas une bonne pratique de mettre tout votre projet dans ce dossier.
McSas

2
@McSas, que proposez-vous comme alternative pour obtenir le même effet que ci-dessus?
spieglio

3
@cspiegl Vous pouvez utiliser la NODE_PATHvariable d'environnement
Christopher Tarquini

5

À mon humble avis, la façon la plus simple d'y parvenir est de créer un lien symbolique au démarrage de l'application node_modules/app(ou comme vous l'appelez) qui pointe vers ../app. Ensuite, vous pouvez simplement appeler require("app/my/module"). Des liens symboliques sont disponibles sur toutes les principales plateformes.

Cependant, vous devez toujours diviser votre contenu en modules plus petits et maintenables qui sont installés via npm. Vous pouvez également installer vos modules privés via git-url, il n'y a donc aucune raison d'en avoir un, un répertoire d'application monolithique.


La prise en charge sous Windows nécessite une connaissance plus approfondie de Node et du système d'exploitation. Il peut limiter l'utilisation généralisée d'un projet open source.
Steven Vachon

En général, je n'utiliserais pas ce modèle pour une bibliothèque (ce que sont la plupart des projets open source). Cependant, il est possible de créer ces liens symboliques dans le hook de compilation npm, de sorte qu'aucune connaissance approfondie n'est requise par l'utilisateur.
Johannes Ewald du

Bien sûr, mais Node.js sous Windows ne prend pas en charge les liens symboliques par défaut.
Steven Vachon

4

Dans votre propre projet, vous pouvez modifier n'importe quel fichier .js utilisé dans le répertoire racine et ajouter son chemin d'accès à une propriété de la process.envvariable. Par exemple:

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

Ensuite, vous pouvez accéder à la propriété partout:

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

4

Une autre réponse:

Imaginez cette structure de dossiers:

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

    • test.js

Ensuite, dans test.js , vous devez exiger des fichiers comme celui-ci:

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

et dans main.js :

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

Vous pouvez maintenant utiliser babel et le résolveur de module d'extension de babel avec cela. Fichier babelrc pour configurer 2 dossiers racine:

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

Maintenant, vous pouvez exiger des fichiers de la même manière dans les tests et dans src :

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

et si vous voulez utiliser la syntaxe du module es6 :

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

puis vous importez des fichiers dans des tests et src comme ceci:

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


3

Le examplesrépertoire ne pourrait-il pas contenir un node_modulesavec un lien symbolique vers la racine du projet project -> ../../permettant ainsi aux exemples d'utiliser require('project'), bien que cela ne supprime pas le mappage, il permet à la source d'utiliser require('project')plutôt querequire('../../') .

J'ai testé cela, et cela fonctionne avec la v0.6.18.

Liste du projectrépertoire:

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

Le contenu de index.jsaffecte une valeur à une propriété de l' exportsobjet et l'invoque console.logavec un message indiquant qu'elle était requise. Le contenu de test.jsis require('project').


pouvez-vous montrer le code source de votre test s'il vous plaît? bien, et cela fonctionnerait si je devais exiger ('project.a') de cette façon?
Totty.js

Qu'entendez-vous par require('project.a')? Je pense que cela pourrait signifier require('project/a'), bien que ce require('project').asoit également possible?
Dan D.

mais avec votre exemple, je devrais créer ces dossiers dans chaque dossier où il y a un module qui a besoin de la méthode require. Quoi qu'il en soit, vous devrez faire attention aux heures de "../" en fonction du dossier.
Totty.js

En fait, le lien n'aurait besoin que d'être dans un node_modulesrépertoire du parent le plus proche des deux fichiers et le lien serait alors le même pour les deux. Voir nodejs.org/api/…
Dan D.

Et serait relative de cet endroit. Par exemple:project/node_modules/project -> ../ .
Dan D.

2

Si quelqu'un cherche encore un autre moyen de contourner ce problème, voici ma propre contribution à l'effort:

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

L'idée de base: vous créez un fichier JSON à la racine du projet qui mappe vos chemins de fichiers à des noms abrégés (ou demandez à use-automapper de le faire pour vous). Vous pouvez ensuite demander vos fichiers / modules en utilisant ces noms. Ainsi:

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

Il y a donc ça.


2

Ce que j'aime faire, c'est tirer parti de la façon dont le nœud se charge à partir du répertoire node_module pour cela.

Si on essaie de charger le module "chose", on ferait quelque chose comme

require('thing');

Le nœud recherchera alors le répertoire 'thing' dans le répertoire 'node_module'.

Étant donné que le node_module est normalement à la racine du projet, nous pouvons tirer parti de cette cohérence. (Si node_module n'est pas à la racine, alors vous avez d'autres maux de tête auto-induits à gérer.)

Si nous allons dans le répertoire et que nous en ressortons, nous pouvons obtenir un chemin cohérent vers la racine du projet de noeud.

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

Ensuite, si nous voulons accéder au répertoire / happy, nous le ferions.

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

Bien que ce soit un peu hacky, cependant je pense que si la fonctionnalité de la façon dont charge les node_modules change, il y aura de plus gros problèmes à gérer. Ce comportement doit rester cohérent.

Pour clarifier les choses, je le fais, car le nom du module n'a pas d'importance.

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

Je l'ai utilisé récemment pour angular2. Je veux charger un service à partir de la racine.

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

À propos de votre référence angulaire, avec une application CLI standard, vous pouvez simplement importer src/app/my.service, vous pouvez également configurer VSC pour utiliser des importations non relatives pour les fichiers dactylographiés.
Ploppy

2

J'ai écrit ce petit package qui vous permet d'exiger des packages par leur chemin relatif depuis la racine du projet, sans introduire de variables globales ni remplacer les valeurs par défaut des nœuds

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

Ça marche comme ça

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

Parfois, j'ai des packages privés dans le projet principal, ce script rompt avec cela. En plus de cela, je ne suis pas sûr que cela fonctionnera bien avec webpack (au cas où vous utilisez webpack avec node.js comme je le fais)
Totty.js

Si vous avez des répertoires imbriqués avec des fichiers de package, chaque répertoire ne pourra exiger que des fichiers dans son package. N'est-ce pas le comportement que vous souhaitez? Je n'ai pas testé avec webpack.
gafi

Cela a parfaitement fonctionné pour un projet simple et est beaucoup plus facile que toutes les autres réponses.
byxor

2

Je veux juste donner suite à l' excellente réponse de Paolo Moretti et de Browserify. Si vous utilisez un transpilateur (par exemple, babel, dactylographié) et que vous avez des dossiers séparés pour le code source et transpilé comme src/et dist/, vous pouvez utiliser une variante des solutions comme

node_modules

Avec la structure de répertoires suivante:

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

vous pouvez ensuite laisser babel etc transpiler le srcrépertoire versdist répertoire.

lien symbolique

En utilisant un lien symbolique, nous pouvons supprimer certains niveaux d'imbrication:

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

Une mise en garde avec babel --copy-files Le --copy-filesdrapeau de babelne gère pas bien les liens symboliques. Il peut continuer à naviguer dans le ..lien symbolique et à voir récurremment des fichiers sans fin. Une solution de contournement consiste à utiliser la structure de répertoires suivante:

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

De cette façon, le code sous srcsera apprésolu src, alors que babel ne verra plus de liens symboliques.


Merci mais je ne recommanderais pas de faire cette magie. Vous perdrez d'abord toutes les importations, elles ne seront pas calculées par votre IDE. Si vous utilisez d'autres outils comme le type de flux, cela ne fonctionnera pas non plus correctement.
Totty.js

En fait, le flux semble fonctionner dans mon cas, ce qui n'est pas surprenant car les solutions dépendent du modèle de résolution de module de nœud standard et des liens symboliques. Ce n'est donc pas vraiment magique pour des outils comme le flux de comprendre. Mais les IDE sont différents.
user716468

2

Je cherchais exactement la même simplicité pour exiger des fichiers de n'importe quel niveau et j'ai trouvé un alias de module .

Installez simplement:

npm i --save module-alias

Ouvrez votre fichier package.json, ici vous pouvez ajouter des alias pour vos chemins, par exemple

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

Et utilisez vos alias simplement:

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


1

Nous sommes sur le point d'essayer une nouvelle façon de résoudre ce problème.

En prenant des exemples d'autres projets connus comme spring et guice, nous définirons un objet "context" qui contiendra toutes les instructions "require".

Cet objet sera ensuite transmis à tous les autres modules pour utilisation.

Par exemple

var context = {}

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

Cela nous oblige à écrire chaque module comme une fonction qui reçoit des opts, ce qui nous semble de toute façon une meilleure pratique.

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

puis vous vous référerez au contexte au lieu d'exiger des trucs.

var module1Ref = context.moduel1;

Si vous le souhaitez, vous pouvez facilement écrire une boucle pour faire les instructions require

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

Cela devrait vous faciliter la vie lorsque vous souhaitez vous moquer (tests) et résout également votre problème en cours de route tout en rendant votre code réutilisable en tant que package.

Vous pouvez également réutiliser le code d'initialisation du contexte en séparant la déclaration des beans. par exemple, votre main.jsfichier pourrait ressembler à

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

Cette méthode s'applique également aux bibliothèques externes, pas besoin de coder en dur leurs noms à chaque fois que nous en avons besoin - cependant elle nécessitera un traitement spécial car leurs exportations ne sont pas des fonctions qui attendent du contexte.

Plus tard, nous pouvons également définir les beans comme des fonctions - ce qui nous permettra de requiredifférents modules en fonction de l'environnement - mais cela hors de la portée de ce thread.


1

J'avais des problèmes avec ce même problème, j'ai donc écrit un package appelé include .

Incluez des poignées pour déterminer le dossier racine de votre projet en localisant votre fichier package.json, puis passez l'argument de chemin que vous lui donnez au require () natif sans tout le désordre de chemin relatif. J'imagine que ce n'est pas un remplacement de require (), mais un outil pour exiger la gestion de fichiers ou de bibliothèques non packagés / non tiers. Quelque chose comme

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

J'espère que cela peut être utile.


1

Si le fichier js du point d'entrée de votre application (c'est-à-dire celui sur lequel vous exécutez réellement "node") se trouve dans le répertoire racine de votre projet, vous pouvez le faire très facilement avec le module rootpath npm . Installez-le simplement via

npm install --save rootpath

... puis tout en haut du fichier js du point d'entrée, ajoutez:

require('rootpath')();

À partir de ce moment, tous les appels requis sont désormais relatifs à la racine du projet - par exemple require('../../../config/debugging/log'); devient require('config/debugging/log');(où le dossier de configuration se trouve à la racine du projet).


1

En termes simples, vous pouvez appeler votre propre dossier en tant que module:

Pour cela, nous avons besoin de: module global et module-app-path

ici "App-module-path" est le module, il vous permet d'ajouter des répertoires supplémentaires au chemin de recherche du module Node.js Et "global" est, tout ce que vous attachez à cet objet sera b disponible partout dans votre application.

Jetez maintenant un œil à cet extrait:

global.appBasePath = __dirname;

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

__dirname est le répertoire courant du nœud. Vous pouvez donner ici votre propre chemin pour rechercher le chemin du module.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.