Hubungan antara CommonJS, AMD dan RequireJS?

840

Saya masih sangat bingung tentang CommonJS, AMD dan RequireJS , bahkan setelah banyak membaca.

Saya tahu bahwa CommonJS (sebelumnya ServerJS ) adalah grup untuk mendefinisikan beberapa spesifikasi JavaScript (yaitu modul) ketika bahasa tersebut digunakan di luar browser. Spesifikasi modul CommonJS memiliki beberapa implementasi seperti Node.js atau RingoJS , kan?

Apa hubungan antara CommonJS , Asynchronous Module Definition (AMD) dan RequireJS ?

Apakah RequireJS merupakan implementasi dari definisi modul CommonJS ? Jika ya, lalu apa AMD itu?

Gremo
sumber
31
Membaca Requirejs.org/docs/whyamd.html akan banyak menjelaskan karena menyebutkan semuanya. (mempostingnya sebagai komentar karena saya tidak menganggap ini sebagai jawaban lengkap).
mmutilva
5
Bisakah saya bertanya atau menambahkan lebih banyak; Bagaimana atau di mana laporan impor ES2015 cocok dengan semua ini; misalnya mengimpor Ember dari 'bara';
testndtv
Ada juga systemjs yang memuat salah satu format modul JS yang didukung seperti (CommonJS, UMD, AMD, ES6).
Andy

Jawaban:

770

RequireJS mengimplementasikan AMD API (sumber) .

CommonJS adalah cara mendefinisikan modul dengan bantuan exportsobjek, yang mendefinisikan konten modul. Sederhananya, implementasi CommonJS mungkin bekerja seperti ini:

// someModule.js
exports.doSomething = function() { return "foo"; };

//otherModule.js
var someModule = require('someModule'); // in the vein of node    
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };

Pada dasarnya, CommonJS menetapkan bahwa Anda harus memiliki require()fungsi untuk mengambil dependensi, exportsvariabel untuk mengekspor konten modul dan pengidentifikasi modul (yang menggambarkan lokasi modul yang terkait dengan modul ini) yang digunakan untuk memerlukan dependensi ( sumber ). CommonJS memiliki berbagai implementasi, termasuk Node.js , yang Anda sebutkan.

CommonJS tidak dirancang secara khusus dengan mempertimbangkan browser, sehingga tidak cocok di lingkungan browser dengan sangat baik ( saya benar-benar tidak memiliki sumber untuk ini - itu hanya mengatakan di mana-mana, termasuk situs RequireJS. ) Rupanya, ini memiliki sesuatu untuk lakukan dengan memuat asinkron, dll.

Di sisi lain, RequireJS mengimplementasikan AMD, yang dirancang agar sesuai dengan lingkungan browser ( sumber ). Rupanya, AMD dimulai sebagai spin-off dari format Transport CommonJS dan berkembang menjadi API definisi modulnya sendiri. Karenanya kesamaan antara keduanya. Fitur baru dalam AMD adalah define()fungsi yang memungkinkan modul untuk menyatakan dependensinya sebelum dimuat. Misalnya, definisi dapat berupa:

define('module/id/string', ['module', 'dependency', 'array'], 
function(module, factory function) {
  return ModuleContents;  
});

Jadi, CommonJS dan AMD adalah API definisi modul JavaScript yang memiliki implementasi yang berbeda, tetapi keduanya berasal dari sumber yang sama.

  • AMD lebih cocok untuk browser, karena mendukung pemuatan dependensi modul yang tidak sinkron.
  • RequireJS adalah implementasi AMD , sementara pada saat yang sama berusaha untuk menjaga semangat CommonJS (terutama dalam pengidentifikasi modul).

Untuk lebih membingungkan Anda, RequireJS, saat menjadi implementasi AMD, menawarkan pembungkus CommonJS sehingga modul-modul CommonJS hampir dapat langsung diimpor untuk digunakan dengan RequireJS.

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});

Saya harap ini membantu untuk memperjelas hal-hal!

jakee
sumber
7
Lihat proyek uRequire.org yang menjembatani kesenjangan dari 2 format - tulis dalam salah satu (atau keduanya), sebarkan ke salah satu dari dua atau <script> sederhana
Angelos Pikoulas
51
FYI Browserify sekarang akan memungkinkan Anda menggunakan CommonJS di browser.
Eruant
9
@ Eruant Tapi, masih belum memiliki sifat asinkron seperti AMD.
Inanc Gumus
8
Alasan mengapa CommonJS tidak cocok di browser seperti yang disebutkan dalam dokumen RequireJS - "CommonJS membutuhkan () adalah panggilan sinkron, diharapkan untuk mengembalikan modul segera. Ini tidak berfungsi dengan baik di browser" . Info lebih lanjut di sini .
msenni
4
@aaaaaa Anda mungkin ingin mengaktifkan beberapa fitur tergantung pada permintaan pengguna; jadi sifat async AMD mungkin berguna.
Inanc Gumus
199

CommonJS lebih dari itu - ini adalah proyek untuk mendefinisikan API dan ekosistem umum untuk JavaScript. Salah satu bagian dari CommonJS adalah spesifikasi Modul . Node.js dan RingoJS adalah runtime JavaScript sisi-server, dan ya, keduanya mengimplementasikan modul berdasarkan spesifikasi Modul CommonJS.

AMD (Asynchronous Module Definition) adalah spesifikasi lain untuk modul. RequireJS mungkin merupakan implementasi AMD yang paling populer. Satu perbedaan utama dari CommonJS adalah bahwa AMD menetapkan bahwa modul dimuat secara tidak sinkron - itu artinya modul dimuat secara paralel, yang bertentangan dengan memblokir eksekusi dengan menunggu beban selesai.

AMD umumnya lebih banyak digunakan dalam pengembangan JavaScript sisi-klien (di-browser) karena ini, dan Modul CommonJS umumnya digunakan di sisi-server. Namun, Anda dapat menggunakan spesifikasi modul di lingkungan mana pun - misalnya, RequireJS menawarkan petunjuk untuk berjalan di Node.js dan browserify adalah implementasi Modul CommonJS yang dapat berjalan di browser.

Nate
sumber
20
Mengapa beranda CommonJS begitu mengerikan ... Saya hanya mencoba melihat spek resmi. Ini memiliki kesalahan sintaksis, dokumentasi tidak lengkap dan halaman wiki tidak menyelesaikan.
taco
7
Bukan itu artinya memuat modul secara tidak sinkron. Anda mungkin berbicara tentang pemuatan dinamis / malas. Dengan async, Anda menyarankan file untuk dimuat dan kemudian beberapa waktu kemudian akan memanggil kembali setelah selesai memuat. Dengan sinkronisasi, Anda menyarankan file untuk dimuat dan kemudian seluruh utas blok sampai file itu selesai memuat; tidak ada kode lebih lanjut yang dijalankan hingga file dimuat. Yang pertama dapat menghasilkan kinerja yang lebih baik dengan biaya yang tidak dapat diprediksi, sedangkan yang terakhir dapat menghasilkan hasil yang sama setiap kali dan dengan demikian lebih dapat diprediksi. Perhatikan kebiasaan ini dapat dikurangi dengan menggunakan berbagai optimasi.
perry
Terima kasih atas jawabannya. Sekarang modul resmi di JS dengan ES2015, apakah ini berarti bahwa mereka lebih disukai daripada AMD atau JS umum?
Akhoy
Itu tidak berarti bahwa mereka lebih disukai. Semuanya terserah kebutuhan pengembang. Saya tidak berpikir bahwa tidak meninggalkan opsi dan pergi untuk modul ES6 adalah ide yang bagus. Namun, menggunakan UMD yang baik, Anda bisa mengatasi masalah itu. Memuat bundel CommonJS yang disinkronkan dengan AMD adalah ide yang baik (terbaik) secara umum (untuk peningkatan kinerja). Jika Anda merasa Anda harus memiliki lebih banyak kendali, tentu saja. Dan kamu harus.
Maciej Sitko
187

Jawaban singkatnya adalah:

CommonJS dan AMD adalah spesifikasi (atau format) tentang bagaimana modul dan dependensinya harus dinyatakan dalam aplikasi javascript.

RequireJS adalah pustaka pemuat skrip yang kompatibel dengan AMD, dan ini contoh lainnya.

Sesuai dengan CommonJS:

Diambil dari buku Addy Osmani .

// package/lib is a dependency we require
var lib = require( "package/lib" );

// behavior for our module
function foo(){
    lib.log( "hello world!" );
}

// export (expose) foo to other modules as foobar
exports.foobar = foo;

Sesuai AMD:

// package/lib is a dependency we require
define(["package/lib"], function (lib) {

    // behavior for our module
    function foo() {
        lib.log( "hello world!" );
    }

    // export (expose) foo to other modules as foobar
    return {
        foobar: foo
    }
});

Di tempat lain modul dapat digunakan dengan:

require(["package/myModule"], function(myModule) {
    myModule.foobar();
});

Beberapa latar belakang:

Sebenarnya, CommonJS lebih dari sekadar deklarasi API dan hanya sebagian yang membahasnya. AMD dimulai sebagai spesifikasi rancangan untuk format modul pada daftar CommonJS, tetapi konsensus penuh tidak tercapai dan pengembangan lebih lanjut dari format dipindahkan ke grup amdjs . Argumen di sekitar format mana yang lebih baik menyatakan bahwa CommonJS berupaya untuk mencakup serangkaian kekhawatiran yang lebih luas dan bahwa itu lebih cocok untuk pengembangan sisi server mengingat sifat sinkronnya, dan bahwa AMD lebih cocok untuk pengembangan sisi klien (browser) mengingat sifat asinkron dan karakteristiknya. fakta bahwa ia berakar pada implementasi modul deklarasi Dojo.

Sumber:

mmutilva
sumber
1
Melihat kode daripada deskripsi membantu! :) AMD compliantsebenarnya RequireJS, kan?
Asim KT
Apakah saya kehilangan sesuatu, atau ada sesuatu yang salah ketik? Anda mendefinisikan "package / lib" tetapi kemudian membutuhkan "package / myModule".
RullDawg
Saya selalu suka membaca sedikit tentang sejarah mengapa ada sesuatu seperti itu! Terima kasih telah memberikan latar belakang itu!
Andru
@RullDawg Tidak, "package / lib" tidak didefinisikan di sini, ini adalah ketergantungan pihak ke-3 yang digunakan di sini.
Robert Siemer
28

Mengutip

AMD :

  • Satu pendekatan browser-pertama
  • Memilih perilaku asinkron dan kompatibilitas mundur yang disederhanakan
  • Itu tidak memiliki konsep File I / O.
  • Ini mendukung objek, fungsi, konstruktor, string, JSON dan banyak jenis modul lainnya.

CommonJS :

  • Pendekatan pertama server
  • Dengan asumsi perilaku sinkron
  • Meliputi serangkaian kekhawatiran yang lebih luas seperti I / O, sistem File, Janji dan banyak lagi.
  • Mendukung modul yang tidak dibungkus, dapat terasa sedikit lebih dekat dengan ES.next/Harmony spesifikasi, membebaskan Anda dari pembungkus define () yang AMDmemberlakukan.
  • Hanya mendukung objek sebagai modul.
zangw
sumber
17

Cukup normal untuk mengatur program JavaScript menjadi beberapa file dan untuk memanggil child-modulesdari main js module.

Masalahnya adalah JavaScript tidak menyediakan ini. Bahkan hari ini di Chrome dan FF versi browser terbaru.

Tapi, apakah ada kata kunci dalam JavaScript untuk memanggil modul JavaScript lain?

Pertanyaan ini mungkin menjadi kehancuran total dunia bagi banyak orang karena jawabannya adalah TIDAK .


Dalam ES5 (dirilis pada 2009) JavaScript tidak memiliki kata kunci seperti impor , sertakan , atau butuhkan .

ES6 menyimpan hari (dirilis pada 2015) dengan mengajukan kata kunci impor ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), tetapi tidak ada browser yang mengimplementasikannya.

Jika Anda menggunakan Babel 6.18.0 dan transpile dengan opsi ES2015 saja

import myDefault from "my-module";

kamu akan mendapatkan requirelagi.

"use strict";
var _myModule = require("my-module");
var _myModule2 = _interopRequireDefault(_myModule);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

Ini karena requireberarti modul akan diambil dari Node.js. Node.js akan menangani semuanya mulai dari membaca file tingkat sistem hingga fungsi pembungkus ke dalam modul.

Karena dalam fungsi JavaScript adalah satu-satunya pembungkus yang mewakili modul.

Saya banyak bingung tentang CommonJS dan AMD?

Baik CommonJS dan AMD hanyalah dua teknik berbeda cara mengatasi JavaScript "cacat" untuk memuat modul pintar.

prosti
sumber
3
Sebaiknya perbarui jawaban Anda karena sekarang semua browser modern mendukung import
vsync
@vsync, ya, silakan edit jawaban saya, karena saya belum mengikuti segmen ini selama beberapa waktu.
prosti