Ökningen av Rumpan-mindre Hemsida

0
91

Det verkar som alla coola kids har delat sig i två grupperingar: de Huvudlösa CMS publiken på ena sidan och Statisk Webbplats Generator publiken på den andra. Medan jag erkänna att de är ganska coola team namn, jag fann mig oförmögen att välja en sida. För att parafrasera Groucho Marx, “jag bryr mig inte tillhöra någon klubb som kommer att ha mig som medlem.”

För min egen blogg (som är pinsamt tomt just nu), en statisk webbplats generator kan vara en bra passform. System som Hugo och Jekyll har både varit starkt rekommenderas av utvecklare som jag älskar och litar på och ser bra ut vid första anblicken, men jag slog stötestenar när jag ville ändra mitt tema eller skapa mer komplexa JavaScript och interaktioner på olika sidor. Det finns sätt att lösa båda dessa problem, men det är inte den typ av helgen som jag vill ha.

Förutom att jag älskar att experimentera, göra nya saker, och jag har fått en stor crush på Vue på nu. Med en Huvudlös CMS-installation med en front-end som är frikopplat från back-end kan vara en bra kombination för mig, men efter 7+ år PHP smutskastning med WordPress, hela installationen känns som overkill för mina grundläggande behov.

Vad jag egentligen vill ha är en statisk webbplats generator som kommer att låta mig skriva en blogg som en del av en större sida app så att jag har utrymme att prova nya saker och har fortfarande full kontroll över styling, utan behovet av en databas eller någon form av back-end. Det är en lång väg för att berätta att jag har hittat min egen klubb att gå med, med en avgjort un-cool namn.

Gör dig redo för det…

Butt-mindre Hemsida

Eftersom det inte finns någon back-end, för att få det? 😶

Det tar ett par steg för att gå butt-mindre:

  1. Setup en enda sida app med Vue
  2. Generera varje rutt vid kompileringen
  3. Skapa blogg och artikel komponenter
  4. Integrera Webpack att tolka Wiki innehåll
  5. Utöka funktionaliteten med plugins
  6. Vinst!

Som sista punkt måste vara en del av varje förslag, eller hur?

Jag vet att det ser ut som en massa steg, men det är inte riktigt lika tufft som det verkar. Låt oss bryta ner steg tillsammans.

Setup en enda sida app med Vue

Låt oss få Vue igång. Vi kommer att behöva Webpack att göra det.

Jag får det, Webpack är ganska skrämmande även när du vet vad som händer. Det är nog bäst att låta någon annan göra det riktigt svåra jobbet, så vi kommer att använda de Vue Progressiva Web App Standardtext som vår stiftelse och göra ett par justeringar.

Vi kan använda standard setup från reporäntan, men även när jag skriver denna artikel, det var förändringar som görs där. I intresse av att inte ha allt detta paus på oss, vi kommer att använda en repo som jag skapade för demonstrationsändamål. Att räntan har en gren för varje steg kommer vi att täcka in detta inlägg för att hjälpa till att följa med.

Visa på GitHub

Kloning reporäntan och kolla in steg-1 gren:

$ git clone https://github.com/evanfuture/vue-yes-blog.git steg-1
$ cd-vue-ja-blogg
$ npm install
$ npm köra dev

En av mina favorit delar av moderna utveckling är att det tar bara trettio sekunder för att få en progressiv web app igång!

Nästa, låt oss komplicera saker och ting.

Generera varje rutt vid kompileringen

Out of the box, enda sida appar har bara en enda kontaktpunkt. Med andra ord, det lever livet på en och samma WEBBADRESS. Detta är inte rimligt i vissa fall, men vi vill att vår app för att känna sig som en vanlig webbplats.

Vi kommer att behöva använda oss av historien läge i Vue Router-filen för att göra det. Det första vi ska göra det på genom att lägga till mode: “historia” till Routern objekts egenskaper så här:

// src/router/index.js
Vue.använd(Router);

export standard ny Router({
läge: ‘historien’,
rutter: [
// …

Våra starter app har två vägar. Utöver Hej, vi har en andra komponent som kallas Banan som bor på vägen /banan. Utan historia läge, URL för att sidan skulle vara http://localhost:1982/#/banana. Historia mode rensar upp till http://localhost:1982/banana. Mycket mer elegant!

Allt detta fungerar ganska bra i utveckling-läge (npm köra dev), men låt oss ta en titt på hur det skulle se ut i produktion. Här är hur vi sammanställa allt:

$ npm köra bygga

Detta kommando kommer att skapa din Vue plats i den ./dist-mappen. För att se det live, det är ett praktiskt kommando för att starta upp en super enkel HTTP-server på din Mac:

$ cd-dist
$ python -m SimpleHTTPServer

Ledsen Windows folk, jag vet inte motsvarande!

Nu besöker localhost:8000 i din webbläsare. Du kommer att se din webbplats som den kommer att visas i en produktionsmiljö. Klicka på den Banan länk, och allt är väl.

Uppdatera sidan. Oops! Detta visar att vår första problemet med enda sida appar: det är bara en HTML-fil som genereras vid kompileringen, så det finns inget sätt för webbläsaren att veta att banan ska rikta sig till de största app-sidan och ladda vägen utan fancy Apache-stil omdirigeringar!

Naturligtvis finns det en app för det. Eller, åtminstone en plugin. Grundläggande användning är noterade i Vue Progressiva Web App Standardtext dokumentation. Här är hur man säger att vi kan snurra upp plugin:

$ npm install-D prerender-spa-plugin

Låt oss lägga våra vägar till Webpack produktion konfigurationsfil:

// ./build/webpack.prod.conf.js
// …
const SWPrecacheWebpackPlugin = require(‘sw-precache-webpack-plugin’)
const PrerenderSpaPlugin = require(‘prerender-spa-plugin’)
const loadMinified = require(‘./ladda-minified’)
// …
const webpackConfig = sammanfoga(baseWebpackConfig, {
// …
plugins: [
// …
nya SWPrecacheWebpackPlugin({
// …
minify: sant,
stripPrefix: ‘dist/’
}),
// prerender app
nya PrerenderSpaPlugin(
// Sökväg till sammanställts app
väg.gå med(__dirname, ‘../dist’),
// Lista över endpoints du vill prerender
[ ‘/’, ‘/banana’ ]
)
]
})

Det är det. Nu, när du kör en ny build, varje rutt i matrisen kommer att bli som en ny inkörsport till appen. Grattis, vi har i princip bara aktiverad statisk webbplats generation!

Skapa blogg och artikel komponenter

Om du hoppa framåt, vi är nu upp till steg-2 gren av min demo repo. Gå vidare och kolla upp det:

$ git checkout steg-2

Detta steg är ganska enkelt. Vi kommer att skapa två nya komponenter och koppla dem samman.

Blogg Komponent

Låt oss registrera bloggen komponent. Vi ska skapa en ny fil som heter YesBlog.vue i /src/komponenter katalog och släppa i koden för visning:

// ./src/components/YesBlog.vue
<mall>
<div class=”blogg”>
<h1>Blogg</h1>
<router-länk=”/”>Hem</router-länk>
<hr/>
<artikel v-for=”artikeln i artiklarna” :key=”artikeln.slug” class=”article”>
<router-länk class=”article__länk” :=”`/blogg/${ artikel.slug }`”>
<h2 class=”article__title”>{{ artikel.titel }}</h2>
<p class=”article__description”>{{artikel.beskrivning}}</p>
</router-länk>
</article>
</div>
</template>

<script>
export standard {
namn: ‘blogg’,
beräknad: {
artiklar() {
return [
{
slug: “första-artikel”,
titel: “Artikel”,
beskrivning till: “Denna artikel är en’s beskrivning’,
},
{
slug: “den andra artikeln’,
titel: “Artikel Två”,
description: “Detta är artikel två’s beskrivning’,
},
];
},
},
};
</script>

Allt vi egentligen gör är att skapa en tom array (artiklar) som kommer att vara fylld med artikel objekt. Denna array skapar vår artikel lista och använder slug parameter som post-ID. Titel och beskrivning parametrar fylla ut inlägget detaljer. För nu, det är alla hårdkodade medan vi få resten av vår kod i stället.

Artikel Komponent

Artikeln komponent är en liknande process. Vi ska skapa en ny fil som heter YesArticle.vue och skapa markup för visning:

// ./src/components/YesArticle.vue
<mall>
<div class=”article”>
<h1 class=”blog__title”>{{artikel.titel}}</h1>
<router-länk=”/blogg”>Tillbaka</router-länk>
<hr/>
<div class=”article__kroppen” v-html=”artikeln.kroppen”></div>
</div>
</template>

<script>
export standard {
namn: ‘YesArticle’,
rekvisita: {
id: {
typ: String,
krävs: sant,
},
},
data() {
return {
artikel: {
titel: här.id,
kropp: ‘<h2>Test</h2><p>Ok, låt’s göra mer nu!</p>’,
},
};
},
};
</script>

Vi kommer att använda som rekvisita skickas tillsammans med routern för att veta vad som artikel-ID som vi jobbar med. För nu, vi ska bara använda den som efter titel, och hardcode kroppen.

Routing

Vi kan inte gå vidare förrän vi lägga till vår nya utsikt till routern. Detta kommer att säkerställa att våra adresser är giltiga och gör att våra navigering ska fungera korrekt. Här är helheten av router-fil:

// ./src/router/index.js
importera Router från ‘vue-router’;
importera Hej från ‘@/components/Hello”;
importera Bananer från ‘@/components/Banan”;
importera YesBlog från ‘@/components/YesBlog’;
importera YesArticle från ‘@/components/YesArticle’;

Vue.använd(Router);

export standard ny Router({
läge: ‘historien’,
rutter: [
{
sökväg: ‘/’,
namn: ‘Hej’,
komponent: Hej,
},
{
sökväg: ‘/banan’,
namn: ‘Banan’,
komponent: Banana,
},
{
sökväg: ‘/blogg’,
namn: ‘YesBlog’,
komponent: YesBlog,
},
{
sökväg: ‘/blogg/:id’,
namn: ‘YesArticle’,
rekvisita: sant,
komponent: YesArticle,
},
],
});

Märker att vi har bilagts /:id till YesArtcle komponent väg och ställ in dess rekvisita till true. Detta är viktigt eftersom de upprätta dynamisk routing vi ställa upp i den del som är rekvisita array i-komponent fil.

Slutligen, vi kan lägga till en länk till vår hemsida som pekar på bloggen. Detta är vad vi släpper in i Hej.vue filen för att få det att gå:

<router-länk=”/blogg”>Blogg</router-länk>
Pre-rendering

Vi har gjort en hel del arbete så här långt, men inget av det kommer att hålla tills vi pre-gör våra vägar. Pre-rendering är ett finare sätt att säga att vi inte berätta för appen vad vägar finns och att dumpa rätt kod i rätt väg. Vi har lagt till en Webpack plugin för detta tidigare, så det här är vad vi kan lägga till vårt Webpack produktion konfigurationsfil:

// ./build/webpack.prod.conf.js
// …
// Lista över endpoints du vill prerender
[ ‘/’, ‘/banan’, ‘/blogg’, ‘/blogg/första-artikel’, ‘/blogg/andra-artikel”]
// …

Jag måste erkänna att denna process kan vara besvärliga och irriterande. Jag menar, vem vill beröra flera filer för att skapa en WEBBADRESS?! Tack och lov, vi kan automatisera detta, som vi kommer att täcka längre ner.

Integrera Webpack att tolka Wiki innehåll

Vi är nu upp till steg-3 gren. Kolla in det om du följer med i koden:

$ git checkout-steg-3
Inlägg

Vi kommer att använda Wiki för att skriva våra inlägg, med några FrontMatter att skapa meta-data funktionalitet.

Brand upp en ny fil i inlägg katalog för att skapa vårt allra första inlägg:

// ./src/inlägg/första artikel.md

titel: Artikel från MD
beskrivning: I vilken hjälte börjar färska
skapad: 2017-10-01T08:01:50+02
uppdaterad:
status: publicera

Här är texten i artikeln. Det är ganska stor, är det inte?

// ./src/posts/andra-artikel.md

titel: Artikel Två från MD
beskrivning: Detta är en annan artikel
skapad: 2017-10-01T08:01:50+02
uppdaterad:
status: publicera

## Låt oss börja med en H2
Och sedan lite text
Och sedan lite kod:
“html –
<div class=”container”>
<div class=”main”>
<div class=”article infoga-wp-taggar-här”>
<h1>Rubrik</h1>
<div class=”article-content”>
<p class=”intro”>Intro Text</p>
<p></p>
</div>
<div class=”article-meta”></div>
</div>
</div>
</div>

Dynamisk Routing

En irriterande sak just nu är att vi behöver hardcode våra vägar för den pre-rendering plugin. Som tur är, är det inte komplicerat att göra detta dynamiskt med lite Node magi. För det första, vi kommer skapa en hjälpare i våra verktyg-fil för att hitta filer:

// ./build/utils.js
// …
const ExtractTextPlugin = require(‘extrahera text-webpack-plugin’)
const fs = require(‘fs’)

exporten.filesToRoutes = function (katalog, förlängning, routePrefix = “) {
funktion findFilesInDir(startPath, filter){
låt resultat = []
if (!fs.existsSync(startPath)) {
konsolen.logga in(“ingen dir “, startPath)
tillbaka
}
const filer = fs.readdirSync(startPath)
för (låt i = 0; i < filer.längd; i++) {
const filename = väg.gå med(startPath, filer[i])
const stat = fs.lstatSync(filnamn)
om (stat.isDirectory()) {
resultat = resultat.concat(findFilesInDir(filnamn, filter)) //recurse
} else if (filnamn.indexOf(filter) >= 0) {
resultat.push(filnamn)
}
}
resultat
}

tillbaka findFilesInDir(väg.gå med(__dirname, katalog), förlängning)
.karta((filnamn) => {
tillbaka filnamn
.byt ut(path.gå med(__dirname, katalog), routePrefix)
.byt ut(extension “)
})
}

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

Detta kan egentligen bara kopieras och klistras in, men vad vi har gjort här är att skapa ett verktyg metod som kallas filesToRoutes() som kommer att ta i en katalog, förlängning, och en valfri routePrefix, och returnerar en array av rutter baserat på en rekursiv sök fil i den katalogen.

Allt vi behöver göra för att göra vår blogg inlägg rutter dynamisk är att förena detta nya utbud i vår PrerenderSpaPlugin rutter. Kraften i ES6 gör det väldigt enkelt:

// ./build/webpack.prod.conf.js
// …
nya PrerenderSpaPlugin(
// Sökväg till sammanställts app
väg.gå med(__dirname, ‘../dist’),
// Lista över endpoints du vill prerender
[
‘/’,
‘/banan’,
‘/blogg’,
…utils.filesToRoutes(‘../src/posts’, ‘.md’, ‘/blogg”)
]
)

Eftersom vi redan har importerat utils på toppen av filen för andra ändamål, kan vi bara använda sprida operatör … att slå samman de nya dynamiska rutter array in här, och vi är klar. Nu är vår pre-rendering är helt dynamisk, endast beroende av oss att lägga till en ny fil!

Webpack Lastare

Vi är nu upp till steg-4 gren:

$ git checkout-steg-4

För att faktiskt fylla vår Wiki-filer till parse-kan innehåll, vi kommer behöva Webpack hjullastare på plats. Igen, någon annan har gjort allt arbete för oss, så vi har bara att installera och lägga till dem till din config.

$ npm install-D json-loader wiki-det-framför-roll-loader wiki-det highlight.js yaml-front-fråga

Vi kommer bara att ringa json-lastare och wiki-det-framför-roll-loader från våra Webpack config, men den senare har inbördes beroenden av wiki-den och highlight.js så ska vi installera dem på samma gång. Också, inget varnar oss om detta, men yaml-fram-frågan är också skyldiga att på så ovanstående kommando lägger till det också.

För att använda dessa fina nya lastare, vi kommer att lägga till ett block för att våra Webpack base-config:

// ./build/webpack.base.conf.js
// …
modulen.exporten = {
// …
modul: {
regler: [
// …
{
test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
loader: ‘url-loader’,
alternativ: {
gräns: 10000,
namn: utils.assetsPath(‘teckensnitt/[namn].[hash:7].[ext]’)
}
},
{
test: /.md$/,
lastare: [‘json-loader’, ‘wiki-det-framför-roll-loader’],
},
]
}
}

Nu, någon gång Webpack möten kräver en förklaring med .md förlängning, kommer den att använda den främre delen-loader (som kommer att korrekt tolka metadata kvarter från våra artiklar, liksom de block av kod), och ta ut JSON och köra det genom json-loader. På detta sätt, vi vet att vi slutar upp med ett objekt för varje artikel som ser ut så här:

// första artikel.md [Object]
{
kropp: “<p>Här är texten i artikeln. Det är ganska stor, är det inte?</p>n”
skapad: “2017-10-01T06:01:50.000 Z”
beskrivning: “vilken hjälte börjar fräsch”
rå: “nnHere är texten i artikeln. Det är ganska stor, är det inte?n”
slug: “första-artikel”
status: “publicera”
titel: “Artikel från MD”
uppdaterad: null
}

Detta är precis vad vi behöver och det är ganska lätt att utöka med andra metadata om du behöver. Men hittills har detta inte göra något! Vi måste kräva att dessa i ett av våra komponenter så att Webpack kan hitta och ladda det.

Vi kan bara skriva:

require(‘../inlägg/första artikel.md’)

…men då skulle vi ha att göra att för varje artikel som vi skapar, och det kommer inte att vara något roligt som vår blogg växer. Vi behöver ett sätt att dynamiskt kräver att alla våra Wiki-filer.

Dynamisk Kräver

Lyckligtvis, Webpack gör detta! Det var inte lätt att hitta dokumentation för detta, men här är det. Det är en metod som kallas kräva.sammanhang() som vi kan använda till att göra precis vad vi behöver. Vi ska lägga upp det för att skriptet avsnitt av vår YesBlog komponent:

// ./src/components/YesBlog.vue
// …
<script>
const inlägg = {};
const req = kräver.sammanhang(‘../posts/’, false, /.md$/);
req.nycklar().forEach((tangent) => {
inlägg[key] = req(key);
});

export standard {
namn: ‘blogg’,
beräknad: {
artiklar() {
const articleArray = [];
Objektet.nycklar(inlägg).forEach((tangent) => {
const artikel = posts[key];
artikel.slug = nyckel.byt(‘./’, “).byt(‘.md’, “);
articleArray.push(artikel);
});
tillbaka articleArray;
},
},
};
</script>
// …

Vad är det som händer här? Vi skapar ett inlägg objekt som vi ska först fylla med artiklar, för att sedan använda den senare inom komponenten. Eftersom vi är pre-gör alla vårt innehåll, detta föremål kommer att vara omedelbart tillgängliga.

Den kräver.sammanhang() metod accepterar tre argument.

  • den katalog där det kommer att sök
  • huruvida eller inte att inkludera underkataloger
  • en regex filter för att återgå filer

I vårt fall, vi vill bara Wiki filer i inlägg katalogen, så:

kräver.sammanhang(‘../posts/’, false, /.md$/);

Detta kommer att ge oss en slags underlig ny funktion/objekt som vi behöver för att tolka för att kunna använda. Det är där req.nycklar() kommer att ge oss en array av den relativa sökvägar till varje fil. Om vi kallar req(nyckel), detta kommer att återvända artikel objekt vi vill, så vi kan tilldela ett värde till en matchande nyckeln i våra inlägg objekt.

Slutligen, i de beräknade artiklar () – metoden, vi kommer att automatiskt generera våra slug genom att lägga till en slug nyckeln till varje inlägg, med ett värde av filnamnet utan en väg eller tillägg. Om vi ville att detta skulle kunna förändras för att tillåta oss att ställa in proppen i Wiki själv, och bara falla tillbaka till auto-generationen. Samtidigt trycker vi på artikel objekt i en array, så att vi har något som är lätt att iterera över i vår komponent.

Extra Kredit

Det finns två saker du antagligen att vilja göra direkt om du använder denna metod. Det första är att sortera efter datum, och det andra är att filter av artikel status (utkast och offentliggjort). Eftersom vi redan har en array, detta kan göras på en rad, lagt till precis innan återvända articleArray:

articleArray.filter(post => post.status === ‘publicera’).typ (a, b) => a.skapade < b.skapat);
Sista Steget

En sista sak att göra nu, och det är att undervisa våra YesArticle komponent att använda de nya uppgifterna vi får längs med rutten förändring:

// ./src/components/YesArticle.vue
// …
data() {
return {
artikel: require(`../posts/${detta.id}.md`), // eslint-disable-line global-kräver -, import – /no-dynamic-kräver
};
},

Eftersom vi vet att vår del kommer att förrenderade, kan vi inaktivera ESLint regler som inte dynamisk och global kräver och kräver sökvägen till den post som motsvarar parametern id. Detta utlöser våra Webpack Wiki lastare, och att vi alla är gjort!

OMG!

Gå vidare och testa det här:

$ npm köra bygga && cd-dist && python -m SimpleHTTPServer

Besök localhost:8000, navigera runt och uppdatera sidorna för att läsa hela appen från new entry point. Det fungerar!

Jag vill bara understryka hur coolt detta är. Vi har gjort en mapp på Wiki-filer till en array av objekt som vi kan använda när vi vill, var som helst på vår webbplats. Himlen är gränsen!

Om du bara vill se hur det hela fungerar, du kan kolla in den sista grenen:

$ git checkout-steg-fullständig

Utöka funktionaliteten med plugins

Min favorit del om den här tekniken är att allt är utbyggbar och utbytbara.

Gjorde någon skapa en bättre Wiki-processor? Bra, byta ut de loader! Behovet av kontroll över din webbplats SEO? Det finns en plugin för att. Måste lägga till en kommentar system? Lägg till att plugin.

Jag gillar att hålla ett öga på dessa två förråd för idéer och inspiration:

  • Awesome Vue.js
  • Awesome Wiki

Vinst!

Du trodde att detta steg var ett skämt?

Det allra sista vi vill göra nu är att resultat från den enkelhet som vi har skapat och nab några gratis webbhotell. Eftersom din webbplats är nu som genereras på din git-arkiv, allt du egentligen behöver göra är att trycka dina ändringar till Github, Bitbucket, Gitlab eller vad kodarkiv du använder. Jag valde Gitlab eftersom privata repos är gratis och att jag inte vill ha mitt utkast allmänheten, även i repo-form.

Efter det är att ställa upp, du behöver för att hitta en värd. Vad du verkligen vill ha är en värd som erbjuder kontinuerlig integration och distribution så att sammanslagning till din master-branch som utlöser npm köra bygga kommandot och regenererar din webbplats.

Jag använde Gitlab egna CI-verktyg för de första månaderna efter att jag satt upp detta. Jag hittade installationsprogrammet för att vara lätt men felsökning problem att vara svårt. Jag har nyligen bytt till Netlify, som har en enastående gratis plan och några bra CLI verktyg inbyggda.

I båda fallen kan du peka din egen domän på deras servrar och även installera ett SSL-certifikat för HTTPS-stöd—den sista punkten är viktigt om du någonsin vill experimentera med saker som getUserMedia API, eller skapa en butik för att göra försäljningen.

Med allt detta sätta upp, du är nu medlem i Rumpan-mindre Webbplats club. Grattis och välkomna, vänner! Förhoppningsvis hittar du denna för att vara ett enkelt alternativ till komplexa content management-system för din egen personliga hemsida och att det tillåter dig att experimentera med lätthet. Vänligen låt mig veta i kommentarerna om du fastnar på vägen…eller om du lyckas bortom dina vildaste drömmar. 😉