Stworzenie sitemapy w node.js

Ma艂y przyjemny kod 馃槈
Na pocz膮tku pobieramy wszystkie pliki z foldera build za pomoc膮 readdir, nast臋pnie p臋telka po tych plikach. Robimy split po kropce aby dobra膰 si臋 do rozszerzenia a interesuje nas oczywi艣cie html
Je偶eli rozszerzeniem oka偶e si臋 html to wszystko pakujemy do tablicy urlPart.
Na ko艅cu budujemy xml sitemap i zapisujemy to przez writeFile i to tyle.

const fs = require("fs");

const htmlPlace = "build";
const ulrPart = [];

fs.readdir(`${htmlPlace}`, function (err, files) {
    if (err)
        throw err;
    for (let index in files) {
        let rest = files[index].split('.')[1];
        if (rest === 'html') {
            let path = `
                <url>
                    <loc>http://blog.grzegorztomicki.pl/${files[index]}</loc>
                    <changefreq>monthly</changefreq>
                </url>
            `;
            ulrPart.push(path);
        }

    }

    const template = `
        <?xml version="1.0" encoding="UTF-8"?>
        <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
            ${ulrPart.join('')}</urlset>`;

    fs.writeFile(`./sitemap.xml`, template, function (err) {});
});

艁adowanie CSS i CSS modules w tym samym czasie Webpack

W react mo偶emy importowa膰 css jak i css jako modu艂y.
Ale co je艣li chcemy zrobi膰 do w tym samym czasie powiedzmy doda膰 globalny styl np. normalize.css?

Importowanie jako modu艂:

import React from 'react'
import styles from './moj-komponent.css';

const MyComponent => <div className={styles.jakasKlasa}></div>

No ale jak u偶y膰 css powiedzmy jakie艣 zewn臋trznej biblioteki:

import React from 'react'
import './moj-komponent-zewnetrzny.css';

const MyComponent => <div className="jakasKlasa"></div>

Aby tego dokona膰 nale偶y zmodyfikowa膰 webpack. Ja korzystam z create-react-app i modyfikuj臋 zar贸wno wersj臋 dev jak i prod webpacka.

module: {
    rules: [
        {
            // wcze艣niej by艂o /\.css$/
            test: /^(?!.*?\.module).*\.css$/,
           
            // dalej zostawiamy jak by艂o czyli
            use: [
              require.resolve('style-loader'),
              {
                loader: require.resolve('css-loader'),
                options: {
                  importLoaders: 1,
                  modules: true,
                  localIdentName: '[name]__[local]__[hash:base64:5]'
                },
                ...
        },
        // dodajemy nast臋pn膮 regu艂臋 dla zewn臋trznych css
        {
            test: /\.module\.css$/,
            use: [
                require.resolve('style-loader'),
                require.resolve('css-loader')
            ],
        },
    ]
}

Teraz mo偶emy u偶y膰 w jednym komponencie zar贸wno css modu艂贸w jak i zewn臋trznych bibliotek.
Nale偶y pami臋ta膰 偶e zewn臋trzny komponent musi mie膰 w nazwie *.module.css

import React from 'react'
import styles from './moj-komponent.css';
import './jakis-zewnetrzny.module.css'

const MyComponent => <div className={`${styles.jakasKlasa} jakas-klasa-z-zewnatrz`}></div>

W wersji produkcyjnej webpack kopiuj臋 ca艂膮 regu艂臋 css i wstawiam poni偶ej,
zmieniam test: /\.css$/, na test: /\.module\.css$/,
Ustawiam modules: false i tyle.

Importowanie absolutne w Create React App

Jak pozby膰 si臋 zagnie偶d偶onych 艣cie偶ek w pejekcie.
Np. taka nie艂adna 艣cie偶ka jak poni偶ej.

import TopImage from '../../../components/TopImage/TopImage';

Chcemy mie膰 co艣 takiego, czy do foldera components czy do containers czy innych folder贸w w src.

import TopImage from 'components/TopImage/TopImage';

Najpro艣ciej jak mo偶na to tworzymy plik w folderze src o nazwie .env tak z kropk膮 na pocz膮tku.
W nim wpisujemy NODE_PATH=src/ robimy save i uruchamiamy project jak zwykle przez npm run start

Od tej chili zamiast podawa膰 ca艂膮 艣cie偶k臋 podajemy components, containers, hoc czy inne foldery jakie mamy w projekcie.

Innym sposobem jest modyfikacja package.json

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build"
}

Dodajemy NODE_PATH=src/

"scripts": {
   "start": "NODE_PATH=src/ react-scripts start",
   "build": "NODE_PATH=src/ react-scripts build"
}

Jest jeden problem z u偶ytkownikami windowsa jak zwykle 馃槈 NODE_PATH=src/ w package.json nie zadzia艂a.
Nale偶y zainstalowa膰 modu艂 cross-env czyli npm install –save-dev cross-env i zmodyfikowa膰 package.json, oczywi艣cie to tylko w wypadku windowsa.

"scripts": {
   "start": "cross-env NODE_PATH=src/ react-scripts start",
   "build": "cross-env NODE_PATH=src/ react-scripts build"
}

I to tyle chyba ten pierwszy spos贸b jest mniej inwazyjny i powinien zadzia艂a膰 na wszystkich platformach.

ES6, var vs let

Przyk艂ad u偶ycia let oraz var

for (var i = 0; i < 5; ++i) {
  setTimeout(function () {
    console.log(i); // Wynik 5 razy 5 :)
  }, 100);  
}
for (let i = 0; i < 5; ++i) {
  setTimeout(function () {
    console.log(i); // Wynik 0, 1, 2, 3, 4
  }, 100);  
}

呕eby to wykona膰 bez let mo偶na by zrobi膰 tak jak poni偶ej.

for (var i = 0; i < 5; ++i) {
    (function(n) {
        setTimeout(function(){
            console.log(n); // Wynik 0, 1, 2, 3, 4
        }, 100);
    }(i));
}

Object.keys, values, entries

Poni偶ej kilka przyk艂ad贸w jak dobra膰 si臋 do obiekt贸w 馃檪

var codes = {
  reset: [0, 0],
  bold: [1, 22]
};

Object.keys(codes).forEach(function (key) {
  console.log(key); // "reset", "bold"
});

Object.values(codes).forEach(function (key) {
  console.log(key); // [0,0] [1,22]
});

Object.entries(codes).forEach(function (key) {
  console.log(key); // ["reset", [0, 0]] ["bold", [1, 22]]
});

U偶ycie operator spread syntax czyli […]

W ES6 pojawi艂a si臋 nowa funkcjonalno艣膰 nazywana „Spread syntax” operacje na tablicach czy obiektach. Poni偶ej kilka przyk艂ad贸w u偶ycia. W ES5 jest to concat.

W ES6

const boys = ["Ja艣", "Grze艣", "Ada艣"];
const girls = ["Ma艂gosia", "Ania", "Czesia"];

let people = [...boys, ...girls];

console.log(people); // ["Ja艣", "Grze艣", "Ada艣", "Ma艂gosia", "Ania", "Czesia"]

W ES5

const boys = ["Ja艣", "Grze艣", "Ada艣"];
const girls = ["Ma艂gosia", "Ania", "Czesia"];

let people = boys.concat(girls);

console.log(people); // ["Ja艣", "Grze艣", "Ada艣", "Ma艂gosia", "Ania", "Czesia"]

Inny przyk艂ad:

const divs = document.querySelector('div');

// u偶ycie call
[].foreach.call(divs, function(div) {
   console.log(div);
});

// u偶ycie spread
[...divs].foreach(div => {
    console.log(div)
}

show/hide scroll React

Ukrywanie buttona scroll-top je偶eli wysoko艣膰 przekroczy 200 oraz dodanie obs艂ugi zdarzenia na onClick i wywo艂anie funkcji scrollToTop i metody scrollIntoView.

export default BackToTop extends Component {
    state = {
        scrolling: false,
        scrollPosHeight: 200
    }

    componentDidMount() {
        console.log('componentDidMount()');
        window.addEventListener('scroll', this.hideShowButtonTop);
    };

    componentWillUnmount() {
        console.log('componentWillUnmount()');
        window.removeEventListener('scroll', this.hideShowButtonTop);
    };

    hideShowButtonTop = () => {
        const scrollPos = window.pageYOffset || document.documentElement.scrollTop;
        const myDiv = document.querySelector('.back-to-top');
        (scrollPos > this.state.scrollPosHeight && scrollPos !== 0) ? myDiv.style.display = 'block' : myDiv.style.display = 'none';
    }

    scrollToTop() {
        const logoView = document.getElementById('logo');
        logoView.scrollIntoView({
            behavior: 'smooth'
        })
    }

    render() {
        return (
            <div onClick={this.scrollToTop} className="back-to-top"></div>
        )
    };
};

Template strings w Javascript ES6, ES2015

Ile razy cz艂owiek si臋 m臋czy艂 aby zwyk艂y formularz ze zmiennymi zapisa膰 w js 馃槈
Z pokonaniem tego problemu si臋gamy po template string. U偶ywamy tego znaku (`) znajduje si臋 on nad tabulatorem z angielskiego backtick, po naszemu odwr贸cony apostrof a zmienne umieszczamy w takiej formie ${zmienna}
Wszystko razem mo偶na zapisa膰 `${zmienna}`

A teraz ma艂e przyk艂ady.

Powiedzmy 偶e mamy sobie obiekt.

var person = {
    name: 'Greg',
    job: 'front-end',
    city: 'Warszawa'
}

A html to:

var html =
'<div class="person">'+
    '<h1>' + person.name + '</h1>' +
    '<h2>' + person.job + ' ' + person.city + '</h2>' +
'</div>';

A nie pro艣ciej tak?:

const html = `
    <div class="person">
        <h1>${person.name}</h1>
        <h2>${person.job} ${person.city}</h2>
    </div>
`;

Oczywi艣cie mo偶na te zmienne mno偶y膰, dodawa膰 odejmowa膰 itd. 馃檪

const x = 1;
const y = 2;
const result = `${ x + y }`;

console.log(result); // 1 + 2 = 3

Taki zapis jak pokaza艂em niesamowicie skraca nam prac臋 i mniej b艂臋d贸w pope艂niamy, ale jest jeden problem i to powa偶ny a zwie si臋 on IE (Internet Explorer) 馃檪
Niestety nasz kod musi by膰 jeszcze przez jaki艣 czas wstecz kompatybilny ze starymi przegl膮darkami, dlatego w swojej pracy u偶ywam gulp, webpacka a czasami je r贸wnie偶 艂膮cz臋.

Ma艂e wyt艂umaczenie:
1. Gulp to, oparty o platform臋 Node.js, system do automatyzacji pracy. G艂贸wnym jego zadaniem jest wi臋c zautomatyzowanie wielu czynno艣ci, jakie musi wykona膰 programista podczas swojej pracy. Przyk艂ad u偶ycia – zerknij tutaj
2. Webpack to narz臋dzie, kt贸re rozwi膮zuje problem dzielenia kodu na modu艂y i pozwala 艂atwo zarz膮dza膰 zale偶no艣ciami wyst臋puj膮cymi mi臋dzy nimi.

Wi臋cej poszukajcie sobie w google bo naprawd臋 warto zna膰 te technologie.

Wracaj膮c do naszego problemu z IE i nie tylko, ja u偶y艂em biblioteki gulp-bable
Najpierw instalacja z linii komend biblioteki gulp-babel

npm install --save-dev gulp-babel babel-core babel-preset-es2015

Teraz dodajemy do gulpfile.js nasz膮 bibliotek臋 oraz task

const gulp = require('gulp');
const babel = require('gulp-babel');


gulp.task('js', function () {
    return gulp.src('src/**/*.js')
        .pipe(babel({
            "presets": ["es2015"]
        }))
        .pipe(gulp.dest('dist'));
});

Taki kod w pliku template.js kt贸ry chcemy zmieni膰 na es2015 umieszczamy w folderze src

const person = {
    name: 'Greg',
    job: 'front-end',
    city: 'Warszawa'
}

const html = `
    <div class="person">
        <h1>${person.name}</h1>
        <h2>${person.job} ${person.city}</h2>
    </div>
`;

console.log(html);

const x = 1;
const y = 2;
const result = `${ x + y }`;

console.log(result);

Po uruchomieniu taska js w folderze dist otrzymujemy js zmieniony na es205, wynik poni偶ej

'use strict';

var person = {
    name: 'Greg',
    job: 'front-end',
    city: 'Warszawa'
};

var html = '\n    <div class="person">\n        <h1>' + person.name + '</h1>\n        <h2>' + person.job + ' ' + person.city + '</h2>\n    </div>\n';

console.log(html);

var x = 1;
var y = 2;
var result = '' + (x + y);

console.log(result);

I ten kod za艂膮czamy do naszej strony b臋dzie dzia艂a膰 r贸wnie偶 ze starszymi przegl膮darkami.

Oczywi艣cie to tylko pobie偶ne poruszenie tego tematu, wi臋cej w google 馃槈

Pasek post臋pu przewijania strony.

Dobrych praktyk UX nigdy za wiele. Warto czasami do strony doda膰 co艣 co nawet w najmniejszym stopniu zwi臋kszy czas przebywania usera na stronie.

Najpierw pobieramy o ile przewin臋li艣my stron臋 od lewego g贸rnego rogu window.pageYOffset,
p贸藕niej pobieramy wysoko艣膰 okna bez uwzgl臋dniania toolbar贸w i scrollbar贸w window.innerHeight, nast臋pnie pobieramy document.body.clientHeight czyli wysoko艣膰 ca艂ego okna.

const ProgressBar = function () {

    window.addEventListener('scroll', () => {
        let ws = window.pageYOffset,
            wh = window.innerHeight,
            dh = document.body.clientHeight;
        let scrollPercent = (ws / (dh-wh)) * 100;
        const progressBar = document.querySelector('#progress');
        if(ws > 50) {
            progressBar.setAttribute('style','width:'+ scrollPercent + '%');
        } else {
            progressBar.removeAttribute('style');
        }
    });

}();

Je偶eli przewiniemy o wi臋cej ni偶 50px wtedy do id progress dodajemy style width, je偶eli jest mniejsze to usuwamy atrybut style z id.

Dodajemy te偶 css aby to zadzia艂a艂o.

.bar {
    position: fixed;
    background: rgb(255, 0, 0);
    height: 10px;
    width: 0;
    top: 0;
}

Dzia艂aj膮cy przyk艂ad mo偶na znale藕膰 tutaj – dzia艂aj膮cy przyk艂ad

Listowanie folderu w node

Aby wylistowa膰 folder z plikami i zapisa膰 list臋 plik贸w jako json na potrzeby tej strony – blog.grzgorztomicki.pl nale偶y oczywi艣cie mie膰 najpierw zainstalowane nodejs

Tworzymy plik powiedzmy list_images.js

Najpierw u偶ywamy wbudowanej biblioteki fs – fs

const fs = require("fs");
const nameGallery = "chiny";
const name = "test";

const test = [];
const author = "Grzegorz Tomicki";

let now = new Date();
let date = now.getDate() + "." + (now.getMonth()+1) + "." + now.getFullYear();

let datePublished = new Date().toISOString().slice(0,10);
let dateModified = datePublished;

Czytamy folder z plikami jpg za pomoc膮 fs.readdir

fs.readdir(`./sources/images/${nameGallery}/1200/`, function (err, files) {
if (err)
throw err;
for (let index in files) {

Tutaj u偶ywamy czego艣 nowego z ES6 a mianowicie „template string”. U偶ywamy do tego znaku obok jeden na klawiaturze ` a zmienne podajemy w postaci ${} co艣 wspania艂ego 馃檪
Poni偶ej s膮 dwa przyk艂ady u偶ycia a mianowicie path jak i template – wiele linii jak wida膰 nie trzeba skleja膰 za pomoc膮 „+” cud malina 馃檪

let path = `{"path":"./images/${nameGallery}/","img":"${files[index]}","alt":""}`;
test.push("\r\n\t\t\t\t" + path);
}

const template = (`
{
  "head": {
    "title": "",
    "description": ""
  },
  "body": {
    "title": "",
    "date": "${date}",
    "text": "",
    "items": [$ {
      test
    }]
  },
  "footer": {
    "js": "../../build/js/boundle.min.js"
  },
  "schema": {
    "datePublished": "${datePublished}",
    "dateModified": "${dateModified}",
    "author": "${author}"
  }
}
`);

Zapisujemy plik za pomoc膮 fs.writeFile

fs.writeFile(`./sources/data/site/${name}.json`, template, function (err) {});
});

Aby oczywi艣cie uruchomi膰 ten plik nale偶y go uruchomi膰 przez komend臋 w konsoli node list_images.js
Ca艂y proces tworzenia strony mo偶na znale藕膰 pod tym linkiem tutaj