¿Cómo hacer que node.js requiera absoluto? (en lugar de relativo)

234

Me gustaría solicitar mis archivos siempre por la raíz de mi proyecto y no en relación con el módulo actual.

Por ejemplo, si mira https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js línea 6 verá

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

Eso es realmente malo OMI. Imagine que me gustaría poner todos mis ejemplos más cerca de la raíz solo en un nivel. Eso sería imposible, porque tendría que actualizar más de 30 ejemplos y muchas veces dentro de cada ejemplo. A esto:

express = require('../')

Mi solución sería tener un caso especial para raíz basada: si una cadena comienza con un $, entonces es relativa a la carpeta raíz del proyecto.

Cualquier ayuda es apreciada, gracias

Actualización 2

Ahora estoy usando require.js que le permite escribir de una manera y funciona tanto en el cliente como en el servidor. Require.js también te permite crear rutas personalizadas.

Actualización 3

Ahora me mudé a webpack + gulp y uso el requerimiento mejorado para manejar módulos en el lado del servidor. Vea aquí la justificación: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/

Totty.js
fuente
Si alguna vez decide usar una constante / variable de ruta raíz explícita, esta respuesta funciona para eso . La solución utiliza un pequeño módulo github para determinar la ruta raíz.
impulsado por vapor el

Respuestas:

162

Y que hay con:

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

Requiere el archivo como si fuera necesario desde el archivo js principal, por lo que funciona bastante bien siempre que su archivo js principal esté en la raíz de su proyecto ... y eso es algo que agradezco.

cronvel
fuente
No es una mala idea (: luego puede definir algunos otros métodos para reasignar de alguna manera la aplicación en su módulo require.main. Creo que podría hacer require.main.req ('client / someMod'). Buena idea, pero esto sería ser más detallado que mis requisitos actuales. Además, no creo que valga la pena porque tampoco me gusta browserify porque los cambios no son instantáneos y se pierden los cambios (porque mi código debe ejecutarse tanto en el navegador como en node.js).
Totty.js
44
Si lo encuentra demasiado detallado, simplemente use .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel
Sí, esto puede ser útil para alguien que todavía quiere usar browserify para el lado del cliente. Para mí ya no hay necesidad, pero gracias de todos modos por su respuesta (:
Totty.js
66
SI PRINCIPAL ESTÁ EN LA RAÍZ DE SU PROYECTO :)
Alexander Mills
12
Esta solución no funcionará si el código está cubierto con pruebas unitarias como la prueba Mocha
alx lark el
129

Hay una sección realmente interesante en el Manual de Browserify :

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

No todo en una aplicación pertenece adecuadamente al npm público y la sobrecarga de configurar un npm privado o un repositorio de git sigue siendo bastante grande en muchos casos. Aquí hay algunos enfoques para evitar el ../../../../../../../problema de las rutas relativas.

nodo_módulos

Las personas a veces se oponen a colocar módulos específicos de la aplicación en node_modules porque no es obvio cómo registrar sus módulos internos sin también registrar los módulos de terceros desde npm.

¡La respuesta es bastante simple! Si tiene un .gitignorearchivo que ignora node_modules:

node_modules

Simplemente puede agregar una excepción con !cada uno de sus módulos de aplicación internos:

node_modules/*
!node_modules/foo
!node_modules/bar

Tenga en cuenta que no puede ignorar un subdirectorio, si el padre ya se ignora. Entonces, en lugar de ignorar node_modules, debe ignorar cada directorio dentro node_modules con el node_modules/*truco, y luego puede agregar sus excepciones.

Ahora, en cualquier lugar de su aplicación, podrá require('foo') o require('bar')no tener una ruta relativa muy grande y frágil.

Si tiene muchos módulos y desea mantenerlos más separados de los módulos de terceros instalados por npm, puede colocarlos todos en un directorio node_modulescomo node_modules/app:

node_modules/app/foo
node_modules/app/bar

Ahora podrá require('app/foo')o require('app/bar') desde cualquier lugar de su aplicación.

En su .gitignore, simplemente agregue una excepción para node_modules/app:

node_modules/*
!node_modules/app

Si su aplicación tenía transformaciones configuradas en package.json, deberá crear un package.json separado con su propio campo de transformación en su directorio node_modules/fooo node_modules/app/foocomponente porque las transformaciones no se aplican a través de los límites del módulo. Esto hará que sus módulos sean más robustos frente a los cambios de configuración en su aplicación y será más fácil reutilizar de forma independiente los paquetes fuera de su aplicación.

enlace simbólico

Otro truco útil si está trabajando en una aplicación en la que puede crear enlaces simbólicos y no necesita admitir ventanas es vincular una lib/ o una app/carpeta node_modules. Desde la raíz del proyecto, haga:

ln -s ../lib node_modules/app

y ahora desde cualquier parte de su proyecto podrá solicitar archivos lib/haciendo require('app/foo.js')para obtener lib/foo.js.

caminos personalizados

Es posible que vea algunos lugares que hablan sobre el uso de la $NODE_PATH variable de entorno o opts.pathspara agregar directorios para el nodo y browserify para buscar módulos.

A diferencia de la mayoría de las otras plataformas, el uso de una matriz de directorios de ruta con estilo de shell $NODE_PATHno es tan favorable en el nodo en comparación con el uso efectivo del node_modulesdirectorio.

Esto se debe a que su aplicación está más estrechamente acoplada a una configuración de entorno de tiempo de ejecución, por lo que hay más partes móviles y su aplicación solo funcionará cuando su entorno esté configurado correctamente.

node y browserify son compatibles pero desalientan el uso de $NODE_PATH.

Paolo Moretti
fuente
17
El único inconveniente de ponerlo en la node_modulescarpeta es que hace que sea más difícil nukear la rm -rf node_modulescarpeta ( )
Michael
13
@Michael No es mucho más difícil: git clean -dx node_modules
Peter Wilkinson
3
O, en caso de que haya olvidado la git cleansintaxis, siempre se puede rm -rf node_modules && git checkout node_modules: asegúrese de que git stashhaya cambios en los node_modulessubdirectorios.
derenio
1
Me gusta la idea de usar node_modules, pero no para almacenar el código fuente teniendo en cuenta lo volátil que puede ser. ¿No tendría más sentido publicar el módulo separado y guardarlo como una dependencia en el proyecto original? Proporciona una solución clara a la volatilidad del directorio node_modules y solo se basa en npm, en lugar de depender de git, enlaces simbólicos o la solución $ NODE_PATH.
Kevin Koshiol
1
NODE_PATH parece el camino a seguir. "su aplicación solo funcionará cuando su entorno esté configurado correctamente" ¡esto siempre es cierto! ¿No es más fácil configurar el entorno (generalmente en un archivo) que cambiar cada importación en cada archivo?
CpILL
73

Me gusta hacer una nueva node_modulescarpeta para el código compartido, luego dejar que node y require hagan lo que mejor sabe hacer.

por ejemplo:

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

Por ejemplo, si estás dentro car/index.js, puedes require('helper')y el nodo lo encontrará.

Cómo funcionan los node_modules

El nodo tiene un algoritmo inteligente para resolver módulos que es único entre las plataformas rivales.

Si eres require('./foo.js')de /beep/boop/bar.js, el nodo buscará ./foo.jsen /beep/boop/foo.js. Las rutas que comienzan con ./o ../siempre son locales al archivo que llama require().

Sin embargo, si necesita un nombre no relativo como require('xyz')from /beep/boop/foo.js, el nodo busca estas rutas en orden, deteniéndose en la primera coincidencia y generando un error si no se encuentra nada:

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

Para cada xyzdirectorio que existe, el nodo primero buscará un xyz/package.jsonpara ver si "main"existe un campo. El "main"campo define qué archivo debe encargarse si require()la ruta del directorio.

Por ejemplo, si /beep/node_modules/xyzes el primer partido y /beep/node_modules/xyz/package.jsontiene:

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

entonces las exportaciones de /beep/node_modules/xyz/lib/abc.jsserán devueltas por require('xyz').

Si no hay package.jsono no hay "main"campo, index.jsse supone:

/beep/node_modules/xyz/index.js
Blair Anderson
fuente
2
Gran explicación sobre cómo funciona al cargar un módulo
desde el
2
Esta es una solución muy elegante, evita todos los problemas en las respuestas anteriores. Debe considerarse la respuesta, en mi humilde opinión.
rodurico
38

El panorama

Parece "realmente malo" pero dale tiempo. Es, de hecho, realmente bueno. Los require()s explícitos brindan una total transparencia y facilidad de comprensión que es como un soplo de aire fresco durante el ciclo de vida de un proyecto.

Piénselo de esta manera: está leyendo un ejemplo, sumergiendo los dedos de los pies en Node.js y ha decidido que es "realmente una mala OMI". Ustedes son líderes dudosos de la comunidad Node.js, personas que han registrado más horas escribiendo y manteniendo aplicaciones Node.js que nadie. ¿Cuál es la posibilidad de que el autor haya cometido un error tan novato? (Y estoy de acuerdo, desde mi experiencia en Ruby y Python, al principio parece un desastre).

Hay muchas exageraciones y contra-exageraciones en torno a Node.js. Pero cuando el polvo se asiente, reconoceremos que los módulos explícitos y los paquetes "locales primero" fueron un importante impulsor de la adopción.

El caso comun

Por supuesto, node_modulesdesde el directorio actual, se busca el padre, el abuelo, el bisabuelo, etc. Entonces, los paquetes que ha instalado ya funcionan de esta manera. Por lo general, puede require("express")hacerlo desde cualquier parte de su proyecto y funciona bien.

Si se encuentra cargando archivos comunes desde la raíz de su proyecto (tal vez porque son funciones de utilidad comunes), entonces esa es una gran pista de que es hora de hacer un paquete. Los paquetes son muy simples: mueva sus archivos node_modules/y colóquelos package.json allí. Voila! Se puede acceder a todo en ese espacio de nombres desde todo su proyecto. Los paquetes son la forma correcta de llevar su código a un espacio de nombres global.

Otras soluciones

Yo personalmente no uso estas técnicas, pero sí responden a tu pregunta, y por supuesto conoces tu propia situación mejor que yo.

Puede configurar $NODE_PATHla raíz de su proyecto. Ese directorio se buscará cuando usted require().

A continuación, podría comprometer y requerir un archivo local común de todos sus ejemplos. Ese archivo común simplemente reexporta el archivo verdadero en el directorio de abuelos.

examples / downloads / app.js (y muchos otros como este)

var express = require('./express')

ejemplos / descargas / express.js

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

Ahora, cuando reubica esos archivos, el peor de los casos es arreglar el módulo de una cuña .

JasonSmith
fuente
14
Estoy de acuerdo en que los chicos de Node.js deben haber elegido los requisitos relativos por una razón. Simplemente no puedo ver sus ventajas, ni de su respuesta. Todavía me siento "mal";)
Adam Schmideg
21
"Ustedes son los líderes de la comunidad Node.js" - Los mismos líderes decidieron usar devoluciones de llamada en lugar de futuros / promesas. La mayoría de mis consultorías de nodejs implican maldecir a dichos "líderes" y convencer a la gente para que se mude a JVM. Lo que es mucho más fácil después de unos meses de usar nodejs :)
David Sergey
8
@nirth, muévete a JVM? Por el amor de Dios, ¿por qué?
Ivancho
31
"Ustedes son los líderes adivinos de la comunidad Node.js", por favor eviten este tono desalentador.
atlex2
15
Maldita sea, es el segundo que adivina a los líderes de los nodos. Así es como progresa la industria. Si los chicos del nodo no adivinaran los líderes que apuntalaron los modelos de concurrencia basados ​​en hilos, no tendríamos un nodo.
d512
20

Echa un vistazo a node-rfr .

Es tan simple como esto:

var rfr = require('rfr');
var myModule = rfr('projectSubDir/myModule');
mar cálido
fuente
Creo que la segunda línea debería ser var myModule = rfr ('/ projectSubDir / myModule');
Sikorski el
1
De los documentos: var module2 = rfr ('lib / module2'); // Se puede omitir la barra inclinada inicial.
igelineau
Lo intenté y rfr funciona bien para ejecutar con el nodo, pero rompe la navegación de código con VS Code ... No he podido encontrar una solución, para poder usar autocompletar en VS ...
Alex Mantaut
13

Si usa hilo en lugar de npm , puede usar espacios de trabajo .

Digamos que tengo una carpeta servicesque deseo requerir más fácilmente:

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

Para crear un espacio de trabajo de Yarn, cree un package.jsonarchivo dentro de services folder:

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

En su paquete principal.json agregue:

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

Ejecutar yarn installdesde la raíz del proyecto.

Luego, en cualquier parte de su código, puede hacer:

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

en lugar de algo como:

const { myFunc } = require('../../../../../../services/foo')
cyberwombat
fuente
66
¿Quizás sea una idea aclarar que esto solo funciona para hilo , no para npm? Pensé que probablemente también funcionaría para npm, así que pasé un poco de tiempo preguntándome qué había hecho mal hasta que intenté usar hilo. Podría haber sido una suposición estúpida, pero quizás no soy el único.
ArneHugo
2
He editado un poco para aclarar. Perdón por la confusion.
cyberwombat
12

En mi humilde opinión, la forma más fácil es definir su propia función como parte del GLOBALobjeto. Cree projRequire.jsen la raíz de su proyecto con los siguientes contenidos:

var projectDir = __dirname;

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

En su archivo principal antes de requireincorporar cualquiera de los módulos específicos del proyecto:

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

Después de eso, lo siguiente funciona para mí:

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

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


@Totty, he encontrado otra solución que podría funcionar para el caso que describiste en los comentarios. La descripción será tl;dr, así que mejor muestro una imagen con la estructura de mi proyecto de prueba .

Aleksei Zabrodskii
fuente
bueno, hasta ahora esta parece la mejor manera de hacerlo. Lo hago: GLOBAL.requires = require ('r'). R; en mi archivo index.js. Pero tengo un problema en mis pruebas de votos, no ejecutan index.js, por lo que mis pruebas fallan porque requiere S no está definido. De todos modos, por ahora puedo agregar GLOBAL.requires = require ('r'). R; en la parte superior de cada prueba. alguna idea mejor? github.com/totty90/production01_server/commit/…
Totty.js
el problema ocurre cuando estoy en "pathes-test / node_modules / other.js" y necesito el "pathes-test / node_modules / some.js". Debería requerir ('./ some') en lugar de require ("prj / some"). ¿Y de esta manera toda mi aplicación estaría en el directorio node_modules?
Totty.js
@Totty, no hay problema que requiera prj/somede prj/other(recién probado require('prj/some'). Todos los módulos comunes de su aplicación pueden ir allí (por ejemplo, la capa de base de datos). No hará ninguna diferencia en sus, digamos, libes. Intenta ver si es adecuado.
Aleksei Zabrodskii
sí, lo he actualizado: github.com/totty90/production01_server/tree/master/node_modules/… que funcionó muy bien. ¿Pero puedo poner todos mis archivos en un nivel sin usar node_modules?
Totty.js
12

Yo uso process.cwd()en mis proyectos. Por ejemplo:

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

Vale la pena señalar que esto dará como resultado requireun camino absoluto, aunque aún no he tenido problemas con esto.

Walter Roman
fuente
1
Esa es una mala idea porque CWD no tiene que ser el mismo directorio donde se guarda la aplicación.
jiwopene
11

Hay una buena discusión sobre este tema aquí .

Me encontré con el mismo problema arquitectónico: querer una forma de darle a mi aplicación más organización y espacios de nombres internos, sin:

  • mezclar módulos de aplicación con dependencias externas o molestarse con repositorios privados de npm para código específico de la aplicación
  • utilizando requisitos relativos, que dificultan la refactorización y la comprensión
  • usando enlaces simbólicos o cambiando la ruta del nodo, lo que puede oscurecer las ubicaciones de origen y no jugar bien con el control de origen

Al final, decidí organizar mi código usando convenciones de nomenclatura de archivos en lugar de directorios. Una estructura se vería algo así como:

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

Luego en código:

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');

y dependencias externas están disponibles desde node_modules como de costumbre:

var express = require('express');

De esta manera, todo el código de la aplicación se organiza jerárquicamente en módulos y está disponible para todos los demás códigos relativos a la raíz de la aplicación.

La principal desventaja es, por supuesto, que en un explorador de archivos, no puede expandir / colapsar el árbol como si realmente estuviera organizado en directorios. Pero me gusta que sea muy explícito acerca de dónde proviene todo el código, y no usa ninguna 'magia'.

iluminado indirectamente
fuente
Desde la esencia que vinculó, la solución # 7, "The Wrapper", es bastante simple y conveniente.
Pier-Luc Gendreau
Veo una pequeña conveniencia más: "mover" un archivo a una "carpeta" diferente se convierte en un cambio de nombre, que es más fácil que mover un archivo. Además, tiendo a notar que después de media hora de trabajo en el proyecto, casi todo mi árbol de aplicaciones se expande de todos modos. Agregar 1 nivel de espacio de carpeta puede hacer que la gran base de código sea manejable y no introducir demasiado, ../x/xque ya es legible.
Ski
Está reinventando carpetas, utilizando puntos en lugar de barras, para superar una clara falta en nodejs.
Simone Gianni
9

Suponiendo que la raíz de su proyecto es el directorio de trabajo actual, esto debería funcionar:

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

// require file relative to current working directory
config = require( path.resolve('.','config.js') );
protometa
fuente
config = require('./config.js');También es válido.
cespon
77
@cespon no, eso es solo relativo al archivo requerido.
protometa
8

He probado muchas de estas soluciones. Terminé agregando esto a la parte superior de mi archivo principal (por ejemplo, index.js):

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

Esto agrega la raíz del proyecto a NODE_PATH cuando se carga el script. El me permite requerir cualquier archivo en mi proyecto haciendo referencia a su ruta relativa desde la raíz del proyecto como var User = require('models/user'). Esta solución debería funcionar siempre que esté ejecutando un script principal en la raíz del proyecto antes de ejecutar cualquier otra cosa en su proyecto.

senornestor
fuente
8

Algunas de las respuestas dicen que la mejor manera es agregar el código al nodo_módulo como un paquete, estoy de acuerdo y es probablemente la mejor manera de perder el ../../../requerimiento, pero ninguno de ellos brinda una forma de hacerlo.

desde la versión 2.0.0, puede instalar un paquete desde archivos locales, lo que significa que puede crear una carpeta en su raíz con todos los paquetes que desee,

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

así que en package.json puede agregar modules(o fooy bar) como un paquete sin publicar o usar un servidor externo como este:

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

Después de eso, puede hacerlo npm install, y puede acceder al código con var foo = require("foo"), como lo hace con todos los demás paquetes.

Aquí se puede encontrar más información :

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

y aquí cómo crear un paquete:

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

Yan Mayatskiy
fuente
1
"Esta característica es útil para el desarrollo local fuera de línea y para la creación de pruebas que requieren la instalación de npm donde no desea acceder a un servidor externo, pero no debe usarse al publicar paquetes en el registro público".
Ryan Smith
7

Podrías usar un módulo que hice, Undot . No es nada avanzado, solo un ayudante para que puedas evitar esos infierno de puntos con simplicidad.

Ejemplo:

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

Podría definir algo como esto en su app.js:

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

y luego, cada vez que desee requerir algo de la raíz, sin importar dónde se encuentre, simplemente use requireFromRoot en lugar del require vanilla. Funciona bastante bien para mí hasta ahora.

usuario1417684
fuente
¡Gracias! Creo que esto es bastante inteligente y directo.
Ryan
Perdóname padre porque he pecado. Porté esto a ES6 y obtuve el siguiente: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Me encanta la solución, pero ¿realmente tienes que unir __dirname así?
Nuck
1
Mi memoria es un poco confusa en esto, pero creo que __dirname cambia el valor dependiendo del archivo en el que se usa. Ahora puede ser que, dado que la función se define en un solo lugar pero se usa en varios lugares, el valor permanecería constante incluso sin este enlace, pero lo hice para asegurarme de que este sea el caso.
user1417684
hizo esto hace mucho tiempo, causa dolores al probar envs y cosas por el estilo. No vale la pena los gastos generales. aleatorio nuevo global hace que nuevas personas sean inciertas bla bla
The Dembinski
¿Y cómo requirefunciona esto?
Darko Maksimovic
5

Esta es la forma en que lo estoy haciendo durante más de 6 meses. Utilizo una carpeta llamada node_modules como mi carpeta raíz en el proyecto, de esta manera siempre buscará esa carpeta en todas partes que llamo un requerimiento absoluto:

  • nodo_módulos
    • mi proyecto
      • index.js puedo requerir ("myProject / someFolder / hey.js") en lugar de require ("./ someFolder / hey.js")
      • someFolder que contiene hey.js

Esto es más útil cuando está anidado en carpetas y es mucho menos trabajo cambiar la ubicación de un archivo si está configurado de manera absoluta. Solo uso 2 los requisitos relativos en toda mi aplicación .

Totty.js
fuente
44
Yo uso enfoque similar, excepto que agrego local (proyecto de) node_modulesen /src, y dejar /node_modulesa los vendedores para mantener las cosas separadas. Así que tengo /src/node_modulespara el código local y /node_modulespara los vendedores.
Marius Balčytis
33
En mi humilde opinión, la carpeta node_modules es solo para node_modules. No es una buena práctica poner todo su proyecto dentro de esa carpeta.
McSas
2
@McSas, ¿qué sugeriría como alternativa para obtener el mismo efecto que el anterior?
spieglio
3
@cspiegl Puede usar la NODE_PATHvariable de entorno
Christopher Tarquini
5

En mi opinión, la forma más fácil de lograr esto es mediante la creación de un enlace simbólico en el inicio de la aplicación node_modules/app(o como se llame) que apunta ../app. Entonces puedes simplemente llamar require("app/my/module"). Los enlaces simbólicos están disponibles en todas las plataformas principales.

Sin embargo, aún debe dividir sus cosas en módulos más pequeños y fáciles de mantener que se instalan a través de npm. También puede instalar sus módulos privados a través de git-url, por lo que no hay razón para tener un directorio de aplicaciones monolítico.

Johannes Ewald
fuente
El soporte en Windows requiere un conocimiento más profundo de Node y el sistema operativo. Puede limitar el uso generalizado de un proyecto de código abierto.
Steven Vachon
En general, no usaría este patrón para una biblioteca (que son la mayoría de los proyectos de código abierto). Sin embargo, es posible crear estos enlaces simbólicos en el gancho de compilación npm para que el usuario no necesite un conocimiento profundo.
Johannes Ewald
Claro, pero Node.js en Windows no admite enlaces simbólicos por defecto.
Steven Vachon
4

En su propio proyecto, puede modificar cualquier archivo .js que se use en el directorio raíz y agregar su ruta a una propiedad de la process.envvariable. Por ejemplo:

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

Luego puede acceder a la propiedad desde cualquier lugar:

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

Otra respuesta:

Imagina esta estructura de carpetas:

  • nodo_módulos
    • lodash
  • src
    • subdir
      • foo.js
      • bar.js
    • main.js
  • pruebas

    • test.js

Luego, en test.js , debe requerir archivos como este:

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

y en main.js :

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

Ahora puede usar babel y babel-plugin-module-resolver con esto. archivo babelrc para configurar 2 carpetas raíz:

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

Ahora puede requerir archivos de la misma manera en pruebas y en src :

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

y si quieres usar la sintaxis del módulo es6 :

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

luego importas archivos en pruebas y src como este:

import foo from "foo"
import bar from "bar"
import _ from "lodash"
Soldados
fuente
3

No podría el examplesdirectorio de contener una node_modulescon un enlace simbólico a la raíz del proyecto project -> ../../permitiendo así que los ejemplos de uso require('project'), aunque esto no elimina el mapeo, sí permite a la fuente a utilizar require('project')en lugar de require('../../').

He probado esto y funciona con v0.6.18.

Listado de projectdirectorio:

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

El contenido de index.jsasigna un valor a una propiedad del exportsobjeto e invoca console.logcon un mensaje que indica que fue requerido. El contenido de test.jses require('project').

Dan D.
fuente
¿puede mostrar el código fuente de su prueba por favor? bien, ¿y funcionaría si tuviera que requerir ('proyecto.a') de esta manera?
Totty.js
¿Qué quieres decir con require('project.a')? Creo que eso podría significar require('project/a'), aunque require('project').atambién es posible?
Dan D.
pero con su ejemplo, necesitaría crear esas carpetas en cada carpeta donde hay un módulo que necesita el método requerido. De todos modos, debe tener cuidado con los tiempos de "../" dependiendo de la carpeta.
Totty.js
En realidad, el enlace solo necesitaría estar en un node_modulesdirectorio en el padre más cercano de ambos archivos y el enlace sería el mismo para ambos. Ver nodejs.org/api/…
Dan D.
Y sería relativo desde esa ubicación. Por ejemplo: project/node_modules/project -> ../.
Dan D.
2

Si alguien está buscando otra forma de solucionar este problema, esta es mi propia contribución al esfuerzo:

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

La idea básica: crea un archivo JSON en la raíz del proyecto que asigna tus rutas de archivo a nombres abreviados (u obtienes use-automapper para que lo haga por ti). Luego puede solicitar sus archivos / módulos con esos nombres. Al igual que:

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

Entonces ahí está eso.

Jon Stout
fuente
2

Lo que me gusta hacer es aprovechar cómo se carga el nodo desde el directorio node_module para esto.

Si uno intenta cargar la "cosa" del módulo, haría algo como

require('thing');

Node buscará el directorio 'thing' en el directorio 'node_module'.

Dado que node_module está normalmente en la raíz del proyecto, podemos aprovechar esta coherencia. (Si node_module no está en la raíz, entonces tiene que lidiar con otros dolores de cabeza autoinducidos).

Si entramos en el directorio y luego salimos de él, podemos obtener una ruta coherente a la raíz del proyecto de nodo.

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

Entonces, si queremos acceder al directorio / happy, haremos esto.

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

Aunque es bastante hacky, creo que si cambia la funcionalidad de la carga de node_modules, habrá problemas más grandes con los que lidiar. Este comportamiento debe permanecer consistente.

Para aclarar las cosas, hago esto, porque el nombre del módulo no importa.

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

Lo usé recientemente para angular2. Quiero cargar un servicio desde la raíz.

import {MyService} from 'root/../../app/services/http/my.service';
justonpoints
fuente
Acerca de su referencia angular, con una aplicación CLI estándar, simplemente puede importar src/app/my.service, también puede configurar VSC para usar importaciones no relativas para archivos de mecanografía.
Ploppy
2

Escribí este pequeño paquete que le permite solicitar paquetes por su ruta relativa desde la raíz del proyecto, sin introducir ninguna variable global o anular los valores predeterminados del nodo

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

Funciona así

// 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()
gafi
fuente
A veces tengo paquetes privados en el proyecto principal, este script se romperá con eso. Además de eso, no estoy seguro de que funcione bien con webpack (en caso de que use webpack con node.js como lo hago yo)
Totty.js
Si ha anidado directorios con archivos de paquete, cada directorio solo podrá requerir archivos dentro de su paquete. ¿No es ese el comportamiento que quieres? No he probado con webpack.
gafi
Esto funcionó perfectamente para un proyecto simple y es mucho más fácil que cualquiera de las otras respuestas.
byxor
2

Solo quiero seguir la gran respuesta de Paolo Moretti y Browserify. Si está utilizando un transpilador (por ejemplo, babel, mecanografiado) y tiene carpetas separadas para el código fuente y el código transpilado como src/y dist/, podría usar una variación de las soluciones como

nodo_módulos

Con la siguiente estructura de directorios:

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

entonces puede dejar que babel, etc. transpile srcdirectorio a distdirectorio.

enlace simbólico

Con el enlace simbólico podemos eliminar algunos niveles de anidamiento:

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

Una advertencia con babel --copy-files La --copy-filesbandera de babelno trata bien los enlaces simbólicos. Puede seguir navegando en el ..enlace simbólico y ver recusivamente archivos interminables. Una solución alternativa es usar la siguiente estructura de directorios:

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

De esta manera, el código debajo srcaún se habrá appresuelto src, mientras que Babel ya no verá enlaces simbólicos.

usuario716468
fuente
Gracias pero no recomendaría hacer esta magia. Primero perderá todas las importaciones, su IDE no las calculará. Si usa otras herramientas como el tipo de flujo, tampoco funcionará correctamente.
Totty.js
En realidad, el flujo parece funcionar en mi caso, lo cual no es sorprendente ya que las soluciones dependen del modelo de resolución del módulo de nodo estándar y los enlaces simbólicos. Por lo tanto, no es realmente mágico que las herramientas como flow entiendan. Pero los IDE son diferentes.
user716468
2

Estaba buscando exactamente la misma simplicidad para requerir archivos de cualquier nivel y encontré un alias de módulo .

Solo instale:

npm i --save module-alias

Abra su archivo package.json, aquí puede agregar alias para sus rutas, por ejemplo

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

Y usa tus alias simplemente:

require('module-alias/register')
const deep = require('@deep')
const module = require('something')
Talha Imam
fuente
1

Estamos a punto de probar una nueva forma de abordar este problema.

Tomando ejemplos de otros proyectos conocidos como spring y guice, definiremos un objeto de "contexto" que contendrá toda la declaración "require".

Este objeto se pasará a todos los demás módulos para su uso.

Por ejemplo

var context = {}

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

Esto requiere que escribamos cada módulo como una función que recibe opciones, lo que nos parece una mejor práctica de todos modos.

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

y luego te referirás al contexto en lugar de requerir cosas.

var module1Ref = context.moduel1;

Si lo desea, puede escribir fácilmente un bucle para hacer las declaraciones requeridas

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

Esto debería hacer la vida más fácil cuando quieres simular (pruebas) y también resuelve tu problema en el camino mientras haces que tu código sea reutilizable como un paquete.

También puede reutilizar el código de inicialización de contexto separando la declaración de beans. por ejemplo, su main.jsarchivo podría verse así

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

Este método también se aplica a bibliotecas externas, no es necesario codificar sus nombres cada vez que los requerimos; sin embargo, requerirá un tratamiento especial ya que sus exportaciones no son funciones que esperen contexto.

Más adelante también podemos definir beans como funciones, lo que nos permitirá requirediferentes módulos de acuerdo con el entorno, pero fuera del alcance de este hilo.

chico mograbi
fuente
1

Estaba teniendo problemas con este mismo problema, así que escribí un paquete llamado include .

Incluya identificadores para averiguar la carpeta raíz de su proyecto a través de la ubicación de su archivo package.json, luego pase el argumento de ruta que le da al require nativo () sin todo el desorden de ruta relativo. Me imagino que esto no es un reemplazo de require (), sino una herramienta para requerir el manejo de archivos o bibliotecas no empaquetadas / de terceros. Algo como

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

Espero que esto pueda ser útil.

Anthony Nichols
fuente
1

Si el archivo js del punto de entrada de su aplicación (es decir, en el que realmente ejecuta "nodo") está en el directorio raíz del proyecto, puede hacerlo realmente fácilmente con el módulo rootpath npm . Simplemente instálelo a través de

npm install --save rootpath

... luego, en la parte superior del archivo js del punto de entrada, agregue:

require('rootpath')();

A partir de ese momento, todas las llamadas requeridas ahora son relativas a la raíz del proyecto, por ejemplo, se require('../../../config/debugging/log'); convierte en require('config/debugging/log');(donde la carpeta de configuración está en la raíz del proyecto).

Andrew Faulkner
fuente
1

En líneas simples, puede llamar a su propia carpeta como módulo:

Para eso necesitamos: módulo global y de módulo de ruta de aplicación

aquí "App-module-path" es el módulo, le permite agregar directorios adicionales a la ruta de búsqueda del módulo Node.js Y "global" es que todo lo que adjunte a este objeto estará disponible en todas partes en su aplicación.

Ahora eche un vistazo a este fragmento:

global.appBasePath = __dirname;

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

__dirname es el directorio actual en ejecución del nodo. Puede dar su propia ruta aquí para buscar la ruta del módulo.

Troyano
fuente