Browserify - Cara memanggil fungsi yang dibundel dalam file yang dihasilkan melalui browserify di browser

96

Saya baru mengenal nodejs dan browserify. Saya mulai dengan tautan ini .

Saya memiliki file main.js yang berisi kode ini

var unique = require('uniq');

var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];

this.LogData =function(){
console.log(unique(data));
};

Sekarang saya menginstal modul uniq dengan npm:

 npm install uniq

Kemudian saya menggabungkan semua modul yang diperlukan mulai dari main.js menjadi satu file bernama bundle.js dengan perintah browserify:

browserify main.js -o bundle.js

File yang dihasilkan terlihat seperti ini:

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var unique = require('uniq');

var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];

this.LogData =function(){
console.log(unique(data));
};

},{"uniq":2}],2:[function(require,module,exports){
"use strict"

function unique_pred(list, compare) {
  var ptr = 1
    , len = list.length
    , a=list[0], b=list[0]
  for(var i=1; i<len; ++i) {
    b = a
    a = list[i]
    if(compare(a, b)) {
      if(i === ptr) {
        ptr++
        continue
      }
      list[ptr++] = a
    }
  }
  list.length = ptr
  return list
}

function unique_eq(list) {
  var ptr = 1
    , len = list.length
    , a=list[0], b = list[0]
  for(var i=1; i<len; ++i, b=a) {
    b = a
    a = list[i]
    if(a !== b) {
      if(i === ptr) {
        ptr++
        continue
      }
      list[ptr++] = a
    }
  }
  list.length = ptr
  return list
}

function unique(list, compare, sorted) {
  if(list.length === 0) {
    return []
  }
  if(compare) {
    if(!sorted) {
      list.sort(compare)
    }
    return unique_pred(list, compare)
  }
  if(!sorted) {
    list.sort()
  }
  return unique_eq(list)
}

module.exports = unique
},{}]},{},[1])

Setelah memasukkan file bundle.js ke halaman index.htm saya, bagaimana cara memanggil fungsi logData ??

SharpCoder
sumber
Di mana Anda ingin menyebutnya? Dan mengapa Anda ingin menyebutnya?
artur grzesiak
2
@arturgrzesiak: Saya ingin menggunakan fungsi ini di salah satu proyek saya yang lain yang akan saya jalankan di browser.
SharpCoder

Jawaban:

83

Secara default, browserify tidak mengizinkan Anda mengakses modul dari luar kode yang di-browser-kan - jika Anda ingin memanggil kode dalam modul yang di-browser-kan, Anda harus menjelajah kode Anda bersama dengan modul. Lihat http://browserify.org/ untuk contohnya.

Tentu saja, Anda juga dapat secara eksplisit membuat metode Anda dapat diakses dari luar seperti ini:

window.LogData =function(){
  console.log(unique(data));
};

Kemudian Anda dapat menelepon LogData()dari mana saja di halaman itu.

thejh
sumber
1
Terima kasih. Ini bekerja. Apakah ini berarti, saat membuat fungsi daripada mengatakan this.functionName, saya harus menulis window.functionName? Apakah kami memiliki solusi lain untuk ini? Ada alasan untuk menggunakan window.functionName?
SharpCoder
21
"Anda seharusnya menjelajah kode Anda bersama dengan modul" - Ugh, bagaimana jika saya ingin melakukan sesuatu seperti itu onclick="someFunction()". Anda tidak mungkin membantah bahwa itu kasus penggunaan yang langka!?!
BlueRaja - Danny Pflughoeft
57
Ada kekurangan dokumentasi yang serius di mana pun untuk pemula tentang cara menggunakan Browserify pada klien.
Oliver Dixon
1
ya, dokumentasi harus menyatakan dengan jelas bahwa ini adalah keputusan desain yang harus dihindari, tetapi berikan jalur yang jelas untuk membuatnya berfungsi saat Anda tidak memiliki alternatif (dalam kasus saya, menggunakan data dari template untuk mengisi objek JS) ... terima kasih @thejh karena telah menunjukkan solusi sederhana! ;)
Alexandre Martini
1
Saya bahkan tidak dapat memikirkan situasi di mana Anda TIDAK AKAN ingin membuat fungsi utama Anda tersedia di luar modul. Bagaimana ini bukan perilaku default? Jenis aplikasi web apa yang tidak memanggil fungsi?
Cybernetic
101

Bagian penting dari menggabungkan modul mandiri dengan Browserify adalah --sopsinya. Ini mengekspos apa pun yang Anda ekspor dari modul Anda menggunakan node module.exportssebagai variabel global. File tersebut kemudian dapat dimasukkan ke dalam <script>tag.

Anda hanya perlu melakukan ini jika karena alasan tertentu Anda ingin variabel global tersebut diekspos. Dalam kasus saya, klien memerlukan modul mandiri yang dapat disertakan dalam halaman web tanpa perlu mengkhawatirkan bisnis Browserify ini.

Berikut adalah contoh di mana kami menggunakan --sopsi dengan argumen module:

browserify index.js --s module > dist/module.js

Ini akan mengekspos modul kita sebagai variabel global bernama module.
Sumber .

Pembaruan: Terima kasih kepada @fotinakis. Pastikan Anda lewat --standalone your-module-name. Jika Anda lupa bahwa --standalonemengambil argumen, Browserify mungkin akan membuat modul kosong secara diam-diam karena tidak dapat menemukannya.

Semoga ini menghemat waktu Anda.

Matas Vaitkevicius
sumber
2
Saya mencoba untuk menjelajah kode ES6 berlabel. Tetapi objek mandiri kosong ketika saya mencoba untuk menghiburnya di browser. Kode ES6 sederhana tanpa modul apa pun berfungsi dengan baik dalam mode mandiri. Ada petunjuk tentang ini?
Yohanes
@jackyrudetsky tidak tahu, saya akan merekomendasikan menambahkan pertanyaan tentang SO, kedengarannya seperti masalah yang menarik. bisa terkait dengan ini. github.com/substack/node-browserify/issues/1357
Matas Vaitkevicius
1
@fotinakis Sebenarnya itu adalah masalah di Browserify github.com/substack/node-browserify/issues/1537
Yohanes
3
IMO ini harus menjadi jawaban yang diterima. Jika Anda menggunakan fungsi global, jauh lebih baik untuk memiliki namespace Anda sendiri daripada menggantung setiap fungsi di luar jendela.
VictorB
1
@VictorB semua variabel global dalam Javascript adalah elemen jendela, jadi kedua metode mencapai hal yang sama (menambahkan variabel global ke jendela)
David Lopez
37

Jawaban @Matas Vaitkevicius dengan opsi mandiri Browserify benar ( jawaban @ thejh menggunakan variabel global jendela juga berfungsi, tetapi seperti yang dicatat orang lain, ini mencemari namespace global sehingga tidak ideal). Saya ingin menambahkan sedikit lebih banyak detail tentang cara menggunakan opsi mandiri.

Dalam skrip sumber yang ingin Anda paketkan, pastikan untuk mengekspos fungsi yang ingin Anda panggil melalui module.exports. Dalam skrip klien, Anda dapat memanggil fungsi-fungsi yang terbuka ini melalui <bundle-name>. <func-name> . Berikut contohnya:

File sumber saya src / script.js akan memiliki ini:
module.exports = {myFunc: func};

Perintah browserify saya akan terlihat seperti ini:
browserify src/script.js --standalone myBundle > dist/bundle.js

Dan skrip klien saya dist / client.js akan memuat skrip yang dibundel
<script src="bundle.js"></script>
dan kemudian memanggil fungsi yang terekspos seperti ini:
<script>myBundle.myFunc();</script>


Tidak perlu memerlukan nama bundel dalam skrip klien sebelum memanggil fungsi yang terpapar, misalnya <script src="bundle.js"></script><script>var bundled = require("myBundle"); bundled.myFunc();</script>tidak perlu dan tidak akan berfungsi.

Faktanya, seperti semua fungsi yang dibundel oleh browserify tanpa mode mandiri, fungsi yang dibutuhkan tidak akan tersedia di luar skrip yang dibundel . Browserify memungkinkan Anda menggunakan beberapa fungsi Node di sisi klien, tetapi hanya di skrip yang dibundel itu sendiri ; ini tidak dimaksudkan untuk membuat modul mandiri yang dapat Anda impor dan gunakan di mana saja di sisi klien, itulah sebabnya kami harus mengatasi semua masalah tambahan ini hanya untuk memanggil satu fungsi di luar konteks yang dibundel.

Galen Long
sumber
3
Wow! Akhirnya contoh praktis.
N73k
1
Contoh yang bagus, tetapi sejauh "itu mencemari namespace global oleh karena itu tidak ideal" tidak mengikuti secara otomatis, itu mungkin dapat diterima jika hanya satu fungsi; Hanya asap dan cermin, bahkan myBundlemenempel pada objek jendela, window.myBundle.myFunc()bukan jendela.
MyFunc
1
Harus ada poin ekstra untuk orang yang memberikan contoh ujung ke ujung.
Sharud
Begitulah dokumentasi harus ditulis
Ellery Leung
8

Saya baru saja membaca jawabannya dan sepertinya tidak ada yang menyebutkan penggunaan cakupan variabel global? Yang berguna jika Anda ingin menggunakan kode yang sama di node.js dan di browser.

class Test
{
  constructor()
  {
  }
}
global.TestClass = Test;

Kemudian Anda dapat mengakses TestClass di mana saja.

<script src="bundle.js"></script>
<script>
var test = new TestClass(); // Enjoy!
</script>

Catatan: TestClass kemudian tersedia di mana saja. Yang sama dengan menggunakan variabel jendela.

Selain itu, Anda dapat membuat dekorator yang mengekspos kelas ke cakupan global. Yang sangat bagus tapi menyulitkan untuk melacak di mana variabel didefinisikan.

DDD
sumber
Seperti yang Anda sendiri katakan, menambahkan fungsi untuk globalmenghasilkan efek yang sama seperti menambah window, yang telah dicakup oleh thejh. Jawaban ini tidak menambah informasi baru.
Galen Long
@GalenLong mungkin Anda lupa bahwa tidak ada variabel jendela di node.js? Dan beberapa pustaka yang menargetkan node dan browser mungkin ingin menggunakan global sebagai gantinya. Jawaban saya mendapat beberapa upvote dan belum di minus jadi saya pikir informatif untuk orang lain jika bukan untuk Anda.
DDD
Anda benar, @Azarus. Ada dua jawaban duplikat lainnya di halaman itu dan saya salah memasukkan jawaban Anda ke dalam kelompok. Permintaan maaf saya.
Galen Long
hanya ingin dicatat bahwa tanda kurung gantung di sini adalah praktik yang sangat buruk untuk javascript, misalnya: menerapkan pola ini ke kata kunci kembali dan bersiap untuk menangis. misalnya, return {}tetapi jatuhkan kurung kurawal buka ke baris berikutnya.
Sgnl
1
@Azarus Saya membuat biola untuk menunjukkan apa yang saya maksud - jsfiddle.net/cubaksot/1
Sgnl
6

Baca README.md dari browserify tentang --standaloneparameter atau google "browserify umd"

undoZen
sumber
19
Ini lebih merupakan petunjuk di mana menemukan jawaban daripada jawaban.
pengguna2314737
ini membawa saya ke solusi yang saya cari selama dua hari (cara menggunakan output browserify dari lingkungan require.js). Terima kasih!
Flion
2

Agar fungsi Anda tersedia dari HTML dan dari node sisi server:

main.js:

var unique = require('uniq');

function myFunction() {
    var data = [1, 2, 2, 4, 3];
    return unique(data).toString();
}
console.log ( myFunction() );

// When browserified - we can't call myFunction() from the HTML, so we'll externalize myExtFunction()
// On the server-side "window" is undef. so we hide it.
if (typeof window !== 'undefined') {
    window.myExtFunction = function() {
        return myFunction();
    }
}

main.html:

<html>
    <head>
        <script type='text/javascript' src="bundle.js"></script>
    <head>
    <body>
        Result: <span id="demo"></span>
        <script>document.getElementById("demo").innerHTML = myExtFunction();</script>
    </body>
</html>

Lari:

npm install uniq
browserify main.js > bundle.js

dan Anda akan mendapatkan hasil yang sama saat membuka main.html di browser seperti saat menjalankan

node main.js
Ori Miller
sumber
2

Contoh minimal runnable

Ini pada dasarnya sama dengan: https://stackoverflow.com/a/43215928/895245 tetapi dengan file konkret yang memungkinkan Anda untuk menjalankan dan mereproduksinya sendiri dengan mudah.

Kode ini juga tersedia di: https://github.com/cirosantilli/browserify-hello-world

index.js

const uniq = require('uniq');

function myfunc() {
  return uniq([1, 2, 2, 3]).join(' ');
}
exports.myfunc = myfunc;

index.html

<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Browserify hello world</title>
</head>
<body>
<div id="container">
</body>
</div>
<script src="out.js"></script>
<script>
document.getElementById('container').innerHTML = browserify_hello_world.myfunc();
</script>
</html>

Penggunaan Node.js:

#!/usr/bin/env node

const browserify_hello_world = require('./index.js');

console.log(browserify_hello_world.myfunc());

Hasilkan out.jsuntuk penggunaan browser:

npx browserify --outfile out.js --standalone browserify_hello_world index.js

Baik browser dan baris perintah menunjukkan hasil yang diharapkan:

1 2 3

Diuji dengan Browserify 16.5.0, Node.js v10.15.1, Chromium 78, Ubuntu 19.10.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
1
The exports.myfunc.= myfuncporsi ini benar-benar penting dan tidak terjawab dalam jawaban lainnya.
parttimeturtle
2

ini sangat sederhana - seluruh konsep ini tentang membungkus

1. alternatif - objek "ini"

untuk tujuan ini saya akan menganggap Anda memiliki "hanya 1 skrip untuk seluruh aplikasi {{app_name}}" dan "1 fungsi {{function_name}}"

tambahkan fungsi {{function_name}} ke objek "ini"

function {{function_name}}(param) {}
->
this.{{function_name}} = function(param) {}

maka Anda harus memberi nama objek itu agar tersedia - Anda akan melakukannya menambahkan param "mandiri dengan nama" seperti yang disarankan orang lain

jadi jika Anda menggunakan "watchify" dengan "browserify" gunakan ini

var b = browserify({
    ...
    standalone: '{{app_name}}'
});

atau baris perintah

browserify index.js --standalone {{app_name}} > index-bundle.js

maka Anda dapat memanggil fungsi Anda dari browser

{{app_name}}.{{function_name}}(param);
window.{{app_name}}.{{function_name}}(param);

2. alternatif - objek "jendela"

tambahkan fungsi {{function_name}} ke objek "window"

function {{function_name}}(param) {}
->
window.{{function_name}} = function(param) {}

maka Anda dapat memanggil fungsi Anda dari browser

{{function_name}}(param);
window.{{function_name}}(param);

-

mungkin saya membantu seseorang

BG BRUNO
sumber
1

Anda punya beberapa pilihan:

  1. Biarkan plugin browserify-bridge mengekspor modul secara otomatis ke modul entri yang dibuat. Ini berguna untuk proyek SDK atau situasi di mana Anda tidak perlu mengikuti apa yang diekspor secara manual.

  2. Ikuti pola pseudo-namespace untuk eksposur roll-up:

Pertama, atur perpustakaan Anda seperti ini, manfaatkan pencarian indeks pada folder:

/src
--entry.js
--/helpers
--- index.js
--- someHelper.js
--/providers
--- index.js
--- someProvider.js
...

Dengan pola ini, Anda mendefinisikan entri seperti ini:

exports.Helpers = require('./helpers');
exports.Providers = require('./providers');
...

Perhatikan kebutuhan secara otomatis memuat index.js dari masing-masing sub-folder

Di subfolder Anda, Anda bisa menyertakan manifes serupa dari modul yang tersedia dalam konteks itu:

exports.SomeHelper = require('./someHelper');

Pola ini berskala sangat baik dan memungkinkan pelacakan kontekstual (folder demi folder) dari apa yang akan disertakan dalam api yang digulung.

elemen dalam
sumber
-1
window.LogData =function(data){
   return unique(data);
};

Panggil fungsi tersebut hanya dengan LogData(data)

Ini hanya sedikit modifikasi pada jawaban thejh tetapi yang penting

Pratik Khadtale
sumber
Modifikasi ini tidak relevan dengan perhatian penanya dan tidak menambahkan informasi baru mengingat jawaban yang sudah ada.
Galen Long
-2

Untuk tujuan debugging, saya menambahkan baris ini ke code.js saya:

window.e = function(data) {eval(data);};

Kemudian saya bisa menjalankan apa pun bahkan di luar paket.

e("anything();");
Karveiani
sumber