sql >> Databáze >  >> RDS >> SQLite

Vytvoření první offline aplikace pomocí Node.js a SQLite

„Offline first“ je paradigma vývoje aplikací, ve kterém vývojáři zajišťují, aby funkčnost aplikace nebyla ovlivněna dočasnou ztrátou síťového připojení. Progresivní webové aplikace, které působí jako nativní aplikace, ale běží jako webové aplikace, jsou často postaveny na tomto paradigmatu.

Tento tutoriál vás naučí, jak vytvořit první offline aplikaci s Node.js a databází SQLite. Začněme úvodem do progresivních webových aplikací.

Úvod do PWA

Progresivní webové aplikace (PWA) jsou webové aplikace, které využívají servisní pracovníky, manifesty a další funkce webové platformy a progresivní vylepšování, aby uživatelům poskytly zážitek srovnatelný s nativními aplikacemi.

PWA mohou někdy překonat nativní aplikace, pokud jde o efektivitu. Fungují na vyžádání a jsou vždy k dispozici, aniž by spotřebovávali cennou paměť smartphonu nebo data. Uživatelé spotřebují méně dat, když zvolí PWA před nativní verzí stejné aplikace. Stále mohou uložit PWA na svou domovskou obrazovku; lze jej nainstalovat bez nutnosti úplného stahování.

Co stavíme?

Abychom demonstrovali sílu progresivních webových aplikací, vytvoříme jednoduchou blogovou aplikaci.

Uživatel s ním bude moci komunikovat jako s jinými PWA, jako je Twitter PWA. Pojďme na to.

Inicializovat aplikaci NodeJs

Ušpiníme si ruce. Chcete-li začít, vytvoříme složku projektu pomocí příkazu níže:

mkdir PWA && cd PWA

Poté inicializujeme aplikaci Node.js pomocí příkazů níže:

npm init -y

Výše uvedený příkaz vytvoří package.json soubor pro aplikaci.

Dále vytvořte v naší složce projektu následující strukturu složek:

Nastavení expresního serveru

S nastavením naší aplikace nainstalujme Express a vytvořte náš server Node.js pomocí příkazu níže:

npm install express

Poté vytvoříme několik složek a souborů ve veřejné složce:

  • soubor css/style.css
  • soubor js/app.js

Dále vytvořte index.js soubor v kořenovém adresáři projektu s následujícími úryvky kódu níže:

const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(path.join(__dirname, "public")));

app.get("/", function (req, res) {
  res.sendFile(path.join(__dirname, "public/index.html"));
});
app.listen(8000, () => console.log("Server is running on Port 8000"));

Ve fragmentu kódu importujeme expresní vytvořit náš server a cestu modul. Naši aplikaci jsme nakonfigurovali tak, aby vykreslovala naše statické soubory pomocí express.static metodou, která vede cestu ke statické složce (public), jsme vytvořili kořenovou cestu naší aplikace a vykreslili index.html soubor. Poté jsme aplikaci nakonfigurovali tak, aby naslouchala portu 8000 .

Připojte se k databázi SQLite

S nastavením serveru pro naši aplikaci pojďme vytvořit a připojit naši aplikaci, abychom uložili podrobnosti o našem blogu. Chcete-li začít, spusťte níže uvedený příkaz a nainstalujte závislost sqlite3.

npm install sqlite3

Poté ve vstupním bodě index.js přidejte úryvek kódu níže, abyste vytvořili a připojili aplikaci k databázi SQLite.

const db = new sqlite3.Database("db.sqlite", (err) => {
  if (err) {
    // Cannot open database
    console.error(err.message);
    throw err;
  } else {
    console.log("Connected to the SQLite database.");
  }
});

Dále vytvoříme seznam blogů, které uložíme do naší databáze a později vykreslíme na straně klienta s níže uvedeným fragmentem kódu:

let blogs = [
  {
    id: "1",
    title: "How To Build A RESTAPI With Javascript",
    avatar: "images/coffee2.jpg",
    intro: "iste odio beatae voluptas dolor praesentium illo facere optio nobis magni, aspernatur quas.",
  },
  {
    id: "2",
    title: "How to Build an Offline-First Application with Node.js,"
    avatar: "images/coffee2.jpg",
"iste odio beatae voluptas dolor praesentium illo facere optio nobis magni, aspernatur quas.",
  },
  {
    id: "3",
    title: "Building a Trello Clone with React DnD",
    avatar: "images/coffee2.jpg",
    intro: "iste odio beatae voluptas dolor praesentium illo facere optio nobis magni, aspernatur quas.",
  },
];

Každý blokovaný příspěvek v naší aplikaci bude mít id , název , avatar a úvod pole.

Nyní vytvořte databázovou tabulku s názvem blogy a uložte podrobnosti o blogu, které jsme právě vytvořili výše, pomocí fragmentu kódu níže:

db.run(
  `CREATE TABLE blog (id INTEGER PRIMARY KEY AUTOINCREMENT, title text,avatar text,intro text)`,
  (err) => {
    if (err) {
      // console.log(err)
      // Table already created
    } else {
      // Table just created, creating some rows
      var insert = "INSERT INTO blogs (title, avatar, intro) VALUES (?,?,?)";
      blogs.map((blog) => {
        db.run(insert, [
          `${blog.title}`,
          `${blog.avatar}`,
          `${blog.intro}`,
        ]);
      });
    }
  }
);

Ve fragmentu kódu jsme vytvořili tabulku blogy pomocí db.run. Soubor db.run metoda bere jako parametr dotaz SQL, pak procházíme naše pole blogů a vkládáme je do tabulky blogů, kterou jsme právě vytvořili pomocí funkce map js.

Zobrazení záznamů databáze

Nyní se podívejme na záznamy, které jsme právě vytvořili pomocí Arctype. Chcete-li zobrazit záznamy ve vaší databázi SQLite pomocí Arctype, postupujte takto:

  • Nainstalujte Arctype
  • Spusťte aplikaci pomocí node index.js k vytvoření databáze
  • Spusťte Arctype a klikněte na kartu SQLite

  • Klikněte na Vybrat soubor SQLite a vyhledejte db.sqlite soubor vygenerovaný při spuštění serveru.
  • Měli byste vidět tabulku blogů a záznamy, které vytváříme, jak ukazuje snímek obrazovky níže:

Vykreslit stránku

V tuto chvíli jsme připojili aplikaci k SQLite databázi a také vložili nějaké záznamy do databáze. Nyní otevřete index.html a přidejte následující úryvky kódu níže:

<!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" />
    <link rel="stylesheet" href="css/style.css" />
    <title>Blogger</title>
    <link rel="manifest" href="manifest" />
  </head>
  <body>
    <section>
      <nav>
        <h1>Blogger</h1>
        <ul>
          <li>Home</li>
           <li class="active">Blog</li>
        </ul>
      </nav>
      <div class="container"></div>
    </section>
    <script src="js/app.js"></script>
  </body>
</html>

Vytvořili jsme jednoduché označení s odkazy na náš manifest ve výše uvedeném souboru, který vytvoříme v další sekci styly a app.js soubory.

Poté vytvoříme blogy trasu v našem index.js soubor vrátit blogy na stranu klienta.

...
app.get("/blogs", (req, res) => {
  res.status(200).json({
    blogs,
  });
});
...

V našem public/js/app.js soubor, odešleme žádost o získání do koncového bodu blogu, abychom získali blogy z našeho backendu. Poté procházíme blogy a cílíme na kontejner třídy a zobrazit je.

let result = "";
fetch("http://localhost:8000/blogs")
  .then((res) => res.json())
   .then(({ rows } = data) => {
    rows.forEach(({ title, avatar, intro } = rows) => {
      result += `
       <div class="card">
            <img class="card-avatar" src="/${avatar}"/>
            <h1 class="card-title">${title}</h1>
            <p class="intro">${intro}</p>
            <a class="card-link" href="#">Read</a>
        </div>
       `;
    });
    document.querySelector(".container").innerHTML = result;
  })
  .catch((e) => {
    console.log(e);
  });

Do naší aplikace také přidáme nějaké styly v public/css/style.css s níže uvedeným fragmentem kódu:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background: #fdfdfd;
  font-size: 1rem;
}
section {
  max-width: 900px;
  margin: auto;
  padding: 0.5rem;
  text-align: center;
}
nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
ul {
  list-style: none;
  display: flex;
}
li {
  margin-right: 1rem;
}
h1 {
  color: #0e9c95;
  margin-bottom: 0.5rem;
}
.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  grid-gap: 1rem;
  justify-content: center;
  align-items: center;
  margin: auto;
  padding: 1rem 0;
}
.card {
  display: flex;
  align-items: center;
  flex-direction: column;
  width: 15rem auto;
  background: #fff;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
  border-radius: 10px;
  margin: auto;
  overflow: hidden;
}
.card-avatar {
  width: 100%;
  height: 10rem;
  object-fit: cover;
}
.card-title {
  color: #222;
  font-weight: 700;
  text-transform: capitalize;
  font-size: 1.1rem;
  margin-top: 0.5rem;
}
.card-link {
  text-decoration: none;
  background: #16a0d6e7;
  color: #fff;
  padding: 0.3rem 1rem;
  border-radius: 20px;
  margin: 10px;
}
.intro {
  color: #c2c5c5;
  padding: 10px;
}
.active {
  color: #16a0d6e7;
}

Nyní otevřete package.json soubor a přidejte spouštěcí skript.

"start": "node index.js"

V tomto okamžiku jsme nastavili naši aplikaci. Ale nemůžeme spustit naši aplikaci, když server neběží nebo když není k dispozici síťové připojení pro produkci. Pojďme to nastavit v další sekci.

Optimalizace aplikace

Potřebujeme, aby naše aplikace byla kompatibilní se všemi velikostmi obrazovek. Přidáme také barvu motivu přidáním označení níže do sekce záhlaví našeho index.html soubor.

<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#16a0d6e7"/>

Vytvořte manifest

Musíme popsat naši aplikaci a jak by se měla chovat, když je nainstalována na zařízení uživatele. Můžeme to udělat vytvořením manifestu.

Vytvořte manifest soubor v kořenovém adresáři projektu a přidejte následující konfigurace:

{
    "name": "Blogger"
    "short_name": "Blogger"
    "start_url": "/",
    "display": "standalone",
    "background_color": "#0e9c95",
    "theme_color": "#16a0d6e7",
    "orientation": "portrait",
    "icons": []
}

V našem manifestu jsme definovali následující konfigurace:

  • jméno :Toto definuje zobrazovaný název aplikace.
  • krátký_název :Toto definuje název, který se zobrazí pod ikonou aplikace při instalaci.
  • start_url :Toto sdělí prohlížeči kořenovou adresu URL aplikace.
  • zobrazit :Toto sdělí prohlížeči, jak má aplikaci zobrazit.
  • barva_pozadí: Toto definuje barvu pozadí aplikace při instalaci.
  • theme_color: Toto definuje barvu stavového řádku.
  • orientace: Toto definuje orientaci, která se má použít během zobrazení aplikace.
  • ikony: Toto definuje ikony nebo obrázky různých velikostí, které se mají použít jako domovské ikony naší aplikace.

Ruční vytváření ikon na domovské obrazovce může být velmi komplikovaným úkolem, ale nemusíte se obávat. Využijeme modul třetí strany známý jako pwa-asset-generator ke generování ikon různých velikostí z naší hlavní ikony aplikace ve veřejném adresáři pomocí příkazu níže:

#change directory to the public folder
cd public
#generate icons
npx pwa-asset-generator logo.png icons

Výše uvedený příkaz vytvoří ikony složku ve veřejné složce s mnoha ikonami pro naši aplikaci, spolu s některými JSON na terminálu, který vložíme do našeho pole ikon v manifestu.

Pole ikon v našem manifestu by mělo vypadat takto:

"icons": [
    {
      "src": "public/icons/manifest-icon-192.maskable.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "public/icons/manifest-icon-192.maskable.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "maskable"
    },
    {
      "src": "public/icons/manifest-icon-512.maskable.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "public/icons/manifest-icon-512.maskable.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]

Příkaz také vygeneroval značkovací odkazy na vygenerované ikony.

Zkopírujte a vložte označení do hlavní části označení na public/index.html soubor.

Nastavení servisních pracovníků

S vytvořeným manifestem pojďme nastavit servisní pracovníky. Service worker je část kódu JavaScript, kterou váš prohlížeč spouští na pozadí v samostatném vláknu, aby zpracoval mezipaměť pro aktiva a data, která si ukládáte pro budoucí požadavky, abyste povolili offline podporu pro vaši aplikaci.

Vytvořte tedy blogger.serviceWorker.js veřejné složka. Pro servisního pracovníka existuje mnoho událostí (push, aktivace, instalace, načtení, zpráva, synchronizace), ale pro ukázku v tomto tutoriálu se budeme zabývat instalací, aktivací a načíst Události. Předtím musíme vytvořit pole pro uložení všech prostředků, které jsme použili v naší aplikaci.

const assets = [
  "/",
  "css/style.css",
  "js/app.js",
  "/images/blog1.jpg",
  "/images/blog2.jpg",
  "/images/blog3.jpg,"
];

Poté si poslechneme instalaci událost pro registraci a uložení našich statických souborů do mezipaměti prohlížeče. Dokončení tohoto procesu nějakou dobu trvá. K přeskočení čekání použijeme skipWaiting().

const BLOGGER_ASSETS = "blogger-assets";
self.addEventListener("install", (installEvt) => {
  installEvt.waitUntil(
    caches
      .open(BLOGGER_ASSETS)
      .then((cache) => {
        cache.addAll(assets);
      })
      .then(self.skipWaiting())
      .catch((e) => {
        console.log(e);
      })
  );
});
...

Poté musíme vymazat mezipaměť, abychom odstranili staré prostředky, kdykoli je aktualizován servisní pracovník. Za tímto účelem si poslechneme aktivaci úryvek kódu níže:

...
self.addEventListener("activate", function (evt) {
  evt.waitUntil(
    caches
      .keys()
      .then((keysList) => {
        return Promise.all(
          keysList.map((key) => {
            if (key === BLOGGER_ASSETS) {
              console.log(`Removed old cache from ${key}`);
              return caches.delete(key);
            }
          })
        );
      })
      .then(() => self.clients.claim())
  );
});

Ve výše uvedeném fragmentu kódu používáme waitUntil způsob na servisním pracovníkovi. Tato metoda čeká na dokončení akce a poté zkontrolujeme, zda aktiva, která se snažíme vymazat, jsou aktiva naší aktuální aplikace, než je smažeme.

Dále potřebujeme soubory uložené v naší mezipaměti, abychom je mohli používat.

self.addEventListener("fetch", function (evt) {
  evt.respondWith(
    fetch(evt.request).catch(() => {
      return caches.open(BLOGGER_ASSETS).then((cache) => {
        return cache.match(evt.request);
      });
    })
  );
})

Když je na stránce zadán požadavek, PWA zkontroluje naši mezipaměť a přečte z ní, pokud jsou v mezipaměti data, místo aby šel do sítě. Poté pomocí respondWith způsob, přepíšeme výchozí nastavení prohlížeče a zajistíme, že naše událost vrátí slib. Když je cache kompletní, můžeme vrátit cache odpovídající požadavku evt.request. Když je cache připravena, můžeme vrátit cache, která odpovídá evt.request.

Úspěšně jsme zřídili našeho servisního pracovníka. Nyní jej zpřístupníme v naší aplikaci.

Zaregistrujte servisního pracovníka

Nyní registrujte našeho servisního pracovníka v našem public/js/app.js soubor s níže uvedeným fragmentem kódu:

...
if ("serviceWorker" in navigator) {
  window.addEventListener("load", function () {
    navigator.serviceWorker
      .register("/blogger.serviceWorker.js")
      .then((res) => console.log("service worker registered"))
      .catch((err) => console.log("service worker not registered", err));
  });
}

Zde zkontrolujeme, zda prohlížeč naší aplikace podporuje servisní pracovníky (samozřejmě ne všechny prohlížeče podporují servisní pracovníky), poté zaregistrujeme náš soubor servisních pracovníků.

Nyní spusťte aplikaci pomocí příkazu níže:

npm start

Pro přístup k aplikaci přejděte na localhost:8000 ve svém prohlížeči.

Kontrola Google Lighthouse

Nyní zkontrolujeme, zda jsme správně nastavili naše PWA pomocí kontroly Google Lighthouse. Klikněte pravým tlačítkem myši na svůj prohlížeč a vyberte „kontrola“. Na kartách kontroly vyberte maják a klikněte na vygenerovat zprávu. Pokud s vaší aplikací vše proběhlo v pořádku, měli byste vidět výstup podobný tomu na snímku obrazovky níže:

Úspěšně jsme vytvořili naši první aplikaci. Můžete také zastavit server a otestovat aplikaci v režimu offline.

Závěr

Progresivní webové aplikace (PWA) využívají moderní rozhraní API k poskytování rozšířených možností, spolehlivosti a instalovatelnosti s jedinou kódovou základnou. Umožňují vašemu koncovému uživateli používat vaši aplikaci bez ohledu na to, zda má či nemá připojení k internetu. Měli byste bez obav rozdělit úložiště a přidat do projektu další funkce. Hodně štěstí!


  1. Použití SELECT INTO OUTFILE v MySQL

  2. Zkrátit všechny tabulky v databázi MySQL jedním příkazem?

  3. Vzory šablon a modifikátory pro číselné formátování v PostgreSQL

  4. Jak uložit Java Date do Mysql datetime pomocí JPA