NodeJS membutuhkan modul / paket global

160

Saya mencoba untuk menginstal secara global dan kemudian menggunakan foreverdan forever-monitorseperti ini:

npm install -g forever forever-monitor

Saya melihat output yang biasa dan juga operasi yang menyalin file ke jalur global, tetapi kemudian jika saya mencoba require("forever");saya mendapatkan kesalahan mengatakan bahwa modul tidak ditemukan.

Saya menggunakan versi terbaru dari kedua node dan npm dan saya sudah tahu tentang perubahan yang dibuat npm dalam instalasi global vs lokal, tapi saya benar-benar tidak ingin menginstal secara lokal pada setiap proyek dan saya sedang bekerja pada platform yang tidak dapat mendukung linksehingga npm linksetelah instalasi global tidak memungkinkan bagi saya.

Pertanyaan saya adalah: mengapa saya tidak bisa memerlukan paket yang terinstal secara global? Apakah itu fitur atau bug? Atau saya melakukan sesuatu yang salah?

PS: Hanya untuk membuatnya jelas: Saya tidak ingin menginstal secara lokal.

alexandernst
sumber
jadi ~/.config/yarn/globaluntuk benang
localhostdotdev

Jawaban:

216

Di Node.js, mengharuskan tidak melihat di folder tempat modul global dipasang.

Anda dapat memperbaikinya dengan mengatur variabel lingkungan NODE_PATH. Di Linux ini akan:

export NODE_PATH=/usr/lib/node_modules

Catatan: Ini tergantung di mana modul global Anda sebenarnya diinstal.

Lihat: Memuat dari folder global .

Daniel Uzunu
sumber
24
Di mesin Ubuntu 13.10 saya, jalur global untuk modul berbeda dari yang Anda tunjukkan di sini. Saya harus menggunakan export NODE_PATH=/usr/local/lib/node_modulessebagai gantinya.
Drew Noakes
11
Jika Anda menggunakan Windows 7/8 dan belum mengganti default instalasi Node mana pun, mengatur NODE_PATHvariabel lingkungan ke C:\Users\{USERNAME}\AppData\Roaming\npm\node_moduleskemungkinan akan berfungsi.
Wes Johnson
5
@WesJohnson Just %AppData%\npm\node_modulesakan bekerja pada Windows 10.
theblang
6
Jika saya mengatur, NODE_PATHbisakah saya menggunakan modul global dan lokal secara bersamaan?
Paulo Oliveira
6
Atau alih-alih jalur statis, yaitu jika Anda menggunakan NVM:NODE_PATH=$(npm root -g)
holmberd
98

Setelah Anda menginstal paket secara global, Anda harus menghubungkan proyek lokal dengan paket global

npm install express -g
cd ~/mynodeproject/
npm link express  

Lihat di sini

pengguna568109
sumber
2
Saya menjalankan platform yang tidak mendukung tautan (seperti yang dinyatakan pertanyaan saya) blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst
1
platform mana yang Anda gunakan?
user568109
1
Saya benar-benar tidak ingin dipusingkan dengan tautan (atau tautan simbolik sama sekali). Saya hanya ingin menginstal paket secara global dan membutuhkannya. Saya tahu NPM dirancang ulang untuk menghindari hal ini, tetapi seberapa sulit untuk mencapai sesuatu seperti ini?
alexandernst
13
Bagaimana jika saya tidak punya proyek? Katakan ~/some-stand-alone-random-nodejs-test.js. Saya tidak ingin mengubah folder rumah saya menjadi direktori proyek. Saya tidak ingin membuat folder baru untuk setiap percobaan kecil.
AnnanFay
1
Bekerja dengan sempurna pada Windows 8.1. Dari cd baris perintah node ke folder node_modules lokal proyek saya kemudian dieksekusi npm link <module>Kemudian Anda akan melihat jalan pintas (tautan) yang dibuat dalam folder node_module proyek Anda yang merujuk pada modul global node.
dynamiclynk
26

Permintaan maaf untuk necromancy tapi saya dapat menentukan jalur hard-coded ke modul yang diinstal secara global:

var pg = require("/usr/local/lib/node_modules/pg");

Ini tidak sempurna tetapi mengingat bahwa Unity3d mencoba untuk "mengkompilasi" semua javascript yang termasuk dalam direktori proyek saya benar-benar tidak dapat menginstal paket apa pun.

Thomas Ingham
sumber
4
Unity3D tidak mendukung JavaScript. Ini mendukung sintaks seperti JS untuk interpreter / kompiler Boo-nya (Boo adalah bahasa mirip-Python untuk .NET) yang dipasarkan secara menipu sebagai "JavaScript" . Nama yang lebih akurat untuk bahasa yang didukung Unity adalah UnityScript . Karena itu bahkan tidak dekat dengan bahasa yang sama, di sebelah tidak ada JS yang ditulis untuk web atau untuk Node.js akan berfungsi di Unity. Jauh lebih banyak info tentang perbedaan pada wiki Unity resmi: wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Slipp D. Thompson
19

Saya tahu ini adalah pertanyaan lama, tetapi saya menemukan ini ketika mencoba melakukan beberapa versi memeriksa menggunakan semverdalam preinstallskrip package.json. Karena saya tahu saya tidak bisa bergantung pada modul lokal yang diinstal, saya menggunakan ini untuk meminta semverdari node_modulesfolder global (seperti npmtergantung pada itu saya tahu ada di sana):

function requireGlobal(packageName) {
  var childProcess = require('child_process');
  var path = require('path');
  var fs = require('fs');

  var globalNodeModules = childProcess.execSync('npm root -g').toString().trim();
  var packageDir = path.join(globalNodeModules, packageName);
  if (!fs.existsSync(packageDir))
    packageDir = path.join(globalNodeModules, 'npm/node_modules', packageName); //find package required by old npm

  if (!fs.existsSync(packageDir))
    throw new Error('Cannot find global module \'' + packageName + '\'');

  var packageMeta = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json')).toString());
  var main = path.join(packageDir, packageMeta.main);

  return require(main);
}

Saya suka pendekatan ini karena ini tidak memerlukan pemasangan modul khusus apa pun untuk dapat digunakan.

Saya tidak menggunakan NODE_PATHsolusi seperti yang disarankan orang lain karena saya ingin ini berfungsi pada mesin siapa pun, tanpa harus memerlukan konfigurasi / pengaturan tambahan sebelum menjalankannpm install proyek saya.

Cara ini dikodekan, itu hanya dijamin untuk menemukan modul tingkat atas (diinstal menggunakan npm install -g ...) atau modul yang dibutuhkan oleh npm(tercantum di dependenciessini: https://github.com/npm/npm/blob/master/package.json ). Jika Anda menggunakan versi NPM yang lebih baru, ia mungkin menemukan dependensi dari paket yang diinstal secara global karena ada struktur yang lebih rata untuk node_modulesfolder sekarang.

Semoga ini bermanfaat bagi seseorang.

Joe Skeen
sumber
19

Sesuai dokumentasi , Node.js akan mencari di lokasi berikut secara default:

  1. Path ditentukan dalam NODE_PATHvariabel lingkungan .

    Catatan: NODE_PATHvariabel lingkungan disetel ke daftar jalur absolut yang dipisahkan oleh titik dua.

  2. node_modulesFolder saat ini . (lokal)

  3. $HOME/.node_modules (global)

    Catatan: $HOMEadalah direktori home pengguna.

  4. $HOME/.node_libraries (global)
  5. $PREFIX/lib/node (global)

    Catatan: $PREFIXapakah Node.js dikonfigurasi node_prefix.

    Untuk memeriksa nilai saat ini node_prefix, jalankan:

    node -p process.config.variables.node_prefix

    Catatan: Awalan berhubungan dengan --prefixparam selama build dan relatif terhadap param process.execPath. Jangan bingung dengan nilai dari npm config get prefixperintah. sumber

Jika modul yang diberikan tidak dapat ditemukan, itu berarti tidak ada di salah satu lokasi di atas.

Lokasi folder root global tempat modul dipasang dapat dicetak oleh: npm root -g(secara default path dihitung pada waktu berjalan kecuali ditimpa dalam npmrcfile ).

Larutan

Anda dapat mencoba solusi berikut ini:

  • Tentukan lokasi modul global Anda dalam NODE_PATHvariabel lingkungan. Misalnya

    echo 'require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node

    Untuk menguji dan mencetak nilai NODE_PATH, jalankan:

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • Untuk solusi yang lebih permanen, tautkan $HOME/.node_modulesfolder pengguna global Anda untuk menunjuk ke folder root, dengan menjalankan perintah ini:

    ln -vs "$(npm root -g)" "$HOME"/.node_modules

    Kemudian uji ulang melalui: echo 'require("forever")' | nodeperintah.

  • Ubah sementara folder saat ini ke tempat ekstensi telah diinstal secara global, sebelum menjalankan skrip. Misalnya

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • Konfigurasikan tujuan instalasi global dalam npmfile userconfig (lihat :)npm help 5 npmrc atau dengan userconfigparam (--prefix ).

    Untuk menampilkan konfigurasi saat ini, jalankan: npm config list .

    Untuk mengedit konfigurasi saat ini, jalankan: npm config edit.

  • Tentukan jalur lengkap lokasi modul simpul saat menelepon require(). Misalnya

    require("/path/to/sub/module")
  • Instal paket ke lokasi khusus, mis

    npm install forever -g --prefix "$HOME"/.node_modules

    Namun, instalasi akan gagal ~/.node_modules/lib/node_modules/ , sehingga lokasi masih perlu ditambahkan.

    Lihat: paket instalasi npm lokal ke lokasi kustom

  • Buat symlink di folder saat ini dari lokasi paket global. Misalnya

    npm link forever
kenorb
sumber
Sepertinya 4. Folder node_modules saat ini. (lokal) mendapat prioritas lebih dari 3. $ PREFIX / lib / node (global)
Király István
Folder node_modules lokal selalu diprioritaskan daripada folder global!
Király István
14

Anda dapat menggunakan paket requireguntuk memecahkan masalah ini:

var forever = require('requireg')('forever')

akan melakukan trik.

Juga, ada modul lain, yang global-npmkhusus untuk hanya menggunakan global npm, Anda dapat melihat kode pendek dan melihat bagaimana teknik ini bekerja.

JP Richardson
sumber
menarik, tetapi metode NODE_PATH mungkin lebih kanonik
Alexander Mills
keindahan NODE_PATHjuga, bahwa Anda tidak perlu mengubah kode apa pun. (Kasus penggunaan saya menilai banyak proyek siswa, di mana saya tidak ingin menjalankan npm installuntuk masing-masing, dan juga tidak ingin mereka memberikan node_modulesdirektori).
amenthes
Tidak, itu tidak akan melakukan trik karena Anda tidak dapat meminta requiregsejak awal, inilah intinya.
thisismydesign
6

Untuk utilitas CLI yang bergantung pada modul besar, seperti puppeteer, saya suka menelurkan npm root -gdan menggunakannya untuk memerlukan modul global.

try {
  const root = require('child_process').execSync('npm root -g').toString().trim()
  var puppeteer = require(root + '/puppeteer')
} catch (err) {
  console.error(`Install puppeteer globally first with: npm install -g puppeteer`)
  process.exit(1)
}
Christophe Marois
sumber
3

Anda dapat meletakkan baris ini di .profilefile Anda :

export NODE_PATH = "$ (npm konfigurasi dapatkan awalan) / lib / node_modules"

Ini akan nodemenggunakan jalur global.

Luis Paulo
sumber
1
Tidak. Ini adalah cara umum untuk mendapatkan global node_modules. Ini adalah jawaban lama tapi saya ingat saya mendapatkannya dari suatu tempat di dokumentasi. Bagaimanapun, di komputer saya (pada tahun 2020) node_modulesdirektori global npm adalah usr/lib/node_modules. Ngomong-ngomong, saya percaya npm config get prefixkarena ini digunakan secara global oleh npm setiap kali paket global diinstal jadi seharusnya benar.
Luis Paulo
1
Either way (saya tidak mengatakan ini dalam jawaban awal saya karena saya tidak terlalu berpengalaman di Node.JS), menggunakan paket yang terinstal secara global dalam suatu program adalah kasus penggunaan tepi dan jarang dilakukan karena dalam proyek itu akan membuat masalah kapan pun proyek berkomitmen untuk VCS dan dikloning di lingkungan lain karena ketergantungan khusus itu tidak ada dalam package.jsonfile atau di yarn.lock/ package-lock.json.
Luis Paulo
1
Oh! Saya mengerti sekarang. Saya yakin Anda salah mengira NODE_PATH dengan PATH. PATH adalah tempat shell akan mencari executable. NODE_PATH adalah tempat simpul akan mencari paket. Itu akan mulai dengan melihat direktori saat ini untuk sebuah node_modulesfolder, lalu itu adalah induknya, kemudian itu adalah induknya, ... sampai ia menemukan node_modulesfolder yang berisi modul itu. Namun, jika Anda menginstal paket secara global, itu tidak akan berada di dalam node_modulesfolder di atas direktori skrip saat ini sehingga Anda menggunakan NODE_PATH sebagai cadangan di mana node akan mencari paket.
Luis Paulo
1
ahahahah @Luis Paulo kau sepenuhnya benar !! Maafkan saya! Saya akan mencoba dan menghapus beberapa komentar saya untuk mencegah kebingungan, pekerjaan yang baik dan terima kasih
Ryan Taylor
@Ryan Taylor Anda tidak boleh menghapus komentar dan pertanyaan begitu mereka terselesaikan karena orang lain dapat memiliki yang sama. Sekarang sepertinya saya punya monolog di komentar! ahahahah
Luis Paulo