Emmet przyspieszamy pisanie HTML

W uproszczeniu, emmet pomaga nam w szybkim pisaniu html
Może występować jako plugin czy może być wbudowany do edytora którego używamy.
Ja używam visual studio code i on jest tam wbudowany w dodatku bardzo ładnie podpowiada składnię.
Poniżej to tylko mała lista przydatnych funkcji resztę można znaleźć tutaj

Zaczniemy od podstaw.
Napisz ! dostaniemy podstawę HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>
<body>

</body>
</html>

Inne podstawowe i często używane to:

link
<link rel="stylesheet" href="" />

link:css
<link rel="stylesheet" href="style.css" />

link:favicon
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />

link:rss
<link rel="alternate" type="application/rss+xml" title="RSS" href="rss.xml" />

style
<style></style>

script
<script></script>

script:src
<script src=""></script>
img
<img src="" alt="" />

a
<a href=""></a>

br
<br />

hr
<hr />

c
<!-- -->
mn
<main></main>

sect
<section></section>

art
<article></article>

hdr
<header></header>

ftr
<footer></footer>

adr
<address></address>

str
<strong></strong>
for
<form action=""></form>

input
<input type="text" />

label
<label for=""></label>

button:s
<button type="submit"></button>

button:r
<button type="reset"></button>

btn
<button></button>

select
<select name="" id=""></select>

tarea lub textarea
<textarea name="" id="" cols="30" rows="10"></textarea>

> oraz +

nav>ul>li

<nav>
  <ul>
    <li></li>
  </ul>
</nav>

div+p+span

<div></div>
<p></p>
<span></span>

Teraz pomieszamy lekko 😉

ul>li>div+p+span

<ul>
   <li>
      <div></div>
      <p></p>
      <span></span>
   </li>
</ul>

Każdy tag możemy dodać wiele razy *

ul>li*3>p

<ul>
  <li>
    <p></p>
  </li>
  <li>
    <p></p>
  </li>
  <li>
    <p></p>
  </li>
</ul>

Grupowanie przez użycie ()

ul>li(p+span)*2

<ul>
  <li></li>
  <p></p>
  <span></span>
  <p></p>
  <span></span>
</ul>

Dodanie class i id

ul>li>p.text#top

<ul>
  <li>
    <p class="text" id="top"></p>
  </li>
</ul>

Można dodać kilka klas

ul>li>p.text.top#top

<ul>
  <li>
    <p class="text top" id="top"></p>
  </li>
</ul>

Dodać można również unikalne class czy id

ul>li.text*2>p

<ul>
  <li class="text">
    <p></p>
  </li>
  <li class="text">
    <p></p>
  </li>
</ul>

Dodanie treści { }

ul>li>p.text*2>p{Treść}

<ul>
  <li>
    <p class="text">
      <p>Treść</p>
    </p>
    <p class="text">
      <p>Treść</p>
    </p>
  </li>
</ul>

Dodanie numerowania za pomocą $

ul>li>p.text$*2>p{Treść $}

<ul>
  <li>
    <p class="text1">
      <p>Treść 1</p>
    </p>
    <p class="text2">
      <p>Treść 2</p>
    </p>
  </li>
</ul>

Można też zacząć od konkretnego numeru @

ul>li>p.text$@10*2>p{Treść $@3}

<ul>
  <li>
    <p class="text10">
      <p>Treść 3</p>
    </p>
    <p class="text11">
      <p>Treść 4</p>
    </p>
  </li>
</ul>

A i najważniejsze do uzupełniania treści a mianowicie lorem ipsum wystarczy wpisać lorem i treść gotowa 🙂

Breakpoints w Sass

W dzisiejszym świecie css nie obejdzie się bez breakpointów do RWD. Praktycznie wszyscy używają scss a w takim razie możemy użyć mixin.

Najpierw tworzę listę breakpoints jako mapę, którą będziemy wykorzystywać w naszych stylach. Poniżej przykładowa lista, do własnych projektów użyj własnej listy.

$breakpoints: (
  xs: 512px,
  sm: 768px,
  md: 896px,
  lg: 1152px,
  xl: 1280px
);

Następna czynność to użycie mixin i expression. Użyłem w tym przykładzie min-width ale również można użyć max-width. Dokładnie chodzi o @media (min-width: 512px) {} lub @media (max-width: 512px) {} wybór należy już tylko od Ciebie.

@mixin breakpoint( $breakpoint ) {
  @if map-has-key( $breakpoints, $breakpoint ) {
     @media ( min-width: #{ map-get( $breakpoints, $breakpoint ) } ) {
       @content;
     }
  } @else if type_of( $breakpoint ) == number and unit( $breakpoint ) == px or unit( $breakpoint ) == em or unit( $breakpoint ) == rem {
     @media (min-width: $breakpoint ) {
       @content;
     }
   } @else {
     @warn "Nie można pobrać żadnej wartości z `#{$breakpoint}`. Nie jest zdefiniowany w mapie `$breakpoints` lub jest nieprawidłową liczbą px, em, lub rem.";
  }
}

Ale jak tego używać, nic prostszego.

p {
 padding: 10px;
 @include breakpoint(xs) {
   margin-top: 10px;
 }
}

Co ostatecznie da nam po kompilacji.

p {
 padding: 10px;
 @media (min-width: 512px) {
   margin-top: 10px;
 }
}

W tym przykładzie jest możliwość użycia własnego breakpointa. Wystarczy przekazać do @include szerokości i jednostki. Tak jak poniżej.

p {
 padding: 10px;
 @include breakpoint(1600px) {
   margin-top: 10px;
 }
}

Cztery sposoby centrowania elementu w div

Cztery sposoby centrowania elementu w div.
Najpierw przygotujemy style dla html, mały reset nie jest zły 😉

* {
  padding: 0;
  margin: 0;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  overflow: hidden;
}

oraz html

<div class="wrapper">
  <p></p>
</div>

A teraz konkrety:

I. Podstawowy i zawsze działający styl.

.wrapper {
  display: block;
  width: 100%;
  height: 100%;
}

p {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: blue;
  width: 100px;
  height: 100px;
  margin: auto;
}

II. Przykład z użyciem flex

.wrapper {
  display: flex;
  height: 100%;
  align-items: center;
  justify-content: center;
}

p {
  background-color: blue;
  width: 100px;
  height: 100px;
}

III. Styl oparty o transform.

.wrapper {
  display: block;
  width: 100%;
  height: 100%;
}

p {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100px;
  height: 100px;
  transform: translate(-50%, -50%);
  background-color: blue;
}

IV. Ostatni styl oparty o grid. Niestety grid jest słabo wspierany ale jeżeli nie obchodzą nas starsze przeglądarki w szczególności z serii IE to czemu nie użyć 🙂

.wrapper {
  display: grid;
  width: 100%;
  height: 100%;
}

p {
  width: 100px;
  height: 100px;
  align-self: center;
  justify-self: center;
  background-color: blue;
}

Jak przyspieszyć ładowanie CSS

Podam dwa sposoby na przyspieszenie renderowania się stron.

I. Sposób

Pierwszy sposób dotyczy najnowszych przeglądarek ale w przyszłości będzie działać wszędzie. Tego sposobu używa aliexpress.com 🙂 Chyba największy sklep na świecie, więc czy Chińczycy mogą się mylić 😉
Poniższy przykład wyrenderuje stronę dopiero wtedy kiedy przetworzy całą zawartość app.css

<head>
  <link rel="stylesheet" href="app.css" />
</head>
<body>
  <header class="page-header">...</header>

  <section class="sidebar">...</section>

  <main class="content">...</main>

  <footer class="page-footer">...</footer>
</body>

Możemy lekko poprawić wydajność powyższego rozwiązania a przynajmniej tak nam się może wydawać.

<head>
  <link rel="stylesheet" href="common.css" />
  <link rel="stylesheet" href="page-header.css" />
  <link rel="stylesheet" href="sidebar.css" />
  <link rel="stylesheet" href="content.css" />
  <link rel="stylesheet" href="page-footer.css" />
</head>
<body>
  <header class="page-header">...</header>

  <section class="sidebar">...</section>

  <main class="content">...</main>

  <footer class="page-footer">...</footer>
</body>

Niestety ale powyższe rozwiązanie pod http/2 połączy wszystko i będzie tak samo działo jak rozwiązanie pierwsze czyli blokowało renderowanie strony.

Inne podejście które używa aliexpress.com to umieszczanie styli w samym body w poszczególnych sekcjach. Przeglądarka renderuje poszczególne sekcje niezależnie od siebie. Coś na styl web components.

<head>
  <link rel="stylesheet" href="common.css" />
</head>
<body>
  <link rel="stylesheet" href="page-header.css" />
  <header class="page-header">...</header>

  <link rel="stylesheet" href="sidebar.css" />
  <section class="sidebar">...</section>

  <link rel="stylesheet" href="content.css" />
  <main class="content">...</main>

  <link rel="stylesheet" href="page-footer.css" />
  <footer class="page-footer">...</footer>
</body>

II. Sposób

Praktycznie wszystkie strony posiadają skrypt google analytics który umieszczamy w head. Zazwyczaj przed zamknięciem head i tutaj jest błąd.
Okazuje się ze takie rozwiązanie jak poniżej jest błędne bo tak jak w przykładzie pierwszym renderuje się najpierw cały css, a później tworzony jest script.

<head>
  <link rel="stylesheet" href="style.css" />
  <script>
    var script = document.createElement('script');
    script.src = 'speed.js';
    document.getElementsByTagName('head')[0].appendChild(script);
  </script>
</head>

Wystarczy zmiana kolejności wykonywania się elementów.

<head>
  <script>
    var script = document.createElement('script');
    script.src = 'speed.js';
    document.getElementsByTagName('head')[0].appendChild(script);
  </script>
  <link rel="stylesheet" href="style.css" />
</head>

Oczywiście najlepszym rozwiązaniem jest dodanie async do skryptów i wtedy nasz problem znika 😉

Kilka przydatnych Chrome Dev Tools trików

Kilka użytecznych przykładów użycia „console”.

Najpierw stwórzmy sobie plik html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <p>DZISIAJ W ...</p>
    <script src="console.js"></script>
  </body>
</html>

Później tworzę plik console.js a w nim będą przykłady użycia różnych zapisów „console”

const persons = [{ name: "Adam", age: 18 }, { name: "Greg", age: 20 }];

// podstawowe użycie
console.log("Podstawowy");

// interpolacja danych do stringa na dwa sposoby
console.log("Hellow World %s", "💩");
// lub template
const poop = "💩";
console.log(`Hellow World ${poop}`);

// style
console.log("%c Hellow World %s", "font-size: 50px; color: red");

// Ostrzeżenie wyświetlane na żółto
console.warn("Warn");

// Bład wyświetlany na czerwono
console.error("Error");

// informacja
console.info("Info");

// test
const p = document.querySelector("p");
console.assert(p.classList.contains("ouch"), "Brak klasy");

// czyszczenie
// console.clear();

// Podglad elementów DOM
console.log(p);
console.dir(p);

// Grupowanie elementów
persons.forEach(person =&gt; {
// console.group(`${person.name}`);
console.groupCollapsed(`${person.name}`);
console.log(`To jest ${person.name}`);
console.log(`${person.name} ma ${person.age} lat`);
console.groupEnd(`${person.name}`);
});

// Zliczanie występowania tych samych elementów
console.count("Test");
console.count("Test");
console.count("Greg");
console.count("Test");
console.count("Greg");
console.count("Test");

// np. czas pobierania danych
console.time("pobranie danych");
fetch("https://api.github.com/users/tomik23")
.then(data =&gt; data.json())
.then(data =&gt; {
console.timeEnd("pobranie danych");
console.log(data);
});

// Prezentowanie tabelaryczne
console.table(persons);

I na końcu coś co nie jest związane z „console” ale również się przydaje mianowicie dodanie debugger; to js. Kiedy następuje wywołanie instrukcji debugger, uruchomienie programu zatrzymywane jest na wyrażeniu debugger. Działa to tak jak ustawienie breakpointu w kodzie źródłowym skryptu.

function showAllStirngs() {
debugger;
}

Poniżej printscreen pokazujący Chrome Dev Tools

Mapowanie kolorów scss

Zaczynamy od deklaracji kolorów które będą nam potrzebne w projekcie.

$colors: (
  grey: (
    base: #4d4e55,
    light: #c8c8ce
  ),
  yellow: (
    base: #ffae00
  ),
  green: (
    base: #00ff15
  )
);

Oczywiście nic nie stoi na przeszkodzie aby modyfikować naszą deklarację dodając następne nazwy kolorów light, lighter, lightest, dark, darker, darkest
Mniej więcej wyglądało by tak.

$colors: (
  grey: (
    base: #4d4e55,
    light: xxxx,
    lighter: xxxx,
    lightest: xxxx,
    dark: xxxx
    darker: xxxx
    darkest: xxxx
  ),
  yellow: (
    base: #ffae00
  ),
  green: (
    base: #00ff15
  )
);

Teraz czas na @mixin trochę przerażająco wygląda 😉

@mixin color-modifiers($attribute: 'color', $prefix: '-', $separator: '-', $base: 'base') {
  @each $name, $color in $colors {
    &#{$prefix}#{$name} {
      @each $tone, $hex in $color {
        &#{if($tone != $base, #{$separator}#{$tone}, '')} {
          #{$attribute}: $hex;
        }
      }
    }
  }
}

A użycie jest dość oczywiste 😉

.text {
  @include color-modifiers;
}

Wynik naszego kodu to zestaw czterech klas które zareklamowaliśmy powyżej.

.text-grey { color:#4d4e55 }
.text-grey-light { color:#c8c8ce }
.text-yellow { color:#ffae00 }
.text-green { color:#00ff15 }

create-react-app i scss

Aby umożliwić korzystanie z scss w create-react-app robię podstawowe rzeczy. Najpierw zerknij w package.json na razie jest minimalistycznie teraz z konsoli uruchamiam npm run eject

Potrzebnych nam są jeszcze trzy biblioteki node-sass, sass-loader oraz resolve-url-loader.
Ja używam yarna czyli uruchamiam

yarn add -D sass-loader node-sass resolve-url-loader

lub dla tych co używają NPM

npm i -D sass-loader node-sass resolve-url-loader

Najpierw zajmiemy się wersją deweloperską znajduje się w folderze config -> webpack.config.dev.js
Kod wstawiam między
test: /\.(js|jsx|mjs)$/ a między test: /\.css$/

{
    test: /\.scss$/,
        include: [paths.appSrc, paths.appNodeModules],
            use: [
                {
                    loader: require.resolve('style-loader'),
                    options: {
                        sourceMap: true
                    }
                },
                {
                    loader: require.resolve('css-loader'),
                    options: {
                        importLoaders: 1,
                        modules: true,
                        localIdentName: '[local]'
                    },
                },
                require.resolve('resolve-url-loader'),
                {
                    loader: require.resolve('sass-loader'),
                    options: {
                        sourceMap: true
                    }
                }
            ]
},

a wersji produkcyjnej która również znajduje się w folderze config -> webpack.config.prod.js
Również w tym samym miejscu umieszczamy poniższy kod miedzy test: /\.(js|jsx|mjs)$/ a test: /\.css$/

{
    test: /\.scss$/,
        include: [paths.appSrc, paths.appNodeModules],
            use: [
                {
                    loader: require.resolve('style-loader'),
                    options: {
                        sourceMap: true
                    }
                },
                {
                    loader: require.resolve('css-loader'),
                    options: {
                        importLoaders: 1,
                        modules: true,
                        localIdentName: '[sha1:hash:hex:4]',
                    },
                },
                require.resolve('resolve-url-loader'),
                {
                    loader: require.resolve('sass-loader'),
                    options: {
                        sourceMap: true
                    }
                }
            ]
},

Różnica między dev jest localIdentName: ‚[local]’ a prod localIdentName: ‚[sha1:hash:hex:4]’ w dev pokazuję normalne klasy ‚home’ czy ‚container’ a w prod te klasy są zmienione np. na coś takiego ‚ea27’ 😉 Oczywiście

I tyle teraz uruchamiamy yarn start lub npm start

Mini sass grid

.row {
    display: flex;
    flex-wrap: wrap;
}

$columns: 12;

@for $i from 1 through $columns {
    .col-#{$i} {
        flex: 0 0 100% / $columns * $i;
    }
    .col-offset-#{$i} {
        margin-left: 100% / $columns * $i;
    }
}

// Responsive Breakpoints
[class^="col-"] {
    // Tablets
    @media (max-width: 768px) {
        flex-basis: 50%;
    }
    // Mobiles
    @media (max-width: 480px) {
        flex-basis: 100%;
    }
}

Docker + wordpress + phpmyadmin wersja Windows

Nie opiszę tutaj wszystkiego związanego z dockerem bo jestem świerzynka w tym temacie oraz jest tego tyle że po prostu nie da się tego opisać bez przepisywania dokumentacji 😉
Będzie to tylko mały wycinek tego co jest mi potrzebne do frontentu z przykładem użycia WordPress, MySQL oraz phpMyAdmin na Windowsie.

Do czego można by użyć Dockera?

Powiedźmy że chcemy stworzyć aplikację składającą się właśnie z WordPress + MySQL + phpMyAdmin aby przygotować nowy theme czy plugin.
Wszystko to musimy zainstalować osobno na komputerze do tego PHP + apache2 lub użyć Xampp’a, ale co jeśli musielibyśmy użyć kilku wersji PHP 5.5 czy 5.6 i do tego MySQL również w kilku wersjach.

Normalnie czekało by nas bardzo długie konfigurowanie każdej instancji, odinstalowanie elementów i instalacja nowych oraz ich konfiguracja czyli jednym słowem koszmar.

W takich przypadkach pomocny jest właśnie Docker. Wystarczy wybrać kontener z wersją aplikacji i już. Można nawet uruchomić wiele kontenerów równolegle, dzięki czemu możemy testować aplikację w kilku rożnych wersjach w tym samym czasie!
Najważniejsze przynajmniej dla mnie jest to że nie zaśmiecamy sobie środowiska zbędnymi instalacjami, a jak wiemy w tym względzie Windows jest dość ułomnym środowiskiem i można go łatwo „zepsuć”.

Teraz trochę definicji.

Docker jest narzędziem , które pozwala umieścić program oraz jego zależności w przenośnym wirtualnym kontenerze. Umożliwia utworzenie kontenerów zawierających pojedyncze aplikacje ale także łączyć je w większe środowiska.

Ok zaczynamy zabawę.

Najpierw należy zainstalować Dockera na komputerze cały proces jest opisany na zerknij tutaj
W dalszej części będziemy korzystać z narzędzia Docker Compose ono jest dla wersji MAC jak i Windows jest zaszyte w instalacji Docker zaś linuxowcy muszą je osobno doinstalować.

Otwieramy konsole i wpisujemy

docker run hello-world

Jeżeli wszystko przebiegło poprawnie powinniśmy zobaczyć w konsoli to co poniżej.

Sprawdźmy jakie mamy obrazy, powinien być jeden hello-world, aby to sprawdzić piszemy

docker images

i dostajemy

Może co poważniejszego zainstalujmy na przykład nginx

docker container run -it -p 80:80 nginx

Kilka chwil i mamy uruchomioną instancję nginx, otwieramy przeglądarkę i http://localhost/index.html i mamy powitalną stronę

Teraz wyobraźcie sobie ile czasu by to zajęło w konwencjonalnym podejściu instalacja tego pod Windosem 🙂

Kilka przydatnych komend poniżej.

  • docker – wyświetla wszystkie podstawowe komendy
  • docker help – podstawowa komenda dzięki której można sprawdzić składnie oraz wyszukać inne komendy
  • docker pull [nazwaObrazu] – pobranie obrazu
  • docker search [imageName:imageTag] – komenda wyszukuje obrazy o podanej nazwie i tagu
  • docker run [args] [imageName:imageTag/imageId] – stworzenie oraz uruchomienie kontenera z obrazu
  • -it – tryb interaktywny (możemy np: korzystać z bash’a)
  • -p – protokół mapuje wystawiony port naszego kontenera na port naszego localhost
  • -d – tryb deamon, działa na zasadzie usługi
  • -expose – pozwala nam wystawić post naszego kontenera na zewnątrz
  • docker ps – komenda pokazuje nam działające kontenery jeżeli chcemy zobaczyć również te niedziałające docker ps -a
  • docker kill/stop [containerName/containerId] – komenda służy do wyłączenia działającego kontenera. Zazwyczaj korzysta się z containerId z 3 pierwszych znaków
  • docker docker rename [containerOldName] [containerNewName] – komenda służy do zmiany nazwy kontenera
  • docker rm [containerName/containerId] – usunięcie kontenera z naszego komputera o zadanej nazwie lub id
  • docker rmi [imageName:imageTag/imageId] – usuniecie z naszego komputera obrazu o podanej nazwie i tagu lub id

To tylko ułamek wszystkich flag więcej można znaleźć tutaj.

Przejdźmy do konkretów.

A mianowicie chce uruchomić tak jak na wstępie pisałem WordPress + MySQL + phpMyaAmin i swój własny theme i tutaj przyda nam się Docker Compose.
Najpierw usuńmy pozostałości po naszych poprzednich próbach. Zobaczmy co jest zainstalowane najpierw

docker images -a

później

docker rm containerId

– czyli pierwsze 3 znaki kontenera i enter.

Zaczynamy od stworzenia folderu

mkdir docker-setup

następnie

cd docker-setup

i uruchamiam visual studio code przez komendę code .

Do vsc instaluje plugin Docker poniżej


plugin pokazuję kontenery images oraz Docker Hub wystarczy kliknąć na wielorybka, trochę upraszcza nam pracę mniej pisania w konsoli 😉

Na początku tworzę w docker-setup .dockerignore praktycznie coś na styl gita

Następnie tworzę plik docker-compose.yml w nim będzie działać się cała magia 🙂

  • version – oznacza wersję Docker Compose
  • services – sekcja, w której definiujemy serwisy
  • mysql:5.7 – nazwa własna usługi
  • image – wskazujemy z jakiego obrazu ma być zbudowany kontener
  • build – wskazujemy ścieżkę do pliku Dockerfile naszego serwisu – w projekcie nie używamy
  • ports – definiujemy porty, które będą mapowane z konteneru
  • links – zależność pomiędzy kontenerami, db oraz WordPress
  • environment – zmienna środowiskowa dla danego kontenera

Aby uruchomić Docker Compose w naszym terminalu używamy komendy

docerk-compose up

w miejscu w którym mamy docker-compose.yml

Za pierwszym razem wszystkie zależności które są w yml są zaciągane – nasza baza danych jak i WordPress.
Poniżej screen z vsc oraz z chrome w którym mamy WordPress w wersji do zainstalowania 🙂

Dodajmy do tego całego naszego środowiska również phpMyAdmin

phpmyadmin:
 depends_on:
  - db
 image: phpmyadmin/phpmyadmin
 ports:
  - 8080:80
 environment:
  MYSQL_ROOT_PASSOWRD: test

Musimy najpierw zastopować wszystkie kontenery czy to przez „ctrl+c” lub z innej konsoli „docker-compose down” albo z vsc prawy przycisk na poszczególny kontener i Remove Container jak kto woli. Ja używam docker-compose down jest najpewniejszym sposobem zamknięcia uruchomionych kontenerów.

Po dodaniu phpMyAdmin uruchamiamy ponownie „docker-compose up”

Wszystko działa szybciej bo pobierany jest tylko obraz phpMyAdmin, aby sprawdzić czy działa wchodzimy na to co ostawiliśmy mianowicie http://localhost:8080
Podajemy „Użytkownika root Hasło test” tak jak podaliśmy w docker-compose.yml
I naszym oczom ukazuje się phpMyAdmin z utworzoną baza wp

Wracamy do okna http://localhost/wp-admin/install.php tam instalujemy jak zawsze i wypełniamy danymi ale ZARAZ ZARAZ!!! jeśli wyłączymy wszystkie kontenery to co dodaliśmy do WordPress a mianowicie strony, artykuły wszystko to nam zniknie!!! Nie no tak to nie możne być!

Dodajemy własne artykuły wszystko co jest nam potrzebne w WordPressa i za pomocą phpMyAdmin eksportujemy bazę do pliku db.sql (nazwa oczywiście może być inna) nie musimy tego robić możemy pobrać jakąś inną bazę danych z innego WordPress jeżeli takową posiadamy i wystarczy to przygotowania naszego theme.
Dump bazy umieszczam w folderze „data/db.sql” w naszym projekcie oraz dodaje odpowiedni wpis w docker-compose.yml

db:
 image: mysql:5.7
 volumes:
  - ./data:/docker-entrypoint-initdb.d
 restart: always
 ...

volumes pobiera nam db.sql za każdym razem gdy uruchamiamy „docker-compose up” i mamy z głowy uzupełnianie danych w bazie, możemy wejść na http://localhost i zobaczyć naszego WordPress

Dodajemy własne theme.

Teraz druga cześć chcemy dodać własny theme, ponownie stopujemy docker-compose down w głównym folderze naszego projektu dodaje folder wp-content/themes/newTemplate z plikami odpowiedzialnymi za theme.
Teraz aby to zostało zaciągnięte i widoczne w WordPressie należy dodać values tym razem do wpisu wordpress.

Ponownie docker-compose up, teraz możemy pracować na theme, aby zobaczyć zmiany które zrobiliśmy w theme wystarczy odświeżyć WordPress F5 w przeglądarce. Nie trzeba stopować kontenerów.

Źródła znajdują się pod tym adresem

Gulp workflow: minimalizacja zdjęć i konwersja na webp

Kiedyś w zamierzchłych czasach używałem perla + lib ImageMagick do konwersji zdjęć, ale mamy XXI wiek i Node 😉
Od jakiegoś czasu zmienił się mój workflow dotyczący obróbki zdjęć na potrzeby stron internetowych.
Do tej pory używałem gulp-image, gulp-imagemin i wiele innych, ale zawsze coś było nie tak, zawsze czegoś brakowało.
Ostatnio używam takiego zapisu jak poniżej

<picture>
    <source class="img-responsive" srcset="./images/thumbnail/IMG_5600.webp" type="image/webp">
    <source class="img-responsive" srcset="./images/thumbnail/IMG_5600.jpg" type="image/jpeg">
    <img class="img-responsive" src="./images/thumbnail/IMG_5600.jpg" alt="">
</picture>

i potrzebowałem również webp, no i co następna biblioteka gulp-webp jest potrzebna 🙁
Mały research i okazało się że jest biblioteka sharp, która bardzo dobrze zastępuje ImageMagick więcej na tej stronie. Biblioteka ta jest w stanie zastąpić wszystko co do tej poru używałem.

Obecnie korzystam z pluginu gulp-responsive który pod spodem używa tejże biblioteki sharp.
Zmiana rozmiaru obrazu za pomocą tej biblioteki jest zazwyczaj 4x-5x szybsza niż w przypadku najszybszych ustawień ImageMagick i GraphicsMagick, a więc czemu jej nie używać. Oczywiście ta bibliotek nie tylko do zmniejsza grafiki ale również przycina, zmieniania formatu, zapisu do grayscale czyli szarości i wiele innych użytecznych rzeczy potrafi 🙂

Dobra zaczynamy cały proces.
Oczywiście musimy mieć zainstalowane node w naszym środowisku ale to nie temat na ten artykuł.

Na początek tworzymy package.json

npm init -y

Instalujemy wszystkie potrzebne biblioteki

npm i -D gulp gulp-responsive gulp-load-plugins

Tworzymy folder ze zdjęciami „sources” następnie gulpfile.js

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();

gulp.task('images', function () {
    return gulp.src(['sources/**/*.{jpg,png}'])
        .pipe($.responsive({
            '*.jpg': [{
                width: 1200,
                height: 800
            }, {
                // Konwertujemy jpg do formatu webp
                width: 1200,
                height: 800,
                rename: {
                    extname: '.webp'
                }
            }]
        }, {
                // globalne ustawienia
                max: true,
                quality: 65,
                progressive: true,
                withMetadata: false,
                errorOnEnlargement: true
            }))
        .pipe(gulp.dest('dist'));
});

Oczywiście aby ten wynalazek uruchomić należy tak jak wszystkie taski w gulpie czyli:

gulp images

Ustawienia globalne:
max parametr potrzebny gdy zdjęcie jest zrobione w pionie – trzyma proporcje
quality wiadomo jakość dla grafik jpg jak i webp
progressive, jpg ładuje się od góry do dołu linia po linii, progresywny ładuje się całościowo w „kiepskiej” jakości i jest stopniowo wyostrzany
withMetadata usuwane są wszystkie metadane z pliku
errorOnEnlargement pokazuje błędy jeżeli takowe się pojawią

Biblioteka jest bardzo szybka 137 zdjęć (ponad 550MB) w rozdzielczości 2700×1800 zajęło tej bibliotece 32s z ustawieniami globalnymi jak powyżej bez webp. Oczywiście szybkość zależy od hardwaru jaki posiadamy.

Więcej można przeczytać na githubie opisane są tam bardziej skomplikowane użycia tej biblioteki jak dostępne opcje konfiguracyjne.