JavaScript: Parcel praca z kodem przy minimalnej konfiguracji

Opublikowano: 09.05.2023 - tagi: JavaScript TypeScript Narzędzie

Czym jest Parcel?

Jeśli masz już doświadczenie w pisaniu we front-end coś takiego, jak Webpack pewnie obiło Ci się o uszy.

Parcel to coś podobnego do Webpack'a. Służy do kompilowania kodu jak: JavaScript, TypeScript, CSS/SCSS itp. Czyli pisząc w skrócie Parcel daje programiście wszystko, co potrzebne, żeby zacząć tworzyć aplikacje.

Ktoś może zapytać: skoro istnieje Webpack to po co kolejne tego typu narzędzie?! To, co wyróżnia Parcel to ograniczenie konfiguracji do zbędnego minimum.

Potrzebujesz narzędzia, które: przekompiluje Ci kod z TypeScript do JavaScript? Dodaje style napisane SCSS? Zminimalizuje kod? Stworzy build'a gotowego do wrzucenia na produkcję?

Chcesz po prostu zacząć działać? Użyj Parcel.

Instalacja

Pierwszy krok to instalacja. Wpisz komendę:

npm install --save-dev parcel

Następnie stwórz plik index.html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Parcel</title>
</head>
<body>
<script type="module" src="index.ts"></script>
</body>
</html>

W przykładzie użyjemy TypeScript. Do pliku dołączany jest index.ts, który będzie zawierał cały nasz kod.

Następnie do pliku packge.json dodaj to:

{
  "source": "index.html",
  "scripts": {
    "start": "parcel",
    "build": "parcel build"
  }
}

Skrypt start uruchamia aplikację. Z kolei build tworzy... build'a.

Użycie

Stwórz plik: product.ts i dodaj kod:

interface Product {
	name: string;
	price: number;
}

export const product: Product = {
	name: 'Some product',
	price: 150
}

Teraz index.ts:

import product from './product.ts';

console.log(product); // { name: "Some product", price: 150 }

Wpisz w terminalu komendę:

npm run start

NodeJS: Jak pobrać dane w postaci zwykłych obiektów w Mongoose?

Opublikowano: 06.05.2023 - tagi: NodeJS Baza danych MongoDB Mongoose JavaScript TypeScript Dane

Problem

Pobierając dane za pomocą biblioteki Mongoose dostajesz obiekt lub listę obiektów typu Mongoose document. Tego typu dokument jest znacznie większy od zwykłego obiektu JavaScript.

Ostatnio natknąłem się na jeden problem. Przykład:

const getFromDb = async (id) => {
	return await SomeModel.findOne({ id });
}

const someRow = await getFromDb(id);

expect(someRow.data).toEqual([1, 2, 3, 4]);

Funkcja getFromDb zwraca jakieś dane dla konkretnego rekordu. Sprawdzane jest, czy pole data zawiera odpowiednie dane. Jeśli ten przykład napisany jest w TypeScript to test nie przejdzie, mimo że dane się zgadzają!

W czym jest problem? W typie, jaki Mongoose nadało polu data. Nie jest to zwykłe Array a CoreMongooseArray!

Co zrobić, żeby zwracało zwykłe obiekty JavaScript?

Rozwiązanie

Żeby nie pobierać Mongoose document a zwykłe obiekty wystarczy do zapytania dodać opcję lean:

const getFromDb = async (id) => {
	return await SomeModel.findOne({ id }).lean();
}

Problem rozwiązany!

Dodatkowo wg dokumentacji pobieranie danych w taki sposób jest znacznie szybsze! Czyli same plusy prawda?

Nie do końca. Najpierw trzeba zrozumieć jak działa Mongoose document.

Dokumenty Mongoose

Mongoose pozwala na tworzenie różnych użytecznych funkcji w modelu do przetwarzania danych. Na przykład:

const personSchema = new mongoose.Schema({
  firstName: {
    type: String,
    get: capitalizeFirstLetter
  },
  lastName: {
    type: String,
    get: capitalizeFirstLetter
  }
});

personSchema.virtual('fullName').get(function() {
  return `${this.firstName} ${this.lastName}`;
});

function capitalizeFirstLetter(v) {
  return v.charAt(0).toUpperCase() + v.substring(1);
}

const Person = mongoose.model('Person', personSchema);

await Person.create({ firstName: 'benjamin', lastName: 'sisko' });

const somePerson = await Person.findOne();

console.log(somePerson.fullName); // 'benjamin sisko' zmienione w 'Benjamin Sisko'
console.log(somePerson.firstName); // 'benjamin' zmienione w 'Benjamin' wywołuje capitalizeFirstLetter
console.log(somePerson.lastName); // 'sisko' zmienione w 'Sisko' wywołuje capitalizeFirstLetter

Problem wystąpi gdy wywołasz to samo zapytanie z opcją lean:

...

const somePerson = await Person.findOne().lean();

console.log(somePerson.fullName); // undefined
console.log(somePerson.firstName); // benjamin
console.log(somePerson.lastName); // sisko

Jak widać kosztem użycia lean jest pozbycie się różnego rodzaju pomocniczych funkcjonalności do przetwarzania danych.

Jeśli nie jest Ci to koniecznie potrzebne korzystaj z lean.


Podsumowanie: Kwiecień 2023

Opublikowano: 30.04.2023 - tagi: Podsumowanie Kwiecień 2023 Blog

W kwietniu opublikowałem 4 wpisy:


React:

  1. Do czego służy useReducer?
  2. Obsługa formularzy

Inne:

  1. Blog: Podsumowanie drugiego roku

NodeJS:

  1. Skąd pobrać wersję dla CHROMIUM_REVISION?

Przeczytałem jedną książkę:

  1. Miasto w chmurach - Anthony Doerr

Przesłuchałem trzy audiobooki:

  1. Andromeda - Therese Bohman
  2. Harda - Elżbieta Cherezińska
  3. Hyperfocus - Chris Bailey

React: Obsługa formularzy

Opublikowano: 25.04.2023 - tagi: JavaScript React Formularz

Jak obsługiwać formularze?

Obsługa formularzy w React jest prosta. Istnieją oczywiście biblioteki do przetwarzania danych z formularzy. W tym wpisie podam przykłady, jak ogarnąć formularz bez dodatkowej biblioteki.

Przykłady

Przykład 1 - Pobieranie wartości

import React from 'react';

const App = () => {
    return (
        <>
            <label htmlFor="name">Name:</label>
            <input type="text" id="name" name="name" onChange={(e) => console.log(e.target.value)}/>
        </>
    );
}

Pierwszy przykład pokazuje, jak pobrać dane z danej kontrolki. Żeby, to zrobić należy podpiąć się pod zdarzenie onChange i przekazać funkcję, która pobierze dane.

Przykład 2 - Pobieranie wartości jeszcze raz

import React, { useState } from 'react';

const initFormState = {
    name: '',
    javascript: false,
    java: false,
    swift: false,
}

const App = () => {
    const [formState, setFormState] = useState(initFormState);

    const onChangeHandler = e => {
        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
        setFormState({
            ...formState,
            [e.target.name]: value
        })
    };

    const onSubmitHandler = e => {
        e.preventDefault();
        console.log('formState: ', formState)
    }

    return (
        <>
            <form onSubmit={onSubmitHandler}>
                <label htmlFor="name">Name:</label>
                <input type="text" id="name" name="name" onChange={onChangeHandler} value={formState.name} />
                <fieldset>
                    <legend>Select preferred programming languages</legend>
                    <input type="checkbox" id="javascript" name="javascript" onChange={onChangeHandler} checked={formState.javascript}/>
                    <label htmlFor="javascript">JavaScript</label>
                    <input type="checkbox" id="java" name="java" onChange={onChangeHandler} checked={formState.java}/>
                    <label htmlFor="java">Java</label>
                    <input type="checkbox" id="swift" name="swift" onChange={onChangeHandler} checked={formState.swift}/>
                    <label htmlFor="swift">Swift</label>
                </fieldset>
                <div>
                    <button type="submit">Send</button>
                </div>
            </form>
        </>
    );
}

Można napisać uniwersalną funkcję, która pobierze dane z całego formularza. Spójrz na funkcję onChangeHandler.

Za pomocą linijki kodu:

e.target.value

Możesz pobrać dane prawie ze wszystkich kontrolek. Prawie. Wyjątkiem jest kontrolka typu checkbox. Jeśli masz do czynienia z checkbox użyj:

e.target.checked

Kolejny fragment kodu:

setFormState({
	...formState,
	[e.target.name]: value
})

Odpowiedzialny jest za zaktualizowanie stanu formularza. Żeby to zadziałało, musisz nadać każdej kontrolce formularza nazwę za pomocą atrybutu: name.

Dzięki tak napisanej funkcji onChangeHandler możesz pobrać dane z całego formularza!

Przykład 3 - Wypełnianie formularza danymi

Poniżej przykład jak wypełnić formularz danymi lub go zresetować.

import React, { useState } from 'react';

const initFormState = {
    name: '',
    javascript: false,
    java: false,
    swift: false,
    color: '',
    transport: ''
}

const Form = ({onSubmit, data}) => {
    const [formState, setFormState] = useState(initFormState);

    useEffect(() => {
        setFormState(data);
    }, [data]);

    const onChangeHandler = e => {
        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
        setFormState({
            ...formState,
            [e.target.name]: value
        })
    };

    const onSubmitHandler = e => {
        e.preventDefault();
        onSubmit(formState);
    }

    return (
        <>
            <form onSubmit={onSubmitHandler}>
                <label htmlFor="name">Name:</label>
                <input type="text" id="name" name="name" onChange={onChangeHandler} value={formState.name} />
                <fieldset>
                    <legend>Select preferred programming languages</legend>
                    <input type="checkbox" id="javascript" name="javascript" onChange={onChangeHandler} checked={formState.javascript}/>
                    <label htmlFor="javascript">JavaScript</label>
                    <input type="checkbox" id="java" name="java" onChange={onChangeHandler} checked={formState.java}/>
                    <label htmlFor="java">Java</label>
                    <input type="checkbox" id="swift" name="swift" onChange={onChangeHandler} checked={formState.swift}/>
                    <label htmlFor="swift">Swift</label>
                </fieldset>
                <label htmlFor="color">Select your favorite color</label>
                <select id="color" name="color" onChange={onChangeHandler} value={formState.color}>
                    <option>None selected</option>
                    <option value="red">Red</option>
                    <option value="green">Green</option>
                    <option value="blue">Blue</option>
                </select>
                <fieldset>
                    <legend>Transport</legend>
                    <input type="radio" id="bike" name="transport" value="bike" onChange={onChangeHandler} checked={formState.transport === 'bike'} />
                    <label htmlFor="bike">Bike</label>
                    <input type="radio" id="car" name="transport" value="car" onChange={onChangeHandler} checked={formState.transport === 'car'} />
                    <label htmlFor="car">Car</label>
                    <input type="radio" id="train" name="transport" value="train" onChange={onChangeHandler} checked={formState.transport === 'train'} />
                    <label htmlFor="train">Train</label>
                </fieldset>
                <div>
                    <button type="submit">Send</button>
                </div>
            </form>
        </>
    );
}

const preparedFormState = {
    name: 'Jan Kowalski',
    javascript: false,
    java: false,
    swift: true,
    color: 'green',
    transport: 'bike'
}

const App = () => {
    const [data, setData] = useState(initFormState);

    const onSubmitHandler = formState => {
        console.log('formState: ', formState)
    }

    const onLoadData = () => {
        setData(preparedFormState);
    }

    const onResetForm = () => {
        setData(initFormState);
    }

    return (
        <>
           <Form data={data} onSubmit={onSubmitHandler} />
           <button onClick={onLoadData}>Load data</button>
           <button onClick={onResetForm}>Reset form</button>
        </>
    );
}

NodeJS: Skąd pobrać wersję dla CHROMIUM_REVISION?

Opublikowano: 18.04.2023 - tagi: Backend NodeJS Wersja

Jak zainstalować konkretną wersję?

Biblioteka node-chromium pozwala na zainstalowanie konkretnej wersji Chromium.

Można to zrobić tak:

export NODE_CHROMIUM_REVISION=1129607

lub stworzyć plik .npmrc i dodać:

node_chromium_revision=1129607

Tylko skąd pobrać dokładną rewizję?

Skąd pobrać CHROMIUM_REVISION?

Znalazłem dwa źródła:

Pierwsza strona pozwala na wyszukiwanie na podstawie wersji przeglądarki, ale też rewizji:

https://vikyd.github.io/download-chromium-history-version/#/

Druga wyświetla datę wypuszczenia Chromium + rewizję:

https://registry.npmmirror.com/binary.html?path=chromium-browser-snapshots/