Browserify: come chiamare la funzione raggruppata in un file generato tramite browserify nel browser


95

Sono nuovo su nodejs e browserify. Ho iniziato con questo collegamento .

Ho il file main.js che contiene questo codice

var unique = require('uniq');

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

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

Ora installo il modulo uniq con npm:

 npm install uniq

Quindi raggruppo tutti i moduli richiesti a partire da main.js in un singolo file chiamato bundle.js con il comando browserify:

browserify main.js -o bundle.js

Il file generato ha questo aspetto:

(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])

Dopo aver incluso il file bundle.js nella mia pagina index.htm, come posso chiamare la funzione logData ??


Dove vuoi chiamarlo? E perché vuoi chiamarlo?
artur grzesiak

2
@arturgrzesiak: Voglio utilizzare questa funzione in uno dei miei altri progetti che eseguirò nel browser.
SharpCoder

Risposte:


80

Per impostazione predefinita, browserify non ti consente di accedere ai moduli dall'esterno del codice browserificato: se vuoi chiamare il codice in un modulo browserificato, dovresti browserify il tuo codice insieme al modulo. Vedi http://browserify.org/ per esempi di questo.

Naturalmente, potresti anche rendere esplicitamente il tuo metodo accessibile dall'esterno in questo modo:

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

Quindi puoi chiamare LogData()da qualsiasi altra parte della pagina.


1
Grazie. Funziona. Questo significa che, mentre creo funzioni invece di dire this.functionName, dovrei scrivere window.functionName? Abbiamo qualche altra soluzione per questo? Qualche motivo per utilizzare window.functionName?
SharpCoder

19
"dovresti browserify il tuo codice insieme al modulo" - Ugh, e se volessi fare qualcosa di simile onclick="someFunction()". Non si può certo sostenere che sia un caso d'uso raro!?!
BlueRaja - Danny Pflughoeft

55
C'è una grave mancanza di documentazione ovunque per i principianti su come utilizzare effettivamente Browserify sul client.
Oliver Dixon

1
sì, la documentazione dovrebbe chiaramente affermare che questa è una decisione di progettazione da evitare, ma fornire un percorso chiaro per farlo funzionare quando non si dispone di un'alternativa (nel mio caso, utilizzando i dati del modello per popolare un oggetto JS) ... grazie @thejh per aver indicato una soluzione semplice! ;)
Alexandre Martini

1
Non riesco nemmeno a pensare a una situazione in cui NON vorresti rendere disponibili le tue principali funzioni al di fuori del modulo. In che modo questo comportamento non è predefinito? Che tipo di applicazione web non chiama le funzioni?
Cibernetico

100

La parte fondamentale del raggruppamento di moduli standalone con Browserify è l' --sopzione. Espone tutto ciò che esporti dal tuo modulo usando il nodo module.exportscome variabile globale. Il file può quindi essere incluso in un <script>tag.

Hai solo bisogno di farlo se per qualche motivo hai bisogno che quella variabile globale sia esposta. Nel mio caso il cliente necessitava di un modulo autonomo che potesse essere incluso nelle pagine web senza che si dovessero preoccupare di questa attività di Browserify.

Ecco un esempio in cui usiamo l' --sopzione con un argomento di module:

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

Questo esporrà il nostro modulo come una variabile globale denominata module.
Fonte .

Aggiornamento: grazie a @fotinakis. Assicurati si sta passando --standalone your-module-name. Se dimentichi che --standaloneaccetta un argomento, Browserify potrebbe generare silenziosamente un modulo vuoto poiché non è riuscito a trovarlo.

Spero che questo ti faccia risparmiare tempo.


2
Sto cercando di browserify codice ES6 babelified. Ma l'oggetto standalone è vuoto quando provo a console nel browser. Il semplice codice ES6 senza alcun modulo funziona bene in modalità standalone. Qualche suggerimento su questo?
John

@jackyrudetsky non ne ho idea, consiglierei di aggiungere una domanda su SO, sembra un problema interessante. potrebbe essere correlato a questo. github.com/substack/node-browserify/issues/1357
Matas Vaitkevicius

1
@fotinakis In realtà era un problema in Browserify github.com/substack/node-browserify/issues/1537
John

3
IMO questa dovrebbe essere la risposta accettata. Se stai usando una funzione globale, è molto meglio avere il tuo spazio dei nomi piuttosto che sospendere ogni funzione dalla finestra.
VictorB

1
@VictorB tutte le variabili globali in Javascript sono elementi della finestra, quindi entrambi i metodi ottengono la stessa cosa (aggiungendo le variabili globali alla finestra)
David Lopez

37

La risposta di @Matas Vaitkevicius con l'opzione standalone di Browserify è corretta (funziona anche la risposta di @ thejh che utilizza la variabile globale della finestra , ma come altri hanno notato, inquina lo spazio dei nomi globale quindi non è l'ideale). Volevo aggiungere un po 'più di dettagli su come utilizzare l'opzione standalone.

Nello script sorgente che vuoi raggruppare, assicurati di esporre le funzioni che vuoi chiamare tramite module.exports. Nello script client, puoi chiamare queste funzioni esposte tramite <bundle-name>. <func-name> . Ecco un esempio:

Il mio file sorgente src / script.js avrà questo:
module.exports = {myFunc: func};

Il mio comando browserify sarà simile a questo:
browserify src/script.js --standalone myBundle > dist/bundle.js

E il mio script client dist / client.js caricherà lo script in bundle
<script src="bundle.js"></script>
e quindi chiamerà la funzione esposta in questo modo:
<script>myBundle.myFunc();</script>


Non è necessario richiedere il nome del bundle nello script client prima di chiamare le funzioni esposte, ad esempio <script src="bundle.js"></script><script>var bundled = require("myBundle"); bundled.myFunc();</script>non è necessario e non funzionerà.

In effetti, proprio come tutte le funzioni in bundle da browserify senza modalità standalone, la funzione require non sarà disponibile al di fuori dello script in bundle . Browserify consente di utilizzare alcune funzioni del nodo lato client, ma solo nello script in bundle stesso ; non ha lo scopo di creare un modulo autonomo che puoi importare e utilizzare ovunque sul lato client, motivo per cui dobbiamo affrontare tutti questi problemi extra solo per chiamare una singola funzione al di fuori del suo contesto in bundle.


3
Wow! Finalmente un esempio pratico.
N73k

1
Buon esempio, ma nella misura in cui "inquina lo spazio dei nomi globale quindi non ideale" non segue automaticamente, potrebbe essere accettabile se è solo una funzione; Solo fumo e specchi, myBundlesi attacca anche all'oggetto finestra, window.myBundle.myFunc()invece di window.myFunc ()
joedotnot

1
Ci dovrebbero essere punti extra per le persone che forniscono esempi end-to-end.
Sharud

È così che dovrebbe essere scritta la documentazione
Ellery Leung,

7

Ho appena letto le risposte e sembra che nessuno abbia menzionato l'uso dell'ambito della variabile globale? Il che è utile se vuoi usare lo stesso codice in node.js e nel browser.

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

Quindi puoi accedere a TestClass ovunque.

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

Nota: il TestClass diventa quindi disponibile ovunque. Che equivale a usare la variabile window.

Inoltre è possibile creare un decoratore che esponga una classe all'ambito globale. Il che è davvero bello ma rende difficile tenere traccia di dove è definita una variabile.


Come dici tu stesso, l'aggiunta della funzione a globalproduce lo stesso effetto dell'aggiunta a window, che era già coperta da jh. Questa risposta non aggiunge nuove informazioni.
Galen Long

@GalenLong forse hai dimenticato che non esiste una variabile di finestra in node.js? E alcune librerie che prendono di mira il nodo e il browser potrebbero voler utilizzare invece globale. La mia risposta ha ottenuto alcuni voti positivi e non è ancora in meno, quindi penso che sia informativo per gli altri se non per te.
GGD

Hai ragione, @Azarus. C'erano altre due risposte duplicate sulla pagina e ho incluso erroneamente la tua nel gruppo. Mie scuse.
Galen Long,

Voglio solo notare che le parentesi quadre impiccate qui sono una pessima pratica per javascript, ad esempio: applica questo modello alla parola chiave return e preparati a piangere. ad esempio, return {}ma rilasciare la parentesi graffa di apertura fino alla riga successiva.
Sgnl

1
@Azarus ho creato un violino per dimostrare cosa intendo - jsfiddle.net/cubaksot/1
Sgnl

6

Leggi README.md di browserify sul --standaloneparametro o google "browserify umd"


19
Questo è più un suggerimento su dove trovare una risposta che una risposta.
user2314737

questo mi ha portato alla soluzione che stavo cercando per due giorni (come utilizzare l'output browserify da un ambiente require.js). grazie!
Flion

2

Per avere la tua funzione disponibile sia dall'HTML che dal nodo lato 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>

Correre:

npm install uniq
browserify main.js > bundle.js

e dovresti ottenere gli stessi risultati quando apri main.html in un browser come durante l'esecuzione

node main.js

2

Esempio minimo eseguibile

Questo è fondamentalmente lo stesso di: https://stackoverflow.com/a/43215928/895245 ma con file concreti che ti permetteranno di eseguirlo e riprodurlo facilmente da solo.

Questo codice è disponibile anche su: 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>

Utilizzo di Node.js:

#!/usr/bin/env node

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

console.log(browserify_hello_world.myfunc());

Genera out.jsper l'utilizzo del browser:

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

Sia il browser che la riga di comando mostrano l'output previsto:

1 2 3

Testato con Browserify 16.5.0, Node.js v10.15.1, Chromium 78, Ubuntu 19.10.


1
La exports.myfunc.= myfuncparte di questo era assolutamente critica e mancava in altre risposte.
parttimeturtle

1

Hai alcune opzioni:

  1. Lascia che il plugin browserify-bridge esporti automaticamente i moduli in un modulo di ingresso generato. Ciò è utile per i progetti SDK o le situazioni in cui non è necessario tenere il passo manualmente con ciò che viene esportato.

  2. Segui un modello di pseudo-spazio dei nomi per l'esposizione del roll-up:

Per prima cosa, organizza la tua libreria in questo modo, sfruttando le ricerche di indice sulle cartelle:

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

Con questo modello, definisci la voce in questo modo:

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

Notare che require carica automaticamente index.js da ciascuna rispettiva sottocartella

Nelle tue sottocartelle, puoi semplicemente includere un manifest simile dei moduli disponibili in quel contesto:

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

Questo modello si adatta molto bene e consente il monitoraggio contestuale (cartella per cartella) di cosa includere nell'API arrotolata.


1

è davvero semplice: l'intero concetto riguarda il confezionamento

1. alternativa - oggetto "questo"

a questo scopo presumo che tu abbia "solo 1 script per l'intera app {{app_name}}" e "1 funzione {{function_name}}"

aggiungi la funzione {{function_name}} all'oggetto "this"

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

quindi devi nominare quell'oggetto per renderlo disponibile - lo farai aggiungere il parametro "standalone with name" come altri consigliano

quindi se usi "watchify" con "browserify" usa questo

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

o riga di comando

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

quindi puoi chiamare la tua funzione dal browser

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

2. alternativa - oggetto "finestra"

aggiungi la funzione {{function_name}} all'oggetto "window"

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

quindi puoi chiamare la tua funzione dal browser

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

-

forse aiuto qualcuno


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

Chiama la funzione semplicemente con LogData(data)

Questa è solo una leggera modifica alla risposta di thejh ma importante


Questa modifica è irrilevante per le preoccupazioni del richiedente e non aggiunge alcuna nuova informazione date le risposte già esistenti.
Galen Long

-2

Per scopi di debug ho aggiunto questa riga al mio code.js:

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

Quindi potrei eseguire qualsiasi cosa anche al di fuori del pacchetto.

e("anything();");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.