Guten Tag, Freunde!
Der Hauptzweck eines Modul-Builders oder -Bündlers wie Webpack oder Parcel besteht darin, sicherzustellen, dass alle für die Ausführung der Anwendung erforderlichen Module in der richtigen Reihenfolge in einem minimierten Skript (für die Produktionserstellung) enthalten sind, das im Index enthalten ist. html.
Tatsächlich können Builder in der Regel nicht nur JS, sondern auch HTML- und CSS-Dateien optimieren, Less, Sass in CSS, TypeScript, React and Vue (JSX) in JavaScript konvertieren und mit Bildern, Audio, Video und anderen arbeiten Datenformate und bieten außerdem zusätzliche Funktionen, z. B.: Erstellen einer Karte mit (verwendeten) Ressourcen oder Quellen (Quellkarte), visuelle Darstellung der Größe des gesamten Bundles und seiner einzelnen Teile (Module, Bibliotheken), Aufteilen des Codes in Teile (Chunks), einschließlich Nummer, für Wiederverwendungszwecke (zum Beispiel werden Bibliotheken, die in mehreren Modulen verwendet werden, in einer separaten Datei herausgenommen und nur einmal geladen), intelligentes Laden von Paketen von npm (zum Beispiel nur Laden der russischen Lokalisierung von moment.js), alle Arten von Plugins zum Lösen bestimmter Aufgaben usw.
In dieser Hinsicht gehört die Führung natürlich zu Webpack. Was ist jedoch, wenn wir ein Projekt entwickeln, in dem die meisten Funktionen dieses großartigen Tools nicht benötigt werden? Gibt es Alternativen zu dieser Technologie, die einfacher zu erlernen und zu verwenden sind? Für mich war die Antwort auf diese Frage Paket . Übrigens, wenn Sie mehr über Webpack erfahren möchten, empfehle ich Ihnen, dieses Video anzuschauen . Meine Datei mit den Webpack-Einstellungen für dieses Tutorial befindet sich hier .
Mit Ihrer Erlaubnis werde ich die Dokumentation nicht in meinen eigenen Worten nacherzählen, zumal sie auf Russisch verfügbar ist, sondern mich auf die praktische Komponente konzentrieren: Mit Hilfe von Vorlagenzeichenfolgen und dynamischem Import erstellen wir ein SPA, das aus drei Seiten in JavaScript besteht. Formatieren Sie die Anwendung mit CSS, schreiben Sie eine einfache Funktion in TypeScript, importieren Sie sie in die Anwendung, formatieren Sie den Container für die Ergebnisse dieser Funktion mit Sass und erstellen Sie die Anwendung mit Parcel sowohl im Entwicklungs- als auch im Produktionsmodus.
Der Projektcode ist hier .
Wenn Sie interessiert sind, folgen Sie mir bitte.
Anwendung
Bereit? Dann lass uns gehen.
Erstellen Sie das Paket-Tutorial-Verzeichnis.
Wir gehen darauf ein und initialisieren das Projekt mit
npm init -y.
Erstellen Sie die Datei index.html. Wir werden eine der Standard-Bootstrap-Cover-Vorlagen verwenden:
<head>
...
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<!-- Bootstrap class -->
<body class="text-center">
<! -- Main script -->
<script src="index.js"></script>
</body>
Gehen Sie zur offiziellen Bootstrap-Website , gehen Sie zum Abschnitt Beispiele, suchen Sie das Cover in Benutzerdefinierte Komponenten und drücken Sie Strg + U (Befehlstaste + U), um den Seitencode anzuzeigen.
Erstellen Sie das Verzeichnis src, und es befinden sich zwei weitere Ordner darin - js und css.
Erstellen Sie die folgenden Dateien im Verzeichnis js: header.js, footer.js, home.js, projects.js und contact.js. Dies sind Module oder, wenn Sie möchten, Komponenten unserer Anwendung: Kopf- und Fußzeile, Inhalt der Haupt- und anderer Seiten.
Erstellen Sie im CSS-Verzeichnis eine style.css-Datei.
Im Moment sieht die Projektstruktur folgendermaßen aus:
-- parcel-tutorial
-- src
-- css
-- style.css
-- js
-- contact.js
-- footer.js
-- header.js
-- home.js
-- projects.js
-- index.html
-- index.js
-- package.json
Zurück zum Bootstrap.
Kopieren Sie den Seitencode mit geringfügigen Änderungen in die entsprechenden Module.
header.js:
export default `
<header class="masthead mb-auto">
<div class="inner">
<h3 class="masthead-brand">Parcel Tutorial</h3>
<nav class="nav nav-masthead justify-content-center">
<a class="nav-link active" name="home">Home</a>
<a class="nav-link" name="projects">Projects</a>
<a class="nav-link" name="contact">Contact</a>
</nav>
</div>
</header>
`.trim()
Bitte beachten Sie, dass wir die href in den Links geändert haben.
footer.js:
export default `
<footer class="mastfoot mt-auto">
<div class="inner">
<p>© 2020. All rights reserved.</p>
</div>
</footer>
`.trim()
home.js:
export default `
<h1 class="cover-heading">Home page</h1>
<p class="lead">Home page content</p>
`.trim()
projects.js:
export default `
<h1 class="cover-heading">Projects page</h1>
<p class="lead">Projects page content</p>
`.trim()
contact.js:
export default `
<h1 class="cover-heading">Contact page</h1>
<p class="lead">Contact page content</p>
`.trim()
Vergessen Sie nicht, die Stile von cover.css nach style.css zu kopieren.
Öffnen Sie index.js.
Importieren wir die Kopf-, Fuß- und Stile:
import header from './src/js/header.js'
import footer from './src/js/footer.js'
import './src/css/style.css'
Der Inhalt der Haupt- und anderer Seiten wird dynamisch geladen, wenn auf den Link geklickt wird. Daher erstellen wir ein solches Objekt:
const pages = {
home: import('./src/js/home.js'),
projects: import('./src/js/projects.js'),
contact: import('./src/js/contact.js')
}
Der Eigenschaftsname dieses Objekts ist die entsprechende (vom Benutzer angeforderte) Seite.
Wir generieren die Startseite mit den zuvor importierten Kopf- und Fußzeilenkomponenten:
// Bootstrap classes
document.body.innerHTML = `
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
${header}
<main role="main" class="inner cover"></main>
${footer}
</div>
`.trim()
Der Inhalt der Seiten wird im Hauptelement angezeigt, daher definieren wir ihn:
const mainEl = document.querySelector('main')
Erstellen Sie eine Seitenrenderfunktion:
const renderPage = async name => {
const template = await pages[name]
mainEl.innerHTML = template.default
}
Wir müssen warten, bis das entsprechende Modul geladen ist, also verwenden wir async / await (das Schlüsselwort await unterbricht die Ausführung der Funktion). Die Funktion nimmt den Namen der angeforderten Seite (Name) und verwendet ihn, um auf die entsprechende Eigenschaft des Seitenobjekts (Seiten [Name]) zuzugreifen. Wir fügen dann die resultierende Vorlage in mainEl ein. In der Tat gibt await ein Modulobjekt zurück, das die Vorlage enthält. Wenn Sie eine Vorlage als Markup in mainEl einfügen, müssen Sie daher auf die Standardeigenschaft des Module-Objekts verweisen (Module werden standardmäßig exportiert). Andernfalls wird eine Fehlermeldung angezeigt. Es ist nicht möglich, das Objekt in HTML zu konvertieren.
Rendern Sie die Hauptseite:
renderPage('home')
Der aktive Link, der der aktuellen Seite entspricht, hat die aktive Klasse. Wir müssen die Klassen wechseln, wenn wir eine neue Seite rendern. Lassen Sie uns die Hilfsfunktion implementieren:
const toggleClass = (activeLink, currentLink) => {
if (activeLink === currentLink) {
return;
} else {
activeLink.classList.remove('active')
currentLink.classList.add('active')
}
}
Die Funktion akzeptiert zwei Argumente - einen Link mit der Klasse active (activeLink) und dem Link, auf den geklickt wurde (currentLink). Wenn die angegebenen Links übereinstimmen, tun wir nichts. Ansonsten ändern wir die Klassen.
Schließlich müssen wir einen Link-Klick-Handler hinzufügen. Lassen Sie uns noch eine Hilfsfunktion implementieren:
const initClickHandlers = () => {
const navEl = document.querySelector('nav')
navEl.addEventListener('click', ev => {
if (ev.target.tagName === 'A') {
const activeLink = navEl.querySelector('.active')
const currentLink = ev.target
toggleClass(activeLink, currentLink)
renderPage(currentLink.name)
}
})
}
In dieser Funktion finden wir zuerst das nav-Element. Anschließend verarbeiten wir durch Delegierung die Klicks auf die Links: Wenn das Zielelement das A-Tag ist, erhalten wir den aktiven Link (Link mit der aktiven Klasse), den aktuellen Link (den Link, auf den geklickt wurde), ändern die Klassen und rendern die Seite. Der Wert des Namensattributs des aktuellen Links wird als renderPage-Argument übergeben.
Wir sind fast fertig mit der App. Bevor Sie jedoch mit dem Erstellen eines Projekts mit Parcel fortfahren, müssen Sie Folgendes beachten: Heute beträgt die Unterstützung für dynamische Module gemäß Kann ich Daten verwenden 90%? Das ist viel, aber wir sind nicht bereit, 10% unserer Benutzer zu verlieren. Daher muss unser Code in eine weniger moderne Syntax konvertiert werden. Babel wird zur Transpilation verwendet. Wir müssen zwei zusätzliche Module verbinden:
import "core-js/stable";
import "regenerator-runtime/runtime";
Bitte beachten Sie, dass wir diese Pakete nicht mit npm installieren.
Lassen Sie uns außerdem sofort eine Funktion in TypeScript implementieren, die sehr einfach ist, z. B. eine Funktion zum Hinzufügen von zwei Zahlen.
Erstellen Sie eine index.ts-Datei im Verzeichnis js mit folgendem Inhalt:
export const sum = (a: number, b: number): number => a + b
Der einzige Unterschied zu JavaScript, abgesehen von der Dateierweiterung (.ts), besteht darin, dass wir explizit die von der Funktion akzeptierten und zurückgegebenen Wertetypen angeben - in diesem Fall number. Tatsächlich könnten wir uns darauf beschränken, den Rückgabetyp zu definieren. TypeScript ist klug genug zu verstehen, dass die übergebenen Argumente Zahlen sein müssen, wenn der Rückgabewert eine Zahl ist. Unwichtig.
Importieren wir diese Funktion in index.js:
import { sum } from './src/js/index.ts'
Und nennen Sie es mit den Argumenten 1 und 2 in renderPage:
const renderPage = async name => {
// ...
mainEl.insertAdjacentHTML('beforeend', `
<output>Result of 1 + 2 -> <span>${sum(1, 2)}<span></output>
`)
}
Styling des Funktionsergebniscontainers mit Sass. Erstellen Sie im CSS-Ordner eine style.scss-Datei mit folgendem Inhalt:
$color: #8e8e8e;
output {
color: $color;
border: 1px solid $color;
border-radius: 4px;
padding: .5rem;
user-select: none;
transition: transform .2s;
& span {
color: #eee;
}
&:hover {
transform: scale(1.1);
}
}
Importieren wir diese Stile in index.js:
import './src/css/style.scss'
Beachten Sie erneut, dass wir TypeScript und Sass nicht mit npm installieren.
Wir sind mit der Bewerbung fertig. Weiter zum Paket.
Paket
Um Parcel global zu installieren, müssen Sie den Befehl
npm i parcel-bundler -gim Terminal ausführen .
Öffnen Sie package.json und konfigurieren Sie Parcel so, dass es im Entwicklungs- und Produktionsmodus ausgeführt wird:
"scripts": {
"dev": "parcel index.html --no-source-maps --open",
"pro": "parcel build index.html --no-source-maps --no-cache"
},
Das Team
npm run devbeginnt mit dem Aufbau des Projekts für die Entwicklung und das Team beginnt npm run promit der Produktion. Aber was bedeuten all diese Flaggen? Und warum haben wir Babel, TypeScript und Sass nicht über npm installiert?
Tatsache ist, dass Parcel automatisch alle Abhängigkeiten installiert, wenn es deren Import oder Verwendung in der Anwendung erkennt. Wenn Parcel beispielsweise Stylesheets sieht, die aus einer .scss-Datei importiert wurden, wird Sass installiert.
Nun zu den Teams und Flaggen.
Verwenden Sie zum Erstellen des Projekts im Entwicklungsmodus den Befehl
parcel index.html, wobei index.html der Einstiegspunkt der Anwendung ist, d. H. Eine Datei, die einen Link zum Hauptskript oder zu den Hauptskripten enthält. Außerdem startet dieser Befehl einen lokalen Server unter localhost: 1234.
Das Flag
--no-source-mapsbedeutet, dass wir keine Ressourcenkarten benötigen.
Flagge
--openWeist Parcel an, index.html zu öffnen, nachdem ein Browser auf dem lokalen Server erstellt wurde.
Verwenden Sie den Befehl, um ein Projekt im Produktionsmodus zu erstellen
parcel build index.html. Eine solche Assembly setzt die Minimierung von JS-, CSS- und HTML-Dateien voraus.
Das Flag
--no-cachebedeutet, dass das Zwischenspeichern von Ressourcen deaktiviert wird. Caching bietet eine hohe Geschwindigkeit beim Erstellen und Wiederherstellen des Projekts in Echtzeit. Dies ist relevant bei der Entwicklung, aber nicht zu viel bei der Montage eines fertigen Produkts.
Noch ein Punkt: Standardmäßig legt Parcel die generierten Dateien im dist-Ordner ab, der erstellt wird, wenn er fehlt. Das Problem ist, dass beim Neuerstellen alte Dateien nicht gelöscht werden. Um diese Dateien zu entfernen, benötigen Sie ein spezielles Plugin, zum Beispiel Paket-Plugin-Clean-Easy .
Installieren Sie dieses Plugin mit
npm i parcel-plugin-clean-easy -D und fügen Sie Folgendes zu package.json hinzu:
"parcelCleanPaths": [
"dist",
".cache"
]
parcelCleanPaths sind Verzeichnisse, die beim Wiederherstellen entfernt werden müssen.
Das Paket ist jetzt vollständig konfiguriert. Öffnen Sie ein Terminal, geben Sie ein
npm run devund drücken Sie die Eingabetaste.
Parcel erstellt das Projekt im Entwicklungsmodus, startet den lokalen Server und öffnet die Anwendung in einem Browser. Ausgezeichnet.
Versuchen wir nun, ein Projekt für die Produktion zusammenzustellen.
Wir führen den Befehl aus
npm run pro.
Wir starten die Anwendung im Browser.
Ups, es sieht so aus, als wäre etwas schief gelaufen.
Werfen wir einen Blick auf die generierte index.html. Was sehen wir dort? Hinweis: Achten Sie auf die Pfade in den Link- und Skript-Tags. Ich weiß nicht genau, womit es verbunden ist, aber Parcel konvertiert relative Links in "/ path-to-file", und der Browser liest solche Links nicht.
Um dieses Problem zu lösen, müssen Sie dem "Pro" -Skript das Flag "--public-url" hinzufügen.
Wir beginnen mit dem Wiederaufbau.
Die relativen Pfade sind korrekt und die Anwendung funktioniert. Cool.
Das ist alles für mich. Danke für die Aufmerksamkeit.