W tym tygodniu porozmawiamy sobie o tym jak odpalić aplikację React'ową bez użycia webpacka. Dodatkowo różnica między innerText i textContent, prosty ale skuteczny TIP odnośnie logowania zmiennych w konsoli, co nowego w ES9, oraz zapowiedź wpisu o JavasScript modules. Zapraszam.

React without webpack

Dan Abramov przez ostatni tydzień mocno "tweetował" o tym, jak uruchomić aplikację napisaną w React bez użycia webpacka. Tak po prostu - HTML+JS. Dzięki temu dowiedziałem się o istnieniu unpkg.com i o tym, że babel-standalone parsuje <script type="text/babel">. Ale po kolei...

unpkg.com

Robicie szybki POC (Proof of concept)? Nie chcecie setupować projektu poprzez npm init i instalację pakietów? UNPKG.COM przychodzi z pomocą.

Strona serwuje wszyskie pakiety, które możecie znaleźć na npmie poprzez CDN (content delivery network). Żeby dobrać się do interesującego nas pakietu wystarczy wstukać adres:

https://unpkg.com/:package@:version/:file

Jeśli chcemy dodać Reacta do naszej aplikacji poprzez <script> to szukamy:

https://unpkg.com/react

Z automatu zostajemy przekierowani na stronę https://unpkg.com/react@16.4.1/index.js. Niestety nie jest to content, który zadziała w tagu <script>.

Zawartość unpkg.com/react@16.4.1/index.js

'use strict';

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react.production.min.js');
} else {
  module.exports = require('./cjs/react.development.js');
}

Ale to nie problem. Z adresu kasujemy index.js i unpkg serwuje nam zawartość całego folderu paczki React.

Zawartość folderu React

Wchodzimy do folderu umd i wybieramy react.development.js. Taki plik możemy załączyć do naszego pliku index.html.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>React without webpack</title>
    <script src="https://unpkg.com/react@16.4.1/umd/react.development.js"></script>
</head>
<body>
    
</body>
</html>

Sam React to nie wszystko. Do renderowania componentów w naszym drzewie DOM potrzebujemy jeszcze paczki ReactDOM. Plik znajdziemy pod adresem https://unpkg.com/react-dom@16.4.1/umd/react-dom.development.js.

<script src="https://unpkg.com/react@16.4.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4.1/umd/react-dom.development.js"></script>

Od teraz możemy używać Reacta bez kroku budowania ;)

...
<body>
    <div id="root"></div>
    <script>
        const component = React.createElement("div", { className: "my-div" }, "content");
        ReactDOM.render(component, document.querySelector("#root"));
    </script>
</body>
...

Wynikiem powyższego kodu będzie strona:
wynik-kodu

A co z JSX ?

No dobra, ale pisanie komponentów Reactowych bez użycia składni JSX to katorga. Uwierzcie mi...byłem tam - nie polecam ;) Z pomocą przychodzi nam pakiet babel-standalone, który jak dwa poprzednie pakiety Reactowe, znajdziemy na https://unpkg.com/.

<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>

Teraz wystarczy, że zmienimy typ naszego script tag na text/babel i jesteśmy w domu ;) Przeglądarka z automatu próbuje parsować tag <script> traktując go jak text/javascript. Jeśli ustawimy inny typ, przeglądarka nie będzie parsować danego <script> taga. Zrobi to za nas babel.

JSX przy użyciu "text/babel"

<script type="text/babel">
    const Component = ({ children, className }) => (
        <div className={ className }>
            { children }
        </div>
    );

    ReactDOM.render(<Component>content</Component>, document.querySelector("#root"));
</script>

I to wszystko! Możecie zrobić POC bez ustawiania webpacka itp. :)

Wystarczy dodać 3 skrypty:

<script src="https://unpkg.com/react@16.4.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4.1/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>

i ustawić <script type="text/babel">...twój kod JSX...</script>.

Cały boilerplate snippet:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>React without webpack</title>
    <script src="https://unpkg.com/react@16.4.1/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16.4.1/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">

        const Component = ({ children, className }) => (
            <div className={ className }>
                { children }
            </div>
        );
    
        ReactDOM.render(<Component>content</Component>, document.querySelector("#root"));
    </script>
</body>
</html>

UWAGA

--TL;DR--
POC = tak
Produkcja = nie!

Jest tylko jedno "ale", o którym musicie pamiętać. Taki boilerplate jest spoko dla POC, albo gdy uczycie kogoś Reacta, chcecie coś szybko sprawdzić itp. itd. Nigdy nie używajcie tego "na produkcji". Sam babel-standalone zajmuje 1.87 MB. Uwierzcie mi - nie chcecie serwować Waszej aplikacji z takim "overheadem" :) ... Do wydań produkcyjnych użyjcie bundlera, który wykorzysta babela do transpliacji kodu JSX do standardowego JS'a. Co więcej nowoczesne bundlery mają wiele dodatkowych opcji takich jak tree-shaking, minimalizacja kodu itp. itd. :) ...

production ready JSX preprocessor

Dan Abramov słusznie skomentował tweet na temat tego learning loga:

Jeśli nie chcecie używać webacka czy innego bundlera wystarczy, że użyjecie babel-cli i babel-preset-react-app.

$ npm init -y
$ npm install -D babel-cli@6 babel-preset-react-app@3

Następnie odpalacie babela w trybie --watch, który zareaguje na każdą zmianę w pliku źródłowym i przetranspiluje Wam go do postaci docelowej.

$ npx babel --watch src --out-dir . --presets react-app/prod

As simple as Sass compiler :)

Dzięki Dan za komentarz ;)

innerText vs textContent

Jeśli czytaliście moją ostatnią relację z meetjs, to wspominałem tam o tym, że zainteresowała mnie oferta Coders Labu. Wtedy nie chciałem zapeszać, ale dziś mogę Wam zdradzić, że przeszedłem rektruację na wykładowcę i 21 lipca poprowadzę swoje pierwsze, próbne, zajęcia! :) Liczę na nowe, ciekawe doświadzenia i rozwój w sferze przekazywania wiedzy.

Przed prowadzeniem swoich pierwszych zajęć, kandydat na wykładowcę, uczestniczy w zajęciach jako obserwator. W zeszłym tygodniu miałem przyjemność obserwować lekcje z modułu ES6. Jednym z poruszanych tematów były string-templates.

Szablony znaków mają to do siebie, że wstawiają cały tekst pomiędzy znakami `.

const text = `
        some text
`;
// ^^^^^ - te dwa taby wejdą w skład ciągu znaków, 
// tak samo jak znak nowej linii (\n), znajdujący się zaraz po `
// i znak nowej linii po słówku 'text'

Screen-Shot-2018-07-01-at-11.29.27

Wiadomo :) ...prawda ?

No dobra, a wiedzieliście, że jak ustawicie zawartość węzła DOM poprzez innerText to przeglądarka zamieni wam \n na znaczniki <br> ?

zamiana \n na br

Inaczej zadziała ustawienie przez textContent:

Screen-Shot-2018-07-01-at-11.33.31

Za to odczyt jest odwrotny :) innerText zwróci nam tekst bez białych znaków, innerHTML i textContent zwórcą nam wszystkie białe znaki zawarte w tekście.

Załóżmy, że na stronie mamy taki kod:

<body>
    <div id="root">
        Text content
        <div>Some other node text</div>
    </div>
    <script>
        const root = document.querySelector("#root");

        console.log(root.innerHTML);
        console.log(root.innerText);
        console.log(root.textContent);
    </script>
</body>

Wynikiem jaki dostaniemy w consoli będzie:

Screen-Shot-2018-07-01-at-11.35.05

To tak w ramach ciekawostki :)

ES9 - co nowego?

W tym tygodniu został opublikowany nowy standard JavaScript - ES9/ES2018. Jeśli jesteście ciekawi co nowego wnosi do języka to zapraszam do osobnego wpisu na ten temat - ES9 - co nowego?

console.log({ variableName })

Używacie console.log do "debuggowania" Waszych aplikacji? No pewnie! Kto nie używa ;) ...Chociaż debuggowanie to zbyt duże słowo - do debuggowania jest debugger ;) Za to często zdarza mi się logować wartości poszczególnych zmiennych w konsoli.

Niestety jeśli zmiennych mamy kilka to bardzo łatwo można się zgubić.

    const a = true;
    const b = "some text";
    const c = false;
    
    console.log(a, b, c); // true "some text" false

Do prezentacji nazw zmiennych możecie użyć shorthand object properties notation z ES6 :)

console.log({ a, b, c }); // { a: true, b: "some text", c: false }

Mała rzecz a cieszy :)

Console log with shorthand object properties


I tym optymistycznym akcentem kończymy dzisiejszy odcinek learning log'a :)

Jest jeszcze jedna rzecz, której się nauczyłem w tym tygodniu. Chodzi o natywne wsparcie przeglądarek dla modułów JavaScript. Ale jest to na tyle obszerny temat, że postanowiłem go opisać w osobnym wpisie na blogu. Jeśli nie możecie się doczekać - sprawdźcie super artykuł Addy'ego Osmani'ego i Mathias'a Bynens'a Using JavaScript modules.

Trzymajcie się! I do zobaczenia za tydzień w kolejnym learning logu ;)