Saya memiliki skrip yang saya perlukan dari skrip Node.js, yang ingin saya jaga agar mesin JavaScript tetap independen.
Misalnya, saya hanya ingin melakukannya exports.x = y;
jika berjalan di bawah Node.js. Bagaimana saya bisa melakukan tes ini?
Ketika memposting pertanyaan ini, saya tidak tahu fitur modul Node.js didasarkan pada CommonJS .
Untuk contoh spesifik yang saya berikan, pertanyaan yang lebih akurat adalah:
Bagaimana sebuah skrip dapat mengetahui apakah skrip tersebut diperlukan sebagai modul CommonJS?
javascript
node.js
commonjs
theosp
sumber
sumber
Jawaban:
Dengan mencari dukungan CommonJS , inilah yang dilakukan oleh perpustakaan Underscore.js :
Edit: ke pertanyaan Anda yang diperbarui:
Contoh di sini mempertahankan pola Modul.
sumber
Yah tidak ada cara yang dapat diandalkan untuk mendeteksi berjalan di Node.js karena setiap situs web dapat dengan mudah mendeklarasikan variabel yang sama, namun, karena tidak ada
window
objek di Node.js secara default Anda dapat pergi sebaliknya dan memeriksa apakah Anda menjalankan di dalam Browser.Ini yang saya gunakan untuk libs yang seharusnya berfungsi baik di Browser dan di bawah Node.js:
Itu mungkin masih meledak dalam kasus yang
window
didefinisikan di Node.js tetapi tidak ada alasan yang baik untuk seseorang melakukan ini, karena Anda secara eksplisit perlu meninggalkanvar
atau mengatur properti padaglobal
objek.EDIT
Untuk mendeteksi apakah skrip Anda diperlukan sebagai modul CommonJS, sekali lagi itu tidak mudah. Satu-satunya hal yang umum ditentukanJS adalah bahwa A: Modul akan dimasukkan melalui panggilan ke fungsi
require
dan B: Modul mengekspor barang melalui properti padaexports
objek. Sekarang bagaimana itu diterapkan diserahkan kepada sistem yang mendasarinya. Node.js membungkus konten modul dalam fungsi anonim:Lihat: https://github.com/ry/node/blob/master/src/node.js#L325
Tapi jangan coba mendeteksi itu melalui beberapa
arguments.callee.toString()
hal gila , alih-alih gunakan saja kode contoh saya di atas yang memeriksa Browser. Node.js adalah lingkungan yang lebih bersih sehingga tidak mungkinwindow
dinyatakan di sana.sumber
window
pada baris pertama modul Anda, Anda seharusnya tidak memiliki masalah. Anda juga bisa menjalankan fungsi anonim dan memeriksa[[Class]]
darithis
dalamnya (hanya bekerja dalam modus non-ketat) Lihat "Kelas" di bawah: bonsaiden.github.com/JavaScript-Garden/#typeoftypeof self === 'object'
mungkin lebih aman karenatypeof window === 'undefined'
gagal pada lingkup pekerja web.Saat ini saya menemukan kesalahan deteksi Node yang tidak mengetahui Node-environment di Electron karena pendeteksian fitur yang menyesatkan. Solusi berikut mengidentifikasi lingkungan proses secara eksplisit.
Identifikasi hanya Node.js
Ini akan menemukan jika Anda menjalankan dalam proses Node, karena
process.release
berisi "metadata yang terkait dengan rilis [Node-] saat ini".Setelah menelurkan io.js nilai
process.release.name
mungkin juga menjadiio.js
(lihat proses-doc ). Untuk mendeteksi lingkungan yang siap-Node dengan benar saya kira Anda harus memeriksa sebagai berikut:Identifikasi Node (> = 3.0.0) atau io.js
Pernyataan ini diuji dengan Node 5.5.0, Electron 0.36.9 (dengan Node 5.1.1) dan Chrome 48.0.2564.116.
Identifikasi Node (> = 0.10.0) atau io.js
Komentar @ daluege mengilhami saya untuk memikirkan bukti yang lebih umum. Ini seharusnya bekerja dari Node.js> = 0.10 . Saya tidak menemukan pengidentifikasi unik untuk versi sebelumnya.
P: Saya memposting jawaban itu di sini karena pertanyaannya mengarahkan saya ke sini, meskipun OP sedang mencari jawaban untuk pertanyaan yang berbeda.
sumber
process
danprocess.version
ada di dalam bundel, jadi saya menambahkan pemeriksaan tambahan untukprocess.version
tempatprocess.release.node
yang tidak ditentukan pada sisi klien tetapi memiliki versi simpul sebagai nilai pada sisi serverprocess.version
variabel (dalam reaksi, webpack, atau react-webpack). Saya akan menghargai setiap petunjuk di mana variabel versi didefinisikan untuk menambahkannya ke jawabannya. Bergantung pada batasan release.node ke simpul> = 3.xxfunction isNodejs() { return typeof "process" !== "undefined" && process && process.versions && process.versions.node; }
Masalah dengan mencoba mencari tahu di lingkungan mana kode Anda berjalan adalah bahwa objek apa pun dapat dimodifikasi dan dideklarasikan sehingga hampir mustahil untuk mengetahui objek mana yang asli dari lingkungan, dan yang telah dimodifikasi oleh program.
Namun, ada beberapa trik yang dapat kita gunakan untuk mencari tahu dengan pasti di lingkungan mana Anda berada.
Mari kita mulai dengan solusi yang diterima secara umum yang digunakan di perpustakaan garis bawah:
typeof module !== 'undefined' && module.exports
Teknik ini sebenarnya sangat baik untuk sisi server, seperti ketika
require
fungsi dipanggil, itu me-resetthis
objek ke objek kosong, dan mendefinisikan kembalimodule
untuk Anda lagi, yang berarti Anda tidak perlu khawatir tentang gangguan luar. Selama kode Anda dimuatrequire
, Anda aman.Namun, ini berantakan di browser, karena siapa pun dapat dengan mudah menentukan
module
untuk membuatnya tampak seperti objek yang Anda cari. Di satu sisi ini mungkin perilaku yang Anda inginkan, tetapi juga menentukan variabel apa yang pengguna perpustakaan dapat gunakan dalam lingkup global. Mungkin seseorang ingin menggunakan variabel dengan namamodule
yang adaexports
di dalamnya untuk penggunaan lain. Itu tidak mungkin, tetapi siapa kita untuk menilai variabel apa yang bisa digunakan orang lain, hanya karena lingkungan lain menggunakan nama variabel itu?Kuncinya adalah, jika kita mengasumsikan bahwa skrip Anda sedang dimuat dalam lingkup global (yang akan menjadi itu jika dimuat melalui tag skrip) variabel tidak dapat dicadangkan dalam penutupan luar, karena browser tidak mengizinkan itu . Sekarang ingat dalam simpul,
this
objek adalah objek kosong, namunmodule
variabel masih tersedia. Itu karena itu dinyatakan dalam penutupan luar. Jadi kita dapat memperbaiki cek garis bawah dengan menambahkan cek tambahan:this.module !== module
Dengan ini, jika seseorang menyatakan
module
dalam lingkup global di browser, itu akan ditempatkan dithis
objek, yang akan menyebabkan tes gagal, karenathis.module
, akan menjadi objek yang sama dengan modul. Pada simpul,this.module
tidak ada, danmodule
ada dalam penutupan luar, sehingga tes akan berhasil, karena mereka tidak setara.Dengan demikian, tes terakhir adalah:
typeof module !== 'undefined' && this.module !== module
Catatan: Meskipun ini sekarang memungkinkan
module
variabel untuk digunakan secara bebas di lingkup global, masih dimungkinkan untuk memotong ini di browser dengan membuat penutupan baru dan menyatakan dimodule
dalamnya, kemudian memuat skrip dalam penutupan itu. Pada saat itu pengguna sepenuhnya mereplikasi lingkungan simpul dan mudah-mudahan tahu apa yang mereka lakukan dan sedang mencoba melakukan gaya simpul yang diperlukan. Jika kode ini disebut dalam tag skrip, kode itu masih aman dari penutupan luar baru.sumber
Cannot read property 'module' of undefined
karena ini tidak terdefinisi dalam tes moka misalnyaBerikut ini berfungsi di browser kecuali secara sengaja, disabotase secara eksplisit:
Bam.
sumber
process+''
bukanprocess.toString()
?Object.prototype.toString.call(process)
var process = null;
akan menyebabkan kasus kedua gagal. Dalam Javascript dan Java, ekspresi'' + x
menghasilkan sama sepertix.toString()
kecuali ketikax
jahat, yang pertama menghasilkan"null"
atau di"undefined"
mana yang terakhir akan menimbulkan kesalahan.Berikut ini cara yang cukup keren untuk melakukannya:
Ini berfungsi karena di browser, variabel global 'ini' memiliki referensi sendiri yang disebut 'jendela'. Referensi mandiri ini tidak ada di Node.
Untuk memutus peramban yang disarankan di atas, Anda harus melakukan sesuatu seperti yang berikut ini
sebelum melakukan pemeriksaan.
sumber
const isBrowser = this.window !== undefined
? Dan secara teori dalam simpul saya bisa lakukanthis.window = this
untuk menipu solusi.Deteksi lingkungan lainnya :
(Artinya: sebagian besar jawaban di sini baik-baik saja.)
Agak paranoid bukan? Anda dapat membuat ini lebih bertele-tele dengan memeriksa lebih banyak global .
Tapi JANGAN !.
Semua ini di atas dapat dipalsukan / disimulasikan.
Misalnya memalsukan
global
objek:Ini tidak akan dilampirkan ke objek global asli Node tetapi akan dilampirkan ke
window
objek di browser. Jadi itu akan menyiratkan bahwa Anda berada di Node env di dalam browser.Hidup ini singkat!
Apakah kita peduli jika lingkungan kita dipalsukan? Itu akan terjadi ketika beberapa pengembang bodoh mendeklarasikan variabel global yang disebut
global
dalam lingkup global. Atau beberapa dev jahat menyuntikkan kode ke dalam env kami entah bagaimana.Kami dapat mencegah kode kami dari mengeksekusi ketika kami menangkap ini, tetapi banyak dependensi lain dari aplikasi kami mungkin terjebak dalam hal ini. Jadi akhirnya kode akan rusak. Jika kode Anda cukup baik, Anda seharusnya tidak mempedulikan masing-masing dan setiap kesalahan konyol yang bisa dilakukan oleh orang lain.
Terus?
Jika menargetkan 2 lingkungan: Browser dan Node;
"use strict"
; dan cukup periksawindow
atauglobal
; dan dengan jelas menunjukkan bahwa dalam dokumen itu kode Anda hanya mendukung lingkungan ini. Itu dia!Jika memungkinkan untuk use case Anda; alih-alih deteksi lingkungan; lakukan deteksi fitur sinkron dalam blok coba / tangkap. (ini akan membutuhkan beberapa milidetik untuk dijalankan).
misalnya
sumber
Sebagian besar solusi yang diusulkan sebenarnya dapat dipalsukan. Cara yang kuat adalah dengan memeriksa
Class
properti internal objek global menggunakanObject.prototype.toString
. Kelas internal tidak dapat dipalsukan dalam JavaScript:sumber
Object.prototype.toString
yang merupakan praktik yang sangat buruk.var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
({}.toString.call(window))
sama"[object global]"
.window.toString()
menghasilkan"[object Window]"
Bagaimana dengan menggunakan objek proses dan memeriksa execPath untuk
node
?sumber
window.process = {execPath: "/usr/local/bin/node"};
?Terkait: untuk memeriksa apakah telah diperlukan sebagai modul vs dijalankan langsung di node, Anda dapat memeriksa
require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_modulesumber
Inilah variasi saya tentang apa yang di atas:
Untuk menggunakannya, Anda memodifikasi "Rumah" pada baris terakhir kedua menjadi apa pun yang Anda inginkan nama modul berada di browser dan mempublikasikan apa pun yang Anda inginkan nilai modul (biasanya konstruktor atau objek literal) ).
Di browser objek global adalah jendela, dan memiliki referensi untuk dirinya sendiri (ada window.window yang merupakan == jendela). Tampaknya bagi saya ini tidak mungkin terjadi kecuali Anda berada di browser atau di lingkungan yang ingin Anda percaya bahwa Anda berada di browser. Dalam semua kasus lain, jika ada variabel 'modul' global yang dideklarasikan, ia menggunakan variabel itu jika tidak menggunakan objek global.
sumber
Saya menggunakan
process
untuk memeriksa node.js seperti ituatau
Didokumentasikan di sini
sumber
process.title
dapat diubahPada tulisan ini, jawaban ini lebih merupakan opsi "segera hadir", karena memanfaatkan fitur JavaScript yang sangat baru.
The
runtime
nilai akan baiknode
ataunot node
.Seperti yang disebutkan, ini bergantung pada beberapa fitur JavaScript baru.
globalThis
adalah fitur final dalam spesifikasi ECMAScript 2020. Chaining / nullish coalescing opsional (?
bagian dariglobalThis.process?.release?.name
) didukung di mesin V8, yang dikirimkan bersama Chrome 80. Pada 4/8/2020, kode ini akan bekerja di browser tetapi tidak akan bekerja di Node karena cabang Node 13 menggunakan cabang V8 7.9.xxx. Saya percaya Node 14 (akan dirilis pada 4/21/2020) seharusnya menggunakan V8 8.x +.Pendekatan ini hadir dengan dosis pembatasan yang sehat saat ini. Namun; kecepatan di mana browser / Node dilepaskan, pada akhirnya akan menjadi one-liner yang andal.
sumber
Node.js memiliki
process
objek, jadi selama Anda tidak memiliki skrip lain yang membuatprocess
Anda dapat menggunakannya untuk menentukan apakah kode berjalan pada Node.sumber
Ini adalah cara yang cukup aman dan mudah untuk memastikan kompatibilitas antara javascript sisi-server dan sisi-klien, yang juga akan bekerja dengan browserify, RequireJS atau CommonJS termasuk sisi-klien:
sumber
Sunting : Mengenai pertanyaan Anda yang diperbarui: "Bagaimana skrip dapat mengetahui apakah skrip tersebut diperlukan sebagai modul commonjs?" Saya tidak berpikir itu bisa. Anda dapat memeriksa apakah
exports
objek (if (typeof exports === "object")
), karena spec mengharuskannya disediakan untuk modul, tetapi yang memberitahu Anda adalah ...exports
adalah objek. :-)Jawaban asli:
Saya yakin ada beberapa simbol khusus NodeJS (
tidak, Anda harus menggunakanEventEmitter
, mungkinrequire
untuk mendapatkan modul acara; lihat di bawah ) yang dapat Anda periksa, tetapi seperti kata David, idealnya Anda lebih baik mendeteksi fitur (bukan daripada lingkungan) jika masuk akal untuk melakukannya.Pembaruan : Mungkin sesuatu seperti:
Tapi itu hanya memberitahu Anda bahwa Anda berada dalam lingkungan dengan
require
dan sesuatu yang sangat, sangat mirip dengan NodeJSBuffer
. :-)sumber
window
variabel dalam aplikasi NodeJS. :-)window
dalam modul NodeJS, sehingga mereka dapat mencakup kode yang mengandalkanwindow
menjadi obyek global dan tidak ingin memodifikasi kode tersebut. Saya tidak akan melakukannya, Anda tidak akan melakukannya, tetapi saya yakin seseorang melakukannya. :-) Atau mereka baru sajawindow
berarti sesuatu yang lain sama sekali.typeof process !== "undefined" && process.title === "node"
sumber
Dari sumber paket debug:
https://github.com/visionmedia/debug/blob/master/src/index.js#L6
sumber
Ambil sumber node.js dan ubah untuk mendefinisikan variabel like
runningOnNodeJS
. Periksa variabel itu dalam kode Anda.Jika Anda tidak dapat memiliki node.js versi pribadi Anda sendiri, buka permintaan fitur di proyek. Tanyakan apakah mereka mendefinisikan variabel yang memberi Anda versi node.js yang Anda jalankan. Kemudian periksa variabel itu.
sumber
window
global, saya kira saya akan mengajukan permintaan fitur pada yang itu.var
pernyataan, orang yang baru saja membocorkannya ke namespace global, dan mereka tidak mendapatkan konsep modul mandiri saat ituPosting yang sangat lama, tetapi saya baru saja menyelesaikannya dengan membungkus pernyataan yang diperlukan dalam try-catch
sumber