Questa è la storia di un mio progetto. Uno grosso. Una miscela tra PHP e Node.js. È un'applicazione a singola pagina da un punto di vista e un sito web ottimizzato SEO da un altro. Sono state scritte tonnellate di JavaScript, CSS e HTML. In una parola, un incubo per gli spaghetti per qualsiasi sviluppatore. C'erano cadute e aumenti. Produrre e risolvere bug. Combattere con le ultime tecnologie e finire con una libreria meravigliosamente semplice, che è l'argomento di questo articolo.
Come normalmente accade, il progetto è stato considerato non così grande. Il brief è arrivato, abbiamo discusso di come lo sviluppo sarebbe stato gestito, quali tecnologie sarebbero state utilizzate e come le useremo. Abbiamo fatto un piano e siamo arrivati al lavoro. All'inizio avevamo alcune pagine, controllate da un CMS. All'inizio non c'era molto codice JavaScript perché il nostro sistema distribuiva la maggior parte del contenuto.
Ecco una struttura approssimativa del progetto:
Inseriamo il nostro codice lato client in diverse directory. Il codice lato server era solo PHP al momento, quindi è andato al php
directory. Abbiamo avvolto tutto in circa 30 file e tutto era OK.
Durante il periodo di alcuni mesi, stavamo provando diversi concetti e cambiato il codice del progetto più volte. Dal punto di vista attuale, potrei individuare quattro grandi problemi che abbiamo incontrato.
Sembra che il cliente sia stato soddisfatto del risultato e ha deciso di investire di più nella sua apparizione su Internet. Ci è stato chiesto di creare alcune nuove funzionalità. Alcuni di loro erano solo nuovi posti di contenuto, altri erano aggiunte a pagine già esistenti. Abbiamo iniziato ad aggiungere sempre più file in tutte le cartelle sopra. Ha iniziato a diventare un po 'disordinato, quindi abbiamo deciso di creare sottodirectory per le diverse pagine e salvare il codice necessario lì.
Ad esempio, gli stili CSS per di la pagina era dentro css / su / styles.css
. Il JavaScript in JS / su / scripts.js
e così via. Abbiamo usato uno script PHP che concatena i file. C'erano, ovviamente, parti del sito che erano su diverse pagine e le abbiamo inserite Comune
le directory. Questo andava bene per un po ', ma non funzionava a lungo perché quando le directory si riempivano, era lento modificare qualcosa. Dovevi cercare tre diverse directory per trovare quello che ti serviva. Il sito era ancora scritto principalmente in PHP.
A quel tempo, le applicazioni mobili divennero popolari. Il cliente voleva che il suo sito fosse disponibile per i dispositivi mobili e questa è la grande svolta del progetto. Abbiamo dovuto convertire il sito in un'applicazione a singola pagina. E non solo, doveva avere tonnellate di funzionalità in tempo reale. Naturalmente, non tutto il contenuto del sito doveva essere caricato dinamicamente. Il SEO era ancora una parte importante della visione del cliente. Abbiamo scelto lo stack MEAN per le prossime parti. Il problema era con le vecchie pagine. Il loro contenuto doveva essere servito da PHP, ma la logica delle pagine è cambiata ed è stata completamente realizzata con JavaScript. Per diverse settimane ci siamo sentiti come i passeggeri di Titanic. Avevamo fretta di pubblicare qualcosa, ma c'era un buco dopo l'altro e molto presto, la nostra nave era piena d'acqua (insetti).
Abbiamo usato GruntJS per un po ', ma siamo passati a Gulp. Ha aiutato molto perché abbiamo aumentato la nostra velocità di sviluppo. Tuttavia, era ancora troppo fastidioso aggiungere o modificare componenti esistenti. La solida architettura che avevamo all'inizio è stata trasformata in una complessa miscela di file. Sì, c'erano convenzioni rigide per nominare e posizionare questi file, ma era ancora troppo disordinato. Abbiamo poi sbattuto le nostre teste e abbiamo trovato il seguente formato:
Abbiamo diviso il sito in componenti diversi, che erano come scatole nere. Vivono nella loro stessa cartella. Tutto ciò che riguarda il componente è stato salvato all'interno della sua directory. Abbiamo progettato attentamente, le API delle classi. Erano testabili e comunicativi. Abbiamo scoperto che una struttura come questa funzionava meglio per noi perché avevamo tonnellate di moduli indipendenti. Sì, stiamo mescolando i file JavaScript con stili CSS e modelli HTML, ma è stato semplicemente più semplice lavorare su una base di unità, invece di scavare in profondità in diverse directory.
Quelle pagine che erano vecchie e che dovevamo distribuire tramite PHP, erano anche piene di logica JavaScript. Tuttavia, in alcuni casi, Angular non ha funzionato molto bene. Abbiamo dovuto creare piccoli hack per rendere le cose senza intoppi. Abbiamo finito con una miscela tra i controller angolari e il codice personalizzato. La buona notizia è stata che il budget del progetto è stato ampliato e abbiamo deciso di utilizzare il nostro framework. A quel tempo, stavo sviluppando il mio preprocessore CSS. Il progetto diventa davvero, molto veloce. Molto presto ho portato la mia libreria per l'utilizzo lato client. Linea per riga, è stato trasformato in un piccolo framework, che abbiamo iniziato ad integrare nel progetto.
Questo è probabilmente quello che stai chiedendo. Bene, ce ne sono una decina che offrono un'ampia gamma di funzionalità. Sì, è vero, ma ... non avevamo bisogno di una vasta gamma di funzionalità. Avevamo bisogno di cose specifiche e nient'altro. Eravamo pronti ad accettare il fatto che usando un framework popolare, potremmo aggiungere alcuni kilobyte al carico generale della pagina. Non era un grosso problema.
Lo stato della nostra base di codice era il problema. Ci siamo concentrati sulla costruzione di una buona architettura e siamo tutti d'accordo sul fatto che a volte la soluzione personalizzata si adatta meglio. L'uso di Angular, Ember, Knockout o Backbone ha i suoi benefici, ma la verità è che non esiste una struttura universale.
Mi piacciono le parole di Jeremy Keith, nel suo discorso Il potere della semplicità, ha detto che la cosa più importante nella scelta del tuo strumento è la filosofia della persona che ha realizzato lo strumento e se quella filosofia si allinea con la tua. Se le idee del quadro non sono allineate con le tue, molto presto, andrai contro di loro. La stessa cosa è successa a noi. Abbiamo provato ad usare Angular e c'erano troppe difficoltà. Problemi che siamo stati in grado di risolvere, ma abbiamo usato hack e soluzioni alternative complesse.
Abbiamo anche provato Ember, ma non ha funzionato, perché è fortemente basato sui suoi meccanismi di routing. Backbone era una buona scelta ed era la cosa più vicina alla nostra visione. Tuttavia, quando ho introdotto AbsurdJS, abbiamo deciso di usarlo.
AbsurdJS è stato inizialmente avviato come preprocessore CSS, esteso a un preprocessore HTML ed è stato portato con successo per l'utilizzo lato client. Quindi, all'inizio lo usiamo per compilare JavaScript in HTML o CSS. Sì, mi hai sentito bene; abbiamo iniziato a scrivere i nostri stili e markup in JavaScript (probabilmente sembra strano, ma continua a leggere). Ho spinto in avanti la biblioteca e sono state aggiunte una dozzina di funzionalità.
Quando hai un sistema complesso, con molte pagine, non vuoi veramente risolvere grossi problemi. È molto meglio suddividere tutto in compiti più piccoli e risolverli uno per uno. Abbiamo fatto la stessa cosa Abbiamo deciso che la nostra applicazione sarà costruita con componenti più piccoli, in questo modo:
var assurdo = Assurdo (); var MyComp = absurd.component ('MyComp', costruttore: function () // ...); var instance = MyComp ();
absurd.component
definisce una classe. Chiamando il Mycomp ()
metodo crea una nuova istanza.
Avendo tutti questi piccoli componenti, avevamo bisogno di un canale per la comunicazione. Il modello di osservatore era perfetto per questo caso. Quindi, ogni componente è un dispatcher di eventi.
var MyComp = absurd.component ('MyComp', doSomething: function () this.dispatch ('something-happen');); var instance = MyComp (); instance.on ('something-happen', function () console.log ('Hello!');); instance.doSomething ();
Siamo anche in grado di trasmettere dati insieme al messaggio. La definizione dei componenti e la loro natura di "ascolto-dispacciamento" sono piuttosto banali. Ho adottato questo concetto dagli altri framework popolari, perché sembra naturale. È stato anche molto più facile per i miei colleghi iniziare a usare AbsurdJS.
Insieme al markup PHP servito, abbiamo creato din elementi DOM. Ciò significa che abbiamo bisogno di accedere agli elementi DOM esistenti o nuovi, che verranno successivamente aggiunti alla pagina. Ad esempio, supponiamo di avere il seguente codice HTML:
Titolo della pagina
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Ecco un componente che recupera l'intestazione:
absurd.component ('MyComp', html: '.content h1', costruttore: function () this.populate (); console.log (this.el.innerHTML); // titolo della pagina) ();
Il popolare
il metodo è l'unico Magia metodo nell'intera libreria. Fa molte cose come compilare CSS o HTML, lega eventi e cose del genere. Nell'esempio sopra, vede che c'è un html
proprietà e inizializza il EL
variabile che punta all'elemento DOM. Questo funziona abbastanza bene per noi perché una volta ottenuto questo riferimento, siamo stati in grado di lavorare con gli elementi e i suoi figli. Per quei componenti che necessitavano di elementi creati dinamicamente, il html
la proprietà accetta un oggetto.
absurd.component ('MyComp', html: 'div.content': h1: 'Titolo pagina', p: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', costruttore: function () this .populate (); document.querySelector ('body'). appendChild (this.el);) ();
Il JSON sopra è tradotto nello stesso codice HTML. Ho scelto JSON perché da un punto di vista JavaScript è molto più flessibile. Siamo in grado di unire oggetti, sostituire o eliminare solo parti di esso. Nella maggior parte dei framework popolari, i template sono semplici testi che li rendono difficili da manipolare. AbsurdJS ha anche il suo motore di template.
absurd.component ('MyComp', html: 'div.content': h1: '<% this.title %>', ul: ['<% for(var i=0; i', li: '<% this.availableFor[i] %>','<% %>'], titolo:' That's 'awesome', availableFor: ['tutti i browser', 'Node.js'], costruttore: function () this.populate (); document.querySelector ( 'body') appendChild (this.el).; ) ();
Il risultato è:
È fantastico
- tutti i browser
- Node.js
Il Questo
parola chiave nelle espressioni di cui sopra, punta al componente stesso. Il codice tra <%
e %>
è un JavaScript valido. Quindi, caratteristiche come le proprietà calcolate possono essere facilmente sviluppate direttamente nella definizione del modello. Ovviamente, siamo in grado di utilizzare lo stesso motore di template con markup già esistente. Per esempio:
<% this.title %>
<% for(var i=0; i<this.availableFor.length; i++) %>
- <% this.availableFor[i] %>
<% %>
... potrebbe essere controllato con il seguente componente (il risultato è lo stesso):
absurd.component ('MyComp', html: '.content', titolo: 'That's' awesome ', availableFor: [' tutti i browser ',' Node.js '], costruttore: function () this.populate ();) ();
Ad ogni modo, il punto è che siamo stati in grado di definire modelli o crearli da zero. Siamo anche in grado di controllare i dati che vengono iniettati in modo facile e naturale. Tutto è solo proprietà del buon vecchio oggetto JavaScript.
Abbiamo diviso con successo l'intero sistema in piccoli moduli. Le parti che erano prima dei controller angolari, sono diventate componenti AbsurdJS. Ci siamo resi conto che il loro HTML era strettamente collegato alla loro definizione, che ha completamente cambiato la gestione del markup nell'applicazione. Abbiamo smesso di pensare alla concatenazione, alle convenzioni o qualcosa del genere. Non abbiamo dovuto creare file HTML. Quando guardo indietro, ho potuto vedere questo esatto momento nella nostra storia di commit. È facilmente visibile perché molti file sono stati rimossi dal code-base.
Poi ho pensato, cosa succederà se facciamo la stessa cosa con il CSS. Era ovviamente possibile perché AbsurdJS era un preprocessore CSS e poteva produrre CSS. Abbiamo appena ottenuto la stringa compilata, creata una nuova stile
tag nella capo
della pagina corrente e iniettarlo lì.
absurd.component ('MyComp', css: '.content': h1: color: '# 99FF00', riempimento: 0, margine: 0, p: fontSize: '20px', html : '.content', constructor: function () this.populate ();) ();
Ecco il stile
tag che viene prodotto:
E giorno per giorno abbiamo trasferito gli stili CSS dai file SASS (perché, ad un certo punto, abbiamo scelto SASS come preprocessore CSS) ai componenti AbsurdJS. Per essere onesti, è stato abbastanza facile perché tutte le combinazioni e le variabili che abbiamo sono state definite come funzioni e variabili JavaScript. La condivisione degli stili era ancora più semplice perché tutto era JavasSript.
... quando tutto funziona perfettamente ma senti che qualcosa non va
Stavamo guardando il codice. Ha funzionato. AbsurdJS ha guidato anche le vecchie parti. Le nuove cose usano la stessa libreria. L'HTML e il CSS erano ben separati e collocati direttamente nella definizione dei componenti. Tuttavia, ho sentito che c'era qualcosa di sbagliato. Mi sono fermato per un po 'e mi sono chiesto: "Di cosa è fatta la rete?".
E quello che abbiamo fatto è un po 'diverso. Assomiglia più alla foto qui sotto.
Costruisco siti web da più di dieci anni e ricordo i tempi in cui tutti abbiamo combattuto per la grande separazione di questi tre materiali da costruzione. E quello che ho fatto in questo progetto è esattamente l'opposto. Non c'erano affatto file CSS e HTML (quasi). Tutto era JavaScript.
Molte persone diranno che questo è ridicolo e dovremmo restituire i soldi del cliente. Sì, questo potrebbe essere vero, ma questo concetto ha funzionato perfettamente nel nostro caso. Non abbiamo scritto un'applicazione. In effetti, abbiamo scritto un sacco di componenti indipendenti. Credo che il Web sarà una combinazione di componenti pronti all'uso.
Noi, in quanto sviluppatori, dovremo sviluppare tali componenti e probabilmente collegarci e utilizzare tali componenti scritti da altri. Progetti come AbsurdJS o Polymer stanno dimostrando che questo è possibile e ti incoraggio a sperimentare in questa direzione.
Quindi alla fine l'attività del cliente è andata bene. È stato così bello che ha deciso di lanciare un nuovo servizio. E indovina cosa. Voleva che alcune parti dell'applicazione esistente fossero trasferite nel nuovo progetto. Non posso dirti quanto siamo felici di spostare i componenti da un posto all'altro. Non è stato necessario impostare qualcosa, copiare markup HTML o file CSS. Abbiamo appena ottenuto il file JavaScript del componente, l'abbiamo posizionato da qualche parte e ne abbiamo creato un'istanza. Ha funzionato solo perché non c'erano dipendenze. Non sarei sorpreso se alcuni di questi componenti fossero messi in vendita molto presto. Sono piuttosto leggeri e offrono funzionalità piacevoli collegate al prodotto del cliente.
Sì, abbiamo infranto alcune regole. Regole che personalmente sono d'accordo. Regole che ho seguito per molti anni. Tuttavia, la realtà è che tutti noi desideriamo la qualità e talvolta questa qualità è raggiungibile violando le regole. Vogliamo produrre un codice buono e ben strutturato che sia facilmente mantenibile, flessibile ed estensibile. Non vogliamo guardare indietro e dire: "Oh mio Dio ... è stato scritto da me !?". Quando guardo indietro ora, so perché il codice ha lo stesso aspetto. Sembra che sia stato scritto appositamente per quel progetto.
Se hai trovato interessante questo tutorial, controlla la pagina ufficiale di AbsurdJS. Ci sono guide, documentazione e articoli. Puoi anche provare la biblioteca online. Come ogni altro strumento, AbsurdJS è progettato per un utilizzo specifico. Si adatta bene al nostro progetto e potrebbe adattarsi al tuo. Non lo chiamo nemmeno un framework, perché non mi piace questa definizione. È più simile a una cassetta degli attrezzi piuttosto che a un framework completo. Sentiti libero di sperimentarlo, fare richieste di pull o inviare problemi. È completamente open source e disponibile su GitHub.