Bagaimana cara membuat node.js membutuhkan absolut? (bukannya relatif)


234

Saya ingin meminta file saya selalu oleh root dari proyek saya dan tidak relatif terhadap modul saat ini.

Misalnya jika Anda melihat https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js baris 6 Anda akan melihat

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

Itu IMO yang sangat buruk. Bayangkan saya ingin menempatkan semua contoh saya lebih dekat ke root hanya dengan satu level. Itu tidak mungkin, karena saya harus memperbarui lebih dari 30 contoh dan berkali-kali dalam setiap contoh. Untuk ini:

express = require('../')

Solusi saya adalah memiliki case khusus untuk root: jika sebuah string dimulai dengan $ maka itu relatif terhadap folder root proyek.

Bantuan apa pun dihargai, terima kasih

Perbarui 2

Sekarang saya menggunakan require.js yang memungkinkan Anda menulis dengan satu cara dan berfungsi baik pada klien maupun di server. Require.js juga memungkinkan Anda membuat jalur khusus.

Perbarui 3

Sekarang saya pindah ke webpack + tegukan dan saya menggunakan ditingkatkan-perlu untuk menangani modul di sisi server. Lihat di sini alasannya: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


Jika Anda pernah memutuskan untuk menggunakan konstan / variabel path root eksplisit, jawaban ini berfungsi untuk itu . Solusinya menggunakan modul github kecil untuk menentukan jalur root.
steampowered

Jawaban:


162

Dan bagaimana dengan:

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

Ini membutuhkan file seolah-olah itu diperlukan dari file js utama, jadi itu berfungsi dengan baik selama file js utama Anda adalah di root proyek Anda ... dan itu adalah sesuatu yang saya hargai.


Bukan ide yang buruk (: Anda kemudian dapat mendefinisikan beberapa metode lain untuk memetakan ulang aplikasi dalam modul require.main Anda. Saya pikir Anda kemudian dapat melakukan require.main.req ('client / someMod'). Ide bagus, tapi ini akan menjadi lebih verbose daripada requirejs saya saat ini. Juga saya tidak berpikir bernilai karena saya juga tidak suka browserify karena perubahan tidak instan dan melewatkan perubahan (karena kode saya harus berjalan baik di browser dan node.js).
Totty.js

4
Jika Anda merasa terlalu verbose, gunakan saja .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel

ya, ini bisa berguna untuk seseorang yang masih ingin menggunakan browserify untuk sisi klien. Bagi saya tidak perlu lagi, tapi terima kasih atas jawaban Anda (:
Totty.js

6
JIKA MAIN ADALAH DI ROOT PROYEK ANDA :)
Alexander Mills

12
Solusi ini tidak akan berfungsi jika kode ditutupi dengan unit test seperti Mocha test
alx lark

129

Ada bagian yang sangat menarik di Browserify Handbook :

menghindari ../../../../../../ ..

Tidak semua yang ada dalam suatu aplikasi benar-benar dimiliki oleh npm publik dan overhead pengaturan npm atau git repo pribadi masih agak besar dalam banyak kasus. Berikut adalah beberapa pendekatan untuk menghindari ../../../../../../../masalah jalur relatif.

node_modules

Orang-orang kadang-kadang keberatan untuk menempatkan modul khusus aplikasi ke node_modules karena tidak jelas bagaimana memeriksa modul internal Anda tanpa juga memeriksa modul pihak ketiga dari npm.

Jawabannya cukup sederhana! Jika Anda memiliki .gitignorefile yang mengabaikan node_modules:

node_modules

Anda bisa menambahkan pengecualian dengan !untuk masing-masing modul aplikasi internal Anda:

node_modules/*
!node_modules/foo
!node_modules/bar

Harap perhatikan bahwa Anda tidak dapat membatalkan subdirektori, jika orang tua sudah diabaikan. Jadi, alih-alih mengabaikan node_modules, Anda harus mengabaikan setiap direktori di dalam node_modules dengan node_modules/*triknya, dan kemudian Anda dapat menambahkan pengecualian Anda.

Sekarang di mana saja di aplikasi Anda, Anda akan dapat require('foo') atau require('bar')tanpa memiliki jalur relatif yang sangat besar dan rapuh.

Jika Anda memiliki banyak modul dan ingin membuatnya lebih terpisah dari modul pihak ketiga yang diinstal oleh npm, Anda bisa meletakkan semuanya di bawah direktori node_modulesseperti node_modules/app:

node_modules/app/foo
node_modules/app/bar

Sekarang Anda dapat require('app/foo')atau require('app/bar') dari mana saja di aplikasi Anda.

Di Anda .gitignore, cukup tambahkan pengecualian untuk node_modules/app:

node_modules/*
!node_modules/app

Jika aplikasi Anda memiliki transformasi yang dikonfigurasi dalam package.json, Anda harus membuat package.json terpisah dengan bidang transformasi sendiri di direktori komponen node_modules/fooatau Anda node_modules/app/fookarena transformasi tidak berlaku melintasi batas-batas modul. Ini akan membuat modul Anda lebih kuat terhadap perubahan konfigurasi di aplikasi Anda dan akan lebih mudah untuk menggunakan kembali paket secara terpisah di luar aplikasi Anda.

symlink

Trik lain yang berguna jika Anda mengerjakan aplikasi tempat Anda dapat membuat symlink dan tidak perlu mendukung windows adalah dengan menghubungkan symlink a lib/ atau app/folder node_modules. Dari root proyek, lakukan:

ln -s ../lib node_modules/app

dan sekarang dari mana saja dalam proyek Anda, Anda akan dapat memerlukan file lib/dengan melakukan require('app/foo.js')untuk mendapatkan lib/foo.js.

jalur khusus

Anda mungkin melihat beberapa tempat berbicara tentang menggunakan $NODE_PATH variabel lingkungan atau opts.pathsuntuk menambahkan direktori untuk node dan browserify untuk mencari modul.

Tidak seperti kebanyakan platform lain, menggunakan larik shell-style dari direktori path dengan $NODE_PATHtidak begitu menguntungkan di node dibandingkan dengan menggunakan node_modulesdirektori secara efektif .

Ini karena aplikasi Anda lebih erat digabungkan ke konfigurasi lingkungan runtime sehingga ada lebih banyak bagian yang bergerak dan aplikasi Anda hanya akan bekerja ketika lingkungan Anda diatur dengan benar.

node dan browserify keduanya mendukung tetapi mencegah penggunaan $NODE_PATH.


17
Satu-satunya sisi meletakkannya di node_modulesfolder adalah membuatnya lebih sulit untuk nuke ( rm -rf node_modules) folder
Michael

13
@Michael Tidak terlalu sulit: git clean -dx node_modules
Peter Wilkinson

3
Atau jika Anda lupa git cleansintaksnya, Anda dapat selalu rm -rf node_modules && git checkout node_modules- pastikan untuk git stashberjaga-jaga jika ada perubahan pada node_modulessubdirektori.
derenio

1
Saya suka ide menggunakan node_modules, tetapi tidak untuk menyimpan kode sumber mengingat seberapa volatile itu bisa. Tidakkah lebih masuk akal untuk menerbitkan modul yang terpisah dan menyimpannya sebagai ketergantungan pada proyek asli? Ini memberikan solusi yang jelas untuk volatilitas direktori node_modules dan hanya bergantung pada npm, daripada mengandalkan git, tautan simbolik, atau solusi $ NODE_PATH.
Kevin Koshiol

1
NODE_PATH terlihat seperti cara untuk pergi. "aplikasi Anda hanya akan berfungsi ketika lingkungan Anda diatur dengan benar" ini selalu benar! Bukankah lebih mudah untuk mendapatkan pengaturan lingkungan (biasanya dalam satu file) daripada mengubah setiap impor di setiap file?
CpILL

73

Saya suka membuat node_modulesfolder baru untuk kode bersama, lalu biarkan simpul dan perlu melakukan yang terbaik.

sebagai contoh:

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

Misalnya, jika Anda berada di dalam, car/index.jsAnda dapat require('helper')dan simpul akan menemukannya!

Cara Kerja node_modules

Node memiliki algoritma pintar untuk menyelesaikan modul yang unik di antara platform saingan.

Jika Anda require('./foo.js')dari /beep/boop/bar.js, simpul akan mencari ./foo.jsdi /beep/boop/foo.js. Jalur yang dimulai dengan ./atau ../selalu lokal ke file yang memanggil require().

Namun jika Anda memerlukan nama non-relatif seperti require('xyz')dari /beep/boop/foo.js, node mencari jalur ini secara berurutan, berhenti pada pertandingan pertama dan meningkatkan kesalahan jika tidak ada yang ditemukan:

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

Untuk setiap xyzdirektori yang ada, node pertama-tama akan mencari untuk xyz/package.jsonmelihat apakah "main"ada lapangan. The "main"mendefinisikan bidang yang file harus bertanggung jawab jika Anda require()jalur direktori.

Misalnya, apakah /beep/node_modules/xyzini pertandingan pertama dan /beep/node_modules/xyz/package.jsonmemiliki:

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

maka ekspor dari /beep/node_modules/xyz/lib/abc.jsakan dikembalikan oleh require('xyz').

Jika tidak ada package.jsonatau tidak ada "main"bidang, index.jsdiasumsikan:

/beep/node_modules/xyz/index.js

2
penjelasan hebat tentang cara kerjanya ketika memuat modul
goenning

2
Ini adalah solusi yang sangat elegan, menghindari semua masalah dalam jawaban di atas. Harus mempertimbangkan jawabannya, imho.
rodurico

38

Gambar besar

Tampaknya "sangat buruk" tetapi berikan waktu. Ini sebenarnya sangat bagus. require()S eksplisit memberikan transparansi total dan kemudahan pemahaman yang seperti menghirup udara segar selama siklus hidup proyek.

Pikirkan seperti ini: Anda membaca contoh, mencelupkan jari kaki Anda ke Node.js dan Anda telah memutuskan itu adalah "IMO benar-benar buruk." Anda adalah pemimpin menebak-nebak dari komunitas Node.js, orang-orang yang telah log jam lebih banyak menulis dan memelihara aplikasi Node.js daripada siapa pun. Apa kesempatan penulis membuat kesalahan pemula? (Dan saya setuju, dari latar belakang Ruby dan Python saya, sepertinya pada awalnya seperti bencana.)

Ada banyak hype dan counter-hype seputar Node.js. Tetapi ketika debu mengendap, kami akan mengakui bahwa modul eksplisit dan paket "lokal pertama" adalah pendorong utama adopsi.

Kasus umum

Tentu saja, node_modulesdari direktori saat ini, maka orang tua, kemudian kakek nenek, kakek buyut, dll dicari. Jadi paket yang Anda instal sudah berfungsi seperti ini. Biasanya Anda dapat require("express")dari mana saja di proyek Anda dan itu berfungsi dengan baik.

Jika Anda menemukan diri Anda memuat file-file umum dari root proyek Anda (mungkin karena mereka adalah fungsi utilitas umum), maka itu adalah petunjuk besar bahwa inilah saatnya untuk membuat paket. Paket sangat sederhana: pindahkan file Anda ke dalam node_modules/dan letakkan di package.json sana. Voila! Segala sesuatu di namespace itu dapat diakses dari seluruh proyek Anda. Paket adalah cara yang benar untuk memasukkan kode Anda ke ruang nama global.

Penanganan lainnya

Saya pribadi tidak menggunakan teknik ini, tetapi mereka menjawab pertanyaan Anda, dan tentu saja Anda tahu situasi Anda sendiri lebih baik daripada saya.

Anda dapat mengatur $NODE_PATHke root proyek Anda. Direktori itu akan dicari ketika Anda require().

Selanjutnya, Anda dapat berkompromi dan membutuhkan file lokal umum dari semua contoh Anda. File umum itu hanya mengekspor ulang file sebenarnya di direktori kakek-nenek.

contoh / unduhan / app.js (dan banyak lainnya menyukainya)

var express = require('./express')

contoh / unduhan / express.js

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

Sekarang ketika Anda memindahkan file-file itu, kasus terburuk adalah memperbaiki modul satu shim .


14
Saya setuju bahwa orang-orang Node.js harus memilih saudara yang membutuhkan karena suatu alasan. Saya hanya tidak bisa melihat kelebihannya, juga dari jawaban Anda. Masih terasa "buruk" bagi saya;)
Adam Schmideg

21
"Anda adalah pemimpin menebak-nebak dari komunitas Node.js" - Para pemimpin yang sama memutuskan untuk menggunakan panggilan balik alih-alih masa depan / janji. Mayoritas konsultasi simpul saya melibatkan kutukan, "pemimpin", dan meyakinkan orang untuk pindah ke JVM. Yang jauh lebih mudah setelah beberapa bulan menggunakan nodejs :)
David Sergey

8
@ nth, pindah ke JVM? Demi Tuhan, mengapa?
Ivancho

31
"Anda adalah pemimpin menebak-nebak dari komunitas Node.js" harap hindari nada yang mengecilkan pikiran ini.
atlex2

15
Sial benar dia pemimpin simpul menebak kedua. Begitulah cara industri berkembang. Jika node guys tidak menebak pemimpin yang mendukung model concurrency berbasis thread, kami tidak akan memiliki node.
d512

20

Lihatlah node-rfr .

Sesederhana ini:

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

saya pikir baris kedua harus var myModule = rfr ('/ projectSubDir / myModule');
Sikorski

1
Dari dokumen: var module2 = rfr ('lib / module2'); // Memimpin tebasan dapat dihilangkan.
igelineau

Saya mencobanya dan ini berfungsi baik untuk mengeksekusi dengan node, tetapi ia memecah kode navigasi dengan VS Code ... Saya belum dapat menemukan solusi, untuk dapat menggunakan autocomplete di VS ...
Alex Mantaut

13

Jika Anda menggunakan benang alih-alih npm, Anda dapat menggunakan ruang kerja .

Katakanlah saya memiliki folder yang servicesingin saya minta dengan lebih mudah:

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

Untuk membuat ruang kerja Benang, buat package.jsonfile di dalam services folder:

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

Di package.json utama Anda, tambahkan:

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

Jalankan yarn installdari akar proyek.

Lalu, di mana pun dalam kode Anda, Anda dapat melakukan:

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

bukannya sesuatu seperti:

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

6
Mungkin ini ide untuk menjelaskan bahwa ini hanya berfungsi untuk benang , bukan untuk npm? Saya pikir itu mungkin akan bekerja untuk npm juga, jadi menghabiskan sedikit waktu bertanya-tanya apa yang telah saya lakukan salah sampai saya mencoba menggunakan benang sebagai gantinya. Mungkin asumsi yang bodoh, tapi mungkin bukan saya saja.
ArneHugo

2
Saya telah mengedit sedikit untuk memperjelas. Maaf bila membingungkan.
cyberwombat

12

IMHO, cara termudah adalah mendefinisikan fungsi Anda sendiri sebagai bagian dari GLOBALobjek. Buat projRequire.jsdi root proyek Anda dengan konten berikut:

var projectDir = __dirname;

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

Di file utama Anda sebelum requirememasukkan modul spesifik proyek:

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

Setelah itu bekerja untuk saya:

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

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


@ Totty, saya sudah membuat solusi lain, yang bisa berfungsi jika Anda dijelaskan dalam komentar. Deskripsi akan jadi tl;dr, jadi saya lebih baik menampilkan gambar dengan struktur proyek pengujian saya .


yah, sampai sekarang ini sepertinya cara terbaik untuk melakukannya. Saya lakukan: GLOBAL.requires = membutuhkan ('r'). R; dalam file index.js saya. Tapi saya punya masalah dalam tes sumpah saya, mereka tidak menjalankan index.js sehingga tes saya gagal karena memerlukan itu tidak ditentukan. Pokoknya untuk saat ini saya dapat menambahkan GLOBAL.requires = require ('r'). R; di bagian atas setiap tes. ada ide yang lebih baik? github.com/totty90/production01_server/commit/…
Totty.js


masalah terjadi ketika saya berada di "pathes-test / node_modules / other.js" dan saya memerlukan "pathes-test / node_modules / some.js". Saya harus meminta ('./beberapa') alih-alih mengharuskan ("prj / beberapa"). Dan dengan cara ini semua aplikasi saya akan berada di dir node_modules?
Totty.js

@Otty, tidak ada masalah yang membutuhkan prj/somedari prj/other(baru saja diuji require('prj/some'). Modul umum semua aplikasi Anda dapat pergi ke sana (misalnya lapisan basis data). Tidak akan ada bedanya di mana Anda, katakanlah, libberada. Coba dan lihat apakah itu cocok.
Aleksei Zabrodskii

ya, saya telah memperbaruinya: github.com/totty90/production01_server/tree/master/node_modules/… yang bekerja dengan sangat baik. Tapi saya bisa meletakkan semua file saya satu tingkat tanpa menggunakan node_modules?
Totty.js

12

Saya menggunakan process.cwd()dalam proyek saya. Sebagai contoh:

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

Mungkin perlu dicatat bahwa ini akan menghasilkan requirejalan absolut, meskipun saya belum mengalami masalah dengan ini.


1
Itu ide yang buruk karena CWD tidak harus menjadi direktori yang sama di mana aplikasi disimpan.
jiwopene

11

Ada diskusi yang bagus tentang masalah ini di sini .

Saya mengalami masalah arsitektur yang sama: ingin cara memberikan aplikasi saya lebih banyak organisasi dan ruang nama internal, tanpa:

  • mencampur modul aplikasi dengan dependensi eksternal atau mengganggu dengan repo npm pribadi untuk kode khusus aplikasi
  • menggunakan kebutuhan relatif, yang membuat refactoring dan pemahaman lebih sulit
  • menggunakan symlink atau mengubah jalur simpul, yang dapat mengaburkan lokasi sumber dan tidak bermain dengan baik dengan kontrol sumber

Pada akhirnya, saya memutuskan untuk mengatur kode saya menggunakan konvensi penamaan file daripada direktori. Suatu struktur akan terlihat seperti:

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

Kemudian dalam kode:

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

atau hanya

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

dan dependensi eksternal tersedia dari node_modules seperti biasa:

var express = require('express');

Dengan cara ini, semua kode aplikasi diatur secara hierarkis ke dalam modul dan tersedia untuk semua kode lain relatif terhadap root aplikasi.

Kerugian utama tentu saja dalam browser file, Anda tidak dapat memperluas / menciutkan pohon seolah-olah itu sebenarnya diatur ke dalam direktori. Tapi saya suka itu sangat eksplisit tentang dari mana semua kode berasal, dan tidak menggunakan 'sihir'.


Dari inti yang Anda tautkan, solusi # 7, "The Wrapper", cukup sederhana dan nyaman.
Pier-Luc Gendreau

Saya melihat satu lagi kenyamanan kecil - "memindahkan" file ke "folder" yang berbeda menjadi nama - yang lebih mudah daripada memindahkan file. Ditambah lagi, saya cenderung memperhatikan bahwa setelah setengah jam mengerjakan proyek, hampir semua pohon aplikasi saya diperluas. Menambahkan 1 tingkat ruang folder dapat membuat pengelolaan basis kode besar dan tidak memperkenalkan terlalu banyak ../x/xyang sudah dapat dibaca.
Ski

Anda sedang menciptakan kembali folder, menggunakan titik dan bukan garis miring, untuk mengatasi kekurangan nodejs.
Simone Gianni

9

Dengan asumsi root proyek Anda adalah direktori kerja saat ini, ini harus bekerja:

// 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');juga valid.
cespon

7
@cespon no, itu hanya relatif terhadap file yang membutuhkan.
protometa

8

Saya telah mencoba banyak solusi ini. Saya akhirnya menambahkan ini ke bagian atas file utama saya (mis. Index.js):

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

Ini menambahkan root proyek ke NODE_PATH ketika skrip dimuat. Itu memungkinkan saya untuk meminta file apa pun dalam proyek saya dengan mereferensikan jalur relatifnya dari root proyek seperti var User = require('models/user'). Solusi ini akan berfungsi selama Anda menjalankan skrip utama di root proyek sebelum menjalankan apa pun di proyek Anda.


8

Beberapa jawaban mengatakan bahwa cara terbaik adalah menambahkan kode ke node_module sebagai paket, saya setuju dan mungkin cara terbaik untuk menghilangkan ../../../memerlukan tetapi tidak satupun dari mereka yang benar-benar memberikan cara untuk melakukannya.

dari versi 2.0.0Anda dapat menginstal paket dari file lokal, yang berarti Anda dapat membuat folder di root Anda dengan semua paket yang Anda inginkan,

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

jadi di package.json Anda dapat menambahkan modules(atau foodan bar) sebagai paket tanpa menerbitkan atau menggunakan server eksternal seperti ini:

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

Setelah itu Anda lakukan npm install, dan Anda dapat mengakses kode var foo = require("foo"), sama seperti yang Anda lakukan dengan semua paket lainnya.

info lebih lanjut dapat ditemukan di sini:

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

dan di sini cara membuat paket:

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


1
"Fitur ini bermanfaat untuk pengembangan offline lokal dan membuat tes yang memerlukan instalasi npm di mana Anda tidak ingin menekan server eksternal, tetapi tidak boleh digunakan saat menerbitkan paket ke registri publik."
Ryan Smith

7

Anda dapat menggunakan modul yang saya buat, Undot . Tidak ada yang maju, hanya pembantu sehingga Anda dapat menghindari titik-titik itu dengan mudah.

Contoh:

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

6

Anda dapat mendefinisikan sesuatu seperti ini di app.js Anda:

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

dan kemudian kapan pun Anda ingin memerlukan sesuatu dari root, di mana pun Anda berada, Anda cukup menggunakan requireFromRoot sebagai ganti vanilla. Sejauh ini berfungsi dengan baik untuk saya.


Terima kasih! Saya pikir ini cukup cerdas dan mudah.
Ryan

Maafkan aku, ayah, karena aku telah berdosa. Saya porting ini untuk ES6 dan mendapat berikut: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Suka solusinya, tetapi apakah Anda benar-benar harus mengikat __dirname seperti itu?
Nuck

1
Ingatan saya agak kabur tentang ini, tapi saya percaya __dirname nilai perubahan tergantung pada file yang digunakan dalam Sekarang mungkin karena fungsi didefinisikan di satu tempat tetapi digunakan di banyak tempat, nilainya akan tetap konstan bahkan tanpa pengikatan ini, tetapi saya hanya melakukan itu untuk memastikan bahwa ini memang benar adanya.
user1417684

melakukan ini sejak lama, menyebabkan rasa sakit dalam menguji envs dan sejenisnya. tidak sebanding dengan biaya overhead. global baru acak membuat orang baru tidak pasti bla bla
The Dembinski

Dan bagaimana Anda requiremenjalankan fungsi ini?
Darko Maksimovic

5

Inilah cara aktual yang saya lakukan selama lebih dari 6 bulan. Saya menggunakan folder bernama node_modules sebagai folder root saya di proyek, dengan cara ini akan selalu mencari folder itu dari mana-mana saya sebut mutlak membutuhkan:

  • node_modules
    • proyek saya
      • index.js saya dapat meminta ("myProject / someFolder / hey.js") alih-alih membutuhkan ("./ someFolder / hey.js")
      • someFolder yang berisi hey.js

Ini lebih berguna ketika Anda bersarang ke dalam folder dan itu jauh lebih sulit untuk mengubah lokasi file jika diatur secara absolut. Saya hanya menggunakan 2 persyaratan relatif di seluruh aplikasi saya .


4
Saya menggunakan pendekatan yang sama, kecuali bahwa saya menambahkan lokal (proyek) node_modulesdi /src, dan meninggalkan /node_modulesbagi vendor untuk menjaga hal-hal yang terpisah. Jadi saya punya /src/node_modulesuntuk kode lokal dan /node_modulesuntuk vendor.
Marius Balčytis

33
IMHO folder node_modules hanya untuk node_modules. Ini bukan praktik yang baik untuk meletakkan seluruh proyek Anda di dalam folder itu.
McSas

2
@ MCSas apa yang akan Anda sarankan sebagai alternatif untuk mendapatkan efek yang sama seperti di atas?
spieglio

3
@cspiegl Anda dapat menggunakan NODE_PATHvariabel lingkungan
Christopher Tarquini

5

Saya cara termudah untuk mencapai ini adalah dengan membuat tautan simbolis pada startup aplikasi di node_modules/app(atau apa pun namanya) yang menunjuk ke sana ../app. Maka Anda bisa menelepon require("app/my/module"). Tautan simbolik tersedia di semua platform utama.

Namun, Anda tetap harus membagi barang-barang Anda menjadi modul-modul yang lebih kecil dan dapat dipelihara yang dipasang melalui npm. Anda juga dapat menginstal modul pribadi Anda melalui git-url, jadi tidak ada alasan untuk memilikinya, direktori aplikasi monolitik.


Dukungan pada Windows membutuhkan pengetahuan Node dan OS yang lebih mendalam. Ini dapat membatasi penggunaan proyek open source secara luas.
Steven Vachon

Secara umum saya tidak akan menggunakan pola ini untuk perpustakaan (yang kebanyakan proyek open source). Namun, dimungkinkan untuk membuat symlink ini di npm build hook sehingga tidak ada pengetahuan mendalam yang diperlukan oleh pengguna.
Johannes Ewald

Tentu, tetapi Node.js di Windows tidak mendukung symlink secara default.
Steven Vachon

4

Dalam proyek Anda sendiri, Anda bisa memodifikasi file .js yang digunakan di direktori root dan menambahkan path-nya ke properti process.envvariabel. Sebagai contoh:

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

Setelah itu, Anda dapat mengakses properti di mana saja:

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

4

Jawaban lain:

Bayangkan struktur folder ini:

  • node_modules
    • Lodash
  • src
    • subdir
      • foo.js
      • bar.js
    • main.js
  • tes

    • test.js

Kemudian di test.js , Anda perlu meminta file seperti ini:

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

dan di main.js :

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

Sekarang Anda dapat menggunakan babel dan babel-plugin-module-resolver dengan ini. file babelrc untuk mengkonfigurasi 2 folder root:

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

Sekarang Anda dapat meminta file dengan cara yang sama dalam tes dan di src :

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

dan jika Anda ingin menggunakan sintaks modul es6 :

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

maka Anda mengimpor file dalam tes dan src seperti ini:

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


3

Tidak dapat examplesdirektori berisi node_modulesdengan tautan simbolis ke root proyek project -> ../../sehingga memungkinkan contoh untuk digunakan require('project'), meskipun ini tidak menghapus pemetaan, itu memungkinkan sumber untuk menggunakan require('project')daripada require('../../').

Saya telah menguji ini, dan itu berhasil dengan v0.6.18.

Daftar projectdirektori:

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

Isi index.jsmemberikan nilai ke properti exportsobjek dan memanggil console.logdengan pesan yang menyatakan itu diperlukan. Isi test.jsis require('project').


dapatkah Anda menunjukkan kode sumber tes Anda? baik, dan itu akan berhasil jika saya harus meminta ('project.a') dengan cara ini?
Totty.js

Apa maksudmu require('project.a')? Saya pikir itu mungkin berarti require('project/a'), meskipun require('project').ajuga mungkin?
Dan D.

tetapi dengan contoh Anda, saya perlu membuat folder tersebut di setiap folder di mana ada modul yang memerlukan metode yang diperlukan. Pokoknya Anda perlu berhati-hati tentang waktu "../" tergantung pada folder.
Totty.js

Sebenarnya tautan hanya perlu berada di node_modulesdirektori di induk terdekat dari kedua file dan tautan kemudian akan sama untuk keduanya. Lihat nodejs.org/api/…
Dan D.

Dan akan relatif dari lokasi itu. Sebagai contoh: project/node_modules/project -> ../.
Dan D.

2

Jika ada yang mencari cara lain untuk mengatasi masalah ini, inilah kontribusi saya sendiri untuk upaya ini:

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

Gagasan dasar: Anda membuat file JSON di root proyek yang memetakan file folder Anda ke nama-nama singkat (atau menggunakan automapper-use untuk melakukannya untuk Anda). Anda kemudian dapat meminta file / modul Anda menggunakan nama-nama itu. Seperti itu:

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

Jadi begitulah.


2

Yang ingin saya lakukan adalah memanfaatkan bagaimana simpul memuat dari direktori node_module untuk ini.

Jika seseorang mencoba memuat modul "hal", ia akan melakukan sesuatu seperti

require('thing');

Node kemudian akan mencari direktori 'thing' di direktori 'node_module'.

Karena node_module biasanya merupakan akar dari proyek, kita dapat meningkatkan konsistensi ini. (Jika node_module tidak di root, maka Anda memiliki sakit kepala yang disebabkan sendiri untuk ditangani.)

Jika kita masuk ke direktori dan kemudian mundur, kita bisa mendapatkan jalur yang konsisten ke root dari proyek node.

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

Maka jika kita ingin mengakses direktori / happy, kita akan melakukan ini.

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

Meskipun ini sedikit hacky, namun saya merasa jika fungsionalitas dari bagaimana load node_modules berubah, akan ada masalah yang lebih besar untuk dihadapi. Perilaku ini harus tetap konsisten.

Untuk memperjelas, saya melakukan ini, karena nama modul tidak masalah.

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

Saya menggunakannya baru-baru ini untuk angular2. Saya ingin memuat layanan dari root.

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

Tentang referensi Angular Anda, dengan aplikasi CLI standar, Anda cukup mengimpor src/app/my.service, Anda juga dapat mengonfigurasi VSC untuk menggunakan impor non-relatif untuk file skrip.
Ploppy

2

Saya menulis paket kecil ini yang memungkinkan Anda memerlukan paket dengan jalur relatifnya dari root proyek, tanpa memperkenalkan variabel global atau default simpul utama

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

Ini berfungsi seperti ini

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

Terkadang saya memiliki paket pribadi di proyek utama, skrip ini akan putus dengan itu. Selain itu saya tidak yakin akan berfungsi dengan baik dengan webpack (jika Anda menggunakan webpack dengan node.js seperti yang saya lakukan)
Totty.js

Jika Anda memiliki direktori bersarang dengan file paket, masing-masing direktori hanya akan membutuhkan file dalam paketnya. Bukankah itu perilaku yang Anda inginkan? Saya belum diuji dengan webpack.
gafi

Ini bekerja sempurna untuk proyek sederhana dan jauh lebih mudah daripada jawaban lain mana pun.
byxor

2

Hanya ingin menindaklanjuti jawaban hebat dari Paolo Moretti dan Browserify. Jika Anda menggunakan transpiler (misalnya, babel, naskah) dan Anda memiliki folder terpisah untuk sumber dan kode yang diubah seperti src/dan dist/, Anda bisa menggunakan variasi solusi sebagai

node_modules

Dengan struktur direktori berikut:

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

Anda kemudian dapat membiarkan babel dll untuk mengubah srcdirektori ke distdirektori.

symlink

Dengan menggunakan symlink, kita dapat menghilangkan beberapa level sarang:

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

Peringatan dengan babel --copy-file tersebut --copy-filesBendera babeltidak berurusan dengan symlink baik. Mungkin terus bernavigasi ke ..symlink dan secara sembunyi-sembunyi melihat file tanpa akhir. Solusinya adalah dengan menggunakan struktur direktori berikut:

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

Dengan cara ini, kode di bawah srcmasih akan appdiselesaikan src, sedangkan babel tidak akan melihat symlink lagi.


Terima kasih tetapi, saya tidak akan merekomendasikan melakukan sihir ini. Pertama Anda akan kehilangan semua impor, mereka tidak akan dihitung oleh IDE Anda. Jika Anda menggunakan alat lain seperti jenis aliran itu tidak akan berfungsi dengan baik.
Totty.js

Sebenarnya aliran tampaknya berfungsi dalam kasus saya, yang tidak mengejutkan karena solusi tergantung pada model resolusi modul simpul standar, dan symlink. Jadi itu bukan sihir untuk alat seperti aliran untuk mengerti. Tetapi IDE berbeda.
user716468

2

Saya mencari kesederhanaan yang sama persis untuk meminta file dari level apa pun dan saya menemukan modul-alias .

Cukup instal:

npm i --save module-alias

Buka file package.json Anda, di sini Anda dapat menambahkan alias untuk path Anda, misalnya

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

Dan gunakan alias Anda hanya dengan:

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


1

Kami akan mencoba cara baru untuk mengatasi masalah ini.

Mengambil contoh dari proyek lain yang diketahui seperti musim semi dan guice, kita akan mendefinisikan objek "konteks" yang akan berisi semua pernyataan "memerlukan".

Objek ini kemudian akan diteruskan ke semua modul lain untuk digunakan.

Sebagai contoh

var context = {}

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

Ini mengharuskan kami untuk menulis setiap modul sebagai fungsi yang menerima opt, yang menurut kami merupakan praktik terbaik.

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

dan kemudian Anda akan merujuk pada konteks alih-alih membutuhkan barang.

var module1Ref = context.moduel1;

Jika mau, Anda dapat dengan mudah menulis lingkaran untuk melakukan pernyataan yang diperlukan

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

Ini akan membuat hidup lebih mudah ketika Anda ingin mengejek (tes) dan juga memecahkan masalah Anda di sepanjang jalan sambil membuat kode Anda dapat digunakan kembali sebagai sebuah paket.

Anda juga dapat menggunakan kembali kode inisialisasi konteks dengan memisahkan deklarasi kacang darinya. misalnya, main.jsfile Anda bisa terlihat seperti itu

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

Metode ini juga berlaku untuk perpustakaan eksternal, tidak perlu membuat kode nama mereka setiap kali kita memerlukannya - namun itu akan memerlukan perlakuan khusus karena ekspor mereka bukan fungsi yang mengharapkan konteks ..

Kemudian kita juga dapat mendefinisikan kacang sebagai fungsi - yang akan memungkinkan kita untuk requiremodul yang berbeda sesuai dengan lingkungan - tetapi itu keluar dari lingkup utas ini.


1

Saya mengalami masalah dengan masalah yang sama ini, jadi saya menulis sebuah paket bernama include .

Sertakan pegangan yang mencari tahu folder root proyek Anda dengan cara menemukan file package.json Anda, kemudian melewati argumen path yang Anda berikan ke asli memerlukan () tanpa semua kekacauan path relatif. Saya membayangkan ini bukan sebagai pengganti untuk memerlukan (), tetapi alat untuk membutuhkan penanganan file atau pustaka non-paket / non-pihak ketiga. Sesuatu seperti

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

Semoga ini bermanfaat.


1

Jika file entry point js aplikasi Anda (yaitu yang Anda jalankan "node" aktif) ada di direktori root proyek Anda, Anda dapat melakukannya dengan sangat mudah dengan modul npath rootpath . Cukup instal melalui

npm install --save rootpath

... lalu di bagian paling atas dari file entry point js, tambahkan:

require('rootpath')();

Sejak saat itu semua panggilan yang membutuhkan sekarang relatif terhadap root proyek - misalnya require('../../../config/debugging/log'); menjadi require('config/debugging/log');(di mana folder config berada di root proyek).


1

Dalam garis sederhana, Anda dapat memanggil folder Anda sendiri sebagai modul:

Untuk itu kita perlu: modul global dan app-module-path

di sini "App-module-path" adalah modul, itu memungkinkan Anda untuk menambahkan direktori tambahan ke jalur pencarian modul Node.js Dan "global" adalah, apa pun yang Anda lampirkan ke objek ini akan b tersedia di mana saja di aplikasi Anda.

Sekarang lihat cuplikan ini:

global.appBasePath = __dirname;

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

__dirname adalah direktori simpul yang sedang berjalan. Anda dapat memberikan jalur Anda sendiri di sini untuk mencari jalur untuk modul.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.