2012-07-10 24 views
7

Ho visto il discorso di Paul Irish che annunciava Yeoman (www.yeoman.io), e sono appassionato del concetto di gestione di un ambiente di sviluppo continuo. Non contento di aspettare un invito a Yeoman, ho provato Grunt e Brunch. Entrambi si installano facilmente e posso ottenere i nuovi progetti in esecuzione con il minimo sforzo.Importare un progetto JavaScript esistente in un progetto Grunt/Brunch

Non capisco come si possa migrare un progetto esistente in entrambe le piattaforme. Il mio progetto utilizza un singolo spazio dei nomi e utilizza due convenzioni per i moduli (uno per istanziare un altro per l'utilità), ognuno dei quali è avvolto in funzioni anonime autoeseguite che esportano nell'istanza o nello spazio dei nomi.

Ho almeno 200 moduli e molte più semplici funzioni di helper esporta nello spazio dei nomi; quindi non è del tutto efficiente utilizzare la console per crearli in un progetto grunt/brunch e quindi importare manualmente ciascun modulo singolarmente. Inoltre, sto utilizzando almeno 15 diversi strumenti JavaScript di terze parti. Non è chiaro a me come portarli.

Qual è il modo più efficiente di prendere un grande progetto esistente e migrarlo in Grunt/Brunch con il minor numero di refactoring e supporto per strumenti di terze parti arbitrari?

Aggiornamento: tra i due, ho trovato il brunch un po 'più facile da gestire. Se usi lo "scheletro" di azioni (che è "template" - dalla riga di comando {nella cartella in cui vuoi che si verifichi la modifica} esegui "brunch new [nome_progetto] --keleton git: //github.com/brunch /simple-js-skeleton.git ") per puro JS, si ottiene una nuova struttura di cartelle che è in realtà abbastanza reattiva. Tutto ciò che inserisci nelle cartelle "app" (il tuo codice personale) o "venditore" (di terze parti) verrà automaticamente ricompilato per te su modifica file (quando esegui "brunch watch").

Questo è fantastico, tranne. Secondo la documentazione, controlli gli script del fornitore dell'ordine che sono compilati e concatenati insieme dal file config.coffee di Brunch (file di testo JSON). Le modifiche a questo file sembrano non avere alcun effetto, quindi ti ritroverai con condizioni di gara di terze parti dai plug-in in attesa di altri plug-in.

Inoltre, quando si rilascia il proprio codice nella cartella "app" creata automaticamente, si ottiene una versione auto-compilata, in tempo reale e come si modifica il codice; ma non è accessibile. Il brunch offusca l'oggetto window, quindi la mia iniziale dichiarazione del namespace su window.myNameSpace fallisce e anche tutte le successive chiamate di libreria allo spazio dei nomi falliscono. Questo ha qualcosa a che fare con il sistema dei moduli di Brunch, per il quale non riesco a trovare alcuna documentazione.

Ho risolto questo ponendo la classe del mio spazio dei nomi nella cartella "fornitore", assicurandomi che fosse collegata all'oggetto della finestra; tuttavia, ora c'è una condizione di competizione: il mio spazio dei nomi non è sempre disponibile per tutti i miei moduli.

Il problema è ora questo:

Dopo aver copiato tutte le librerie interne ed esterne in un progetto Brunch, come si fa a configurare l'applicazione per caricarli in un ordine sano di mente?

risposta

8

Questo è un po 'un'opera, ma alla fine l'ho capito.Quando ho iniziato con Brunch, non era ovvio come fare il primo passo: importare la mia struttura di directory. Mi ci sono voluti un paio di passaggi sopra la documentazione, prima che diventasse evidente:

  1. Execute brunch new MyAppName -s https://github.com/damassi/Javascript-App-Skeleton, che genererà una struttura di cartelle di file scheletro e config.coffee
  2. Per me, le uniche cartelle importanti in questa struttura sono stati "app" (il contenuto src non elaborato per CSS, JS e HTML), "pubblico" (la destinazione per il contenuto compilato e la posizione che gestisce il server NodeJS) e "fornitore" (il posto per i file di terze parti).
  3. Brunch crea un file config.coffee alla radice della struttura di directory con questo contenuto: files: javascripts: defaultExtension: 'js' joinTo: 'javascripts/app.js': /^app/ 'javascripts/vendor.js': /^vendor/ order: before: [ 'vendor/scripts/console-helper.js', 'vendor/scripts/jquery-1.7.1.min.js' ]
  4. La proprietà di questo oggetto 'joinTo' mi ha confuso, fino a quando ho capito che 'javascript' è in realtà solo una maschera per ' codice lato client 'e che' apps.js 'è in effetti una chiamata per' ottenere tutti i file * .js nella cartella "app", in modo ricorsivo '.
  5. Una volta che è chiaro, tutto ciò che devi fare è lasciare il contenuto in "app". Ho inserito i miei file * .html e images nella sottocartella "assets" e ho inserito tutto il mio contenuto JavaScript in lib.
  6. A questo punto, è possibile eseguire brunch build e brunch watch, e il progetto è attivo e funzionante, compilazione in tempo reale mentre si apportano modifiche, live ricaricamento nel browser.

Mentre il Brunch è meglio fuori dalla scatola rispetto a Grunt con la facilità di usare il passo 6, dove non è riuscito a me è la natura della compilazione in Brunch. Ogni file JavaScript viene incapsulato in un modulo CommonJS e il nome del modulo è basato sul relativo percorso e nome del file ('lib/core/ajax', ecc.). La filosofia di CommonJS non fa per me, e il lavoro di refactoring della mia biblioteca per usare CommonJS è enorme.

Quindi, di nuovo a Grunt. Una volta capito come importare un progetto in Brunch, l'importazione in Grunt era un gioco da ragazzi. Sono su Windows, quindi tutte le chiamate grunt usano grunt.cmd.

  1. chiamata grunt init:jquery (questo può essere ovunque, ho spostato la struttura di directory creata nella mia cartella progetto esistente)
  2. Come Brunch, si ottiene un auto generato struttura di directory e file di configurazione (grunt.js), ma è molto, molto più sottile. La configurazione di Grunt assomiglia a questa: concat: { dist: { src: ['<config:lint.files>'], dest: 'dist/<%= pkg.name %>.js' } }, min: { dist: { src: ['<banner:meta.banner>', '<config:concat.dist.dest>'], dest: 'dist/<%= pkg.name %>.min.js' } }, qunit: { files: ['test/**/*.html'] }, lint: { files: ['grunt.js', 'src/**/*.js', 'test/**/*.js'] }, watch: { files: '<config:lint.files>', tasks: 'lint qunit' }
  3. All'inizio sembrava un po 'estraneo alla mia mente, ma in realtà è piuttosto elegante. La proprietà 'min' definisce il file finale, concatenato, linto e miniato che la mia app web servirà. Il suo valore sorgente è '', che è Grunt magic per esaminare il valore del valore della proprietà dist dest dell'oggetto concat, che viene quindi derivato dal valore della proprietà del file di lint. Quindi, si definiscono le risorse che si desidera vengano linte, concatenate, ridotte e inviate a una destinazione a livello di sfilacciamento.
  4. Una volta che questo pezzo è a posto, devi fare un po 'di lavoro extra per ottenere i pezzi di build, watch e server sul posto. In grunt, quando il server termina l'esecuzione, si chiude. Ciò significa che se si esegue l'attività del server grunt, verrà avviato il server e senza altre attività da eseguire, uscire.
  5. Il mio primo errore è stato quello di raggruppare l'attività del server con l'attività dell'orologio, impostando watch.task = 'server lint qunit'. Questo funziona per la prima modifica apportata all'origine, ma la seconda modifica tenterà di avviare una seconda istanza del server sulla stessa porta e fallire. Invece, è possibile registrare un'attività grunt.registerTask('dev', 'server watch qunit'); e chiamare grunt dev per ottenere un server in esecuzione con generazione continua in tempo reale.
  6. Successivamente, il mio contenuto HTML dipendeva da include lato server per assemblare la pagina.Non riuscivo a capire come farlo funzionare in Nodo, e il lato client include l'uso di <object/> non funziona, in quanto inseriscono il contenuto (nel mio caso vari <script/> e <link/> elementi) in un Iframe, che ovviamente rompe il mio modello del modulo (il mio spazio dei nomi si trova in un oggetto finestra diverso dall'oggetto finestra degli iframe). Fortunatamente, l'oggetto concaturo di grunt è un multitasking e può concatenare qualsiasi cosa. Così ho aggiunto i miei file HTML a concat e la mia app a pagina singola era pronta per essere avviata.
  7. Successivamente, poiché il server del nodo è in esecuzione su una porta diversa dalla mia istanza IIS, si ha il problema di ajax tra domini diversi. Questo SO article mi ha avviato sulla strada giusta, ma alla fine ho dovuto apportare le seguenti modifiche alle intestazioni di contenuto predefinite di IIS: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: X-Requested-With, X-Prototype-Version, Content-Type, Origin, Allow Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS Access-Control-Allow-Origin: http://localhost:88
  8. Infine, poiché sto usando jQuery per il gestore AJAX predefinito, ho dovuto aggiungerlo alle opzioni ajax : xhrFields: { withCredentials: true }
  9. Ovviamente, ci sono implicazioni di sicurezza qui; ma poiché ciò influenzerà solo il mio ambiente di sviluppo e non sarà spinto alla produzione, penso che sia OK.
  10. Ultimo ma non meno importante, ho trascorso un'ora cercando di eseguire il debug di un errore sulla minificazione tramite Uglify, which was conveniently answered by this SO post. Dal momento che Visual Studio insiste sull'inserimento di BOM su tutto il ritmo ("UTF-8 con firma" è l'eufemismo), ma UTF-8 Cast risolve questo in ordine rapido.

Una volta capito tutto, Grunt sembra funzionare piuttosto bene. Non ho ancora avuto la possibilità di iniziare a testare l'effettivo processo di sviluppo in questo nuovo ambiente di generazione continua; ma questo è quello che serviva per arrivare alla possibilità di iniziare.

2

config.coffee non è realmente json piuttosto che js/coffeescript reali, ma la modifica degli ordini dovrebbe funzionare. Puoi aprire un problema nel bugtracker del brunch con l'ordine di configurazione preciso?

Non credo che ci sia un modo veloce per riscrivere l'app per utilizzare i moduli anziché le variabili globali window. A proposito, i globals sono considerati un cattivo gusto. Ma la tua soluzione potrebbe funzionare, sì.

+0

Quello che non ho capito del brunch è che (almeno sembra) richiede il modello del modulo CommonJS. Sto usando un semplice (ma a mio avviso, un pattern Namespace abbastanza elegante) [Vedi http://stackoverflow.com/questions/9072834/auto-generate-visual-studio-vsdoc-for-javascript-library e http://jsfiddle.net/2gxYJ/1/], che in effetti rende la conversione in altri sistemi di moduli (RequireJS, CommonJS, AMD, ecc.) non banale una volta che la libreria è diventata grande. Così, sono passato a Grunt che non impone il vincolo progettuale. – Christopher

+0

Poiché il brunch 1.4 è agnostico ai sistemi di moduli, è possibile anche disabilitare i moduli. –

+0

Questo è eccezionale. L'unica caratteristica mancante è il supporto JSHint. Linting come opzione di costruzione/orologio sarebbe fantastico. La configurazione di Grunt fornisce anche un oggetto jshint/uglifyjs per configurare esplicitamente il loro comportamento. Ad ogni modo, il mio problema principale con il brunch è stato il requisito del modulo, quindi sicuramente darò un'altra possibilità. – Christopher

Problemi correlati