Bonne journée, mes amis!
L'objectif principal d'un générateur de modules ou d'un bundler comme Webpack ou Parcel est de s'assurer que tous les modules nécessaires à l'exécution de l'application sont inclus dans le bon ordre dans un script minifié (pour la production de production) inclus dans l'index. html.
En fait, les constructeurs, en règle générale, peuvent optimiser non seulement JS, mais aussi HTML, les fichiers CSS, peuvent convertir Less, Sass en CSS, TypeScript, React et Vue (JSX) en JavaScript, travailler avec des images, de l'audio, de la vidéo et autres. formats de données, et fournissent également des fonctionnalités supplémentaires, telles que: la création d'une carte des ressources (utilisées) ou des sources (carte source), une représentation visuelle de la taille du bundle entier et de ses parties individuelles (modules, bibliothèques), la division du code en parties (morceaux), y compris number, à des fins de réutilisation (par exemple, les bibliothèques utilisées dans plusieurs modules sont extraites dans un fichier séparé et chargées une seule fois), chargement intelligent des packages à partir de npm (par exemple, ne chargeant que la localisation russe à partir de moment.js), toutes sortes de plugins pour résoudre des tâches spécifiques etc.
À cet égard, Webpack a incontestablement la tête. Cependant, que se passe-t-il si nous développons un projet dans lequel la plupart des fonctionnalités fournies par cet excellent outil ne sont pas nécessaires? Existe-t-il des alternatives à cette technologie plus faciles à apprendre et à utiliser? Pour moi, la réponse à cette question était Parcel . Au fait, si vous souhaitez en savoir plus sur Webpack, je vous recommande de regarder cette vidéo . Mon fichier avec les paramètres Webpack pour ce tutoriel se trouve ici .
Avec votre permission, je ne raconterai pas la documentation dans mes propres mots, d'autant plus qu'elle est disponible en russe, mais je me concentrerai sur le volet pratique, à savoir: en utilisant des chaînes de modèles et des importations dynamiques, nous créerons un SPA composé de trois pages en JavaScript, stylisez l'application avec CSS, écrivez une fonction simple dans TypeScript, importez-la dans l'application, stylisez le conteneur pour les résultats de cette fonction à l'aide de Sass et créez l'application à l'aide de Parcel dans les modes de développement et de production.
Le code du projet est ici .
Si vous êtes intéressé, suivez-moi.
application
Prêt? Alors allons-y.
Créez le répertoire parcel-tutorial.
Nous y entrons et initialisons le projet en utilisant
npm init -y
.
Créez le fichier index.html. Nous utiliserons l'un des modèles de couverture Bootstrap standard:
<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>
Accédez au site Web officiel de Bootstrap , accédez à la section Exemples, recherchez la couverture dans les composants personnalisés, appuyez sur Ctrl + U (Cmd + U) pour afficher le code de la page.
Créez le répertoire src et il contient deux autres dossiers - js et css.
Créez les fichiers suivants dans le répertoire js: header.js, footer.js, home.js, projects.js et contact.js. Ce sont des modules ou, si vous le souhaitez, des composants de notre application: en-tête, pied de page, contenu de la page principale et autres pages.
Dans le répertoire css, créez un fichier style.css.
Pour le moment, la structure du projet ressemble à ceci:
-- parcel-tutorial
-- src
-- css
-- style.css
-- js
-- contact.js
-- footer.js
-- header.js
-- home.js
-- projects.js
-- index.html
-- index.js
-- package.json
Retour à Bootstrap.
Copiez-collez le code de la page dans les modules correspondants avec des modifications mineures.
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()
Veuillez noter que nous avons changé le href en nom dans les liens.
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()
N'oubliez pas de copier les styles de cover.css vers style.css.
Ouvrez index.js.
Importons l'en-tête, le pied de page et les styles:
import header from './src/js/header.js'
import footer from './src/js/footer.js'
import './src/css/style.css'
Le contenu de la page principale et des autres pages sera chargé dynamiquement lorsque le lien sera cliqué, nous créons donc un tel objet:
const pages = {
home: import('./src/js/home.js'),
projects: import('./src/js/projects.js'),
contact: import('./src/js/contact.js')
}
Le nom de propriété de cet objet est la page correspondante (demandée par l'utilisateur).
Nous générons la page de démarrage en utilisant les composants d'en-tête et de pied de page précédemment importés:
// 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()
Le contenu des pages sera affiché dans l'élément principal, nous le définissons donc:
const mainEl = document.querySelector('main')
Créez une fonction de rendu de page:
const renderPage = async name => {
const template = await pages[name]
mainEl.innerHTML = template.default
}
Nous devons attendre que le module correspondant se charge, nous utilisons donc async / await (le mot-clé await met en pause l'exécution de la fonction). La fonction prend le nom de la page demandée (nom) et l'utilise pour accéder à la propriété correspondante de l'objet pages (pages [nom]). Nous insérons ensuite le modèle résultant dans mainEl. En fait, await renvoie un objet Module qui contient le modèle. Par conséquent, lors de l'insertion d'un modèle comme balisage dans mainEl, il est nécessaire de se référer à la propriété par défaut de l'objet Module (les modules sont exportés par défaut), sinon nous recevrons une erreur - il est impossible de convertir l'objet en HTML.
Rendre la page principale:
renderPage('home')
Le lien actif correspondant à la page courante a la classe active. Nous devons changer de classe lors du rendu d'une nouvelle page. Implémentons la fonction d'assistance:
const toggleClass = (activeLink, currentLink) => {
if (activeLink === currentLink) {
return;
} else {
activeLink.classList.remove('active')
currentLink.classList.add('active')
}
}
La fonction prend deux arguments - un lien avec la classe active (activeLink) et le lien qui a été cliqué (currentLink). Si les liens spécifiés correspondent, nous ne faisons rien. Sinon, nous changeons les classes.
Enfin, nous devons ajouter un gestionnaire de clics sur les liens. Implémentons une autre fonction d'assistance:
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)
}
})
}
Dans cette fonction, nous trouvons d'abord l'élément nav. Ensuite, par délégation, nous traitons les clics de lien: si l'élément cible est la balise A, nous obtenons le lien actif (lien avec la classe active), le lien actuel (le lien sur lequel on a cliqué), changeons les classes et rendons la page. La valeur de l'attribut name du lien actuel est transmise comme argument renderPage.
Nous avons presque terminé avec l'application. Cependant, avant de procéder à la construction d'un projet à l'aide de Parcel, il faut noter ce qui suit: aujourd'hui, la prise en charge des modules dynamiques selon Puis-je utiliser les données est de 90%. C'est beaucoup, mais nous ne sommes pas prêts à perdre 10% de nos utilisateurs. Par conséquent, notre code doit être converti en une syntaxe moins moderne. Babel est utilisé pour la transpilation. Nous devons connecter deux modules supplémentaires:
import "core-js/stable";
import "regenerator-runtime/runtime";
Veuillez noter que nous n'installons pas ces packages avec npm.
Aussi, implémentons immédiatement une fonction dans TypeScript, quelque chose de très simple, comme une fonction pour ajouter deux nombres.
Créez un fichier index.ts dans le répertoire js avec le contenu suivant:
export const sum = (a: number, b: number): number => a + b
La seule différence avec JavaScript, outre l'extension de fichier (.ts), est que nous spécifions explicitement les types de valeurs acceptés et renvoyés par la fonction - dans ce cas, nombre. En fait, on pourrait se limiter à définir le type de retour, TypeScript est suffisamment intelligent pour savoir que si la valeur de retour est un nombre, alors les arguments passés doivent être des nombres. Ça ne fait rien.
Importons cette fonction dans index.js:
import { sum } from './src/js/index.ts'
Et appelez-le avec les arguments 1 et 2 dans renderPage:
const renderPage = async name => {
// ...
mainEl.insertAdjacentHTML('beforeend', `
<output>Result of 1 + 2 -> <span>${sum(1, 2)}<span></output>
`)
}
Stylisation du conteneur de résultats de fonction à l'aide de Sass. Dans le dossier css, créez un fichier style.scss avec le contenu suivant:
$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);
}
}
Importons ces styles dans index.js:
import './src/css/style.scss'
Notez à nouveau que nous n'installons pas TypeScript et Sass avec npm.
Nous avons terminé l'application. Passons à Parcel.
parcelle
Pour installer Parcel globalement, vous devez exécuter la commande
npm i parcel-bundler -g
dans le terminal.
Ouvrez package.json et configurez Parcel pour qu'il s'exécute dans les modes de développement et de production:
"scripts": {
"dev": "parcel index.html --no-source-maps --open",
"pro": "parcel build index.html --no-source-maps --no-cache"
},
L'équipe
npm run dev
commence à construire le projet pour le développement et l'équipe commence npm run pro
pour la production. Mais que signifient tous ces drapeaux? Et pourquoi n'avons-nous pas installé Babel, TypeScript et Sass via npm?
Le fait est que Parcel installe automatiquement toutes les dépendances lorsqu'il détecte leur importation ou leur utilisation dans l'application. Par exemple, si Parcel voit des feuilles de style importées à partir d'un fichier .scss, il installe Sass.
Maintenant sur les équipes et les drapeaux.
Pour construire le projet en mode développement, utilisez la commande
parcel index.html
, où index.html est le point d'entrée de l'application, i.e. un fichier contenant un lien vers le ou les scripts principaux. En outre, cette commande démarre un serveur local à localhost: 1234.
Le drapeau
--no-source-maps
signifie que nous n'avons pas besoin de cartes de ressources.
Drapeau
--open
indique à Parcel d'ouvrir index.html après la création dans un navigateur sur le serveur local.
Pour créer un projet en mode production, utilisez la commande
parcel build index.html
. Cet assemblage suppose la minification des fichiers JS, CSS et HTML.
L'indicateur
--no-cache
signifie la désactivation de la mise en cache des ressources. La mise en cache fournit une vitesse élevée de construction et de reconstruction du projet en temps réel. Ceci est pertinent lors du développement, mais pas trop lors de l'assemblage d'un produit fini.
Encore un point: par défaut, Parcel place les fichiers générés dans le dossier dist, qui est créé s'il manque. Le problème est que lors de la reconstruction, les anciens fichiers ne sont pas supprimés. Pour supprimer ces fichiers, vous avez besoin d'un plugin spécial, par exemple parcel-plugin-clean-easy .
Installez ce plugin en utilisant
npm i parcel-plugin-clean-easy -D
et ajoutez ce qui suit à package.json:
"parcelCleanPaths": [
"dist",
".cache"
]
parcelCleanPaths sont des répertoires à supprimer lors de la reconstruction.
Le colis est maintenant entièrement configuré. Ouvrez un terminal, tapez
npm run dev
, appuyez sur Entrée.
Parcel construit le projet en mode développement, démarre le serveur local et ouvre l'application dans un navigateur. Excellent.
Essayons maintenant de monter un projet pour la production.
Nous exécutons la commande
npm run pro
.
Nous lançons l'application dans le navigateur.
Oups, il semble que quelque chose s'est mal passé.
Jetons un coup d'œil à l'index.html généré. Que voit-on là-bas? Conseil: faites attention aux chemins dans les balises de lien et de script. Je ne sais pas exactement à quoi cela est lié, mais Parcel convertit les liens relatifs en "/ chemin-vers-fichier", et le navigateur ne lit pas ces liens.
Afin de résoudre ce problème, vous devez ajouter l'indicateur "--public-url." Au script "pro".
Nous commençons à reconstruire.
Les chemins relatifs sont corrects et l'application fonctionne. Cool.
C'est tout pour moi. Merci de votre attention.