Font Awesome 5 Bundle via NPM - npm

I'm trying to bundle only required Font Awesome 5 icons via webpack, but the icons are not replaced in the DOM.
I've added all required packages from the documentation:
yarn add -D #fortawesome/fontawesome
yarn add -D #fortawesome/fontawesome-pro-solid
yarn add -D #fortawesome/fontawesome-pro-regular
yarn add -D #fortawesome/fontawesome-free-brands
The following custom JS is included:
"use strict";
import fontawesome from '#fortawesome/fontawesome';
import faCheck from '#fortawesome/fontawesome-pro-regular/faCheck';
fontawesome.icon(faCheck);
function iconsDoneRendering () {
console.log('Icons have rendered'); // No output in console
}
fontawesome.dom.i2svg({
callback: iconsDoneRendering,
})
The HTML template:
<head>
<link rel="stylesheet" href="/css/app.css?v2.1.4"> <!-- contains fa-svg-with-js.css -->
</head>
<body>
<ul class="fa-ul">
<li><span class="fa-li"><i class="far fa-phone"></i></span>List item 1</li>
<li><span class="fa-li"><i class="far fa-check"></i></span>List item 2</li>
</ul>
<script src="/js/app.js?v2.1.4"></script>
</body>
The svg path is inside the bundled JS file, but I can't figure out which method needs to be called.
The following JS code solves the problem (since v5.0.2):
"use strict";
import fontawesome from '#fortawesome/fontawesome';
import faCheck from '#fortawesome/fontawesome-pro-regular/faCheck';
import faPhone from '#fortawesome/fontawesome-pro-regular/faPhone';
fontawesome.library.add(faCheck,faPhone);

I realize this is already answered, but I'd like to give some visibility to the full solution since the information above does not include how to execute the SVG icon replacement.
If you're loading Font Awesome 5 via NPM & WebPack for use in front-end HTML like I am, you will need to do something like this in your JS that's included in your bundle:
"use strict";
// Import FontAwesome: https://fontawesome.com/how-to-use/use-with-node-js
import fontawesome from '#fortawesome/fontawesome';
// This enables using FontAwesome in CSS pseudo elements
// see: https://fontawesome.com/how-to-use/svg-with-js#pseudo-elements
fontawesome.config.searchPseudoElements = true;
// Icons should be imported individually to keep bundle size down
import faCheck from '#fortawesome/fontawesome-pro-regular/faCheck';
import faPhone from '#fortawesome/fontawesome-pro-solid/faPhone';
fontawesome.library.add(faCheck, faPhone);
// If really necessary, entire styles can be loaded instead of specifying individual icons
//import solid from '#fortawesome/fontawesome-pro-solid';
//fontawesome.library.add(solid);
// Execute SVG replacement
fontawesome.dom.i2svg();
That last line is key, you have to execute SVG icon replacement manually.

We just released version 5.0.2 and updated the #fortawesome NPM packages to fix a few bugs related to this. Make sure you upgrade before you try anything else.
The missing step of the above example is to add the icon to the library:
fontawesome.library.add(faCheck)

Try to use
fontawesome.library.add(faCheck);
instead of
fontawesome.icon(faCheck);
If it does not work, please update your question with your DOM template, to see how it's defined in there.

Related

How to properly load Bootstrap5's Masonry into Nuxt?

I am trying to use the Masonry plugin with Bootstrap5 and NuxtJS. When I follow the example here
https://getbootstrap.com/docs/5.0/examples/masonry/ and incorporate it into my own codesandbox, I notice that my demo is not in the correct masonry format. See the gaps? My sandbox
My example:
Bootstrap's example:
What do I need to do to get my demo into format shown on the Bootstrap Masonry example page?
I checked how to load the script from a CDN either globally or locally. It was working but at one condition: you needed to NOT start on the masonry page.
Meaning that if you loaded the app on a specific page, then moved to the one with the masonry it was working. But not if you started on this specific page. So, a pretty subpar solution.
This article was really helpful to understand how to wait until the CDN script is fully loaded: https://vueschool.io/articles/vuejs-tutorials/how-to-load-third-party-scripts-in-nuxt-js/
Then I realized that we are far better installing it directly as an NPM dependency. Therefore, I proceeded to the masonry repo. Found a great message on how to setup the whole thing in Nuxt.
And after a removal of some useless stuff and some modern dynamic import, here we are
<template>
<main>
<h1>Bootstrap and Masonry</h1>
<div class="row" id="masonry">
<!-- ... -->
</main>
</template>
<script>
export default {
async mounted() {
if (process.browser) {
let { default: Masonry } = await import('masonry-layout')
new Masonry('#masonry', { percentPosition: true })
}
},
}
</script>
The final solution is looking pretty well and there is not a lot of code. On top of that, the code is properly loaded. And you can load it on a click or any other event.

How do i correctly reference Vue.js node_module from electron-forge boilerplate?

This is a rookie question. I'm trying to take some baby-steps into Electron, Vue, Webpack, and Node. To that end, I've used electron-forge to spool out a boilerplate project as a starting point, like this:
npx create-electron-app my-project --template=typescript-webpack
After the project has been created everything (seemingly) works as expected. If I make any edits I can see webpack is invoked and reloading the content reveals my edits. So far so good.
My next step was to introduce the simplest Vue.js 'hello world' content I could. First, I install Vue.js using NPM, like this:
npm install "vue"
I then edit the boilerplate index.html to look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<h1>💖 Hello World!</h1>
<p>Welcome to your Electron application.</p>
<div id="vue-app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#vue-app',
data: {
message: 'This message is from Vue!'
}
})
</script>
</body>
</html>
Which does not work. If I change the script tag to use the CDN for the Vue.js script (instead of the node_modules folder), everything works as expected.
My conclusion is that although I can reference Vue.js in my node_modules folder at design time that location does not exist in my output at run time. I'm not certain if that is due to how webpack is configured, or due to how electron works - but it strongly implies there must be something I need to do, either programmatically or via the webpack configuration to properly reference the script.
So what is the right way to 'reference' the local Vue.js script?
Thanks!
You need to reference vue via some bundler like webpack (otherwise, like you said, it is not available at runtime). Your method won't work because the generated file structure isn't the same as the one you have during 'design time'
Here's an example with vue-cli which sets up a starter project:
npm i -g #vue/cli
vue create project-name
cd project-name
vue add electron-builder
npm install
Done. Your project is operational.
With one little caveat you would encounter later, if you are using vue-router. Add the following in router.js (it changes router mode to hash instead of history so it works with electron).
export default new Router({
mode: process.env.IS_ELECTRON ? 'hash' : 'history',
})
As a sidenote, vue-cli abstracts away a lot of config. If you ever get lost, just print it out with
vue inspect > ./app/inspect.js.md
(The part after > means save to the named file, otherwise it would print it out in your console.) Check it out, that's the correct set up you're looking for, just auto created with vue-cli.
Also, check out the generated /public/index.html, it has no mention of importing vue ;)
Best of luck
After some tinkering, I came up with this solution:
The HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>💖 Hello World!</h1>
<p>Welcome to your Electron application.</p>
<div id="vue-app">{{ message }}</div>
</body>
</html>
I then added an import statement to the electron-forge boilerplate renderer.ts, like this:
import './vueapp.js';
and finally, I created a new script file called vueapp.js like this:
import Vue from 'vue/dist/vue.js';
var app = new Vue({
el: '#vue-app',
data: {
message: 'Hello Vue!'
}
});
I welcome feedback and comments; this may or may not be the correct approach and would love to hear how others have done this.

Vue cli image wont load with webpack

What am I doing?
I am using the intersection observer API to make lazy loading.
What have I tried?
I tried the code in a simple HTML page and it works perfect, but when I use the code in vue, the images won't load (local images). If I put a htttp source images (online images) it works perfect, too. I think this is a webpack error config. Am I right? How can I fix it?.
Whats the error?
When i use a local image the code doesnt work, if only change that src with something else like this image https://images.pexels.com/photos/69817/france-confectionery-raspberry-cake-fruit-69817.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940 the code WORKS, why i cant make it work with local images?
HTML AND SCRIPT
<template>
<div class="container" id="section3">
<span class="containerTitle">Galeria</span>
<div class="wrapper">
<img v-lazyload data-src="#assets/images/001.jpg" class="card">
</div>
</div>
</template>
<script>
import lazyload from '../directives/lazyload'
export default {
directives:{
lazyload
},
}
</script>
DIRECTIVE
export default{
inserted: el =>{
const options = {
// root:
rootMargin: '0px 0px 0px 0px',
threshold:1
}
var observer = new IntersectionObserver((entries,observer) =>{
entries.forEach(entry => {
if(entry.isIntersecting){
el.src = el.dataset.src
observer.unobserve(el)
console.log('intersecting');
}
})
},options)
observer.observe(el)
}
}
CODE IMAGE
FOLDER
The issue is with your image path.
You can fix it with either using public folder and give it in path.
You can also check for auto suggestion which come up while typing, this may help you to check whether your path is correct or not.
Like this
Your path is wrong. You gave ../assets/images/001.jpg as the path to the image (as stated in your question), but according to your directory tree it's ../assets/001.jpg (or write it like #/assets/001.jpg, # points to root of project). That should fix it.
As far as I remember you can't use # sign inside <template>.
So you can either:
require it
<img v-lazyload :data-src="require('#assets/images/001.jpg')" class="card">
import it
<template>
...
<img v-lazyload data-src="image" class="card">
...
</template>
<script>
import img from '#assets/images/001.jpg';
...
data() {
return {
image: img,
}
}
...
</script>
use relative path
<img v-lazyload data-src="../assets/images/001.jpg" class="card">
You can check how it works in Vue docs
I can't remember why this works, but you need to use the following syntax:
<img v-lazyload data-src="~assets/images/001.jpg" class="card">
with the ~ replacing the ../.
I will update the answer if I figure out exactly why.
doing extensive research i found this article about vuejs and static assets.
https://edicasoft.com/weblog/2018/04/27/static-vs-srcassets-webpack-template-vue-cli/
They said that this kind of problems occurs "because" of webpack,like i though, so the solution for this (i hope not the only solution), but this is the solution so far...
QUOTE
All asset URLs such as , background: url(...) and CSS #import are resolved by Webpack as module dependencies like require('./logo.png').
We then use loaders for Webpack, such as file-loader and url-loader, to process them. Webpack template has already configured these loaders.
File-loader helps to determine the final file location and how to name it using version hashes for better caching. Thus you can put your static assets near your .vue files and use relative paths. There is no need to put them strictly into the ‘assets’ folder.
Url-loader helps to conditionally inline assets such as base64 data URL, reducing the amount of HTTP requests.
So what the hell should I do with it?
The answer is: put your assets in the ‘src’ folder.
I tested this and it works perfect BUT you CANT make a subfolder and this for me, is disorganized.
This is the final folder structure to get this done using intersection observer api as vue directive!

Why doesn't the nested component render as a slottable custom element?

Are there limitations to compiling Svelte components as custom elements? For instance, are we able to nest components? And fill slots in those nested components?
I'm having trouble using a Svelte component as a custom element in my older Vue app.
I've got a Select and a Modal component in this simplified example: https://svelte.dev/repl/4d4ad853f8a14c6aa27f6baf33751eb8?version=3.6.4
I'm then compiling these with a standard-fare rollup.config.js:
export default {
input: "src/components.js",
output: [
// ...
{ file: "dist/index.min.js", format: "umd", name }
],
plugins: [
svelte({
dev: !production,
customElement: true,
// ...
}),
resolve(),
commonjs(),
!production && livereload("public"),
production && terser()
],
// ...
};
Then I go to use the custom elements. On click of the <conversational-select>, I get markup that looks like the following:
<conversational-select label="Domains" firstvaluelabel="All Domains">
<!-- shadow-root -->
<style>...</style>
<span class="select" >
<div class="select-value">Governance Board</div>
<div class="select-label" ></div>
</span>
<!-- The below div is the appropriate markup for Modal but the style isn't inlined and isn't slotted.
<!-- maybe because it didn't append as <sk-modal>? -->
<div ><slot></slot></div>
</conversational-select>
The "Modal" is sort-of rendering. But it doesn't fill the slot with span .chips. Doesn't inline the styles like the conversational-select does. Doesn't seem to attach its own event listeners. But does seem to create the fade transition thanks to Svelte's transition:fade directive.
I can reproduce this with a vanilla html file, so it's not Vue's fault.
Am I breaking some known rule with custom elements, butting up against the limitations of Svelte's custom element compilation, or just mistaken somewhere?
I was the author of the Svelte github issue that has been mentioned. I believe that I have a fix here. There were a few issues that existed:
slotted was never set
"nested" elements were not being added correctly
I expect the Svelte authors to make changes to my pull request, but if you want to use it, you can:
Clone my branch
Run npm && npm build && npm link
Go to your project and run npm link svelte

How to trigger $('.button-collapse').sideNav('hide'); in vuejs 2 without jQuery?

I have successfully added the following code which provides me with the sideNav from materialise:
<v-btn-link v-side-nav:side-nav="nav" class="button-collapse btn-flat" id="btn-side-menu"><i class="material-icons">menu</i></v-btn-link>
<v-side-nav id="side-nav" class="hide-on-small">
<a v-on:click="handleNavDashboard()">Dashboard</a>
<a v-on:click="handleLogout()">Logout</a>
</v-side-nav>
and I use the following methods:
methods: {
handleLogout () {
console.log('LOGGED OUT')
this.$store.dispatch('clearAuthUser')
window.localStorage.removeItem('authUser')
this.$router.push({name: 'login'})
},
handleNavDashboard () {
console.log('GOING DASHBOARD')
console.log(this)
this.$router.push({name: 'dashboard'})
}
}
so when I am on the home page and i click Dashboard, I get the dashboard contents on the screen but the sideNav menu and the darkened background are still there. Materialise-css says you can use this function
$('.button-collapse').sideNav('hide');
to hide it progmatically but I don't have jQuery installed. How to I reset the sideNav after a nav click?
CDN
From Materialize docs:
One last thing to note is that you have to import jQuery before
importing materialize.js!
<body>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="js/materialize.min.js"></script>
</body>
NPM
Much better way, install jQuery via npm :
npm install jquery
and use webpack ProvidePlugin to make jQuery global module available in all of your files
here is sample of webpack.config.js file
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
In Vue.js DOM manipulations are encapsulated inside directives, you can use conditional rendering directives v-if or v-show to make this work without using jquery:
jsFiddle example
Also check component framework Vuetify.js that provide clean, semantic and reusable components.
If you want to include jQuery in to a project which is using requires or imports, then you need to make sure it's required and not included using script tags, because it will be outside the scope of the compiled code (unless it was shimmed), so add the following to your project:
ES6 syntax:
import jQuery from 'jquery';
window.$ = window.jQuery = jQuery
ES5 Syntax:
window.$ = window.jQuery = require('jquery');
And make sure you have installed jQuery:
npm install jquery --save-dev
This puts jQuery into the global scope so it can be used site wide. The docs for that package don't really make that clear, and for some reason they don't mention that jQuery is a dependency, but looking at the code it clearly is for some of the components.
If you don't want to use JQuery and Materialize, you can use the directive :v-show="showAside" or :v-if="showAside" with a property like showAside (in data) and handle the value with a click.
There is a very quick and cheap example: https://jsfiddle.net/nosferatu79/p85rw6xz/