Собственный Javascript в браузерах развился до такой степени, что использование библиотек может добавить ненужной сложности вашему приложению.

Как видно из данных caniuse.com, мы можем использовать модули уже в 69,19% браузеров, а Custom Elements v1 поддерживается в 78,28% браузеров.

С помощью полифиллов вы можете увеличить эти цифры еще больше.

Итак, сегодня мы напишем небольшое руководство о том, как написать блог, основанный на Custom Elements v1 и поддерживающий только новые модули, без необходимости связывания.

Я буду использовать некоторые самодельные минимальные библиотеки, чтобы упростить код, но вам это не обязательно.

Вы можете просмотреть полный код этого руководства.
https://github.com/tonis2/customElement-app

Итак, начнем.

Структура

Сначала давайте создадим файлы для нашего приложения.

Это простая основа для приложения JavaScript, у нас есть папка компонентов, назовите ее components или pages как хотите, но она содержит пользовательские элементы, которые затем вставляются позже. в приложение.

У нас также есть папка utils, я использую ее для файлов, которые экспортируют модули, которые вы хотели бы использовать внутри своих компонентов.
Они похожи на вспомогательные функции, которые внедряются в компоненты моим движком приложения.

В настоящее время мне нужно использовать его только для внедрения функций выборки JavaScript, поэтому я могу легко выполнять вызовы POST, GET.

Доступ к внедряемым утилитам возможен из конструктора всех компонентов, зарегистрированных в App-engine.

Например.

class Home extends HTMLElement {
  constructor(container) {
    super();
// These are injected into Element via App-engine.
    this.api = container.get("api");
    this.router = container.get("router");
  }

Контейнер — это контейнер карты JavaScript, и он содержит все, что экспортируется из utils index.js.

Маршрутизатор вводится движком автоматически.

Я также использую index.js в своих папках-контейнерах для экспорта всех компонентов.
Например.

//home.js
class Home extends HTMLElement {
  ///component logic
}
export default Home;

и

///index.js 
export {default as home} from "./home.js";

Затем в файле запуска приложения мы можем просто импортировать все компоненты сразу в массив.

import * as components from "./components/index.js";

Запуск приложения

Каждому приложению, конечно же, нужен index.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>App</title>
</head>
<link rel="stylesheet" href="./styles/main.css">
<body>
</body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/custom-elements/1.0.8/custom-elements.min.js"></script>
  <script type="module" src="./index.js" defer></script>
</html>

Это то, что мы собираемся использовать, самое важное место для нас это

<script type="module" src="./index.js" defer></script>

Мы хотим, чтобы наши файлы JavaScript были модульными, иначе мы не можем использовать функции импорта и экспорта.

Далее мы запустим наше приложение в корне index.js.

Сверху импортируем сделанную мной библиотеку App-engine, вы можете сделать свою,
это 50 строк кода + роутер, я использовал роутер Navigo.

Основная работа, которую выполняет движок, заключается в загрузке ваших компонентов и утилит в память, привязке утилит и маршрутизатора к компонентам и предоставлении функции для отображения компонентов на веб-странице.

Итак импортируем все компоненты и утилиты + движок.

import App from "https://cdn.rawgit.com/tonis2/component-engine/58660d22/build/bundle.js";
import * as components from "./components/index.js";
import * as utils from "./utils/index.js";

Затем мы регистрируем наши компоненты/утилиты в движке.
Все зарегистрированные компоненты будут иметь имя файла + «-el»,
поэтому home.js станет "дом-эл"

App.register({ components, utils });

Затем мы должны запустить наш Application router, который уже включен в Engine.
В минимальном варианте использования это выглядит так.

App.router
  .on("/", params => {
    App.renderPage("home-el");
  })
  .on("/post/:id", params => {
    App.renderPage("post-el", post);
  })
  .resolve();
App.router.notFound(() => {
  App.renderPage("home-el");
});

У нас есть маршруты, и когда маршрут приземляется, мы говорим Engine отобразить этот компонент и удалить старый компонент.

См. пример здесь.

Создание компонентов

Чтобы сделать пользовательские элементы, я рекомендую прочитать немного о Custom Elements V1 до этого. компиляция или библиотеки для их использования.

Поскольку у нас нет JSX, к которому привыкли разработчики React, я буду использовать библиотеку light-html, создание элементов Dom по-прежнему не очень удобно для нативного JavaScript.
Использование var element = document.createElement(tagName[, options]);

многое создает большой беспорядок, поэтому, на мой взгляд, самый простой способ создать HTML с помощью нативного JavaScript — это использовать шаблонные строки, а light-html сделает это за вас.

Или вы можете сделать это с помощью нативного js, как описано здесь.

Итак, давайте создадим простую домашнюю страницу с веб-компонентом v1.

Пример получает API и утилиту маршрутизатора в конструкторе, а в connectCallback отображает HTML.

В функции рендеринга я получаю случайные данные сообщений здесь, а затем визуализирую это.
Если вы нажмете на сообщение, оно перенаправит вас к этому сообщению.

Я также использую компонент уведомления просто как пример полезности API пользовательских элементов.
Это код для компонента уведомления

class Notifier extends HTMLElement {
  notify(info) {
    let notification = HTML`<span>${info}</span>`;
notification.render(this);
setTimeout(() => {
      notification.remove();
    }, 2000);
  }
}

Он показывает уведомление, а затем удаляет его.

Поэтому, когда я делаю вызов API, я использую.

let notifier = document.querySelector("notifier-el");
    notifier.notify("Posts loading");

Вы можете использовать тот же метод для анимации загрузки или любой другой логики.

Я не стал рассматривать в этом посте каждый фрагмент кода, который у меня есть в приложении, но обязательно проверьте код github и попробуйте сами.