Méthode préférée de création d’un bundle des composants du framework front-end UIkit v3 avec Webpack
Testé fonctionnel UIkit v3.6.19!
Voir aussi: la méthode la plus simple, mais extrêmement limitée en terme de choix des composants qu’on souhaite importer (embarque tous les composants JS du core, embarque les styles d’absolument tous les composants).
Suite à différents tests de génération d’un bundle entièrement à la carte des composants d’UIkit v3 que j’ai effectué et à quelques soucis rencontrés avec l’affichage des icônes, je me suis rendu à l’évidence que le framework open-source développé par YOOTheme n’allait pas pouvoir être intégré à mon projet Symfony dans les règles de l’art.
Pour pouvoir sélectionner à la carte les composants et les icônes qui doivent figurer dans notre bundle (et surtout: retirer tous ceux qui ne vont pas servir!!!) tout en consignant les informations sur notre sélection directement dans le Git de notre projet, nous allons notamment devoir:
- Créer un dossier mirroir des sources d’UIkit (dossier
./node_modules/uikit/*
) dans le dossier qui contient le code spécifique à notre projet (dossier./assets/uikit/*
dans mon cas). - Commenter tous les composants dont nous n’aurons pas besoin pour notre build custom dans les fichiers
assets/uikit/src/scss/theme/_import.scss
etassets/uikit/src/scss/components/_import.scss
(mirroirs de ceux du dossier source./node_modules/uikit/src/scss/*
). - Commenter tous les composants dont nous n’aurons pas besoin pour notre build custom dans les fichiers
assets/uikit/src/js/core/index.js
etassets/uikit/src/js/components/index.js
(mirroirs de ceux du dossier source./node_modules/uikit/src/js/*
). - Consigner notre sélection d’icônes dans des dossiers mirroirs de ceux du dossier source
./node_modules/uikit/src/images/*
- Exécuter un script bash qui va s’occuper de:
- Remplacer les fichiers source de
./node_modules/uikit/*
par leurs versions mirroirs consignées dans./assets/uikit/*
(et ajouter les nouveaux fichiers si il y en a). - Lancer, depuis
./node_modules/uikit
, les commandes de build fournies dans les sources d’UIkit pour notre sélection de composants et d’icônes. - Lancer, depuis la racine du projet Symfony, la commande Webpack de build des sources SCSS, JS et icônes de notre projet (
yarn encore dev
).
- Remplacer les fichiers source de
Cette technique s’inspire du concept de fork, à la différence qu’ici nous n’aurons pas à maintenir un fork à chaque montée de version d’UIkit (un nouveau tag tous les 15 jours au moment où j’écris ces lignes).
Ici, les modifications relatives aux sources d’UIkit sont également versionnées directement dans les sources de notre projet custom alors qu’avec un fork doit avoir par définition son propre dépôt (donc un seul repository à gérer au lieu de deux).
Il s’agit de générer de nouvelles sources « dist » d’UIkit, taillées sur-mesure sur la base de notre propre sélection de composants et d’icônes.
C’est la source présente dans le dossier ./node_modules/uikit/dist
qui est importée par défaut par Webpack lorsque nous déclarons la ligne import UIkit from 'uikit';
dans le fichier assets/app.js
.
Note: en procédant ainsi il devrait (je n’ai pas encore testé) être possible d’ajouter également vos propres composants, développés sur les bases d’UIkit, au build custom.
La configuration de Webpack
Fichier webpack.config.js
Dans la configuration de Webpack, ajouter l’alias pour le chemin vers les sources SCSS d’UIkit dans le dossier ./node_modules
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const Encore = require('@symfony/webpack-encore'); const path = require('path'); [...] Encore .addAliases({ // UIkit: '@uk-scss': path.resolve(__dirname, './node_modules/uikit/src/scss') }) [...] // enables Sass/SCSS support .enableSassLoader() |
Le bundle à la carte des styles (format SCSS)
Note: le build standard des styles d’UIkit (format de sortie/dist CSS) a ceci de particulier qu’il est réalisé à partir des sources LESS. Le framework est bien fourni avec une version SCSS des styles, mais il s’agit juste d’une conversion faite à partir des sources LESS et générée via un script.
En d’autres termes, si nous souhaitons travailler à partir du format SCSS, le build pour cette partie devra être réalisé côté Webpack.
Fichier assets/styles/app.scss
1 2 |
/* Import your custom selection of UIkit components here: */ @import '_uikit-explicit-pieces'; |
Note: selon votre propre organisation de vos fichiers SCSS, l’import de _uikit-explicit-pieces.scss
devrait intervenir très tôt (en tout premier?) dans votre chaîne d’imports.
Fichier assets/styles/_uikit-explicit-pieces.scss
Créer un fichier _uikit-explicit-pieces.scss
qui suit à la lettre les directives de mise en place des styles relatifs au framework front-end UIkit.
L’alias @uk-scss
déclaré plus haut dans le fichier webpack.config.js
est utilisé ici comme racine du chemin vers les fichiers sources.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* * Based on: UIkit v3.6.19 * Source: https://github.com/uikit/uikit/tree/v3.6.19 * Documentation: https://getuikit.com/docs/sass#how-to-build */ /* 1. Your custom variables and variable overwrites. */ //$global-link-color: tomato; /* 2. Import default variables and available mixins. */ @import "@uk-scss/variables-theme.scss"; @import "@uk-scss/mixins-theme.scss"; /* 3. Your custom mixin overwrites. */ //@mixin hook-card() { color: tomato; } /* 4. Import UIkit here: */ //@import "@uk-scss/theme/_import.scss"; // Comment if you don't want to include theme specific styles. @import "@uk-scss/components/_import.scss"; |
Edit: l’utilisation de PurgeCSS avec Webpack rend le reste de la partie SCSS de cet article totalement OBSOLèTE!
Attention: les styles propres à la grille d’UIkit comportent des déclarations de type .uk-child-width-1-4@m
. L’arobase n’étant pas présent dans la regex du defaultExtractor
de PurgeCSS, il faudra faire comme moi dans le code ci-dessous et le rajouter si vous voulez éviter que les styles de la grille soient considérés comme non-utilisés et dégagés du bundle.
En effet, plus besoin d’éditer les fichiers _import.scss
des sources d’UIkit pour commenter les composants dont nous n’avons pas besoin! PurgeCSS se charge de faire le boulot à notre place en scannant les chemins et fichiers que nous allons pointer dans sa configuration pour repérer les IDs et classes que nous utilisons et purement et simplement supprimer toutes les autres de notre bundle!
Voici un exemple à rajouter à la toute fin de votre fichier webpack.config.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[...] // PurgeCSS // if (Encore.isProduction()) { Encore.addPlugin(new PurgeCssPlugin({ paths: glob.sync([ path.join(__dirname, './app/Resources/views/**/*.html.twig'), path.join(__dirname, './web/build/**/*.js') ]), defaultExtractor: (content) => { return content.match(/[\w-/:@]+(?<!:)/g) || []; } })); // } ; // export the final config module.exports = Encore.getWebpackConfig(); |
Cette technique reste une suggestion, mais reconnaissez que c’est tout-de-même bien pratique!
Fichier assets/uikit/src/scss/theme/_import.scss
Ce fichier est, à la base, une copie conforme du fichier source https://github.com/uikit/uikit/blob/v3.6.19/src/scss/theme/_import.scss.
Commenter tous les composants dont vous n’aurez pas besoin pour votre build custom (où commenter carrément l’import de ce fichier dans assets/styles/_uikit-explicit-pieces.scss
si vous pensez que rien ne va vous servir):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
// Base @import "variables.scss"; @import "base.scss"; // Elements @import "link.scss"; @import "heading.scss"; @import "divider.scss"; @import "list.scss"; @import "description-list.scss"; @import "table.scss"; @import "icon.scss"; @import "form-range.scss"; @import "form.scss"; @import "button.scss"; @import "progress.scss"; // Layout @import "section.scss"; @import "container.scss"; @import "tile.scss"; @import "card.scss"; // Common @import "close.scss"; @import "spinner.scss"; @import "marker.scss"; @import "totop.scss"; @import "alert.scss"; @import "placeholder.scss"; @import "badge.scss"; @import "label.scss"; @import "overlay.scss"; @import "article.scss"; @import "comment.scss"; @import "search.scss"; // JavaScript @import "accordion.scss"; @import "drop.scss"; @import "dropdown.scss"; @import "modal.scss"; @import "slider.scss"; @import "sticky.scss"; @import "offcanvas.scss"; @import "leader.scss"; @import "notification.scss"; @import "tooltip.scss"; @import "sortable.scss"; @import "countdown.scss"; @import "grid.scss"; // Navs @import "nav.scss"; @import "navbar.scss"; @import "subnav.scss"; @import "breadcrumb.scss"; @import "pagination.scss"; @import "tab.scss"; @import "slidenav.scss"; @import "dotnav.scss"; @import "thumbnav.scss"; @import "iconnav.scss"; @import "lightbox.scss"; // Utilities @import "animation.scss"; @import "width.scss"; @import "height.scss"; @import "text.scss"; @import "column.scss"; @import "background.scss"; @import "align.scss"; @import "utility.scss"; @import "margin.scss"; @import "padding.scss"; @import "position.scss"; @import "transition.scss"; @import "inverse.scss"; |
Fichier assets/uikit/src/scss/components/_import.scss
Ce fichier est, à la base, une copie conforme du fichier source https://github.com/uikit/uikit/blob/v3.6.19/scss/components/_import.scss.
Commenter tous les composants dont vous n’aurez pas besoin pour votre build custom:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
// Base @import "variables.scss"; @import "mixin.scss"; @import "base.scss"; // Elements @import "link.scss"; //@import "heading.scss"; //@import "divider.scss"; //@import "list.scss"; //@import "description-list.scss"; //@import "table.scss"; @import "icon.scss"; //@import "form-range.scss"; //@import "form.scss"; // After: Icon, Form Range @import "button.scss"; //@import "progress.scss"; // Layout //@import "section.scss"; //@import "container.scss"; //@import "tile.scss"; //@import "card.scss"; // Common @import "close.scss"; // After: Icon //@import "spinner.scss"; // After: Icon //@import "totop.scss"; // After: Icon //@import "marker.scss"; // After: Icon //@import "alert.scss"; // After: Close //@import "placeholder.scss"; //@import "badge.scss"; //@import "label.scss"; //@import "overlay.scss"; // After: Icon //@import "article.scss"; //@import "comment.scss"; //@import "search.scss"; // After: Icon // JavaScript @import "accordion.scss"; //@import "drop.scss"; // After: Card //@import "dropdown.scss"; // After: Card //@import "modal.scss"; // After: Close //@import "slideshow.scss"; //@import "slider.scss"; //@import "sticky.scss"; //@import "offcanvas.scss"; //@import "switcher.scss"; //@import "leader.scss"; @import "notification.scss"; //@import "tooltip.scss"; //@import "sortable.scss"; @import "countdown.scss"; // Scrollspy // Toggle // Scroll @import "grid.scss"; // Navs //@import "nav.scss"; //@import "navbar.scss"; // After: Card, Grid, Nav, Icon, Search //@import "subnav.scss"; //@import "breadcrumb.scss"; //@import "pagination.scss"; //@import "tab.scss"; //@import "slidenav.scss"; // After: Icon //@import "dotnav.scss"; //@import "thumbnav.scss"; //@import "iconnav.scss"; //@import "lightbox.scss"; // After: Close, Slidenav // Utilities //@import "animation.scss"; //@import "width.scss"; //@import "height.scss"; //@import "text.scss"; //@import "column.scss"; //@import "cover.scss"; //@import "background.scss"; //@import "align.scss"; //@import "svg.scss"; //@import "utility.scss"; //@import "flex.scss"; // After: Utility //@import "margin.scss"; //@import "padding.scss"; //@import "position.scss"; //@import "transition.scss"; //@import "visibility.scss"; //@import "inverse.scss"; // Need to be loaded last //@import "print.scss"; |
Les fichiers JS
Fichier assets/app.js
- On importe le fichier SCSS « racine/maître »
app.scss
. C’est celui qui va concentrer l’ensemble des@import
des différents composants. - On importe le bundle* de notre sélection de composants JS via la directive
import UIkit from 'uikit';
. - On importe le bundle* de notre sélection d’icônes via les directives
import Icons from 'uikit/dist/js/uikit-icons'; UIkit.use(Icons);
- On initialise un composant Notification (test)
*: j’explique ça juste en-dessous.
1 2 3 4 5 6 7 8 9 10 11 12 |
// Styles import './styles/app.scss'; // JS (from custom build generated in ./node_modules/uikit/dist/ folder) import UIkit from 'uikit'; // Icons must be imported separately (from custom build generated in ./node_modules/uikit/dist/ folder) import Icons from 'uikit/dist/js/uikit-icons'; UIkit.use(Icons); // Exemple of Notification component inititalization UIkit.notification("Hello World!"); |
Fichier assets/uikit/src/js/core/index.js
Ce fichier est, à la base, une copie conforme du fichier source https://github.com/uikit/uikit/blob/v3.6.19/src/js/core/index.js.
Commenter tous les composants dont vous n’aurez pas besoin pour votre build custom:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
export {default as Accordion} from './accordion'; // export {default as Alert} from './alert'; // export {default as Cover} from './cover'; // export {default as Drop, default as Dropdown} from './drop'; // export {default as FormCustom} from './form-custom'; // export {default as Gif} from './gif'; // export {default as Grid} from './grid'; // export {default as HeightMatch} from './height-match'; // export {default as HeightViewport} from './height-viewport'; export {default as Icon} from './icon'; // export {default as Img} from './img'; // export {default as Leader} from './leader'; // export {default as Margin} from './margin'; // export {default as Modal} from './modal'; // export {default as Nav} from './nav'; // export {default as Navbar} from './navbar'; // export {default as Offcanvas} from './offcanvas'; // export {default as OverflowAuto} from './overflow-auto'; // export {default as Responsive} from './responsive'; // export {default as Scroll} from './scroll'; // export {default as Scrollspy} from './scrollspy'; // export {default as ScrollspyNav} from './scrollspy-nav'; // export {default as Sticky} from './sticky'; // export {default as Svg} from './svg'; // export {default as Switcher} from './switcher'; // export {default as Tab} from './tab'; // export {default as Toggle} from './toggle'; // export {default as Video} from './video'; // Icon components export {Close} from './icon'; // export {Spinner} from './icon'; // export {Slidenav as SlidenavNext} from './icon'; // export {Slidenav as SlidenavPrevious} from './icon'; // export {Search as SearchIcon} from './icon'; // export {IconComponent as Marker} from './icon'; // export {IconComponent as NavbarToggleIcon} from './icon'; // export {IconComponent as OverlayIcon} from './icon'; // export {IconComponent as PaginationNext} from './icon'; // export {IconComponent as PaginationPrevious} from './icon'; // export {IconComponent as Totop} from './icon'; |
Fichier assets/uikit/src/js/components/index.js
Ce fichier est, à la base, une copie conforme du fichier source https://github.com/uikit/uikit/blob/v3.6.19/src/js/components/index.js.
Commenter tous les composants dont vous n’aurez pas besoin pour votre build custom:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
export {default as Countdown} from './countdown'; // export {default as Filter} from './filter'; // export {default as Lightbox} from './lightbox'; // export {default as LightboxPanel} from './lightbox-panel'; export {default as Notification} from './notification'; // export {default as Parallax} from './parallax'; // export {default as Slider} from './slider'; // export {default as SliderParallax} from './slider-parallax'; // export {default as Slideshow} from './slideshow'; // export {default as SlideshowParallax} from './slideshow-parallax'; // export {default as Sortable} from './sortable'; // export {default as Tooltip} from './tooltip'; // export {default as Upload} from './upload'; |
Les icônes
Structure des dossiers (à respecter)
Attention: la documentation d’UIkit vous explique comment remplacer des icônes existantes ou ajouter de nouvelles icônes à votre projet.
Cependant, cette dernière fait mention d’un dossier custom/
dans lequel placer les nouvelles icônes à ajouter à votre projet (avant d’effectuer votre build)… sans préciser à quel endroit de l’arborescence des fichiers du framework celui-ci devrait se trouver (edit: dans src/custom/icons/
)!
La manipulation des icônes fonctionnera très bien si vous déposez vos fichiers de remplacement et vos nouveaux fichiers dans l’un des 3 dossiers suivants:
- Icônes des… erm… (reste à définir):
./assets/uikit/src/images/backgrounds/
- Icônes des composants:
./assets/uikit/src/images/components/
- Icônes de la bibliothèque d’icônes:
./assets/uikit/src/images/icons/
Note: dans le cas où une même icône est utilisée pour un ou plusieurs composants ET dans la bibliothèque (la croix de fermeture par exemple, présente au minimum dans le composant Notification ET dans la bibliothèque), le fichier doit être présent dans les deux dossiers ./assets/uikit/src/images/components/close-icon.svg
et ./assets/uikit/src/images/icons/close.svg
(libellé différent, et le code peut-être différent également pour une même icône, cf. ici (components/close-icon.svg) et là (icons/close.svg)).
Fichier assets/uikit/build/util.js
Ce fichier est, à la base, une copie conforme du fichier source https://github.com/uikit/uikit/blob/v3.6.19/build/util.js.
Je ne donne ci-dessous que la constante const svgo = new SVGO
qui est à modifier avec l’ajout de deux nouveaux paramètres, mais l’intégralité du code issu du fichier source est, bien entendu, à conserver!:
removeAttrs
qui va s’occuper de nettoyer le fichier SVG source en supprimant des attributs, inutiles pour nous, qu’on va par exemple retrouver dans les icônes issues de la populaire bibliothèque Font Awesome.addAttributesToSVGElement
qui va s’occuper d’ajouter les attributswidth="20"
etheight="20"
, nécessaires au bon fonctionnement de la bibliothèque d’icônes UIkit, là où ils manquent. Attention: si ces attributs existent déjà avec des valeurs similaires ou d’autres valeurs, ils ne seront pas écrasés par ce paramètre!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
[...] exports.icons = async function (src) { const svgo = new SVGO({ plugins: [ {removeViewBox: false}, { cleanupNumericValues: { floatPrecision: 3 } }, {convertPathData: false}, {convertShapeToPath: false}, {mergePaths: false}, {removeDimensions: false}, {removeStyleElement: false}, {removeScriptElement: false}, {removeUnknownsAndDefaults: false}, {removeUselessStrokeAndFill: false}, // Remove unwanted attributes // https://github.com/svg/svgo/blob/v1.3.2/examples/test.js#L75 {removeAttrs: {attrs: '(id|class|aria-hidden|focusable|data-prefix|data-icon|role)'}}, // Add "width" and "height" attributes (where missing) with a value of "20" // /!\ Needs to be an array! // /!\ Existant "width" and "height" attributes WON'T be replaced! // https://github.com/svg/svgo/issues/583#issuecomment-275941582 {addAttributesToSVGElement: {attributes: ['width="20"', 'height="20"']}} ] }); [...] |
Petit récapitulatif de l’arborescence attendue
…sous forme de capture d’écran.
Le script bash
Nouvelle méthode (au 04/05/2021):
Dans le fichier package.json
qui devrait se trouver à la racine de votre projet, nous allons ajouter un script qui va générer automatiquement les sources dist optimisées d’UIkit:
1 2 3 4 5 6 7 8 9 |
{ "scripts": { "uk": "./build/build-uikit.sh" }, "devDependencies": { [...] } |
Nous allons ensuite créer un fichier build/build-uikit.sh
qui va contenir le script en question:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#!/usr/bin/env bash # Rendre ce script exécutable: # chmod +x ./build/build-uikit.sh # Générer les sources JS et le sprite d'icônes SVG: # $ yarn run uk # Générer uniquement les sources JS: # $ yarn run uk uikit # Générer uniquement le sprite d'icônes SVG: # $ yarn run uk icons cp -r assets/uikit/* node_modules/uikit/ cd node_modules/uikit # Si le dossier "node_modules" n'existe pas: if [ ! -d "node_modules" ] then npm install fi # Possibilité de passer des arguments: array=("$@") # Si pas d'arguments, on execute la commande par défaut: if [ $# -eq 0 ] then node build/build uikit icons -d # Sinon, on exécute la commande en fonction des arguments passés: else node build/build $@ -d fi |
ATTENTION: afin de rendre ce script exécutable, il faut lancer depuis la racine de votre projet la commande chmod +x ./build/build-uikit.sh
!
Désormais, vous pourrez lancer différentes commandes pour générer votre build à la carte d’UIkit:
yarn run uk
: générer les sources JS et le sprite d’icônes SVG d’UIkityarn run uk uikit
: générer uniquement les sources JS d’UIkityarn run uk icons
: générer uniquement le sprite d’icônes SVG d’UIkit
Note: nous n’avons bien sûr pas de commande relative aux styles car ils sont générés directement via Webpack Encore.
Méthode précédente (dépréciée):
Attention: les sources du framework front-end UIkit consignées dans le dossier node_modules/
de votre projet ont leur propre fichier package.json
. Pour exécuter les différents scripts de build, il convient donc d’avoir au préalable déployé les dépendances Node au sein du dossier à l’aide de la commande npm install
. En d’autres termes, si le dossier node_modules
n’est pas présent dans le dossier ./node_modules/uikit/
, les commandes de build vont vous péter à la tronche :D.
Depuis la racine de votre projet:
On copie nos fichiers custom d’UIkit vers le dossier où sont consignées les sources issues du Git officiel (les fichiers initiaux existants seront écrasés par les nôtres; c’est ce qu’on veut):
1 |
cp -r assets/uikit/* node_modules/uikit/ |
On se rend dans le dossier où sont consignées les sources d’UIkit:
1 |
cd node_modules/uikit |
La manipulation suiffante n’est à effectuer que dans deux cas:
- Vous n’avez encore jamais lancé la commande
npm install
depuis ce dossier et le dossiernode_modules
n’est donc pas présent à la racine de./node_modules/uikit/
. - Vous avez effectué des modifications dans le fichier
./node_modules/uikit/package.json
(vérifier que ce fichier est présent dans./assets/uikit/
; ça peut être une bonne indication du fait qu’il faille lancer les deux commandes ci-dessous).
1 2 |
rm -rf node_modules npm install |
Effectuer un build non-minifié (paramètre -d
– c’est Webpack Encore qui assurera la minification par la suite) des sources JS d’UIkit qui contient uniquement notre sélection de composants et la bibliothèque d’icônes:
1 |
node build/build uikit icons -d |
Note: voir les autres paramètres possibles pour la commande node build/build
.
On retourne à la racine de notre projet et on lance la commande de build propre à Webpack Encore:
1 2 |
cd ../.. yarn encore dev|yarn encore production |
Vos sources pour afficher votre site dans le navigateur sont prêtes!
Quelques chiffres suite à mes tests
- [339 KB] Build JS standard d’UIkit non-minifié (comprend tout le core et tous les composants)
- [136,5 KB] Build JS à la carte d’UIkit non-minifié (comprend uniquement les fonctionnalités du core nécessaires au fonctionnement de ma sélection de composants et les composants suivants: core: accordion, icon | components: countdown, notification – cf. Fichiers JS)
- [130 KB] Build JS standard d’UIkit minifié via les fonctionnalités de build fournies avec le framework
- [52,7 KB] Build JS à la carte d’UIkit minifié via Webpack Encore
Caveats connus!
- Les icônes des composants, si elles proviennent d’une autre source que la bibliothèque UIkit, ne sont pas nettoyées par par les modifications apportées au script de build de cette dernière ce qui occasionne des soucis d’affichage. Solution de correction possible: passer au préalable par Webpack (plutôt que par une modification des scripts de build d’UIkit) pour nettoyer tous les SVG et les rendre « UIkit-compliant » avant de les envoyer vers
./node_modules/uikit/*
et d’effectuer un build.
Méthode alternative (attention: limitations connues au niveau des icônes)
ATTENTION: plusieurs limitations au niveau des icônes avec cette méthode de bundle:
- Les icônes des composants ne s’affichent pas (cf. Diagnostique des erreurs ci-dessous).
- Si la bibliothèque d’icônes (générée séparément) s’affiche bien, cette méthode ne permet de personnaliser celle-ci en ajoutant/supprimant des icônes.
Diagnostique des erreurs:
M’affiche l’erreur suivante en console:
fastdom.js:67 TypeError: Cannot read property ‘cloneNode’ of undefined
at getIcon (icon.js:186)
at UIkitComponent.getSvg (icon.js:63)
at UIkitComponent.connected (svg.js:38)
at hooks.js:10
at Array.forEach ()
at UIkitComponent.UIkit._callHook (hooks.js:10)
at UIkitComponent.UIkit._callConnected (hooks.js:31)
at UIkitComponent.UIkit.$mount (instance.js:28)
at UIkitComponent.UIkit._init (state.js:23)
at new UIkitComponent (global.js:30)
Les icônes des composants sont générées séparément du sprite d’icônes utilisables à la carte (et qui, lui, fonctionne!).
Lorsque je compare aux sources JS fournies dans le dossier dist, je remarque l’absence du code suivant dans mon bundle Webpack:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var closeIcon = "<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" xmlns=\"http://www.w3.org/2000/svg\"><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"1\" y1=\"1\" x2=\"13\" y2=\"13\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"13\" y1=\"1\" x2=\"1\" y2=\"13\"/></svg>"; var closeLarge = "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" x1=\"1\" y1=\"1\" x2=\"19\" y2=\"19\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" x1=\"19\" y1=\"1\" x2=\"1\" y2=\"19\"/></svg>"; var marker = "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"9\" y=\"4\" width=\"1\" height=\"11\"/><rect x=\"4\" y=\"9\" width=\"11\" height=\"1\"/></svg>"; var navbarToggleIcon = "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect y=\"9\" width=\"20\" height=\"2\"/><rect y=\"3\" width=\"20\" height=\"2\"/><rect y=\"15\" width=\"20\" height=\"2\"/></svg>"; var overlayIcon = "<svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"19\" y=\"0\" width=\"1\" height=\"40\"/><rect x=\"0\" y=\"19\" width=\"40\" height=\"1\"/></svg>"; var paginationNext = "<svg width=\"7\" height=\"12\" viewBox=\"0 0 7 12\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" points=\"1 1 6 6 1 11\"/></svg>"; var paginationPrevious = "<svg width=\"7\" height=\"12\" viewBox=\"0 0 7 12\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" points=\"6 1 1 6 6 11\"/></svg>"; var searchIcon = "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"9\" cy=\"9\" r=\"7\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M14,14 L18,18 L14,14 Z\"/></svg>"; var searchLarge = "<svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.8\" cx=\"17.5\" cy=\"17.5\" r=\"16.5\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.8\" x1=\"38\" y1=\"39\" x2=\"29\" y2=\"30\"/></svg>"; var searchNavbar = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10.5\" cy=\"10.5\" r=\"9.5\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"23\" y1=\"23\" x2=\"17\" y2=\"17\"/></svg>"; var slidenavNext = "<svg width=\"14\" height=\"24\" viewBox=\"0 0 14 24\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" points=\"1.225,23 12.775,12 1.225,1 \"/></svg>"; var slidenavNextLarge = "<svg width=\"25\" height=\"40\" viewBox=\"0 0 25 40\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"2\" points=\"4.002,38.547 22.527,20.024 4,1.5 \"/></svg>"; var slidenavPrevious = "<svg width=\"14\" height=\"24\" viewBox=\"0 0 14 24\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" points=\"12.775,1 1.225,12 12.775,23 \"/></svg>"; var slidenavPreviousLarge = "<svg width=\"25\" height=\"40\" viewBox=\"0 0 25 40\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"2\" points=\"20.527,1.5 2,20.024 20.525,38.547 \"/></svg>"; var spinner = "<svg width=\"30\" height=\"30\" viewBox=\"0 0 30 30\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" cx=\"15\" cy=\"15\" r=\"14\"/></svg>"; var totop = "<svg width=\"18\" height=\"10\" viewBox=\"0 0 18 10\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" points=\"1 9 9 1 17 9 \"/></svg>"; |
Pas de résolution à ce jour.
Fichiers impliqués
Fichier assets/app.js
1 2 3 4 5 6 7 |
// Styles import './uikit-explicit-pieces.scss' // JS import UIkit from './uikit-explicit-pieces'; // UIkit UIkit.notification("Hello World!"); |
Fichier webpack.config.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const Encore = require('@symfony/webpack-encore'); const path = require('path'); [...] Encore .addAliases({ // UIkit JS: 'uikit-util': path.resolve(__dirname, './node_modules/uikit/src/js/util'), '@uk-js': path.resolve(__dirname, './node_modules/uikit/src/js'), '@uk-scss': path.resolve(__dirname, './node_modules/uikit/src/scss') }) [...] // enables Sass/SCSS support .enableSassLoader() |
Bundle Javascript – Fichier assets/uikit-explicit-pieces.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
/* * Based on: UIkit v3.6.19 * Source: https://github.com/uikit/uikit/tree/v3.6.19 * Documentation: https://getuikit.com/docs/javascript */ /* * Overrides: * ./node_modules/uikit/src/js/uikit-core.js * ./node_modules/uikit/src/js/uikit.js */ // import UIkit from 'uikit/src/js/api/index'; /* * Overrides: * ./node_modules/uikit/src/js/api/index.js * * Override needed because of the "UIkit.version = VERSION;" line that generates an * "Uncaught ReferenceError: VERSION is not defined" error in browser console! */ import globalAPI from '@uk-js/api/global'; import hooksAPI from '@uk-js/api/hooks'; import stateAPI from '@uk-js/api/state'; import instanceAPI from '@uk-js/api/instance'; import componentAPI from '@uk-js/api/component'; import * as util from 'uikit-util'; const UIkit = function (options) { this._init(options); }; UIkit.util = util; UIkit.data = '__uikit__'; UIkit.prefix = 'uk-'; UIkit.options = {}; // UIkit.version = VERSION; globalAPI(UIkit); hooksAPI(UIkit); stateAPI(UIkit); componentAPI(UIkit); instanceAPI(UIkit); /* END: Overrides: ./node_modules/uikit/src/js/api/index.js */ import Core from '@uk-js/core/core'; import boot from '@uk-js/api/boot'; // import * as components from 'uikit/src/js/core/index'; /* * Overrides: * ./node_modules/uikit/src/js/core/index.js */ import {Accordion, Alert, Cover, Drop, Dropdown, FormCustom, Gif, Grid, HeightMatch, HeightViewport, Icon, Img, Leader, Margin, Modal, Nav, Navbar, Offcanvas, OverflowAuto, Responsive, Scroll, Scrollspy, ScrollspyNav, Sticky, Svg, Switcher, Tab, Toggle, Video} from '@uk-js/core/index'; // Icon components import {Close, Spinner, Slidenav as SlidenavNext, Slidenav as SlidenavPrevious, Search as SearchIcon, IconComponent as Marker, IconComponent as NavbarToggleIcon, IconComponent as OverlayIcon, IconComponent as PaginationNext, IconComponent as PaginationPrevious, IconComponent as Totop} from '@uk-js/core/icon'; /* END: Overrides: ./node_modules/uikit/src/js/core/index.js */ /* From: ./node_modules/uikit/src/js/uikit.js */ // import * as components from 'uikit/src/js/components/index'; /* * Overrides: * ./node_modules/uikit/src/js/components/index.js */ import {Countdown, Filter, Lightbox, LightboxPanel, Notification, Parallax, Slider, SliderParallax, Slideshow, SlideshowParallax, Sortable, Tooltip, Upload} from '@uk-js/components/index'; /* END: Overrides: ./node_modules/uikit/src/js/components/index.js */ import {each} from '@uk-js/util/lang'; // register components /* Declare your selection of UIkit components to be included in the Webpack build and registered here: */ const components = { /* Core components */ Accordion, Alert, Cover, Drop, Dropdown, FormCustom, Gif, Grid, HeightMatch, HeightViewport, Icon, Img, Leader, Margin, Modal, Nav, Navbar, Offcanvas, OverflowAuto, Responsive, Scroll, Scrollspy, ScrollspyNav, Sticky, Svg, Switcher, Tab, Toggle, Video, /* Core components: icon */ Close, Spinner, SlidenavNext, SlidenavPrevious, SearchIcon, Marker, NavbarToggleIcon, OverlayIcon, PaginationNext, PaginationPrevious, Totop, /* Additional components */ Countdown, Filter, Lightbox, LightboxPanel, Notification, Parallax, Slider, SliderParallax, Slideshow, SlideshowParallax, Sortable, Tooltip, Upload }; each(components, (component, name) => UIkit.component(name, component) ); // core functionality UIkit.use(Core); /* Icons must be imported separately, from node_modules/uikit/dist/ folder */ import Icons from 'uikit/dist/js/uikit-icons'; UIkit.use(Icons); boot(UIkit); /* END: Overrides: ./node_modules/uikit/src/js/uikit-core.js, ./node_modules/uikit/src/js/uikit.js */ /* FINALLY, export everything into 'UIkit' object. */ export default UIkit; |
Bundle Styles – Fichier: uikit-explicit-pieces.scss
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
/* * Based on: UIkit v3.6.19 * Source: https://github.com/uikit/uikit/tree/v3.6.19 * Documentation: https://getuikit.com/docs/sass */ /* 1. Your custom variables and variable overwrites. */ //$global-link-color: #DA7D02; /* 2. Import default variables and available mixins. */ @import "@uk-scss/variables-theme.scss"; @import "@uk-scss/mixins-theme.scss"; /* 3. Your custom mixin overwrites. */ //@mixin hook-card() { color: #000; } /* 4. Import UIkit here: */ /* * Overrides: * ./node_modules/uikit/src/scss/uikit-theme.scss */ // // Theme // //@import "@uk-scss/theme/theme/_import.scss"; /* * Overrides: * ./node_modules/uikit/src/scss/theme/_import.scss */ /* * [DEV NOTE] Sachant que les fichiers importés ci-dessous sont relatifs au thème, ils devraient: * - N'être importés qu'à la condition qu'on souhaite personnaliser le rendu graphique du composant en question * - N'être importés de node_modules qu'à la condition qu'ils nous conviennent en l'état... * - ...sinon, être surchargés (en partant impérativement d'un copier-coller de l'original) et modifiés dans le thème */ // Base //@import "@uk-scss/theme/variables.scss"; //@import "@uk-scss/theme/base.scss"; // Elements //@import "@uk-scss/theme/link.scss"; //@import "@uk-scss/theme/heading.scss"; //@import "@uk-scss/theme/divider.scss"; //@import "@uk-scss/theme/list.scss"; //@import "@uk-scss/theme/description-list.scss"; //@import "@uk-scss/theme/table.scss"; //@import "@uk-scss/theme/icon.scss"; //@import "@uk-scss/theme/form-range.scss"; //@import "@uk-scss/theme/form.scss"; //@import "@uk-scss/theme/button.scss"; //@import "@uk-scss/theme/progress.scss"; // Layout //@import "@uk-scss/theme/section.scss"; //@import "@uk-scss/theme/container.scss"; //@import "@uk-scss/theme/tile.scss"; //@import "@uk-scss/theme/card.scss"; // Common //@import "@uk-scss/theme/close.scss"; //@import "@uk-scss/theme/spinner.scss"; //@import "@uk-scss/theme/marker.scss"; //@import "@uk-scss/theme/totop.scss"; //@import "@uk-scss/theme/alert.scss"; //@import "@uk-scss/theme/placeholder.scss"; //@import "@uk-scss/theme/badge.scss"; //@import "@uk-scss/theme/label.scss"; //@import "@uk-scss/theme/overlay.scss"; //@import "@uk-scss/theme/article.scss"; //@import "@uk-scss/theme/comment.scss"; //@import "@uk-scss/theme/search.scss"; // JavaScript //@import "@uk-scss/theme/accordion.scss"; //@import "@uk-scss/theme/drop.scss"; //@import "@uk-scss/theme/dropdown.scss"; //@import "@uk-scss/theme/modal.scss"; //@import "@uk-scss/theme/slider.scss"; //@import "@uk-scss/theme/sticky.scss"; //@import "@uk-scss/theme/offcanvas.scss"; //@import "@uk-scss/theme/leader.scss"; //@import "@uk-scss/theme/notification.scss"; //@import "@uk-scss/theme/tooltip.scss"; //@import "@uk-scss/theme/sortable.scss"; //@import "@uk-scss/theme/countdown.scss"; //@import "@uk-scss/theme/grid.scss"; // Navs //@import "@uk-scss/theme/nav.scss"; //@import "@uk-scss/theme/navbar.scss"; //@import "@uk-scss/theme/subnav.scss"; //@import "@uk-scss/theme/breadcrumb.scss"; //@import "@uk-scss/theme/pagination.scss"; //@import "@uk-scss/theme/tab.scss"; //@import "@uk-scss/theme/slidenav.scss"; //@import "@uk-scss/theme/dotnav.scss"; //@import "@uk-scss/theme/thumbnav.scss"; //@import "@uk-scss/theme/iconnav.scss"; //@import "@uk-scss/theme/lightbox.scss"; // Utilities //@import "@uk-scss/theme/animation.scss"; //@import "@uk-scss/theme/width.scss"; //@import "@uk-scss/theme/height.scss"; //@import "@uk-scss/theme/text.scss"; //@import "@uk-scss/theme/column.scss"; //@import "@uk-scss/theme/background.scss"; //@import "@uk-scss/theme/align.scss"; //@import "@uk-scss/theme/utility.scss"; //@import "@uk-scss/theme/margin.scss"; //@import "@uk-scss/theme/padding.scss"; //@import "@uk-scss/theme/position.scss"; //@import "@uk-scss/theme/transition.scss"; //@import "@uk-scss/theme/inverse.scss"; /* END: Overrides: ./node_modules/uikit/src/scss/theme/_import.scss */ //@import "@uk-scss/theme/components/_import.scss"; /* * Overrides: * ./node_modules/uikit/src/scss/components/_import.scss */ // Base @import "@uk-scss/components/variables.scss"; @import "@uk-scss/components/mixin.scss"; @import "@uk-scss/components/base.scss"; // Elements @import "@uk-scss/components/link.scss"; @import "@uk-scss/components/heading.scss"; @import "@uk-scss/components/divider.scss"; @import "@uk-scss/components/list.scss"; @import "@uk-scss/components/description-list.scss"; @import "@uk-scss/components/table.scss"; @import "@uk-scss/components/icon.scss"; @import "@uk-scss/components/form-range.scss"; @import "@uk-scss/components/form.scss"; // After: Icon, Form Range @import "@uk-scss/components/button.scss"; @import "@uk-scss/components/progress.scss"; // Layout @import "@uk-scss/components/section.scss"; @import "@uk-scss/components/container.scss"; @import "@uk-scss/components/tile.scss"; @import "@uk-scss/components/card.scss"; // Common @import "@uk-scss/components/close.scss"; // After: Icon @import "@uk-scss/components/spinner.scss"; // After: Icon @import "@uk-scss/components/totop.scss"; // After: Icon @import "@uk-scss/components/marker.scss"; // After: Icon @import "@uk-scss/components/alert.scss"; // After: Close @import "@uk-scss/components/placeholder.scss"; @import "@uk-scss/components/badge.scss"; @import "@uk-scss/components/label.scss"; @import "@uk-scss/components/overlay.scss"; // After: Icon @import "@uk-scss/components/article.scss"; @import "@uk-scss/components/comment.scss"; @import "@uk-scss/components/search.scss"; // After: Icon // JavaScript @import "@uk-scss/components/accordion.scss"; //@import "@uk-scss/components/drop.scss"; // After: Card //@import "@uk-scss/components/dropdown.scss"; // After: Card //@import "@uk-scss/components/modal.scss"; // After: Close //@import "@uk-scss/components/slideshow.scss"; //@import "@uk-scss/components/slider.scss"; //@import "@uk-scss/components/sticky.scss"; //@import "@uk-scss/components/offcanvas.scss"; //@import "@uk-scss/components/switcher.scss"; //@import "@uk-scss/components/leader.scss"; @import "@uk-scss/components/notification.scss"; //@import "@uk-scss/components/tooltip.scss"; //@import "@uk-scss/components/sortable.scss"; @import "@uk-scss/components/countdown.scss"; // Scrollspy // Toggle // Scroll @import "@uk-scss/components/grid.scss"; // Navs @import "@uk-scss/components/nav.scss"; @import "@uk-scss/components/navbar.scss"; // After: Card, Grid, Nav, Icon, Search @import "@uk-scss/components/subnav.scss"; @import "@uk-scss/components/breadcrumb.scss"; @import "@uk-scss/components/pagination.scss"; @import "@uk-scss/components/tab.scss"; @import "@uk-scss/components/slidenav.scss"; // After: Icon @import "@uk-scss/components/dotnav.scss"; @import "@uk-scss/components/thumbnav.scss"; @import "@uk-scss/components/iconnav.scss"; @import "@uk-scss/components/lightbox.scss"; // After: Close, Slidenav // Utilities @import "@uk-scss/components/animation.scss"; @import "@uk-scss/components/width.scss"; @import "@uk-scss/components/height.scss"; @import "@uk-scss/components/text.scss"; @import "@uk-scss/components/column.scss"; @import "@uk-scss/components/cover.scss"; @import "@uk-scss/components/background.scss"; @import "@uk-scss/components/align.scss"; @import "@uk-scss/components/svg.scss"; @import "@uk-scss/components/utility.scss"; @import "@uk-scss/components/flex.scss"; // After: Utility @import "@uk-scss/components/margin.scss"; @import "@uk-scss/components/padding.scss"; @import "@uk-scss/components/position.scss"; @import "@uk-scss/components/transition.scss"; @import "@uk-scss/components/visibility.scss"; @import "@uk-scss/components/inverse.scss"; // Need to be loaded last @import "@uk-scss/components/print.scss"; /* END: Overrides: ./node_modules/uikit/src/scss/components/_import.scss */ /* END: Overrides: ./node_modules/uikit/src/scss/uikit-theme.scss */ |