Fremveksten av Rumpe-mindre Nettside

0
119

Det virker som alle de kule barna har delt seg i to cliques: Hodeløse CMS publikum på den ene siden og Statisk side Generator publikum på den andre. Mens jeg innrømme at de er ganske kult team navn, jeg fant meg selv i stand til å velge en side. For å omskrive Groucho Marx, “jeg bryr meg ikke til å tilhøre en klubb som vil ha meg som medlem.”

For min egen enkle blogg (noe som er pinlig tom i øyeblikket), en statisk side generator kunne være en god passform. Systemer som Hugo og Jekyll har begge vært sterkt anbefalt av utviklere jeg er glad i og stoler på, og ser flott ut ved første øyekast, men jeg traff snublesteinene når jeg ønsket å endre mitt tema eller sette opp mer komplekse JavaScript og samhandling på tvers av sider. Det finnes måter å løse begge disse problemene, men det er ikke den type helg jeg ønsker å ha.

I tillegg til det, jeg elsker å eksperimentere, å gjøre nye ting, og jeg har fått en stor crush på Vue i øyeblikket. Å ha en Hodeløs CMS oppsett med en front-end som er frakoblet fra back-end kan være en god kombinasjon for meg, men etter 7+ år med PHP anhuking med WordPress, hele oppsett føles som overkill for min grunnleggende behov.

Det jeg egentlig vil ha er en statisk side generator som lar meg skrive en blogg som en del av en større single-side app slik at jeg har rom for å prøve nye ting, og fortsatt ha full kontroll over styling, uten behov for en database eller noen form for back-end. Dette er en lang vei å fortelle deg at jeg har funnet min egen klubb til å bli med, med en utpreget fn-kult navn.

Gjør deg klar for det…

Butt-mindre Nettside

Fordi det er ingen back-end, få det? 😶

Det tar et par skritt å gå rumpe-mindre:

  1. Oppsett en enkelt side app med Vue
  2. Generere hver rute på bygge gang
  3. Opprette blogg og artikkel komponenter
  4. Integrere Webpack å analysere Markdown innhold
  5. Utvide funksjonaliteten med plugins
  6. Profitt!

Det siste punktet har å være en del av ethvert forslag, ikke sant?

Jeg vet det ser ut som mye av trinnene, men dette er ikke fullt så tøff som den ser ut. La oss bryte ned trinnene sammen.

Oppsett en enkelt side app med Vue

La oss få Vue opp og kjører. Vi kommer til å trenge Webpack til å gjøre det.

Jeg får det, Webpack er ganske skremmende, selv når du ikke vet hva som skjer. Det er nok best å la noen andre gjøre det virkelig hardt arbeid, så vi bruker Vue Progressive Web App Standardtekst som vårt fundament og gjøre noen tilpasninger.

Vi kunne bruke standard oppsett fra repo, men selv mens jeg skrev denne artikkelen, det var endringer som blir gjort der. I interesse av ikke å ha alt dette til pause på oss, vi vil bruke en repo jeg laget for en demonstrasjon. Repo har en avdeling for hvert steg vi vil dekke i dette innlegget for å hjelpe følge med.

Se på GitHub

Kloning repo og sjekk ut trinn-1 gren:

$ git clone https://github.com/evanfuture/vue-yes-blog.git trinn 1
$ cd-vue-ja-blogg
$ npm installere
$ npm kjøre dev

En av mine favoritt deler av den moderne utvikling er at det tar bare tretti sekunder for å få en progressiv web app oppe og kjører!

Neste, la oss komplisere ting.

Generere hver rute på bygge gang

Ut av boksen, enkelt side apper bare har en enkelt inngangspunkt. Med andre ord, det lever våre liv på en enkel URL. Dette er fornuftig i noen tilfeller, men vi ønsker at våre app til å føle seg som en vanlig nettside.

Vi trenger å gjøre bruk av historie-modus i Vue Ruter fil for å gjøre det. For det første, vi vil slå den på ved å legge til modus: “historikk” for å Ruteren objektets egenskaper som så:

// src/router/index.js
Vue.bruk(Ruter);

eksport standard ny Ruter({
modus: ‘historie’,
ruter: [
// …

Våre starter programmet har to ruter. I tillegg til Hei, vi har en annen visning komponent kalt Banan som bor på rute /banan. Uten historie modus, URL for at siden vil være http://localhost:1982/#/banana. Historie-modus som renser opp til http://localhost:1982/banana. Mye mer elegant!

Alt dette fungerer ganske bra i utvikling-modus (npm kjøre dev), men la oss ta en titt på hvordan det vil se ut i produksjon. Her er hvordan vi sammen alt:

$ npm kjøre bygge

At kommandoen vil generere Vue nettstedet til det ./dist-mappen. Å se det live, det er en nyttig kommando for å starte opp en super enkel HTTP-server på din Mac:

$ cd dist
$ python -m SimpleHTTPServer

Beklager Windows folkens, jeg vet ikke tilsvarende!

Nå kan du gå til localhost:8000 i nettleseren din. Vil du se din side som det vil vises i et produksjonsmiljø. Klikk på Banan link, og alt er vel.

Oppdater siden. Oops! Dette avslører vår første problemet med én side apps: det er bare en HTML-fil blir generert ved bygge tid, så det er ingen måte for leseren å vite at /banan bør målrette de viktigste app-side og legg rute uten fancy Apache-stil omdirigeringer!

Selvfølgelig, det er en app for det. Eller i det minste en plugin. Grunnleggende bruk er nevnt i Vue Progressive Web App Standardtekst dokumentasjon. Her er hvordan det sier vi kan spinne opp plugin:

$ npm installere -D prerender-spa-plugin

La oss legge til våre ruter til Webpack produksjon konfigurasjonsfil:

// ./build/webpack.prod.conf.js
// …
const SWPrecacheWebpackPlugin = kreve (sw-precache-webpack-plugin’)
const PrerenderSpaPlugin = kreve(‘prerender-spa-plugin’)
const loadMinified = kreve(‘./load-minified’)
// …
const webpackConfig = flette(baseWebpackConfig, {
// …
plugins: [
// …
nye SWPrecacheWebpackPlugin({
// …
minify: true,
stripPrefix: ‘dist/’
}),
// prerender app
nye PrerenderSpaPlugin(
// Bane til samlet app
banen.bli med(__dirname, ‘../dist’),
// Liste over endepunkter du ønsker å prerender
[ ‘/’, ‘/banana”]
)
]
})

Det er det. Nå, når du kjører et nytt bygg, hver rute i matrisen vil bli regnet som et nytt inngangspunkt til app. Gratulerer, vi har i utgangspunktet bare aktivert statisk side generasjon!

Opprette blogg og artikkel komponenter

Hvis du hopper fremover, vi er nå opp til trinn 2 gren av min demo-repo. Gå videre og sjekk det ut:

$ git checkout-trinn-2

Dette trinnet er ganske grei. Vi vil opprette to nye komponenter, og koble dem sammen.

Blogg Komponent

La oss registrere bloggen komponent. Vi vil opprette en ny fil som heter YesBlog.vue i /src/komponenter katalog og slippe i markeringen for å vise:

// ./src/komponenter/YesBlog.vue
<mal>
<div class=”blogg”>
<h1>Blogg</h1>
<ruter-link=”/”>Hjem</ruter-link”>
<hr/>
<artikkelen v-=”artikkel i “artikler” :key=”artikkelen.slug” class=”article”>
<ruter-link class=”artikkelen__link” :=”`/blogg/${ artikkelen.slug }`”>
<h2 class=”artikkelen__title”>{{ artikkel.tittel }}</h2>
<p class=”artikkelen__description”>{{artikkel.beskrivelse}}</p>
</ruter-link”>
</article>
</div>
</template>

<script>
eksport standard {
name: ‘blogg’,
beregnet: {
artikler() {
tilbake [
{
slug: ‘første-artikkelen’,
tittel: “Artikkel”,
beskrivelse: Denne artikkelen er en ‘s beskrivelse’,
},
{
slug: ‘andre-artikkelen’,
tittel: “Artikkel To’,
beskrivelse: Denne artikkelen er to’s beskrivelse’,
},
];
},
},
};
</script>

Alt vi egentlig gjør her er å skape en plassholder array (artikler) som vil bli fylt med artikkel objekter. Denne tabellen skaper vår artikkel liste og bruker slug parameter som post-ID. Tittel og beskrivelse parametre fylle ut innlegget detaljer. For nå, det er alle hardkodet mens vi få resten av våre kode i stedet.

Artikkel Component

Artikkelen komponent er en tilsvarende prosess. Vi vil opprette en ny fil som heter YesArticle.vue og etablere merkingen for vis:

// ./src/komponenter/YesArticle.vue
<mal>
<div class=”article”>
<h1 class=”blogg__title”>{{artikkel.tittel}}</h1>
<ruter-link=”/blogg”>Tilbake</ruter-link”>
<hr/>
<div class=”artikkelen__kroppen” v-html=”artikkelen.body”></div>
</div>
</template>

<script>
eksport standard {
name: ‘YesArticle’,
rekvisittar: {
id: {
type: String,
nødvendig: true,
},
},
data() {
tilbake {
artikkel: {
tittel: dette.id,
kropp: ‘<h2> – Testing</h2><p>Ok, la’s gjøre mer nå!</p>’,
},
};
},
};
</script>

Vi bruker rekvisitter gått sammen med ruteren for å vite hva artikkel-ID som vi jobber med. For nå, vil vi bare bruke det som tittelen på innlegget, og hardcode kroppen.

Ruting

Vi kan ikke gå videre før vi legger vår nye utsikt til ruteren. Dette vil sikre at våre Nettadresser er gyldige og lar våre navigasjon for å fungere skikkelig. Her er helheten av ruteren filen:

// ./src/router/index.js
import Ruter fra ‘vue-ruter’;
import Hello from ‘@/komponenter/Hei”;
import Banan fra ‘@/komponenter/Banana”;
import YesBlog fra ‘@/komponenter/YesBlog’;
import YesArticle fra ‘@/komponenter/YesArticle’;

Vue.bruk(Ruter);

eksport standard ny Ruter({
modus: ‘historie’,
ruter: [
{
bane: ‘/’,
name: ‘Hei’,
komponent: Hei,
},
{
bane: ‘/banana”,
name: ‘Banan’,
komponent: Banan,
},
{
bane: ‘/blog’,
name: ‘YesBlog’,
komponent: YesBlog,
},
{
bane: ‘/blogg/:id’,
name: ‘YesArticle’,
rekvisitter: true,
komponent: YesArticle,
},
],
});

Legg merke til at vi har lagt /:id-en til YesArtcle komponent banen og sette sine rekvisitter til true. Dette er avgjørende fordi de etablere dynamiske ruting vi satt opp i komponenten rekvisitter utvalg i komponent-fil.

Endelig kan vi legge til en link til vår hjemmeside, som henviser til bloggen. Dette er hva vi slippe inn i den Hallo.vue fil for å få det å gå:

<ruter-link=”/blogg”>Blogg</ruter-link”>
Pre-gjengivelse

Vi har gjort mye av arbeidet så langt, men ingen av den vil holde seg til vi pre-yte våre ruter. Pre-rendering er en fancy måte å si at vi fortelle app hva ruter eksistere og til å dumpe rett markup inn i den høyre ruten. Vi har lagt til en Webpack plugin for dette tidligere, så her er hva vi kan legge til vår Webpack produksjon konfigurasjonsfil:

// ./build/webpack.prod.conf.js
// …
// Liste over endepunkter du ønsker å prerender
[ ‘/’, ‘/banan’, ‘/blog’, ‘/blogg/første-artikkel’, ‘/blogg/andre-artikkelen’ ]
// …

Jeg må innrømme at denne prosessen kan være tungvint og irriterende. Jeg mener, hvem vil berøre flere filer for å lage en URL?! Heldigvis, vi kan automatisere dette, som vi vil dekke ytterligere ned.

Integrere Webpack å analysere Markdown innhold

Vi er nå opp til trinn 3 gren. Sjekk det ut hvis du er følgende sammen i koden:

$ git checkout-trinn-3
Innlegg

Vi vil bruke Markdown å skrive våre innlegg, med noen FrontMatter til å lage meta-data-funksjonalitet.

Brann opp en ny fil i innlegg katalog for å lage vår aller første innlegg:

// ./src/innlegg/første-artikkelen.md

tittel: En Artikkel fra MD
beskrivelse: der helten starter fresh
opprettet: 2017-10-01T08:01:50+02
oppdatert:
status: publish

Her er teksten i artikkelen. Det er ganske stor, er det ikke?

// ./src/innlegg/andre-artikkelen.md

tittel: Artikkel To fra MD
beskrivelse: Dette er en artikkel
opprettet: 2017-10-01T08:01:50+02
oppdatert:
status: publish

## La oss starte med en H2
Og så litt tekst
Og så noen kode:
“html
<div class=”beholder”>
<div class=”main”>
<div class=”article sett inn-wp-koder-her”>
<h1>Tittel</h1>
<div class=”article-content”>
<p class=”intro”>Intro Tekst</p>
<p></p>
</div>
<div class=”article-meta”></div>
</div>
</div>
</div>

Dynamisk Ruting

En irriterende ting i øyeblikket er at vi trenger å hardcode våre ruter for den pre-rendering-plugin. Heldigvis, det er ikke komplisert å gjøre dette dynamisk med en bit av Node magi. For det første, vi vil lage en hjelper i vår utility-filen for å finne filer:

// ./build/utils.js
// …
const ExtractTextPlugin = kreve(‘ekstrakt-tekst-webpack-plugin’)
const fs = kreve(‘fs’)

eksport.filesToRoutes = function (katalog, extension, routePrefix = “) {
funksjonen findFilesInDir(startPath, filter){
la resultatene = []
if (!fs.existsSync(startPath)) {
– konsollen.logg(“ingen dir “, startPath)
tilbake
}
const filer = fs.readdirSync(startPath)
for (la i = 0; i < filer.lengde; i++) {
const filename = vei.bli med(startPath, filer[i])
const stat = fs.lstatSync(filnavn)
hvis (stat.isDirectory()) {
resultatene = resultater.concat(findFilesInDir(filnavn, filter)) //recurse
} else if (filnavn.indexOf(filter) >= 0) {
resultater.trykk(filnavn)
}
}
returnere resultater
}

tilbake findFilesInDir(bane.bli med(__dirname, katalog), forlengelse)
.kart((filnavn) => {
tilbake filnavn
.erstatt(bane.bli med(__dirname, katalog), routePrefix)
.erstatt(extension, “)
})
}

eksport.assetsPath = function (_path) {
// …

Dette kan egentlig bare kopieres og limes inn, men hva vi har gjort her, er å opprette et verktøy metode som kalles filesToRoutes() som tar en katalog, forlengelse, og en valgfri routePrefix, og returnere en rekke ruter basert på en rekursiv fil søk i denne katalogen.

Alt vi trenger å gjøre for å gjøre våre blogginnlegg ruter dynamisk flette denne nye tabellen i vår PrerenderSpaPlugin ruter. Kraften av ES6 gjør dette veldig enkelt:

// ./build/webpack.prod.conf.js
// …
nye PrerenderSpaPlugin(
// Bane til samlet app
banen.bli med(__dirname, ‘../dist’),
// Liste over endepunkter du ønsker å prerender
[
‘/’,
‘/banana”,
‘/blog’,
…utils.filesToRoutes(‘../src/innlegg’, ‘.md’, ‘/blog’)
]
)

Siden vi allerede har importert utils på toppen av filen til andre formål, for vi kan bare bruke spredning operatør … å flette sammen den nye dynamiske ruter matrisen inn i dette, og vi er ferdig. Nå er vår pre-gjengivelsen er helt dynamiske, bare avhengig oss å legge til en ny fil!

Webpack Lastere

Vi er nå opp til trinn 4 gren:

$ git checkout-trinn-4

For å faktisk slå våre Markdown-filer til parse-stand innhold, vi trenger noen Webpack lastere på plass. Igjen, noen andre har gjort alt arbeidet for oss, så vi trenger bare å installere og legge dem til vår config.

$ npm installere -D json-loader markdown-det-foran-uansett-loader markdown-det highlight.js yaml-front-saken

Vi vil bare kalle json-loader og markdown-det-foran-uansett-loader fra våre Webpack config, men sistnevnte har peer avhengigheter av markdown-og det highlight.js, så vil vi installere dem på samme tid. Også, ingenting advarer oss om dette, men yaml-front-saken er også nødvendig, så kommandoen ovenfor legger til at så vel.

Å bruke disse fancy nye lastere, vi kommer til å legge til en blokk til vår Webpack base-config:

// ./build/webpack.base.conf.js
// …
modul.eksport = {
// …
modul: {
regler: [
// …
{
test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
loader: ‘url-loader’,
valg: {
grense: 10000,
navn: utils.assetsPath(‘skrifter/[navn].[hash:7].[ekstern]’)
}
},
{
test: /.md$/,
lastere: [‘json-loader’, ‘markdown-det-foran-uansett-loader’],
},
]
}
}

Nå, noen gang Webpack møter krever en uttalelse med en .md filtype, vil den bruke den foran-uansett-loader (som vil riktig analysere metadata kvartal fra våre artikler så vel som kode blokker), og ta utgang JSON og kjøre det gjennom json-loader. På denne måten, vi vet at vi ender opp med et objekt for hver artikkel som ser ut som dette:

// første-artikkelen.md [Object]
{
kropp: “<p>Her er teksten i artikkelen. Det er ganske stor, er det ikke?</p>n”
opprettet: “2017-10-01T06:01:50.000 Z”
beskrivelse: “der helten starter fresh”
raw: “nnHere er teksten i artikkelen. Det er ganske stor, er det ikke?n”
slug: “første-artikkelen”
status: på “publiser”
tittel: “Artikkel fra MD”
oppdatert: null
}

Dette er akkurat hva vi trenger, og det er ganske enkelt å utvide med andre metadata hvis du trenger det. Men så langt er dette ikke gjør noe! Vi må kreve at disse i en av våre komponenter slik at Webpack kan finne og laste det.

Vi kan bare skrive:

krever(‘../innlegg/første-artikkelen.md’)

…men da ville vi ha å gjøre med at for hver artikkel vi skaper, og det vil ikke være noe moro som bloggen vår vokser. Vi trenger en måte å dynamisk krever at alle våre Markdown-filer.

Dynamisk Krever

Heldigvis, Webpack gjør dette! Det var ikke lett å finne dokumentasjon for dette, men her er det. Det er en metode som kalles krever.kontekst() som vi kan bruke til å gjøre akkurat hva vi trenger. Vi vil legge den til skriptet delen av vår YesBlog komponent:

// ./src/komponenter/YesBlog.vue
// …
<script>
const innlegg = {};
const req = krever.kontekst(‘../innlegg/’, false, /.md$/);
req.nøkler().forEach((nøkkel) => {
innlegg[nøkkel] = kn(nøkkel);
});

eksport standard {
name: ‘blogg’,
beregnet: {
artikler() {
const articleArray = [];
Objektet.tastene(innlegg).forEach((nøkkel) => {
const artikkel = posts[nøkkel];
artikkel.slug = – tasten.erstatt(‘./’, “).erstatt(‘.md’, “);
articleArray.trykk(artikkel);
});
tilbake articleArray;
},
},
};
</script>
// …

Hva skjer her? Vi skal lage et innlegg objekt som vi vil først fylle med artikler, bruk senere i komponenten. Siden vi er pre-gjengivelse alle våre for innhold, har dette objektet vil være umiddelbart tilgjengelig.

Den krever.kontekst () – metoden aksepterer tre argumenter.

  • katalogen der det vil søk
  • om ikke å inkludere undermapper
  • en regex filter for å gå tilbake filer

I vårt tilfelle er vi bare Markdown-filer i innleggene katalogen, slik:

krever.kontekst(‘../innlegg/’, false, /.md$/);

Dette vil gi oss en slags merkelig ny funksjon/objekt som vi må analysere for å bruke. Det er der req.nøkler() vil gi oss et utvalg av de relative stier til hver fil. Hvis vi kaller kn(nøkkel), dette vil returnere artikkelen objektet vi ønsker, slik at vi kan tilordne at verdien til en som er avbildet i våre innlegg objekt.

Til slutt, i de beregnede artikler () – metoden, vi vil auto-genererer våre slug ved å legge til en slug-tasten til hvert innlegg, med en verdi av fil uten en bane eller utvidelser. Hvis vi ønsket å, dette kan endres til å tillate oss å sette den slug i Markdown seg selv, og bare gå tilbake til auto-generasjon. På samme tid, kan vi presse artikkelen objekter inn i en array, slik at vi har noe lett å iterere over i vår komponent.

Ekstra Kreditt

Det er to ting du vil sannsynligvis ønske å gjøre med en gang hvis du bruker denne metoden. Første er å sortere etter dato, og andre er å filtrere etter artikkel status (dvs. utkast og publisert). Siden vi allerede har en tabell, kan dette gjøres på en linje, lagt like før retur articleArray:

articleArray.filteret(post => innlegg.status === ‘publiser’).sorter((a, b) => en.opprettet av < b.opprettet);
Siste Trinn

En siste ting å gjøre nå, og det er instruere våre YesArticle komponent for å bruke de nye dataene vi mottar sammen med ruteendring:

// ./src/komponenter/YesArticle.vue
// …
data() {
tilbake {
artikkel: krever(`../innlegg/${dette.id}.md`), // eslint-disable-linje global-krever, import/nei-dynamisk-krever
};
},

Ettersom vi vet at våre komponenten vil være pre-rendret, kan vi deaktivere ESLint regler som ikke tillater dynamisk og global krever og krever banen til stillingen som samsvarer med id-parameteren. Dette utløser vår Webpack Markdown lastere, og vi er alle gjort!

OMG!

Gå videre og teste ut dette:

$ npm kjøre bygg && cd dist && python -m SimpleHTTPServer

Besøk localhost:8000, navigere rundt og oppdatere sidene lastes inn hele app fra new entry point. Det fungerer!

Jeg ønsker å understreke hvor kult dette er. Vi har slått en mappe med Markdown-filer inn i en array av objekter som vi kan bruke som vi vil, hvor som helst på nettstedet vårt. The sky is The limit!

Hvis du ønsker å bare se hvordan det hele fungerer, kan du sjekke ut den siste grenen:

$ git checkout-trinn-komplett

Utvide funksjonaliteten med plugins

Min favoritt del om denne teknikken er at alt er extensible og kan skiftes ut.

Gjorde noen til å opprette en bedre Markdown-prosessor? Flott, bytt ut loader! Trenger kontroll over nettstedet ditt, er SEO? Det er en plugin for det. Trenger du å legge til en kommentar-system? Legg til at plugin også.

Jeg liker å holde et øye på disse to depoter for ideer og inspirasjon:

  • Awesome Vue.js
  • Awesome Markdown

Profitt!

Du trodde dette trinnet var en spøk?

Den aller siste tingen vi ønsker å gjøre nå er overskuddet fra enkelhet vi har opprettet og nab noen gratis hosting. Siden nettstedet ditt er nå blir generert på git repository, er alt du egentlig trenger er å gjøre er å presse dine endringer til Github, Bitbucket, Gitlab eller hva kode depotet du bruker. Jeg valgte Gitlab fordi privat depot er gratis og jeg ikke ønsker å ha min kladd offentlige, selv i repo-form.

Etter at det er satt opp, trenger du å finne en vert. Hva du egentlig vil ha er en vert som tilbyr kontinuerlig integrasjon og distribusjon slik at sammenslåing til master gren utløser npm kjøre bygge kommando og regenererer nettstedet ditt.

Jeg brukte Gitlab egen CI verktøy for de første månedene etter at jeg setter opp dette. Fant jeg oppsett for å være lett, men feilsøking av problemer til å bli vanskelig. Jeg har nylig slått til Netlify, som har en enestående gratis plan og noen gode CLI verktøy innebygd.

I begge tilfeller, er du i stand til å peke ditt eget domene på sine servere, og til og med oppsett av et SSL-sertifikat for HTTPS-støtte,—det siste punktet er viktig hvis du noen gang ønsker å eksperimentere med ting som getUserMedia API, eller lage en butikk for å gjøre salg.

Med alt dette satt opp, nå er du medlem av Butt-mindre Nettstedet club. Gratulerer og velkommen venner! Forhåpentligvis vil du finne at dette skal være et enkelt alternativ til kompliserte content management systemer for ditt eget personlige nettsted, og at det gir deg mulighet til å eksperimentere med letthet. Vennligst gi meg beskjed i kommentarfeltet hvis du står fast underveis…eller hvis du lykkes som overgår dine villeste drømmer. 😉