Como fazer o node.js exigir absoluto? (em vez de relativo)

234

Gostaria de exigir meus arquivos sempre pela raiz do meu projeto e não em relação ao módulo atual.

Por exemplo, se você consultar a https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js linha 6, verá

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

Isso é muito ruim na IMO. Imagine que eu gostaria de colocar todos os meus exemplos mais próximos da raiz apenas em um nível. Isso seria impossível, porque eu teria que atualizar mais de 30 exemplos e muitas vezes dentro de cada exemplo. Para isso:

express = require('../')

Minha solução seria ter um caso especial para raiz: se uma string começa com $, então é relativa à pasta raiz do projeto.

Qualquer ajuda é apreciada, obrigado

Atualização 2

Agora estou usando o require.js, que permite escrever de uma maneira e funciona tanto no cliente quanto no servidor. O Require.js também permite criar caminhos personalizados.

Atualização 3

Agora, mudei para o webpack + gulp e utilizei o Enhanced-require para manipular módulos no lado do servidor. Veja aqui a justificativa: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/

Totty.js
fonte
Se você decidir usar um constante / variável de caminho raiz explícito, esta resposta funcionará para isso . A solução usa um pequeno módulo github para determinar o caminho raiz.
steampowered

Respostas:

162

E sobre:

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

Ele requer o arquivo como se fosse exigido no arquivo js principal, portanto funciona muito bem desde que o arquivo js principal esteja na raiz do seu projeto ... e isso é algo que eu aprecio.

cronvel
fonte
Não é uma má idéia (: você pode definir alguns outros métodos para remapear o aplicativo de alguma forma no seu módulo require.main. Acho que você poderia, então, exigir require.main.req ('client / someMod'). Boa ideia, mas isso Além disso, acho que não vale a pena porque também não gosto de browserify porque as alterações não são instantâneas e perdem alterações (porque meu código deve ser executado no navegador e no node.js.).
Totty.js
4
Se você achar muito detalhado, use .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel
Sim, isso pode ser útil para alguém que ainda deseja usar o browserify no lado do cliente. Para mim, não há mais necessidade, mas obrigado de qualquer maneira pela sua resposta (:
Totty.js
6
Se os principais está na raiz do seu projeto :)
Alexander Mills
12
Esta solução não funcionará se o código coberto com testes de unidade como teste Mocha
cotovia alx
129

Há uma seção realmente interessante no Manual do Browserify :

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

Nem tudo em um aplicativo pertence adequadamente ao npm público e a sobrecarga de configurar um npm privado ou repositório git ainda é bastante grande em muitos casos. Aqui estão algumas abordagens para evitar o ../../../../../../../problema de caminhos relativos.

node_modules

Às vezes, as pessoas se opõem a colocar módulos específicos de aplicativos em node_modules porque não é óbvio como fazer check-in em seus módulos internos sem também fazer check-in de módulos de terceiros no npm.

A resposta é bem simples! Se você possui um .gitignorearquivo que ignora node_modules:

node_modules

Você pode apenas adicionar uma exceção !para cada um de seus módulos de aplicativos internos:

node_modules/*
!node_modules/foo
!node_modules/bar

Observe que você não pode cancelar o cancelamento de um subdiretório, se o pai já estiver ignorado. Portanto, em vez de ignorar node_modules, você deve ignorar todos os diretórios internos node_modules com o node_modules/*truque e adicionar suas exceções.

Agora, em qualquer lugar do seu aplicativo, você poderá require('foo') ou require('bar')não ter um caminho relativo muito grande e frágil.

Se você possui muitos módulos e deseja mantê-los mais separados dos módulos de terceiros instalados pelo npm, basta colocá-los em um diretório node_modules, como node_modules/app:

node_modules/app/foo
node_modules/app/bar

Agora você poderá require('app/foo')ou require('app/bar') de qualquer lugar no seu aplicativo.

No seu .gitignore, basta adicionar uma exceção para node_modules/app:

node_modules/*
!node_modules/app

Se seu aplicativo tiver transformadas configuradas em package.json, será necessário criar um package.json separado com seu próprio campo de transformação no diretório do componente node_modules/fooou node_modules/app/fooporque as transformações não se aplicam aos limites do módulo. Isso tornará seus módulos mais robustos contra alterações de configuração em seu aplicativo e será mais fácil reutilizar independentemente os pacotes fora do aplicativo.

ligação simbólica

Outro truque útil se você estiver trabalhando em um aplicativo em que é possível criar links simbólicos e não precisar dar suporte ao Windows é vincular uma pasta lib/ ou uma . Na raiz do projeto, faça:app/node_modules

ln -s ../lib node_modules/app

e agora, em qualquer lugar do seu projeto, você poderá solicitar arquivos lib/fazendo o require('app/foo.js')get lib/foo.js.

caminhos personalizados

Você pode ver alguns lugares falando sobre o uso da $NODE_PATH variável de ambiente ou opts.pathsadicionar diretórios para node e browserify para procurar módulos.

Diferentemente da maioria das outras plataformas, o uso de uma matriz de diretórios de caminho no estilo shell $NODE_PATHnão é tão favorável no nó, em comparação com o uso efetivo do node_modulesdiretório.

Isso ocorre porque seu aplicativo está mais fortemente acoplado a uma configuração do ambiente de tempo de execução, para que haja mais partes móveis e seu aplicativo funcionará apenas quando seu ambiente estiver configurado corretamente.

node e browserify suportam, mas desencorajam o uso de $NODE_PATH.

Paolo Moretti
fonte
17
O lado apenas no final de colocá-lo na node_modulespasta é que ela torna mais difícil a arma nuclear ( rm -rf node_modules) pasta
Michael
13
@ Michael não muito mais difícil: git node_modules -Dx limpas
Peter Wilkinson
3
Ou, caso você tenha esquecido a git cleansintaxe, sempre é possível rm -rf node_modules && git checkout node_modules- certifique-se de que git stashhaja alguma alteração nos node_modulessubdiretórios.
derenio
1
Eu gosto da idéia de usar node_modules, mas não para armazenar o código-fonte, considerando o quão volátil ele pode ser. Não faria mais sentido publicar o módulo separado e salvá-lo como uma dependência no projeto original? Ele fornece uma solução clara para a volatilidade do diretório node_modules e depende apenas do npm, em vez de depender do git, links simbólicos ou da solução $ NODE_PATH.
precisa saber é o seguinte
1
NODE_PATH parece o caminho a percorrer. "seu aplicativo só funcionará quando seu ambiente estiver configurado corretamente" isso sempre é verdade! Não é mais fácil configurar o ambiente (geralmente em um arquivo) do que alterar todas as importações em cada arquivo?
CpILL
73

Eu gosto de criar uma nova node_modulespasta para código compartilhado, depois deixar o nó e exigir fazer o que faz melhor.

por exemplo:

- 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 exemplo, se você estiver dentro, car/index.jsvocê pode require('helper')e o nó o encontrará!

Como o node_modules funciona

O nó possui um algoritmo inteligente para resolver módulos que é único entre plataformas rivais.

Se você require('./foo.js')partir /beep/boop/bar.js, o nó irá procurar ./foo.jsno /beep/boop/foo.js. Caminhos que começam com ./ou ../são sempre locais para o arquivo que chama require().

Se, no entanto, você precisar de um nome não relativo, como require('xyz')from /beep/boop/foo.js, o nó pesquisará esses caminhos em ordem, parando na primeira correspondência e gerando um erro se nada for encontrado:

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

Para cada xyzdiretório existente, o nó procurará primeiro um xyz/package.jsonpara ver se "main"existe um campo. O "main"campo define qual arquivo deve ser carregado se você for require()o caminho do diretório.

Por exemplo, se /beep/node_modules/xyzé a primeira correspondência e /beep/node_modules/xyz/package.jsonpossui:

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

as exportações de /beep/node_modules/xyz/lib/abc.jsserão retornadas por require('xyz').

Se não houver package.jsonou nenhum "main"campo, index.jsserá assumido:

/beep/node_modules/xyz/index.js
Blair Anderson
fonte
2
grande explicação sobre como ele funciona durante o carregamento de um módulo
goenning
2
Esta é uma solução muito elegante, evita todos os problemas nas respostas acima. Deve ser considerado a resposta, imho.
Rodurico 21/05/19
38

A grande imagem

Parece "muito ruim", mas reserve um tempo. É, de fato, muito bom. Os explícitos require()oferecem uma total transparência e facilidade de entendimento, como uma lufada de ar fresco durante o ciclo de vida do projeto.

Pense da seguinte maneira: você está lendo um exemplo, mergulhando os pés no Node.js e decidiu que é "uma IMO muito ruim". Vocês são os líderes da comunidade Node.js., pessoas que registraram mais horas escrevendo e mantendo aplicativos Node.js. Qual é a chance do autor cometer um erro tão novo? (E eu concordo, do meu passado em Ruby e Python, parece a princípio um desastre.)

Há muito hype e contra-hype ao redor do Node.js. Porém, quando a poeira baixar, reconheceremos que módulos explícitos e pacotes "locais em primeiro lugar" foram os principais fatores de adoção.

O caso comum

Obviamente, node_modulesno diretório atual, o pai, o avô, o bisavô etc. são pesquisados. Portanto, os pacotes que você instalou já funcionam dessa maneira. Geralmente você pode require("express")de qualquer lugar do seu projeto e funciona bem.

Se você se encontra carregando arquivos comuns da raiz do seu projeto (talvez porque sejam funções utilitárias comuns), essa é uma grande pista de que é hora de criar um pacote. Os pacotes são muito simples: mova seus arquivos para dentro node_modules/e coloque um package.json lá. Voila! Tudo nesse espaço de nome é acessível em todo o seu projeto. Pacotes são a maneira correta de colocar seu código em um espaço para nome global.

Outras soluções alternativas

Pessoalmente, não uso essas técnicas, mas elas respondem à sua pergunta e, é claro, você conhece sua própria situação melhor do que eu.

Você pode definir $NODE_PATHa raiz do seu projeto. Esse diretório será pesquisado quando você require().

Em seguida, você pode comprometer e exigir um arquivo local comum de todos os seus exemplos. Esse arquivo comum simplesmente reexporta o arquivo true no diretório dos avós.

examples / downloads / app.js (e muitos outros similares)

var express = require('./express')

exemplos / downloads / express.js

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

Agora, quando você realoca esses arquivos, o pior caso é consertar o módulo de um calço .

JasonSmith
fonte
14
Concordo que o pessoal do Node.js. deve ter escolhido o relativo exigem por um motivo. Eu simplesmente não consigo ver suas vantagens, nem da sua resposta. Ele ainda se sente "mau" para mim;)
Adam Schmideg
21
“Vocês são líderes de segunda opinião da comunidade Node.js.” - Os mesmos líderes decidiram usar retornos de chamada em vez de futuros / promessas. A maioria da minha consultoria nodejs envolve xingar os referidos "líderes" e convencer as pessoas a mudarem para a JVM. Que é muito mais fácil depois de alguns meses de uso nodejs :)
David Sergey
8
@ nascimento, mudar para JVM? Pelo amor de Deus, por que?
Ivancho 27/02
31
"Vocês são líderes de segunda opinião da comunidade Node.js.", evite esse tom desanimador de pensamentos.
Atlet2
15
Muito bem, ele é o segundo líder do nó. É assim que a indústria progride. Se o pessoal do nó não adivinhasse os líderes que sustentavam os modelos de concorrência baseados em encadeamento, não teríamos o nó.
d512 10/01
20

Dê uma olhada no node-rfr .

É simples assim:

var rfr = require('rfr');
var myModule = rfr('projectSubDir/myModule');
warmsea
fonte
Eu acho que a segunda linha deve ser var myModule = rfr ('/ projectSubDir / myModule');
Sikorski
1
Dos documentos: var module2 = rfr ('lib / module2'); // Barra invertida pode ser omitida.
igelineau
Eu tentei e o rfr funciona bem para executar com o nó, mas interrompe a navegação de código com o VS Code ... Não consegui encontrar uma solução alternativa, para poder usar o preenchimento automático no VS ...
Alex Mantaut
13

Se você estiver usando fios em vez de npm, poderá usar áreas de trabalho .

Digamos que tenho uma pasta servicesque desejo exigir mais facilmente:

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

Para criar um espaço de trabalho do Yarn, crie um package.jsonarquivo dentro de services folder:

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

No seu package.json principal, adicione:

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

Execute a yarn installpartir da raiz do projeto.

Em qualquer lugar do seu código, você pode:

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

em vez de algo como:

const { myFunc } = require('../../../../../../services/foo')
cyberwombat
fonte
6
Talvez seja uma idéia esclarecer que isso só funciona para fios , não para npm? Eu achava que provavelmente também funcionaria para as NPM, então passei um tempinho imaginando o que havia feito de errado até tentar usar fios. Pode ter sido uma suposição estúpida, mas talvez eu não seja a única.
ArneHugo 25/02/19
2
Eu editei um pouco para esclarecer. Desculpe pela confusão.
22419 cyberwombat
12

IMHO, a maneira mais fácil é definir sua própria função como parte do GLOBALobjeto. Crie projRequire.jsna raiz do seu projeto com o seguinte conteúdo:

var projectDir = __dirname;

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

No seu arquivo principal, antes de requirequalquer módulo específico do projeto:

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

Depois disso, funciona para mim:

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

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


@ Totty, eu vim com outra solução, que poderia funcionar no caso que você descreveu nos comentários. A descrição será tl;dr, então é melhor eu mostrar uma imagem com a estrutura do meu projeto de teste .

Aleksei Zabrodskii
fonte
bem, até agora, esta parece a melhor maneira de fazê-lo. Eu faço: GLOBAL.requires = require ('r'). R; no meu arquivo index.js. Mas eu tenho um problema nos meus testes de votos, eles não executam o index.js, então meus testes falham porque exigem que não seja definido. De qualquer forma, por enquanto eu posso adicionar GLOBAL.requires = require ('r'). R; no topo de cada teste. alguma ideia melhor? github.com/totty90/production01_server/commit/…
Totty.js
o problema ocorre quando estou no "pathes-test / node_modules / other.js" e preciso do "pathes-test / node_modules / some.js". Eu deveria exigir ('./ some') em vez de require ("prj / some"). E dessa forma, todo meu aplicativo estaria no diretório node_modules?
precisa saber é o seguinte
@Totty, não há problema exigindo prj/somede prj/other(apenas testada require('prj/some'). Todos os módulos comuns do seu aplicativo podem ir até lá (por exemplo, camada de banco de dados). Não fará diferença onde você está, digamos lib. Tente e veja se é adequado.
Aleksei Zabrodskii
No entanto, eu atualizei: github.com/totty90/production01_server/tree/master/node_modules/… que funcionou muito bem. Mas posso colocar todos os meus arquivos em um nível acima sem usar o node_modules?
precisa saber é o seguinte
12

Eu uso process.cwd()em meus projetos. Por exemplo:

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

Pode valer a pena notar que isso resultará em requireum caminho absoluto, embora eu ainda precise encontrar problemas com isso.

Walter Roman
fonte
1
Isso é péssima idéia, porque o CWD não precisa ser o mesmo diretório em que o aplicativo é salvo.
Jiwopene 27/08/19
11

Há uma boa discussão sobre esse assunto aqui .

Encontrei o mesmo problema de arquitetura: querer uma maneira de fornecer ao meu aplicativo mais organização e espaços de nomes internos, sem:

  • misturando módulos de aplicativos com dependências externas ou incomodando-se com repositórios npm privados para código específico do aplicativo
  • usando exigências relativas, o que dificulta a refatoração e a compreensão
  • usando links simbólicos ou alterando o caminho do nó, o que pode obscurecer os locais de origem e não funciona muito bem com o controle de origem

No final, decidi organizar meu código usando convenções de nomenclatura de arquivos em vez de diretórios. Uma estrutura seria algo como:

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

Então no código:

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

ou apenas

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

e dependências externas estão disponíveis no node_modules como de costume:

var express = require('express');

Dessa forma, todo o código do aplicativo é hierarquicamente organizado em módulos e disponível para todos os outros códigos relativos à raiz do aplicativo.

A principal desvantagem é que, em um navegador de arquivos, você não pode expandir / recolher a árvore como se ela estivesse realmente organizada em diretórios. Mas eu gosto que seja muito explícito sobre a origem de todo o código e não use nenhuma 'mágica'.

indiretamente iluminado
fonte
Na essência que você vinculou, a solução 7, "O invólucro", é bastante simples e conveniente.
Pier-Luc Gendreau
Vejo mais uma pequena conveniência - "mover" um arquivo para uma "pasta" diferente se torna uma renomeação - o que é mais fácil do que mover um arquivo. Além disso, costumo notar que, após meia hora de trabalho no projeto, quase toda a minha árvore de aplicativos é expandida de qualquer maneira. Adicionar 1 nível de espaço na pasta pode tornar grande a base de código gerenciável e não introduzir muito, o ../x/xque já é legível.
Ski
Você está reinventando pastas, usando pontos em vez de barras, para superar uma clara falta de nodejs.
Simone Gianni
9

Supondo que a raiz do seu projeto seja o diretório de trabalho atual, isso deve funcionar:

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

// require file relative to current working directory
config = require( path.resolve('.','config.js') );
protometa
fonte
config = require('./config.js');também é válido.
Cde 17/05
7
@ponpon não, isso é apenas relativo ao arquivo exigido.
Protometa 21/07
8

Eu tentei muitas dessas soluções. Acabei adicionando isso ao topo do meu arquivo principal (por exemplo, index.js):

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

Isso adiciona a raiz do projeto ao NODE_PATH quando o script é carregado. Isso me permite exigir qualquer arquivo no meu projeto, referenciando seu caminho relativo a partir da raiz do projeto, como var User = require('models/user'). Esta solução deve funcionar desde que você esteja executando um script principal na raiz do projeto antes de executar qualquer outra coisa no seu projeto.

senornestor
fonte
8

Algumas das respostas estão dizendo que a melhor maneira é adicionar o código ao node_module como um pacote, eu concordo e provavelmente é a melhor maneira de perder a ../../../necessidade, mas nenhuma delas realmente fornece uma maneira de fazê-lo.

da versão, 2.0.0você pode instalar um pacote a partir de arquivos locais, o que significa que você pode criar uma pasta na raiz com todos os pacotes que desejar,

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

portanto, em package.json, você pode adicionar o modules(ou fooe bar) como um pacote sem publicar ou usar um servidor externo como este:

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

Depois disso npm install, você poderá acessar o código var foo = require("foo"), assim como em todos os outros pacotes.

mais informações podem ser encontradas aqui:

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

e aqui como criar um pacote:

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

Yan Mayatskiy
fonte
1
"Esse recurso é útil para o desenvolvimento offline local e para a criação de testes que exigem a instalação do npm onde você não deseja acessar um servidor externo, mas não deve ser usado ao publicar pacotes no registro público."
Ryan Smith
7

Você poderia usar um módulo que eu criei , Undot . Não é nada avançado, apenas um ajudante para que você possa evitar o inferno com simplicidade.

Exemplo:

var undot = require('undot');
var User = undot('models/user');
var config = undot('config');
var test = undot('test/api/user/auth');
rícino
fonte
6

Você pode definir algo assim no seu app.js:

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

e sempre que desejar exigir algo da raiz, não importa onde esteja, basta usar o requireFromRoot em vez do exigido pela baunilha. Funciona muito bem para mim até agora.

user1417684
fonte
Obrigado! Eu acho que isso é bastante inteligente e direto.
21713 Ryan
Perdoe-me pai por eu ter pecado. Eu portado isso ES6 e tem o seguinte: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Adoro a solução, mas você realmente precisa vincular __dirname assim?
Nuck
1
Minha memória está um pouco nebulosa nisso, mas acredito que __dirname altera o valor dependendo do arquivo em que é usado. Agora, pode ser que, como a função seja definida em um único local, mas usada em vários locais, o valor permaneça constante mesmo sem essa ligação, mas fiz isso apenas para garantir que esse seja realmente o caso.
user1417684
fez isso há muito tempo, causa dores nos testes de envs e afins. não vale a pena a sobrecarga. aleatórios novas marcas globais novas pessoas bla bla incerta
O Dembinski
E como você requireesta função?
Darko Maksimovic
5

Aqui está o caminho real que estou fazendo há mais de 6 meses. Eu uso uma pasta chamada node_modules como minha pasta raiz no projeto, dessa forma, ela sempre procurará essa pasta de qualquer lugar que chamo de requisito absoluto:

  • node_modules
    • meu projeto
      • index.js Eu posso exigir ("myProject / someFolder / hey.js") em vez de exigir ("./ someFolder / hey.js")
      • someFolder que contém hey.js

Isso é mais útil quando você está aninhado em pastas e é muito menos trabalhoso alterar o local de um arquivo se estiver definido de maneira absoluta. Eu uso apenas 2 que o parente exige em todo o meu aplicativo .

Totty.js
fonte
4
Eu uso abordagem semelhante, exceto que eu adicionar local (projecto de) node_modulesem /src, e deixar /node_modulespara os fornecedores para manter as coisas separadas. Então, eu tenho /src/node_modulespara o código local e /node_modulespara os fornecedores.
Marius Balčytis
33
IMHO a pasta node_modules é apenas para node_modules. Não é uma boa prática colocar todo o seu projeto nessa pasta.
McSas #
2
@McSas, o que você sugeriria como alternativa para obter o mesmo efeito acima?
Spieglio
3
@cspiegl Você pode usar a NODE_PATHvariável de ambiente
Christopher Tarquini
5

A maneira mais fácil de conseguir isso é criando um link simbólico na inicialização do aplicativo node_modules/app(ou o que você chamar) que aponta para ../app. Então você pode simplesmente ligar require("app/my/module"). Links simbólicos estão disponíveis em todas as principais plataformas.

No entanto, você ainda deve dividir seu material em módulos menores e de manutenção que são instalados via npm. Você também pode instalar seus módulos particulares via git-url, portanto não há razão para ter um diretório de aplicativos monolítico.

Johannes Ewald
fonte
O suporte ao Windows requer um conhecimento mais profundo do Node e do SO. Pode limitar o uso generalizado de um projeto de código aberto.
precisa
Geralmente, eu não usaria esse padrão para uma biblioteca (que é a maioria dos projetos de código aberto). No entanto, é possível criar esses links simbólicos no gancho de construção npm, para que não haja conhecimento aprofundado exigido pelo usuário.
Johannes Ewald
Claro, mas o Node.js no Windows não suporta links simbólicos por padrão.
Steven Vachon
4

Em seu próprio projeto, você pode modificar qualquer arquivo .js usado no diretório raiz e adicionar seu caminho a uma propriedade da process.envvariável Por exemplo:

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

Depois, você pode acessar a propriedade em qualquer lugar:

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

Outra resposta:

Imagine esta estrutura de pastas:

  • node_modules
    • lodash
  • src
    • subjugar
      • foo.js
      • bar.js
    • main.js
  • testes

    • test.js

Em seguida, no test.js , você precisa exigir arquivos como este:

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

e no main.js :

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

Agora você pode usar o babel e o babel-plugin-module-resolver com isso. arquivo babelrc para configurar 2 pastas raiz:

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

Agora você pode exigir arquivos da mesma maneira nos testes e no src :

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

e se você quiser usar a sintaxe do módulo es6 :

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

então você importa arquivos nos testes e src assim:

import foo from "foo"
import bar from "bar"
import _ from "lodash"
Troopers
fonte
4

Acabei de encontrar este artigo que menciona o app-module-path . Ele permite que você configure uma base como esta:

require('app-module-path').addPath(baseDir);
Ole
fonte
3

O examplesdiretório não pôde conter um node_modulescom um link simbólico para a raiz do projeto project -> ../../, permitindo assim que os exemplos sejam usados require('project'), embora isso não remova o mapeamento, ele permite que a fonte use em require('project')vez de require('../../').

Eu testei isso e funciona com a v0.6.18.

Listagem de projectdiretório:

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

O conteúdo de index.jsatribui um valor a uma propriedade do exportsobjeto e chama console.logcom uma mensagem informando que era necessário. O conteúdo de test.jsé require('project').

Dan D.
fonte
você pode mostrar o código fonte do seu teste, por favor? bem, e funcionaria se eu precisasse ('project.a') dessa maneira?
Totty.js
Como assim require('project.a')? Eu acho que isso pode significar require('project/a'), embora require('project').atambém seja possível?
Dan D.
mas com o seu exemplo, eu precisaria criar essas pastas em cada pasta onde houver um módulo que precise do método require. De qualquer forma, você precisaria tomar cuidado com os horários de "../", dependendo da pasta.
Totty.js
Na verdade, o link precisaria estar apenas em um node_modulesdiretório no pai mais próximo do arquivo e o link seria o mesmo para os dois. Veja nodejs.org/api/…
Dan D.
E seria relativo a partir desse local. Por exemplo: project/node_modules/project -> ../.
Dan D.
2

Se alguém está procurando outra maneira de contornar esse problema, aqui está minha própria contribuição para o esforço:

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

A idéia básica: você cria um arquivo JSON na raiz do projeto que mapeia seus caminhos de arquivos para nomes abreviados (ou obtém use-automapper para fazer isso por você). Você pode solicitar seus arquivos / módulos usando esses nomes. Igual a:

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

Então tem isso.

Jon Stout
fonte
2

O que eu gosto de fazer é aproveitar como o nó é carregado no diretório node_module para isso.

Se alguém tentar carregar o módulo "coisa", alguém faria algo como

require('thing');

O nó procurará o diretório 'thing' no diretório 'node_module'.

Como o node_module normalmente está na raiz do projeto, podemos aproveitar essa consistência. (Se node_module não estiver na raiz, você terá outras dores de cabeça auto-induzidas.)

Se entrarmos no diretório e depois voltarmos a ele, podemos obter um caminho consistente para a raiz do projeto do nó.

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

Então, se quisermos acessar o diretório / happy, faríamos isso.

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

Embora seja um pouco hacky, no entanto, sinto que se a funcionalidade de como o node_modules carrega mudar, haverá problemas maiores para lidar. Esse comportamento deve permanecer consistente.

Para esclarecer, eu faço isso, porque o nome do módulo não importa.

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

Eu usei recentemente para angular2. Eu quero carregar um serviço da raiz.

import {MyService} from 'root/../../app/services/http/my.service';
justonpoints
fonte
Sobre sua referência Angular, com um aplicativo CLI padrão, você pode simplesmente importar src/app/my.service, também pode configurar o VSC para usar importações não relativas para arquivos datilografados.
Ploppy
2

Escrevi este pequeno pacote que permite exigir pacotes pelo caminho relativo da raiz do projeto, sem introduzir variáveis ​​globais ou substituir os padrões de nó

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

Funciona assim

// 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
fonte
Às vezes eu tenho pacotes particulares no projeto principal, esse script vai acabar com isso. Além de que eu não tenho certeza que vai funcionar bem com Webpack (no caso de você usar Webpack com node.js como eu)
Totty.js
Se você tiver diretórios aninhados com arquivos de pacote, cada diretório poderá solicitar apenas arquivos dentro de seu pacote. Não é esse o comportamento que você deseja? Eu não testei com o webpack.
Gafi # 3/17
Isso funcionou perfeitamente para um projeto simples e é muito mais fácil do que qualquer outra resposta.
21717 Byxor
2

Só quero acompanhar a ótima resposta de Paolo Moretti e Browserify. Se você estiver usando um transpilador (por exemplo, babel, texto datilografado) e tiver pastas separadas para código-fonte e código transpilado, como src/edist/ , poderá usar uma variação das soluções como

node_modules

Com a seguinte estrutura de diretórios:

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

então você pode deixar babel etc transpilar srcdiretório para distdiretório.

ligação simbólica

Usando o link simbólico, podemos nos livrar de alguns níveis de aninhamento:

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

Uma ressalva com babel --copy-files A --copy-filesbandeira de babelnão lida bem com links simbólicos. Pode continuar navegando no ..link simbólico e recusando a ver arquivos intermináveis. Uma solução alternativa é usar a seguinte estrutura de diretórios:

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

Dessa forma, o código abaixo srcainda será appresolvido src, enquanto o babel não verá mais links simbólicos.

user716468
fonte
Obrigado, mas eu não recomendaria fazer essa mágica. Primeiro, você perderá todas as importações, elas não serão calculadas pelo seu IDE. Se você usar outras ferramentas como o tipo de fluxo, também não funcionará corretamente.
Totty.js
Na verdade, o fluxo parece funcionar no meu caso, o que não é surpreendente, pois as soluções dependem do modelo de resolução do módulo de nó padrão e dos links simbólicos. Portanto, não é realmente mágico que ferramentas como o fluxo compreendam. Mas os IDEs são diferentes.
user716468
2

Eu estava procurando exatamente a mesma simplicidade para exigir arquivos de qualquer nível e encontrei o apelido de módulo .

Basta instalar:

npm i --save module-alias

Abra seu arquivo package.json, aqui você pode adicionar aliases para seus caminhos, por exemplo

"_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 use seus aliases simplesmente:

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

Estamos prestes a tentar uma nova maneira de resolver esse problema.

Tomando exemplos de outros projetos conhecidos como spring e guice, definiremos um objeto "context" que conterá toda a declaração "require".

Este objeto será passado para todos os outros módulos para uso.

Por exemplo

var context = {}

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

Isso exige que escrevamos cada módulo como uma função que recebe opts, o que nos parece uma prática recomendada de qualquer maneira.

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

e então você se referirá ao contexto em vez de exigir coisas.

var module1Ref = context.moduel1;

Se desejar, você pode escrever facilmente um loop para executar as instruções de solicitação

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

Isso deve facilitar a vida quando você deseja zombar (testes) e também resolve seu problema ao longo do caminho, tornando seu código reutilizável como um pacote.

Você também pode reutilizar o código de inicialização do contexto, separando a declaração de beans dele. por exemplo, seu main.jsarquivo pode parecer tão

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

Esse método também se aplica a bibliotecas externas, sem necessidade de codificar seus nomes toda vez que exigimos - no entanto, será necessário um tratamento especial, pois suas exportações não são funções que esperam contexto.

Posteriormente, também podemos definir beans como funções - o que nos permitirá requirediferentes módulos de acordo com o ambiente - mas que estão fora do escopo desse segmento.

guy mograbi
fonte
1

Eu estava tendo problemas com esse mesmo problema, então escrevi um pacote chamado include .

Inclua identificadores para descobrir a pasta raiz do seu projeto, localizando o arquivo package.json, e depois passe o argumento do caminho que você o fornece ao require () nativo sem toda a confusão relativa do caminho. Imagino que isso não seja um substituto para o require (), mas uma ferramenta para exigir o manuseio de arquivos ou bibliotecas não empacotados / de terceiros. Algo como

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

Espero que isso possa ser útil.

Anthony Nichols
fonte
1

Se o arquivo js do ponto de entrada do aplicativo (ou seja, aquele em que você realmente executa o "nó") estiver no diretório raiz do projeto, você poderá fazer isso com muita facilidade com o módulo rootpath npm . Basta instalá-lo via

npm install --save rootpath

... na parte superior do arquivo js do ponto de entrada, adicione:

require('rootpath')();

A partir desse ponto, todas as chamadas necessárias agora são relativas à raiz do projeto - por exemplo, require('../../../config/debugging/log'); torna-se require('config/debugging/log');(onde a pasta de configuração está na raiz do projeto).

Andrew Faulkner
fonte
1

Em linhas simples, você pode chamar sua própria pasta como módulo:

Para isso, precisamos: módulo global e app-module-path

aqui "App-module-path" é o módulo, ele permite adicionar diretórios adicionais ao caminho de pesquisa do módulo Node.js. E "global" é qualquer coisa que você anexar a esse objeto estará disponível em qualquer lugar do seu aplicativo.

Agora dê uma olhada neste trecho:

global.appBasePath = __dirname;

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

__dirname é o diretório atual em execução do nó. Você pode fornecer seu próprio caminho aqui para procurar o caminho pelo módulo.

Trojan
fonte