Webpack

Figyelem: ha bármit parancssorba másolunk copy-paste megoldással, akkor a parancssorban vagy a fejlesztői felület fájljában a ” és a – és a −− karatkereket írjuk újra át kézzel a saját billentyűzetről, különben valamilyen karakterkódolási probléma miatt hibára futunk!

Modul: ha egy utasítássorozat többször is előfordul egy programban, akkor azt a kódrészletet egy külön fájlba szervezzük ki, amely minden más fájl számára hozzáférhető lesz a megfelelő kulcsszavak használatával. A modul tehát egy külön fájlba elhelyezett kódrészlet. Ezeket a modulokat lehet exportálni és importálni. Azaz egy modul több másik modult is importálhat.

Webpack: a webpack egy module bundler (bundle:csomag), amely a modulokból (itt modulnak számítanak a képek, CSS fájlok, JavaSript fájlok) és a feltelepített npm csomagokból egy bundle-t (csomagot) hoz létre. A webpack figyelembe veszi, hogy mi mit tölt be, így elkerüli a duplikációt, hiszen figyeli, hogy egy csomagot betöltöttünk-e már. A nem használt CSS és JavaScript kódokat is képes kezelni, így rövidebb kódot generál.

A használatához telepítve kell hogy legyen a node és az npm. Ellenőrzése parancssorból: node –version; npm –version;

mappa létrehozása; package.json létrehozása: npm init; ha nincs js fájl, akkor az index.js-t tekinti entry point-nak (package.json-ben “main” key); installálni kell: (itt bugos a WordPress: a parancssor nem tudja értelmezni az innen kimásolt ‐‐ jelet, ezért azt írjuk át a billenytűzetről a parancssorban: ‐‐save-dev) npm install ‐‐save-dev webpack webpack-cli webpack-dev-server copy-webpack-plugin css-loader style-loader; (webpack-cli: command line interface a webpack-hoz; webpack-dev-server: ez a webszerver szolgálja ki a fejlesztés idejére az alkalmazást;copy-webpack-plugin: a fájlokat másolja build időben; css-loader, style-loader: a css fájlok bekötéséhez szükséges); ha szeretném. akkor @-cal a verziószámot is megadhatom a függőségnél, pl. style-loader@1.2.1; a ‐‐save-dev kapcsoló: a devDependencies közé veszi fel a függőségeket; ennek annyiban nincs jelentősége, hogy a webpack csak azokat a kódokat tartja meg, amiket az applikáció fel is használ, de fejlesztői szempontból jó, ha látom, hogy mik azok a függőségek, amelyek csak a fejlesztéshez kellenek; az installálás során létrejön a node_modules mappa, ez tartalmazza a függőségeket;

npm install --save-dev webpack webpack-cli webpack-dev-server copy-webpack-plugin css-loader style-loader;

UPDATE (2021 09 01) valamelyik függőség új verziójával valami lehet, így az npm start futtatása hibára fog futni. Használhatjuk a fenti npm telepítések helyett a következő – régebbi verziókat tartalmazó – package.json-t, s így telepítjük a függőségeket az npm install paranccsal (viszont itt egy halom WARN deprecated figyelmeztetést kapunk):

{
  "name": "idojaras2",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "webpack serve",
    "build": "webpack --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "copy-webpack-plugin": "^9.0.1",
    "css-loader": "^5.2.6",
    "file-loader": "^6.2.0",
    "loader": "^2.1.1",
    "sass": "^1.35.2",
    "sass-loader": "^12.1.0",
    "style": "0.0.3",
    "style-loader": "^3.0.0",
    "ttf-loader": "^1.0.2",
    "webpack": "^5.44.0",
    "webpack-cli": "^4.7.2",
    "webpack-dev-server": "^3.11.2"
  },
  "dependencies": {
    "na92-card": "^1.0.0"
  }
}

Az error jelzése ez lesz: options has an unknown property ‘contentBase’; Megoldása: contentBase was renamed to static, azaz a contentBase property-t át kell nevezni static-ra a webpack.config.js fájlban – erről a fájlról mindjárt szó lesz;

ha elküldjük zippelve az alkalmazást, akkor a node_modules mappát hagyjuk ki, a fogadó fél az npm install paranccsal tudja létrehozni a package.json file alapján;

fel kell venni a projekt gyökérmappájában egy webpack.config.js fájlt, ez fogja a webpack-et konfigurálni; (kézzel kell felvenni és kitölteni);

const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const DIST_DIR = path.resolve(__dirname, 'dist');

module.exports = {
    entry: './app.js',
    output: {
        path: DIST_DIR,
        filename: 'bundle.js'
    },
    plugins: [
        new CopyWebpackPlugin({
            patterns: [
                {from: './index.html', to: DIST_DIR}
            ]
        })
    ],
    module: {
        rules: [
          {
            test: /\.css$/i,
            use: [
              "style-loader",
              "css-loader"
            ]
          },
        ]
    },
    devServer: {
        contentBase: DIST_DIR
    },
}

require: függvényhívás, lényegében import; a JS világban többféle import eljárás terjedt el, ezek közül egy a require; path.resolve: az aktuális mappához hozzáfűzi egy dist nevű mappát; DIST_DIR: ennek a dist mappának az elérési útvonala; module.export: ezt az objectet fogja a js fájl kiexportálni, ez lesz a webpack konfigurációja – ezt az objectet fogja a webpack feldolgozni; entry: az alkalmazás belépési pontja, innen indul el az importok sorozata, innen indulva építi ki a függőségek gráfját, itt dől el, hogy mik lesznek azok a függőségek, amelyek végül belefordulnak az itt meghatározott output-ba; output: a build folyamat kimenete, path: ebbe a mappába teszi a kimeneti fájlt; filename: ez lesz a kimeneti fálj, tetszőlegesen elnevezhető, értelemszerűen a dist mappában lesz; szokásos neve bundle.js plugin: a webpacken belül mindent pluginokkal oldunk meg; egy tömböt vár; több plugint is fel tudnánk sorolni; CopyWebpackPlugin: bizonyos fájlokat átmásol a dist mappába; ez azért van, mert az index.html fájlt sehol sem hivatkozzuk be az app.js fájlba, sehol máshol sem, egyszerűen csak azt szeretnénk, hogy ott legyen az alkalmazás gyökerében; module: a modulok, itt most a css-eket tölti be; test: milyen fájlnevekre egyezen a dolog, ezeket a nevű fájlokat akarjuk betölteni;devServer: futtassunk egy devszervert a lebuildelt alkalmazásból

A package.json “scripts” objectjébe két szkriptet kell felvenni: “start”: “webpack serve”, – ez egy webszervert hoz létre és futtatja az alkalmazást; ha közben átírjuk a kódot, akkor automatikusan újratölti; “build”: “webpack –config webpack.config.js”, – ez buildeli a webpack-et a webpack.config.js-nek megfelelően.

"scripts": {
    "start": "webpack serve",
    "build": "webpack --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

futtatásuk: mivel a start beépített npm-es életciklus: npm start vagy npm run-script start; egyéb script parancsok mindig npm run-script előtaggal, azaz build futtatása: npm run-script build; ekkor létre jön a dist mappában a bundle.js; npm start: elindul a szerver; kiírja a terminál: Project is running at http://localhost:8080/; az index.html-be be kell kötni a bundle.js fájlt:<script src=”bundle.js></script>; nem a relatív elérési utat írjuk be, csak a fájl nevet;

A böngészőben a http://localhost:8080/ oldalon egy figyelmeztetést kaphatunk, ezt le kell ikszelni.

Az app.js-be a css közvetlenül beimportálható: import ‘./styles.css’; de beköthetem az index.html-be is: <link rel=”stylesheet” href=”./styles.css”>; ekkor viszont a webpack.config.js fájlban a CopyWebpackPlugin patterns key-hez tartozó tömbben létre kell hozni a {from: ‘./styles.css’, to: DIST_DIR} objectet, hogy a styles.css fájl bemásolódjon a dist-be; ha pl. képet akarunk berakni az index.html-be, akkor az img mappát ugyanúgy be kell copyzni a dist-be: {from: ‘./img’, to: DIST_DIR};

fontok betöltése; Google fonts-ból index.html head-be:  <link href=”https://fonts.googleapis.com/css2?family=Roboto&display=swap” rel=”stylesheet”>

Sass: Syntactically Awesome Style Sheets; fájlkiterjesztés: scss; styles.scss; bővebben: itt;

változók deklarálása:pl. $base-color: #c6538c;

nesting:

.form-container { 
        form{display:flex;align-items:center}
    };

Parent Selector:

button {background:none;
        background-color:$secondary-color;
        color:#FFFFFF;

            &:hover{
                color:white;
                background-color:#254014;
            }

            &:focus{
                background-color: #3DFF4F;
                color: $font-color;
        }
    }

sass, sass-loader installálása: (itt bugos a WordPress: a parancssor nem tudja értelmezni az innen kimásolt ‐‐ jelet, ezért azt írjuk át a billenytűzetről a parancssorban: ‐‐save-dev) npm install ‐‐save-dev sass sass-loader; a devDependencies-be kerül, mert csak fejlesztési időben van rá szükség, a böngészők nem tudnak mit kezdeni a sass fájlokkal; sass: átfordítja a sass fájlokat css fájlokba; sass-loader betölti a sass fájlokat; a build folyamat css-t épít be a bundle-ba, így futásidőben már nincs szükség a sass-ra; test: /.s[ac]ss$/i – ez a sass és a scss fájlokra fog matchcselni; de írhatnánk ezt is helyette: test: /.scss$/i, ekkor csak az scss fájlokra matccsel; ha a styles.css fájlt átnevezzük styles.scss-re, elvileg maradhat benne az eredeti css nyelvű tartalom, a build folyamat azt is érteni fogja;

sass bekötése: webpack.config.js fájlban a module object rules tömbjébe elhelyezni; továbbá app.js-ben: import ‘./styles.scss’

 {
            //test: /\.css$/i,
            test: /\.s[ac]ss$/i,
            use: [
              "style-loader",
              "css-loader",
              "sass-loader"
            ]
          },

documentáció: https://webpack.js.org/loaders/sass-loader/

.gitignore fájl: mit ne töltsön fel a gitre:

verziószám: main.minor.patch; package.json: 1;Patch releases: 1.0 or 1.0.x or ~1.0.4; Minor releases: 1 or 1.x or ^1.0.4; Major releases: * or x; függőségek telepítése package.json megkötései szerint: npm install; a package-lock.json a használt verzió pontos verziószámát tartalmazza, ha ezen verziószámok szerint akarjuk telepíteni a függőségeket (hogy ne vegye figyelembe az esetleges függőségeket), akkor: npm ci

bootstrap elhelyezése: letöltés a mode_nodulesbe: npm install bootstrap; bekötés: a style.scss-be @import: ‘~bootstrap’; a tilde a node_modulesre mutat, ott fogja keresni a könyvtárat;

WebComponents (jegyzet saját részre)

Figyelem: ha bármit parancssorba másolunk copy-paste megoldással, akkor a parancssorban vagy a fejlesztői felület fájljában a ” és a – és a −− karatkereket írjuk újra át kézzel a saját billentyűzetről, különben valamilyen karakterkódolási probléma miatt hibára futunk!

  • Webcomponent: a képernyő egy részének a kinézetéért és működéséért felelős
  • legjobb példák komponensekre: szabványos HTML elemek – ezek tkp. egymástól független, szeparált egységek, melyek a képernyő egy részének a működéséért felelősek
  • Igény: jó lenne saját komponenseket készíteni …
  • erre korábban is volt lehetőség, pl. jQuery User Interface könyvtár, de ezeket a könyvtárakat használni jóval bonyolultabb, mint amit most a webcomponent szabványok lehetővé tesznek

Olyan szabványok összessége, amelyek lehetővé teszik saját készítésű webalkalmazásokhoz komponensek fejlesztését, amit mint (nyitó és zárótag-gel ellátott) html elemet tudunk beágyazni a webalkalmazásunkba; JavaScript könyvtártól és keretrendszertől függetlenül működnek; a böngésző támogatottsága még nem teljes körű; azaz a szabvány még nem jutott el minden böngészőbe, viszont a webcomponent-eket nem önmagukban használjuk, hanem fejlesztést segítő könyvtárak léteznek, amelyek elfedik az inplementáció nehézségeit.

Szabványok:

  • Custom Elements (egyedi elemek): a szabványos DOM bővítése új, saját elemekkel; elkülönülnek a natív HTML elemektől; Custom Elements API segítségével hozhatóak létre;
  • Shadow Dom: olyan funkció, ami lehetővé teszi a böngésző számára, hogy DOM elemeket jelenítsen meg anélkül, hogy a DOM fába ágyazná; a webalkalmazás fejlesztője nem férhet hozzá az árnyék DOM-hoz mint a beágyazott elemek esetében, de a böngésző képes megjeleníteni; a részfa: árnyékfa (shadow tree); az az elem, amihez a shadow tree kapcsolódik, az az árnyékgazda (shadow host); kapcsolás a JavaScript fájlban a Element.attachShadow() paranccsal (részletesen: itt);
  • ez tkp. a DOM fa és a kapcsolódó stílusok egységbe zárása; a webcomponent egy külön, zárt egység lesz a webalkalmazáson belül; a componentnek vannak bemenetei, amelyekkel szabályozhatjuk a megjelenését, azonban az alkalmazás nem láthat bele a komponentbe. Pl. webalkalmazásban definiált CSS szelektor illeszkedik a webcomponent-re, mégsem fordulhat elő, hogy ez módosítaná a webcomponent megjelenését.
  • ES Modules: a JavaScript kódrészletek újrafelhasználható egységekbe zárása
  • HTML Template: újrafelhasználható HTML sablonok definiálása;

Webcomponent – nem kifejezetten elterjedt technológiá; jó néhány éve itt vannak; a technológiának nem lett túl nagy sikere; oka: ma már nem írnak webalkalmazást csak JavaScriptre alapozva, hanem valamilyen fejlesztői könyvtárt vagy keretrendszert használunk, s ezek a keretrendszerek már tartalmaznak megoldást arra, hogy újrafelhasználható komponenseket írjunk az adott technológián belül; Az a tulajdonság, hogy a webkomponenseket keretrendszertől függetlenül tudjuk használni, úgy látszik, annyira nem vonzó a fejlesztők számára.

Könyvtárak: LitElement, Polymer, Stencil

www.github.com/PolymerLabs/lit-element-starter-js

nagy zöld gomb: code > download zip; megnyitás: VS Code; feldobja, hogy telepítsük a megfelelő bővítményeket; ha nem tettük volna, akkor a bővítmény telepítése: .vscode mappa extensions.json file tartalmazza a telepítendő bővítmények listáját: “recommendations”: [“runem.lit-plugin”]; itt csak egy bővítmény: runem.lit-plugin

  • a my-element.js lesz a lényeg, a többi csak körítés
  • dev mappa: egy mintaprojektet tartalmaz, amivel a komponensünket tudjuk kipróbálni
  • docs, docs-src: a fejlesztést segítő dokumentációt tartalmazzák
  • test mappa: webalkalmazáshoz tudunk teszteket készíteni
  • eslintrc.json: statikus kódelemző eszköz konfigurációja; statikus kódelemző: futtatás nélkül vizsgálja a kódot; különböző anti-patterneket keres

a my-element.js a készítendő webkomponens forrásfájlját tartalmazza; a package.json fájl tartalmazza, hogy az alkalmazás milyen külső könyvtárakat és azok melyik verzióját használja; ezeket telepíteni kell; futtatás: integrated terminal: npm install; létrejön a node_modules mappa; parancs: npm run serve – elindítja a mintaprojektet, amivel a webkomponensünket tudjuk tesztelni; url: http://localhost:8000/dev (per dev!)

my-element.js: a :host{ } szelektor a komponens gyökérelemét jelöli ki, itt tudunk olyan css szabályokat adni, amelyek a komponens egészére érvényesek; a properties(){} mezőnél tudjuk a komponens bemeneteit definiálni;pl. title:{type:String}; render(){return html`<h1>${this.title}</h1> …; ezt a bemenetet adhatjuk meg neki kívülről az index.html-ben: <my-element title=”Ez_lesz_a_cím”>…</my-element>

A render metódus adja vissza a komponenshez tartozó html kódot. A <slot></slot> tag-ek közé kerülnek majd be a kívülről beinjektált tartalmak az index.html-ből, azaz a két tag között renderelődik be az, amit a <my-element></my-element> tag-ek közé írtunk.

Komponens átnevezése: replace In Files: my-element > na91-card; myElement > na91Card; my-element.js > na91-card.js; a név első része a szerzőre, a második része a funkcióra utal; globálisan egyedi kell hogy legyen a névütközés elkerülése miatt;

A webkomponens a webalkalmazáson belül egy elszeparált egységként működik, az inspectorban az <na91-card … > alatt ez áll: #shadow-root, ami a webkomponens elszeparált dom fája; ha a webalkalmazás index.html <style>…</style> részében definiálunk egy stílusszabályt, akkor az csak az injektált tartalomra érvényes (a <slot>…</slot>-ban); maga a webkomponens (a nem injektált tartalomra) saját magának definiálja a stílusszabályokat, a kívülről definiált szabályok nem érvényesek rá; a :host{}-ban definiált szabályok az egész webkomponensre érvényesek (öröklődnek), alatta viszont felülírhatjuk azt egy-egy elemre szelektorokkal;pl. return css `:host{color:red} h1{color:green}` a webkomponensen belül;

Ha csak a :host{}-ban adunk meg stílusszabályt, azt felülírhatja az index.html <style>…</style>-ban megadott stílusszabály, de ha a :host{} alatt adunk meg külön szelektorral stílusszabályt a return css “-en belül, akkor azt már nem írja felül.

webkomponens: az na91-card.js-ben beleégetett tartalom; injektált tartalom: az index.html-ben a <na91-card>…</na91-card>-on belül írt tartalom;

font betöltése: index.html; link a Google fonts-ról: <link href=”https://fonts.googleapis.com/css2?family=Roboto&display=swap” rel=”stylesheet”>; a na91-card.js css :host részéhez: font-family: ‘Roboto’, sans-serif;

az index.html-ben a na91-card{} is lehet szelektor és ugyanúgy stílusozható!

A “package.json” fájlban található egy “docs:build” nevű szkript, ennek a futtatásával tudjuk előállítani a webkomponensünkhöz tartozó bundle fájlt. Ez olyan fájl, amely tartalmaz minden függőséget és elég an npm-re publikálni. A parancs: npm run docs:build; a bundle a “docs/komponens-neve.bundled.js” fájlban lesz elérhető;

Létre kell hozni egy npm package-t, ehhez először hozzunk létre egy új mappát; a mappában hozzunk létre egy új fájlt, ez legyen a komponens-neve.js fájl; ebbe másoljuk be az előzőleg létrehozott bundle tartalmát. Adjuk ki az npm init parancsot; ez létrehozza a package.json fájlt. Hozzunk létre egy README.md fájlt, amibe az eredeti index.html-t másoljuk be, hogy a felhasználó tudja, hogy hogyan kell használni a komponensünket.

Publikálás a https://www.npmjs.com oldalra; regisztrációköteles; parancssor:npm login, majd npm pack, majd npm public; csomaghoz patch készítése: npm version patch; npm publish; A komponenst webalkalmazásban használhatjuk, ekkor a parancs a telepítéshez:(itt bugos a WordPress: a parancssor nem tudja értelmezni az innen kimásolt ‐‐ jelet, ezért azt írjuk át a billenytűzetről a parancssorban: ‐‐save) npm install pacakge-név ‐‐save (előtte package.json file létrehozása: npm init); csomag uninstallálása a package-ből: npm uninstall; csomag eltávolítása az npm oldalról: npm unpublish;

tetszőleges html oldal kódjába betehetjük: <na91-card>…</na91-card>; előtte bekötni a na+1-card.js-t: <script type=”module” src=”node_modules/na91-card/na91-card.js”></script>

saját webkomponens: na91-card

Shadow tree létrehozása JavaScript fájlban:

A <new-tag></new-tag>-et beillesztjük az index.html-be.

Vagy:

Vagy:

There are two limitations: We can create only one shadow root per element. The elem must be either a custom element, or one of: “article”, “aside”, “blockquote”, “body”, “div”, “footer”, “h1…h6”, “header”, “main” “nav”, “p”, “section”, or “span”. Other elements, like , can’t host shadow tree. The mode option sets the encapsulation level. It must have any of two values: “open” – the shadow root is available as elem.shadowRoot. Any code is able to access the shadow tree of elem. “closed” – elem.shadowRoot is always null. Forrás: https://javascript.info/shadow-dom

Shadow DOM is strongly delimited from the main document: 1., Shadow DOM elements are not visible to querySelector from the light DOM. In particular, Shadow DOM elements may have ids that conflict with those in the light DOM. They must be unique only within the shadow tree. 2., Shadow DOM has own stylesheets. Style rules from the outer DOM don’t get applied.