Apa perbedaan antara Bower dan npm?


1763

Apa perbedaan mendasar antara bowerdan npm? Hanya menginginkan sesuatu yang sederhana dan sederhana. Saya telah melihat beberapa rekan saya menggunakan bowerdan secara npmbergantian dalam proyek mereka.




7
Jawaban atas pertanyaan ini tampaknya sudah ketinggalan zaman. Dapatkah seseorang memberi tahu kami apa yang harus dilakukan pada tahun 2016 jika kami menggunakan npm 3 yang mendukung ketergantungan tetap? Apa bedanya karena npm3 dan bower dan apa praktik terbaik saat ini?
amdev

2
Bottom-line, @amdev: bower sekarang sudah tidak digunakan lagi. npm (atau Benang, yang hanya ada sedikit perbedaan) adalah tempatnya. Saya tidak mengetahui adanya alternatif yang layak.
XML

Jawaban:


1914

Semua manajer paket memiliki banyak kerugian. Anda hanya harus memilih yang bisa Anda tinggali.

Sejarah

npm mulai mengelola modul node.js (itu sebabnya paket-paket masuk node_modulessecara default), tetapi ia juga berfungsi untuk front-end ketika dikombinasikan dengan Browserify atau webpack .

Bower dibuat semata-mata untuk front-end dan dioptimalkan dengan mempertimbangkan hal itu.

Ukuran repo

npm jauh, jauh lebih besar daripada bower, termasuk JavaScript tujuan umum (seperti country-datauntuk informasi negara atau sortsuntuk fungsi penyortiran yang dapat digunakan di ujung depan atau ujung belakang).

Bower memiliki jumlah paket yang jauh lebih kecil.

Penanganan gaya dll

Bower termasuk gaya dll.

npm fokus pada JavaScript. Gaya dapat diunduh secara terpisah atau diminta oleh sesuatu seperti npm-sassatau sass-npm.

Penanganan ketergantungan

Perbedaan terbesar adalah bahwa npm melakukan dependensi bersarang (tetapi flat secara default) sementara Bower membutuhkan pohon dependensi flat (menempatkan beban resolusi dependensi pada pengguna) .

Pohon dependensi bertingkat berarti bahwa dependensi Anda dapat memiliki dependensi mereka sendiri yang dapat memiliki dependensi mereka sendiri, dan seterusnya. Hal ini memungkinkan dua modul memerlukan versi berbeda dari ketergantungan yang sama dan masih berfungsi. Catat sejak npm v3, pohon dependensi akan secara default (menghemat ruang) dan hanya sarang jika diperlukan, misalnya, jika dua dependensi memerlukan versi Underscore mereka sendiri.

Beberapa proyek menggunakan keduanya adalah mereka menggunakan Bower untuk paket front-end dan npm untuk alat pengembang seperti Yeoman, Grunt, Gulp, JSHint, CoffeeScript, dll.


Sumber daya


37
Mengapa pohon ketergantungan tidak bersarang melakukan itu dengan baik di ujung depan?
Lars Nyström

24
Bisakah paket npm front-end tidak menjadi pohon dependensi datar juga? Saya menghadapi "mengapa kita membutuhkan 2 manajer paket?" dilema.
Steven Vachon

38
Apa yang Anda maksud dengan "pohon ketergantungan datar"? Pohon datar adalah apa - daftar? Itu bukan pohon.
mvmn

14
Sebenarnya, jalan juga pohon. Ini hanya kasus khusus. Dari WikiPedia: "Dalam matematika, dan lebih khusus lagi dalam teori grafik, pohon adalah grafik tidak terarah di mana setiap dua simpul dihubungkan oleh tepat satu jalur."
Jørgen Fogh

42
NPM 3 mendukung pohon ketergantungan datar sekarang.
vasa

361

Jawaban ini merupakan tambahan dari jawaban Sindre Sorhus. Perbedaan utama antara npm dan Bower adalah cara mereka memperlakukan dependensi rekursif. Perhatikan bahwa mereka dapat digunakan bersama dalam satu proyek.

Pada FAQ npm : (tautan archive.org dari 6 Sep 2015)

Jauh lebih sulit untuk menghindari konflik ketergantungan tanpa ketergantungan sarang. Ini sangat mendasar dalam cara NPM bekerja, dan telah terbukti menjadi pendekatan yang sangat sukses.

Di beranda Bower :

Bower dioptimalkan untuk ujung depan. Bower menggunakan pohon dependensi datar, hanya membutuhkan satu versi untuk setiap paket, mengurangi memuat halaman ke minimum.

Singkatnya, npm bertujuan untuk stabilitas. Bower bertujuan untuk memuat sumber daya yang minimal. Jika Anda menggambar struktur ketergantungan, Anda akan melihat ini:

npm:

project root
[node_modules] // default directory for dependencies
 -> dependency A
 -> dependency B
    [node_modules]
    -> dependency A

 -> dependency C
    [node_modules]
    -> dependency B
      [node_modules]
       -> dependency A 
    -> dependency D

Seperti yang Anda lihat itu menginstal beberapa dependensi secara rekursif. Ketergantungan A memiliki tiga instal yang diinstal!

Punjung:

project root
[bower_components] // default directory for dependencies
 -> dependency A
 -> dependency B // needs A
 -> dependency C // needs B and D
 -> dependency D

Di sini Anda melihat bahwa semua dependensi unik berada pada level yang sama.

Jadi, mengapa repot-repot menggunakan npm?

Mungkin dependensi B memerlukan versi dependensi A yang berbeda dari dependensi C. npm menginstal kedua versi dependensi ini sehingga akan tetap bekerja, tetapi Bower akan memberikan Anda konflik karena tidak menyukai duplikasi (karena memuat sumber daya yang sama pada halaman web adalah sangat tidak efisien dan mahal, juga dapat memberikan beberapa kesalahan serius). Anda harus memilih versi mana yang ingin Anda instal secara manual. Ini dapat memiliki efek bahwa salah satu dependensi akan rusak, tetapi itu adalah sesuatu yang perlu Anda perbaiki.

Jadi, penggunaan umum adalah Bower untuk paket yang ingin Anda terbitkan di halaman web Anda (misalnya runtime , tempat Anda menghindari duplikasi), dan menggunakan npm untuk hal-hal lain, seperti pengujian, pembangunan, optimisasi, pengecekan, dll. (Mis. Waktu pengembangan , di mana duplikasi kurang diperhatikan).

Pembaruan untuk npm 3:

NPM 3 masih melakukan hal yang berbeda dibandingkan dengan Bower. Ini akan menginstal dependensi secara global, tetapi hanya untuk versi pertama yang dihadapinya. Versi lain dipasang di pohon (modul induk, lalu node_modules).

  • [node_modules]
    • dep A v1.0
    • dep B v1.0
      • dep A v1.0 (menggunakan versi root)
    • dep C v1.0
      • dep A v2.0 (versi ini berbeda dari versi root, jadi ini akan menjadi instalasi bersarang)

Untuk informasi lebih lanjut, saya sarankan membaca dokumen npm 3


4
Ini hampir klise sekarang bahwa "pengembangan perangkat lunak adalah semua tentang trade-off." Ini adalah contoh yang bagus. Satu harus memilih baik stabilitas yang lebih besar dengan npm atau beban sumber daya minimal dengan bower.
jfmercer

6
@ Shrek Saya secara implisit menyatakan bahwa Anda sebenarnya dapat menggunakan keduanya. Mereka memiliki tujuan yang berbeda, seperti yang saya nyatakan dalam paragraf terakhir. Ini bukan trade-off di mata saya.
Justus Romijn

Ahh, aku mengerti aku salah paham denganmu. Atau saya tidak cukup membaca. Terimakasih atas klarifikasinya. :-) Baik bahwa keduanya dapat digunakan tanpa trade-off.
jfmercer

4
@AlexAngas Saya telah menambahkan pembaruan untuk npm3. Masih memiliki beberapa perbedaan utama dibandingkan dengan Bower. npm mungkin akan selalu mendukung banyak versi dependensi, sementara Bower tidak.
Justus Romijn

npm 3 semakin dekat ke bower;)
ni3

269

TL; DR: Perbedaan terbesar dalam penggunaan sehari-hari bukan dependensi bersarang ... melainkan perbedaan antara modul dan global.

Saya pikir poster-poster sebelumnya telah membahas dengan baik beberapa perbedaan mendasar. (Penggunaan npm dari dependensi bersarang memang sangat membantu dalam mengelola aplikasi yang besar dan kompleks, meskipun saya pikir itu bukan perbedaan yang paling penting.)

Saya terkejut, bagaimanapun, bahwa tidak ada yang secara eksplisit menjelaskan salah satu perbedaan paling mendasar antara Bower dan npm. Jika Anda membaca jawaban di atas, Anda akan melihat kata 'modul' yang sering digunakan dalam konteks npm. Tapi itu disebutkan dengan santai, seolah-olah itu mungkin hanya perbedaan sintaksis.

Tetapi perbedaan modul vs global ini (atau modul vs 'skrip') mungkin merupakan perbedaan paling penting antara Bower dan npm. Pendekatan NPM untuk meletakkan segala sesuatu di modul mengharuskan Anda untuk mengubah cara Anda menulis Javascript untuk browser, hampir pasti menjadi lebih baik.

Pendekatan Bower: Sumber Daya Global, Seperti <script>Tag

Pada dasarnya, Bower adalah tentang memuat file skrip biasa-lama. Apa pun file skrip itu mengandung, Bower akan memuatnya. Yang pada dasarnya berarti bahwa Bower sama seperti memasukkan semua skrip Anda di plain-old <script>di dalam <head>HTML Anda.

Jadi, pendekatan dasar yang sama dengan yang biasa Anda gunakan, tetapi Anda mendapatkan kenyamanan otomatisasi yang bagus:

  • Anda dulu perlu menyertakan dependensi JS dalam repo proyek Anda (sambil mengembangkan), atau mendapatkannya melalui CDN. Sekarang, Anda dapat melewati bobot unduhan tambahan dalam repo, dan seseorang dapat melakukan bower installapa yang mereka butuhkan secara cepat dan instan, secara lokal.
  • Jika ketergantungan Bower kemudian tentukan dependensinya sendiri, maka ketergantungan itu bower.jsonakan diunduh juga untuk Anda.

Namun lebih dari itu, Bower tidak mengubah cara kita menulis javascript . Apa-apa tentang apa yang ada di dalam file yang dimuat oleh Bower perlu diubah sama sekali. Secara khusus, ini berarti bahwa sumber daya yang disediakan dalam skrip yang dimuat oleh Bower akan (biasanya, tetapi tidak selalu) masih didefinisikan sebagai variabel global , tersedia dari mana saja dalam konteks eksekusi browser.

Pendekatan npm: Modul JS Umum, Injeksi Ketergantungan Eksplisit

Semua kode dalam Node land (dan dengan demikian semua kode dimuat melalui npm) disusun sebagai modul (khususnya, sebagai implementasi dari format modul CommonJS , atau sekarang, sebagai modul ES6). Jadi, jika Anda menggunakan NPM untuk menangani dependensi sisi-browser (melalui Browserify atau sesuatu yang melakukan pekerjaan yang sama), Anda akan menyusun kode Anda dengan cara yang sama seperti yang dilakukan Node.

Orang yang lebih pintar daripada yang pernah saya ajukan pertanyaan 'Mengapa modul?', Tapi di sini ada ringkasan kapsul:

  • Apa pun yang ada di dalam modul adalah penempatan nama secara efektif , artinya ini bukan variabel global lagi, dan Anda tidak dapat secara tidak sengaja merujuknya tanpa bermaksud.
  • Apa pun di dalam modul harus disuntikkan ke dalam konteks tertentu (biasanya modul lain) dengan sengaja untuk memanfaatkannya
  • Ini berarti Anda dapat memiliki beberapa versi dari ketergantungan eksternal yang sama (lodash, katakanlah) di berbagai bagian aplikasi Anda, dan mereka tidak akan bertabrakan / konflik. (Ini sering terjadi secara mengejutkan, karena kode Anda sendiri ingin menggunakan satu versi dependensi, tetapi salah satu dependensi eksternal Anda menentukan yang lain yang bertentangan. Atau Anda punya dua dependensi eksternal yang masing-masing menginginkan versi yang berbeda.)
  • Karena semua dependensi disuntikkan secara manual ke modul tertentu, sangat mudah untuk menjelaskannya. Anda tahu pasti: "Satu-satunya kode yang perlu saya pertimbangkan ketika mengerjakan ini adalah apa yang sengaja saya pilih untuk disuntikkan di sini" .
  • Karena bahkan konten dari modul yang disuntikkan dienkapsulasi di belakang variabel yang Anda tetapkan, dan semua kode dieksekusi dalam ruang lingkup terbatas, kejutan dan tabrakan menjadi sangat mustahil. Jauh lebih kecil kemungkinannya bahwa sesuatu dari salah satu dependensi Anda secara tidak sengaja akan mendefinisikan ulang variabel global tanpa Anda menyadarinya, atau Anda akan melakukannya. (Itu bisa terjadi, tetapi Anda biasanya harus keluar dari cara Anda untuk melakukannya, dengan sesuatu seperti window.variable. Satu kecelakaan yang masih cenderung terjadi adalah menugaskan this.variable, tidak menyadari bahwa thissebenarnya windowdalam konteks saat ini.)
  • Ketika Anda ingin menguji modul individual, Anda dapat dengan mudah tahu: apa lagi (dependensi) yang mempengaruhi kode yang berjalan di dalam modul? Dan, karena Anda secara eksplisit menyuntikkan semuanya, Anda dapat dengan mudah mengejek dependensi tersebut.

Bagi saya, penggunaan modul untuk kode front-end bermuara pada: bekerja dalam konteks yang jauh lebih sempit yang lebih mudah untuk dipikirkan dan diuji, dan memiliki kepastian yang lebih besar tentang apa yang terjadi.


Hanya perlu sekitar 30 detik untuk mempelajari cara menggunakan sintaks modul CommonJS / Node. Di dalam file JS yang diberikan, yang akan menjadi modul, Anda pertama-tama mendeklarasikan dependensi luar yang ingin Anda gunakan, seperti ini:

var React = require('react');

Di dalam file / modul, Anda melakukan apa pun yang biasanya Anda lakukan, dan membuat beberapa objek atau fungsi yang ingin Anda paparkan kepada pengguna luar, dengan memanggilnya mungkin myModule.

Di akhir file, Anda mengekspor apa pun yang ingin Anda bagikan dengan dunia, seperti ini:

module.exports = myModule;

Kemudian, untuk menggunakan alur kerja berbasis CommonJS di browser, Anda akan menggunakan alat-alat seperti Browserify untuk mengambil semua file modul individu itu, merangkum isinya saat runtime, dan menyuntikkan satu sama lain sesuai kebutuhan.

DAN, karena modul ES6 (yang kemungkinan Anda akan transile ke ES5 dengan Babel atau serupa) mendapatkan penerimaan yang luas, dan bekerja baik di browser atau di Node 4.0, kita harus menyebutkan gambaran umum yang baik dari mereka juga.

Lebih lanjut tentang pola untuk bekerja dengan modul di dek ini .


EDIT (Feb 2017): Benang Facebook adalah pengganti / suplemen potensial yang sangat penting untuk npm akhir-akhir ini: manajemen paket offline yang cepat, deterministik, dan dibangun berdasarkan apa yang diberikan npm kepada Anda. Layak dicoba untuk proyek JS apa saja, terutama karena sangat mudah untuk menukar itu masuk / keluar.


EDIT (Mei 2019) "Bower akhirnya telah ditinggalkan . Akhir cerita." (j / t: @DanDascalescu, di bawah, untuk ringkasan bernas.)

Dan, sementara Yarn masih aktif , banyak momentum untuk itu bergeser kembali ke npm setelah mengadopsi beberapa fitur utama Yarn.


13
Senang jawaban ini ada di sini, jawaban populer lainnya tidak menyebutkan detail ini. npm memaksa Anda untuk menulis kode modular.
Juan Mendes

Maaf, dari orang-orang yang tidak terlalu peduli dengan semua fuzzing di javascript parlands tetapi kebetulan ia menjalankan bisnis yang menggunakan aplikasi web kecil. Baru-baru ini terpaksa mencoba npm, dari menggunakan bower dengan toolkit yang kami gunakan untuk mengembangkan web darn. Saya dapat memberitahu Anda bahwa perbedaan terbesar adalah waktu tunggu, npm butuh waktu lama. Ingat bahwa mengkompilasi kartun xkcd dengan orang-orang yang bermain pertarungan pedang berteriak 'menyusun' kepada bos mereka; Itulah yang ditambahkan npm ke bower.
Pedro Rodrigues

129

Pembaruan 2017-Oktober

Bower akhirnya telah ditinggalkan . Akhir dari cerita.

Jawaban yang lebih tua

Dari Mattias Petter Johansson, pengembang JavaScript di Spotify :

Dalam hampir semua kasus, lebih tepat menggunakan Browserify dan npm lebih dari Bower. Ini hanyalah solusi pengemasan yang lebih baik untuk aplikasi front-end daripada Bower. Di Spotify, kami menggunakan npm untuk mengemas seluruh modul web (html, css, js) dan itu bekerja dengan sangat baik.

Bower merek sendiri sebagai pengelola paket untuk web. Akan luar biasa jika ini benar - manajer paket yang membuat hidup saya lebih baik sebagai pengembang front-end akan luar biasa. Masalahnya adalah bahwa Bower tidak menawarkan alat khusus untuk tujuan tersebut. Ia menawarkan TIDAK tooling yang saya tahu npm tidak, dan terutama tidak ada yang secara khusus berguna untuk pengembang front-end. Tidak ada manfaatnya bagi pengembang front-end untuk menggunakan Bower lebih dari npm.

Kita harus berhenti menggunakan bower dan berkonsolidasi sekitar npm. Untungnya, itulah yang terjadi :

Jumlah modul - bower vs. npm

Dengan browserify atau webpack, menjadi sangat mudah untuk menggabungkan semua modul Anda menjadi file yang diperkecil besar, yang luar biasa untuk kinerja, terutama untuk perangkat seluler. Tidak demikian halnya dengan Bower, yang akan membutuhkan lebih banyak tenaga kerja untuk mendapatkan efek yang sama.

NPM juga menawarkan Anda kemampuan untuk menggunakan beberapa versi modul secara bersamaan. Jika Anda belum melakukan banyak pengembangan aplikasi, ini awalnya mungkin akan mengejutkan Anda, tetapi begitu Anda telah mengalami beberapa serangan Ketergantungan, Anda akan menyadari bahwa memiliki kemampuan untuk memiliki beberapa versi dari satu modul adalah hal yang sangat sulit. fitur hebat. Perhatikan bahwa npm menyertakan alat dedupe yang sangat praktis yang secara otomatis memastikan bahwa Anda hanya menggunakan dua versi modul jika Anda benar - benar harus - jika dua modul keduanya dapat menggunakan versi yang sama dari satu modul, mereka akan melakukannya. Tetapi jika mereka tidak bisa , Anda memiliki keluar yang sangat berguna.

(Perhatikan bahwa Webpack dan rollup secara luas dianggap lebih baik daripada Browserify pada Agustus 2016.)


7
<sarcasm> Perlu diingat bahwa bahkan proyek npm 'hello world' memerlukan 300+ modul untuk dijalankan ... </sarcasm>: O
Mariusz Jamro

1
Saya tidak setuju bahwa "file berukuran besar" adalah "luar biasa untuk kinerja, terutama untuk perangkat seluler". Justru sebaliknya: Bandwidth terbatas membutuhkan file kecil, dimuat sesuai permintaan.
Michael Franzl

Saran yang tidak terlalu bagus. Sebagian besar paket npm adalah backend nodejs saja. Jika Anda tidak melakukan javascript di backend, atau Anda tidak memiliki sistem modul, jumlah paket tidak relevan karena Bower akan sesuai dengan kebutuhan Anda jauh lebih baik
Gerardo Grignoli

4
@ GerardoGrignoli: bower sedang keluar .
Dan Dascalescu

45

Bower mengelola satu versi modul, ia hanya mencoba membantu Anda memilih yang benar / terbaik untuk Anda.

Manajemen ketergantungan Javascript: npm vs bower vs volo?

NPM lebih baik untuk modul simpul karena ada sistem modul dan Anda bekerja secara lokal. Bower baik untuk browser karena saat ini hanya ada ruang lingkup global, dan Anda ingin sangat selektif dengan versi yang Anda gunakan.


4
Saya merasa bahwa Sindre menyebutkan bahwa ketika ia berbicara tentang ketergantungan bersarang.
Game Brainiac

5
@Amesbrainiac Anda benar, hanya berpikir saya akan memasukkannya ke dalam kata-kata saya sendiri.
Sagivf

1
@Sagivf Ini BUKAN kata-kata Anda sendiri, kecuali jika Anda juga adalah orang yang memberikan jawaban asli di sini
dayuloli

4
@Sagivf Tidak ada yang salah dengan menyalin ** bagian yang relevan dari jawaban orang lain jika mereka sendiri tidak memberikan jawaban. Itu hanya menyadap saya sedikit Anda mengatakan "hanya berpikir saya akan mengatakannya dengan kata-kata saya sendiri." Kredit harus pergi ke tempat kredit jatuh tempo.
dayuloli

2
Saya tidak tahu mengapa kalian memilih jawaban ini begitu banyak. Memang ada informasi / perspektif baru dalam jawaban ini untuk saya.
Calvin

33

Tim saya pindah dari Bower dan bermigrasi ke npm karena:

  • Penggunaan terprogram terasa menyakitkan
  • Antarmuka Bower terus berubah
  • Beberapa fitur, seperti singkatan url, sepenuhnya rusak
  • Menggunakan Bower dan npm dalam proyek yang sama itu menyakitkan
  • Menyimpan bidang versi bower.json sinkron dengan tag git itu menyakitkan
  • Kontrol sumber! = Manajemen paket
  • Dukungan CommonJS tidak langsung

Untuk detail lebih lanjut, lihat "Mengapa tim saya menggunakan npm, bukan bower" .


17

Temukan penjelasan yang bermanfaat ini dari http://ng-learn.org/2013/11/Bower-vs-npm/

Di satu sisi npm dibuat untuk menginstal modul yang digunakan di lingkungan node.js, atau alat pengembangan yang dibangun menggunakan node.js seperti Karma, lint, minifiers, dan sebagainya. npm dapat menginstal modul secara lokal dalam suatu proyek (secara default di node_modules) atau secara global untuk digunakan oleh banyak proyek. Dalam proyek-proyek besar cara untuk menentukan dependensi adalah dengan membuat file bernama package.json yang berisi daftar dependensi. Daftar itu dikenali oleh npm ketika Anda menjalankan npm install, yang kemudian mengunduh dan menginstalnya untuk Anda.

Di sisi lain, bower dibuat untuk mengelola dependensi frontend Anda. Perpustakaan seperti jQuery, AngularJS, garis bawah, dll. Mirip dengan npm ia memiliki file di mana Anda dapat menentukan daftar dependensi yang disebut bower.json. Dalam hal ini dependensi frontend Anda diinstal dengan menjalankan instalasi bower yang secara default menginstalnya dalam folder yang disebut bower_components.

Seperti yang Anda lihat, meskipun mereka melakukan tugas yang serupa, mereka ditargetkan ke kumpulan perpustakaan yang sangat berbeda.


1
Dengan munculnya npm dedupe, ini agak ketinggalan jaman. Lihat jawaban Mattias .
Dan Dascalescu

7

Bagi banyak orang yang bekerja dengan node.js, manfaat utama dari bower adalah untuk mengelola dependensi yang sama sekali bukan javascript. Jika mereka bekerja dengan bahasa yang dikompilasi ke javascript, npm dapat digunakan untuk mengelola beberapa dependensi mereka. Namun, tidak semua dependensi mereka akan menjadi modul node.js. Beberapa dari mereka yang mengkompilasi ke javascript mungkin memiliki mangling khusus bahasa sumber yang aneh yang membuat melewati mereka dikompilasi untuk javascript pilihan inelegant ketika pengguna mengharapkan kode sumber.

Tidak semuanya dalam paket npm harus javascript yang menghadap pengguna, tetapi untuk paket pustaka npm, setidaknya beberapa di antaranya seharusnya.


Posting blog npmjs ini menyatakan "Paket Anda dapat berisi apa saja, apakah itu ES6, JS sisi klien, atau bahkan HTML dan CSS. Ini adalah hal-hal yang secara alami muncul bersamaan dengan JavaScript, jadi taruh di sana.".
Dan Dascalescu

1
Ada perbedaan antara dapat berisi , dan harus menyertakan . Tentu saja mereka dapat mengandung apa saja, tetapi secara umum, mereka harus menyertakan semacam antarmuka untuk commonJS. Bagaimanapun, ini adalah 'pengelola paket simpul'. Bagian tentang Ini adalah hal-hal yang secara alami muncul bersama Javascript adalah penting. Ada banyak hal yang secara tangensial terkait dengan javascript yang tidak muncul secara alami di sampingnya .
jessopher
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.