Bagaimana saya dapat berbagi kode antara Node.js dan browser?

Saya membuat sebuah aplikasi kecil dengan klien JavaScript (run di browser) dan Node.js server berkomunikasi menggunakan WebSocket.

Saya ingin berbagi kode antara klien dan server. Aku baru saja mulai dengan Node.js dan pengetahuan saya tentang JavaScript modern adalah sedikit berkarat, untuk sedikitnya. Jadi saya masih mendapatkan kepala saya sekitar CommonJS require() fungsi. Jika saya membuat saya paket dengan menggunakan 'ekspor' objek, maka saya tidak bisa melihat bagaimana saya bisa menggunakan file JavaScript di browser.

Saya ingin membuat satu set metode dan kelas yang digunakan pada kedua ujungnya untuk memudahkan encoding dan decoding pesan, dan lain dicerminkan tugas. Namun, Node.js/CommonJS sistem kemasan tampaknya menghalangi saya dari membuat file JavaScript yang dapat digunakan pada kedua belah pihak.

Saya juga mencoba menggunakan JS.Class untuk mendapatkan lebih ketat OO model, tapi saya menyerah karena saya tidak't tahu bagaimana untuk mendapatkan yang disediakan file JavaScript untuk bekerja dengan require(). Apakah ada sesuatu yang saya hilang di sini?

Mengomentari pertanyaan (1)
Larutan

Jika anda ingin menulis sebuah modul yang dapat digunakan baik di sisi client dan sisi server, saya memiliki sebuah posting blog singkat pada metode cepat dan mudah: Tulisan untuk Node.js dan browser, pada dasarnya sebagai berikut (di mana ini adalah sama dengan jendela):

(function(exports){

    // Your code goes here

   exports.test = function(){
        return 'hello world'
    };

})(typeof exports === 'undefined'? this['mymodule']={}: exports);

Atau ada beberapa proyek-proyek yang bertujuan untuk melaksanakan Node.js API pada sisi klien, seperti Marak's gemini.

Anda juga mungkin tertarik dalam DNode, yang memungkinkan anda untuk mengekspos fungsi JavaScript sehingga dapat dipanggil dari mesin lain menggunakan JSON berbasis protokol jaringan.

Komentar (9)

Epeli memiliki solusi yang bagus di sini http://epeli.github.com/piler/ yang bahkan bekerja tanpa perpustakaan, hanya menempatkan ini dalam sebuah file yang bernama share.js

(function(exports){

  exports.test = function(){
       return 'This is a function from shared module';
  };

}(typeof exports === 'undefined' ? this.share = {} : exports));

Pada sisi server hanya menggunakan:

var share = require('./share.js');

share.test();

Dan pada sisi klien hanya memuat file js dan kemudian menggunakan

share.test();
Komentar (3)

Pelajari source code jQuery yang membuat ini bekerja di Node.js modul pola, AMD modul pola, dan global di browser:

(function(window){
    var jQuery = 'blah';

    if (typeof module === "object" && module && typeof module.exports === "object") {

        // Expose jQuery as module.exports in loaders that implement the Node
        // module pattern (including browserify). Do not create the global, since
        // the user will be storing it themselves locally, and globals are frowned
        // upon in the Node module world.
        module.exports = jQuery;
    }
    else {
        // Otherwise expose jQuery to the global object as usual
        window.jQuery = window.$ = jQuery;

        // Register as a named AMD module, since jQuery can be concatenated with other
        // files that may use define, but not via a proper concatenation script that
        // understands anonymous AMD modules. A named AMD is safest and most robust
        // way to register. Lowercase jquery is used because AMD module names are
        // derived from file names, and jQuery is normally delivered in a lowercase
        // file name. Do this after creating the global so that if an AMD module wants
        // to call noConflict to hide this version of jQuery, it will work.
        if (typeof define === "function" && define.amd) {
            define("jquery", [], function () { return jQuery; });
        }
    }
})(this)
Komentar (1)

Saya akan merekomendasikan melihat ke RequireJS adaptor untuk Node.js. Masalahnya adalah bahwa CommonJS modul pola Node.js menggunakan secara default isn't asynchronous, yang menghambat loading di browser web. RequireJS menggunakan AMD pola, yang kedua asynchronous dan kompatibel dengan kedua server dan klien, asalkan anda menggunakan r.js adapter.

Komentar (1)

Don't lupa bahwa representasi string dari suatu fungsi JavaScript merupakan source code untuk fungsi itu. Anda hanya bisa menulis fungsi dan konstruktor di dikemas dengan cara sehingga mereka dapat toString()'a dan dikirim ke klien.

Cara lain untuk melakukan ini adalah menggunakan sistem membangun, menempatkan umum kode di file terpisah, dan kemudian memasukkan mereka ke dalam server dan client scripts. I'm menggunakan pendekatan yang sederhana client/server game melalui WebSockets di mana server dan klien keduanya berjalan pada dasarnya sama permainan lingkaran dan klien tersinkronisasi dengan server setiap tick untuk memastikan tidak ada's kecurangan.

Saya membangun sistem untuk permainan ini adalah sederhana Bash script yang menjalankan file melalui C preprocessor dan kemudian melalui sed untuk membersihkan beberapa sampah cpp daun di belakang, jadi aku bisa menggunakan semua normal preprocessor hal-hal seperti #seperti, #define, #ifdef, dll.

Komentar (1)

Mungkin hal ini tidak sepenuhnya sejalan dengan pertanyaan, tapi saya pikir saya'd berbagi ini.

Saya ingin membuat beberapa string sederhana fungsi utilitas, menyatakan pada String.prototipe, yang tersedia untuk kedua node dan browser. Saya hanya menjaga fungsi-fungsi tersebut dalam sebuah file yang bernama utilities.js (di subfolder) dan dapat dengan mudah referensi baik dari naskah-tag di browser saya kode, dan dengan menggunakan require (menghilangkan .js extension) di saya Node.js script:

my_node_script.js

var utilities = require('./static/js/utilities')

my_browser_code.html

<script src="/static/js/utilities.js"></script>

Saya berharap ini adalah informasi yang berguna untuk orang lain selain saya.

Komentar (3)

Jika anda menggunakan menggunakan modul bundlers seperti webpack untuk bundel file JavaScript untuk penggunaan di browser, anda hanya dapat menggunakan kembali Node.js modul untuk frontend berjalan di browser. Dengan kata lain, anda Node.js modul dapat dibagi antara Node.js dan browser.

Misalnya, anda memiliki kode berikut sum.js:

Normal Node.js modul: sum.js

const sum = (a, b) => {
    return a + b
}

module.exports = sum

Menggunakan modul Node.js

const sum = require('path-to-sum.js')
console.log('Sum of 2 and 5: ', sum(2, 5)) // Sum of 2 and 5:  7

Reuse itu di frontend

import sum from 'path-to-sum.js'
console.log('Sum of 2 and 5: ', sum(2, 5)) // Sum of 2 and 5:  7
Komentar (0)

Server hanya dapat mengirim JavaScript file sumber ke client (browser) tapi trik ini adalah bahwa klien akan memiliki untuk menyediakan mini "ekspor" lingkungan sebelum dapat exec kode dan menyimpannya sebagai modul.

Cara sederhana untuk membuat lingkungan seperti itu adalah dengan menggunakan penutupan. Misalnya, katakanlah anda server menyediakan sumber file melalui HTTP suka http://example.com/js/foo.js. Browser dapat memuat file yang dibutuhkan melalui XMLHttpRequest dan memuat kode seperti:

ajaxRequest({
  method: 'GET',
  url: 'http://example.com/js/foo.js',
  onSuccess: function(xhr) {
    var pre = '(function(){var exports={};'
      , post = ';return exports;})()';
    window.fooModule = eval(pre + xhr.responseText + post);
  }
});

Kuncinya adalah bahwa klien dapat membungkus kode asing ke dalam fungsi anonim yang akan segera berjalan (penutupan) yang menciptakan "ekspor" objek dan kembali agar anda dapat menetapkan mana anda'd suka, daripada mencemari global namespace. Dalam contoh ini, itu ditugaskan ke jendela atribut fooModule yang akan berisi kode yang diekspor oleh file foo.js.

Komentar (2)

Tak satu pun dari solusi sebelumnya membawa CommonJS sistem modul untuk browser.

Seperti yang disebutkan dalam jawaban yang lain, ada manajer aset/packager solusi seperti Browserify atau Piler dan ada RPC solusi seperti dnode atau nowjs.

Tapi aku tak't menemukan sebuah implementasi dari CommonJS untuk browser (termasuk require() fungsi dan ekspor / modul.ekspor benda-benda, dll.). Jadi saya menulis saya sendiri, hanya untuk menemukan kemudian bahwa orang lain telah menulis lebih baik daripada yang saya punya: https://github.com/weepy/brequire. It's disebut Menuntut (pendek untuk Browser yang memerlukan).

Dilihat dari popularitas, manajer aset sesuai dengan kebutuhan sebagian besar pengembang. Namun, jika anda membutuhkan browser pelaksanaan CommonJS, Menuntut mungkin akan sesuai dengan tagihan.

2015 Update: saya tidak lagi menggunakan Menuntut (ini masih't telah diperbarui dalam beberapa tahun). Jika saya'm hanya tulisan kecil, open-source modul dan aku ingin orang untuk dapat dengan mudah menggunakan, maka saya'll mengikuti pola yang mirip dengan Caolan's jawaban (atas) - saya menulis blog post tentang hal itu beberapa tahun yang lalu.

Namun, jika saya'm penulisan modul untuk penggunaan pribadi atau untuk sebuah komunitas yang standar pada CommonJS (seperti Ampersand komunitas) maka saya'll hanya menulis mereka di CommonJS format dan menggunakan Browserify.

Komentar (0)

now.js juga layak lihat. Hal ini memungkinkan anda untuk memanggil server-side dari client-side dan client-side fungsi dari server-side

Komentar (3)

Menulis kode seperti RequireJS modul dan tes anda sebagai Melati tes.

Dengan cara ini kode yang dapat dimuat di mana-mana dengan RequireJS dan tes yang akan dijalankan di browser dengan jasmine-html dan dengan jasmine-node Node.js tanpa perlu mengubah kode atau tes.

Berikut adalah contoh kerja]4 selama ini.

Komentar (0)

Jika anda ingin menulis browser anda di Node.js-seperti gaya yang dapat anda coba dualify.

Tidak ada browser kompilasi kode, sehingga anda dapat menulis aplikasi anda tanpa keterbatasan.

Komentar (0)

Use case: berbagi aplikasi konfigurasi antara Node.js dan browser (ini hanya sebuah ilustrasi, mungkin bukan pendekatan yang terbaik tergantung pada aplikasi anda).

Masalah: anda tidak dapat menggunakan jendela (tidak ada di Node.js) atau global (tidak ada di browser).

Solusi:

  • File config.js:

var config = { foo: 'bar' }; if (typeof modul === 'objek') modul.ekspor = config;

  • Di browser (index.html):
<script src="config.js"></script> <script src="myApp.js"></script>

Sekarang anda dapat membuka dev tools dan mengakses variabel global config

  • Di Node.js (app.js):

const config = require('./config'); konsol.log(config.foo); // Cetak 'bar'

  • Dengan Babel atau Ketangkasan:

impor config dari './config'; konsol.log(config.foo); // Cetak 'bar'

Komentar (3)

Saya menulis modul sederhana, yang dapat diimpor (baik menggunakan butuhkan dalam Node, atau tag script di browser), yang dapat anda gunakan untuk memuat modul-modul kedua dari klien dan dari server.

Contoh penggunaan

1. Mendefinisikan modul

Tempat berikut di file log2.js, di dalam web statis file folder:

let exports = {};

exports.log2 = function(x) {
    if ( (typeof stdlib) !== 'undefined' )
        return stdlib.math.log(x) / stdlib.math.log(2);

    return Math.log(x) / Math.log(2);
};

return exports;

Sederhana seperti itu!

2. Menggunakan modul

Karena itu adalah bilateral modul loader, kita dapat memuat dari kedua belah pihak (client dan server). Oleh karena itu, anda dapat melakukan beberapa hal berikut, tapi anda don't perlu untuk melakukan keduanya sekaligus (apalagi dalam urutan tertentu):

  • Dalam Node

Di Node, it's sederhana:

var loader = require('./mloader.js');
loader.setRoot('./web');

var logModule = loader.importModuleSync('log2.js');
console.log(logModule.log2(4));

Ini harus kembali 2.

Jika file anda isn't di Nodus's direktori saat ini, pastikan untuk memanggil loader.setRoot dengan path ke web statis file folder (atau di mana pun anda modul).

  • Di browser:

Pertama, menentukan halaman web:


    <header>
        <meta charset="utf-8" />
        Module Loader Availability Test

        <script src="mloader.js"></script>
    </header>


        <h1>Result</h1>
        <p id="result"><span style="color: #000088">Testing...</span></p>

        <script>
            let mod = loader.importModuleSync('./log2.js', 'log2');

            if ( mod.log2(8) === 3 && loader.importModuleSync('./log2.js', 'log2') === mod )
                document.getElementById('result').innerHTML = "Your browser supports bilateral modules!";

            else
                document.getElementById('result').innerHTML = "Your browser doesn't support bilateral modules.";
        </script>

Pastikan anda don't buka file langsung di browser anda, karena menggunakan AJAX, saya sarankan anda melihat pada Python 3's http.server modul (atau apa pun yang anda supercepat, baris perintah, folder web server deployment solution) sebagai gantinya.

Jika semuanya berjalan dengan baik, ini akan muncul:

Komentar (0)

Saya menulis ini, itu adalah sederhana untuk menggunakan jika anda ingin mengatur semua variabel ke lingkup global:

(function(vars, global) {
    for (var i in vars) global[i] = vars[i];
})({
    abc: function() {
        ...
    },
    xyz: function() {
        ...
    }
}, typeof exports === "undefined" ? this : exports);
Komentar (0)