Блог

Мој први npm пакет

Категорије:
  • npm пакети

Претходних неколико дана је за мене било веома занимљиво, јер сам радио на објављивању мог првог пакета на npm-у: nuxt-content-highlight. Ради се о омотачу за компоненту <nuxt-content> која омогућава да се делови текста истакну, као да су подвучени маркером. Ту функционалност сам додао овом сајту и користио уз markdown-it за истицање траженог текста на страници са претрагом већ пре више месеци, пре него што је објављен @nuxt/content, али сам је тек сада издвојио у посебан пакет. Пријаве грешака или сугестије можете слати на https://github.com/Strahinja/nuxt-content-highlight/issues.

Nuxtpress

Категорије:
  • ажурирања сајта

Не много после мог претходног писања, Nuxt.js-ов тим је објавио верзију 2.13, која доноси неколико нових додатака за Nuxt.js, међу којима су и @nuxt/components и @nuxt/content. Овај други додатак је званично решење за рад са чланцима у формату Markdown у Nuxt.js-у. Од тада сам у слободно време углавном радио на пребацивању свих делова мог сајта који имају везе са Markdown-ом на @nuxt/content. Осим овога, проучавао сам и начин на који се Nuxt апликација може писати у Typescript-у, што је једна од идеја за неки будући update. Вратимо се сад @nuxt/content-у.

Предности

Осим очигледне предности постојања готовог API-ја за читање чланака у формату Markdown, @nuxt/content нуди и напредно филтрирање и full-text претрагу преко интерфејса сличног MongoDB-у. Сада је довољно ставити .md фајлове у /content и може се написати, рецимо:

async asyncData({ $content })
{
    const latestArticles = await $content('/')
        .where({ type: { $eq: 'article' } })
        .sortBy('date', 'desc')
        .limit(5)
        .fetch();
    return {
        latestArticles,
    };
}

да би се учитало најсвежијих пет чланака сортираних по опадајућем редоследу. Претрага се такође обавља директно:

async asyncData({ $content, route })
{
    const foundArticles = await $content('/')
        .search(route.params.q)
        .fetch();
    return {
        foundArticles,
    };
}

Миграција

Главна разлика у односу на frontmatter-markdown-loader је што се у @nuxt/content-у уместо markdown-it-а за превођење Markdown-а у HTML користи remark. То значи да је за све plugin-ове markdown-it-а потребно користити еквиваленте, наравно уколико они постоје. На пример, за сада не постоји еквивалент pluginmarkdown-it-figure-caption.

Пошто је замисао @nuxt/content-а систем за управљање чланцима у виду фајлова, а не слогова у бази података, за сада не постоји уграђена подршка за складиштење чланака у бази уместо у фајл систему, па је потребно директно позивати remark. Наравно, могуће је напоредо са њим користити и markdown-it, али мислим да је то непотребно дуплирање зависности (dependencies) и није идеално. За сада још увек користим оба решења заједно, док не довршим подршку за приказивање текстова у одељку „Текстови“ уз помоћ remark-а.

Подршка за чланке

Категорије:
  • ажурирања сајта

Данас сам довршио додавање почетног система за приказивање чланака у Markdown-у. За разлику од тога како сам (за сада) реализовао приказивање чланака овог блога, у страницама из одељка „Текстови“ нисам користио frontmatter-markdown-loader. Разлог за ово је што је тај пакет за Nuxt прилагођен ситуацији у којој се серверски део апликације заиста извршава на Node.js серверу и само шаље донекле или делимично обрађен садржај клијентском делу. Уколико хостујемо сајт на статичком серверу, каква је већина (јефтиних) хостинг понуда код домаћих провајдера, користићемо SSG, тј. статички генерисан сајт. Ово не оставља места за додавање и уређивање чланака „у лету“, преко интерфејса саме апликације, па сам одлучио да директно искористим markdown-it.

Пре свега, направио сам фајл markdown-it.js са следећим садржајем:

import markdownIt from 'markdown-it';
import markdownItAbbr from 'markdown-it-abbr';
//...

var md = new markdownIt({html: true})
    .use(markdownItAbbr)
    //...
    ;

//...

export { md };

а затим и фајл plugins/markdown-it.js:

import { md } from '../markdown-it';

export default({ app }, inject) =>
{
    inject('mdRender', markdown => md.render(markdown));
};

Тиме се функција render() убацује у Nuxt-ов context и Vue инстанцу, па може да јој се приступи преко context.app.$mdRender() или this.$mdRender(). Сада једноставно могу да у оквиру компоненте странице напишем:

<template lang="pug">
    static-markdown(:markdown="markdown")
</template>

<script>
import StaticMarkdown from '~/components/StaticMarkdown';
export default {
    name: 'Koord',
    components: { StaticMarkdown },
    data()
    {
        return {
            markdown: '',
        };
    },
    async asyncData({ store, app })
    {
        let linkId = 'koord';
        await store.dispatch('articles/loadArticle', { linkId },
                             { root: true });
        let article = store.getters['articles/article'];
        return {
            markdown: article && article.markdown
                ? app.$mdRender(article.markdown)
                : ''
        };
    }
};
</script>

и Markdown ће бити преведен у HTML, у време генерисања страница, што омогућава видљивост претраживачима. Истовремено, постоји могућност накнадне хидрације подацима из базе. Планирам да овакву комбинацију евентуално применим и на чланке овог блога.

Локални PHP API и JWT, први део

Категорије:
  • ажурирања сајта

Кад желимо да направимо веб апликацију која треба да има могућност измене података, једно од првих питања на које треба одговорити је како ће бити решена веза између фронтенда, који је видљив корисницима, и бекенда, који чини погон апликације. Временом су се усталили стандарди за размену података, као што је AJAX, и формати представљања података, као што је JSON. Следеће питање које се намеће је како контролисати права приступа и измене података. Ако додамо могућност измене чланака или других елемената наше апликације, није згодно да та могућност буде доступна свима. Данас је један од најраспрострањенијих начина ауторизовања JSON Web Token, или скраћено JWT. Он функционише по принципу јавног и тајног кључа. Подаци који нам могу послужити за идентификацију чине JWT; они се потписују тајним кључем, кодирају уз помоћ Base64 и шаљу клијенту. Када клијент жели да приступи заштићеном ресурсу, уз захтев пошаље и JWT, који се декодира и провери дешифровањем потписа јавним кључем. Само јавни кључ који одговара тајном кључу којим је шифрован JWT ће верификовати податке. JWT се састоји од три дела: заглавља (header), главног дела (payload) и потписа (signature), који се после Base64 кодирања раздвајају тачкама.

Рецимо, за токен:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2dvb2dsZS5jb20iLCJhdWQiOiJodHRwczovL2dvb2dsZS5jb20iLCJuYW1lIjoi0J_QtdGC0LDRgCDQn9C10YLRgNC-0LLQuNGbIiwidXNlcm5hbWUiOiJwZXRlcnBhbjEyMzQ1IiwiYWRtaW4iOmZhbHNlLCJpYXQiOjE1ODY1NDE2NjEsImV4cCI6MTU4NjU0NzU2NSwianRpIjoiYTU3MWQ0NWItMTdmNy00N2I3LWJjM2ItZWRhMzFkN2IyNmIzIn0.Hb4Z6bsFFY2k-tshcCtQBOt768MAH0jmYWrnHshfaeM

Paste-овањем на сајту jsonwebtoken.io између осталог добијамо дешифрован JSON, који представља главни део, payload, JWT-а:

{
 "iss": "https://google.com",
 "aud": "https://google.com",
 "name": "Петар Петровић",
 "username": "peterpan12345",
 "admin": false,
 "iat": 1586541661,
 "exp": 1586545925,
 "jti": "a571d45b-17f7-47b7-bc3b-eda31d7b26b3"
}

Сва поља су потпуно опциона, али су нека од њих ипак стандардизована у стандарду RFC 7519. На пример, iat (Issued At) поље садржи Уникс timestamp времена креирања JWT-а, а iss (Issuer) ентитет који је креирао JWT.

Уколико се информације садржане у JWT-у тако лако декодирају, с правом се поставља питање безбедности JWT-а. Управо то је разлог тога да се не препоручује смештање осетљивих података као што су лозинке у payload. JWT служи само да успостави неку тврдњу, рецимо да је вредност параметра name ниска Петар Петровић. Тачност тврдње се проверава дешифровањем потписа јавним кључем.

Додавање тамне теме

Категорије:
  • ажурирања сајта

Најновија ставка коју сам додао мом сајту док радим на подршци за пријављивање преко друштвених мрежа је подршка за тамну тему прилагођену смерницама материјалног дизајна. То се у Vuetify-у изводи релативно једноставно; најтеже је одабрати саме боје тамне палете.

Када се дефинишу боје, потребно је проследити тему Vuetify-у. Ја сам се одлучио да тему поставим у два засебна фајла, који се затим учитавају преко директиве import.

Creative Commons License
Copyright © 1999-
Страхиња Радић (Strahinya Radich)