2014-10-28 5 views
16

Tirando fuori i miei capelli cercando una semplice soluzione per condividere codice, richiesta tramite NPM, su più bundle di Browserify o Webpack. Pensando, esiste una cosa come un "ponte" di file?Soluzione semplice per condividere i moduli caricati tramite NPM su più bundle Browserify o Webpack

Questo non è dovuto a tempo di compilazione (Sono consapevole di watchify), ma piuttosto il desiderio di estrarre fuori tutte le mie librerie specifiche del fornitore in vendor.js in modo di mantenere la mia app.js dimensione del file verso il basso e di non mandare in crash il browser con massiccia sourcemaps. Inoltre, trovo il modo più pulito se dovesse emergere la necessità di visualizzare i js compilati. E così:

// vendor.js 

require('react'); 
require('lodash'); 
require('other-npm-module'); 
require('another-npm-module'); 

E 'molto importante che il codice venga caricato dal NPM al contrario di Bower, o salvati in una directory 'vendor' per poter essere importati attraverso un percorso relativo e identificato tramite uno spessore. Mi piacerebbe mantenere ogni riferimento di libreria tirato via NPM tranne che per la mia vera fonte di applicazione.

In app.js io continuo tutto il mio codice sorgente, e tramite l'array externals, esclude librerie dei venditori sopra elencati dalla compilazione:

// app.js 

var React = require('react'); 
var _  = require('lodash'); 

var Component = React.createClass() 

// ... 

E poi nel index.html, ho bisogno di entrambi i file

// index.html 
<script src='vendor.js'></script> 
<script src='app.js'></script> 

Usando Browserify o Webpack, come posso fare in modo che app.js possa "vedere" in quei moduli caricati via npm? Sono a conoscenza della creazione di un pacchetto con esterni e quindi di referenziare il file diretto (ad esempio, node_modules) tramite un alias, ma spero di trovare una soluzione più automatica e meno "Require.js".

Fondamentalmente, mi chiedo se sia possibile collegare i due in modo che app.js possa guardare all'interno di vendor.js per risolvere le dipendenze. Sembra un'operazione semplice e diretta, ma non riesco a trovare una risposta da nessuna parte su questa rete ampia e ampia.

Grazie!

risposta

11

Con Webpack si utilizzano più punti di accesso e lo CommonChunkPlugin.

tratto dal webpack docs:


Per dividere la vostra applicazione in 2 file, dicono app.js e vendor.js, è possibile richiedere i file del fornitore in vendor.js. Quindi passa questo nome al CommonChunkPlugin come mostrato di seguito.

module.exports = { 
    entry: { 
    app: "./app.js", 
    vendor: ["jquery", "underscore", ...], 
    }, 
    output: { 
    filename: "bundle.js" 
    }, 
    plugins: [ 
    new webpack.optimize.CommonsChunkPlugin(
     /* chunkName= */"vendor", 
     /* filename= */"vendor.bundle.js" 
    ) 
    ] 
}; 

Questo rimuoverà tutti i moduli nel blocco fornitore dal blocco dell'app. Lo bundle.js ora conterrà solo il codice dell'app, senza alcuna delle sue dipendenze. Questi sono in vendor.bundle.js.

Nella pagina HTML caricare vendor.bundle.js prima dello bundle.js.

<script src="vendor.bundle.js"></script> 
<script src="bundle.js"></script> 

+0

presumo reagisco va nella matrice vendor troppo? – Leahcim

+0

stai solo includendo il nome del file del fornitore in quell'array, o dovrebbe essere un percorso? – Leahcim

+0

Non voglio creare un bundle o un chunk separato per la mia libreria separata di componenti che sto condividendo tra progetti, voglio solo richiedere direttamente i file sorgente. Conosci un modo per farlo? (domanda completa: http://stackoverflow.com/questions/31820641/how-to-set-up-a-private-shared-library-of-react-components-with-webpack) – Andy

26

Elencare tutti i vendor file/moduli e utilizzare CommonChunkPlugin è davvero il modo consigliato. Questo diventa piuttosto noioso, e soggetto a errori.

Considerare questi moduli NPM: fastclick e mprogress. Dal momento che non hanno adottato il formato del modulo CommonJS, è necessario dare webpack una mano, come questo:

require('imports?define=>false!fastclick')(document.body); 
require('mprogress/mprogress.min.css'); 
var Mprogress = require('mprogress/mprogress.min.js'), 

Ora supponendo che si vuole sia fastclick e mprogress nel vostro pezzo fornitore, si sarebbe probabilmente provare questo:

module.exports = { 
    entry: { 
    app: "./app.js", 
    vendor: ["fastclick", "mprogress", ...] 

Ahimè, non funziona. È necessario che le chiamate a require():

module.exports = { 
    entry: { 
    app: "./app.js", 
    vendor: [ 
     "imports?define=>false!fastclick", 
     "mprogress/mprogress.min.css", 
     "mprogress/mprogress.min.js", 
     ...] 

Si invecchia, anche con qualche inganno resolve.alias. Ecco la mia soluzione. CommonChunkPlugin consente di specificare un callback che restituirà se si desidera o meno includere un modulo nel blocco del fornitore. Se il codice sorgente propria è in una specifica directory src, e il resto è nella directory node_modules, basta rifiutare i moduli in base al loro percorso:

var node_modules_dir = path.join(__dirname, 'node_modules'), 
    app_dir   = path.join(__dirname, 'src'); 

module.exports = { 
    entry: { 
    app: "./app.js", 
    }, 
    output: { 
    filename: "bundle.js" 
    }, 
    plugins: [ 
    new webpack.optimize.CommonsChunkPlugin(
     /* chunkName= */"vendor", 
     /* filename= */"vendor.bundle.js" 
     function (module, count) { 
     return module.resource && module.resource.indexOf(app_dir) === -1; 
     } 
    ) 
    ] 
}; 

Dove module.resource è il percorso del modulo considerata. Si potrebbe anche fare il contrario, e comprendono solo il modulo se è all'interno node_modules_dir, vale a dire:

 return module.resource && module.resource.indexOf(node_modules_dir) === 0; 

ma nella mia situazione, preferisco dire: "messo tutto ciò che non è nel mio albero dei sorgenti fonte in un pezzo di venditore ".

Spero che questo aiuti.

+0

è il file './App.js' nella directory' src'? – Leahcim

+0

Inoltre, come funziona dove si hanno i moduli npm che si usano per lo sviluppo ma non si desidera in un file di un produttore di produzione? per esempio, supponi di avere 'Backbone.js' e' underscore.js' come 'node_module's, che hai bisogno nel file del venditore, ma hai anche altri' node_modules' che sono stati inclusi solo per scopi di sviluppo e tu no vuoi in bundle in un 'vendor.bundle.js' – Leahcim

+0

@Leahcim sembra una decisione che devi prendere quando carichi i moduli" solo ", non nel file webpack.config. Potresti usare qualcosa come 'DefinePlugin' per definire un' IS_DEV' e richiedere condizionatamente i tuoi moduli nodo di sviluppo .. poi se compili quando 'IS_DEV' è falso, non verrà caricato in primo luogo –