Vue.js webpack - How to use themify-icons? - vue.js

I added the package
yarn add themify-icons-sass
then in my component , I imported it in the script and in the style
<script>
....
import 'themify-icons-sass'
<style lang="scss" scoped>
#import 'themify-icons-sass/themify-icons';
...
but I get a build error
This dependency was not found:
* themify-icons-sass in ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/components/HelloWorld.vue
To install it, you can run: npm install --save themify-icons-sass
Where am I wrong in the import ? thanks for feedback
UPDATE
First, if I want o import it from ./node_modules , then the #import should NOT BE in a scoped style...
So I moved it to a global style in my App.vue
<style lang="scss">
#import "~themify-icons-scss/scss/themify-icons.scss";
#app { ...
Then I got an erro , the node-sass/vendor directory was not bulit.. so I add to rebuild node_sass
yarn add node-sass --force
Now it's taking in account the package but I get another error related to the relative path to the fonts:
These relative modules were not found:
* ../fonts/themify.eot in ./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasInlineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-
loader/lib/selector.js?type=styles&index=0!./src/App.vue
* ../fonts/themify.eot?-fvbane in ./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasIn
lineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue
* ../fonts/themify.svg?-fvbane in ./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasIn
lineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue
* ../fonts/themify.ttf?-fvbane in ./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasInlineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue
* ../fonts/themify.woff?-fvbane in ./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasInlineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue
the themify-icons-scss file structure is the following :
node_modules/themify-icons-scss
fonts
themify.eot
themify.svg
themify.ttf
themify.woff
scss
_core.scss
_extras.scss
_icons.scss
_mixins.scss
_paths.scss
_variables.scss
themify-icons.scss
node_modules/themify-icons-scss/scss/themify-icons.scss
#import "variables";
#import "mixins";
#import "path";
#import "core";
#import "extras";
#import "icons";
themify-icons-scss/scss/_path.scss
#font-face {
font-family: 'themify';
src:url('#{$ti-font-path}/themify.eot?-fvbane');
src:url('#{$ti-font-path}/themify.eot?#iefix-fvbane') format('embedded-opentype'),
url('#{$ti-font-path}/themify.woff?-fvbane') format('woff'),
url('#{$ti-font-path}//themify.ttf?-fvbane') format('truetype'),
url('#{$ti-font-path}/themify.svg?-fvbane#themify') format('svg');
font-weight: normal;
font-style: normal;
this is where there is some issue... with the $ti-font-path as defined in the variables, relative to the scss directory in the package..
themify-icons-scss/scss/_variables.scss
$ti-font-path: "../fonts" !default;
$ti-class-prefix: "ti" !default;
}

SOLVED...
there is a nice recent package ( updated 3 months go, I forked it as an archive for me ..). see themify-icons-scss
yarn add git+http://github.com/Frolki1-Dev/themify-icons-sass
to solve the issue with the relative font path variable in the package _path.scss , I added the package resolve-url-loader. ( see resolve-url-loader on github
yarn add resolve-url-loader --dev
And as per the resolve-url-loader readme, as I want to use webpack loaders I inserted into build/utils
build/utils.js
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// added resolve-url-loaderr with sourceMap true
const resolveUrlLoader = {
loader: 'resolve-url-loader',
options: {
sourceMap: options.sourceMap
}
}
In my App.vue I can import (global , cannot be scoped)
<style lang="scss">
#import "~themify-icons-scss/scss/themify-icons.scss";
#app {
...
And I can check the themify-icons in my component template
<h2>Test Themify Icons</h2>
<div class="row" style="margin-bottom: 30px;">
<div class="col-4"></div>
<div class="col-4">
<span class="ti-email"> Email Me</span>
</div>
</div>

Related

How to use .less file in nuxt js

I created a .less file in my assets/css/myfile.less Nuxt folder and I added some CSS to it.
.edit-btn-color {
background-color: #b1c646;
color: white;
}
.edit-btn-color:hover {
background-color: darken(#b1c646, 10%);
color: white;
}
and in nuxt.config.js I do the following:
export default {
less: ['#/assets/css/myfile.less'],
}
But it does not work.
Since Nuxt2 is still using Webpack4, you need to install the v7 of less-loader (v8 is using Webpack5)
yarn add less-loader#^7 less
Then, create a .less file somewhere, like /assets/css/myfile.less
And use it in nuxt.config.js with this
export default {
css: ['~/assets/css/myfile.less'],
}
The key to use here is css, it's the same for SCSS, SASS, Less, Stylus and so on, as shown in the documentation: https://nuxtjs.org/docs/2.x/features/configuration#the-css-property
The answer for Nuxt v3 would be:
Install Less: npm i less (no less-loader needed).
For Global styles add them to your nuxt.config.ts like this:
export default defineNuxtConfig({
css: ['~/assets/less/main.less'],
})
In your components you could use Less like this:
<style lang="less" scoped>
#import (reference) '../assets/less/helpers.less';
nav {
background-color: darkkhaki;
.my-great-style; /* Imported from helpers.less */
}
</style>

Storybook with vue - SassError: Undefined variable

I am using storybook with Vue. I have some common SCSS I want to use.
I am using the addon in **main.js**
addons: [
'#storybook/preset-scss'
],
This seems to automatically pick up ./src/scss/variables.scss which for testing I have added
body {
border: 10px solid green;
}
This works and hot reloads too the issue is any variables are not found in my components.
So my story list.stories.js imports the list component
import List from '../components/List.vue'
but within the style block I am trying use a var from the variables.scss.
<style lang="scss" scoped>
.list {
border: 1px solid $light-blue;
}
</style>
And get the error
SassError: Undefined variable: "$light-blue".
on line 204 of components/src/components/List.vue
>> border: 2px solid $light-blue;
In main.js add sass-loader to webpack config:
module.exports = {
webpackFinal: async (config) => {
config.module.rules.push({
test: /\.scss$/,
loaders: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: '../src/scss/variables.scss',
},
},
],
});
return config;
}
}
It works with installed css-loader#5, sass-loader#10 and style-loader#2.
If scss is not working, then you can load styles by creating preview-head.html file at config/storybook/preview-head.html
And then just load your CSS there. For example:
<link rel="stylesheet" href="./assets/css/style.css">
<link rel="stylesheet" href="./assets/css/media-screen.css">
Make sure to restart Storybook dev server. npm run storybook:serve

Vue invalid CSS - expected 1 selector or at-rule,

I'm trying to npm run serve in Vue and receiving the following error:
Failed to compile.
./src/App.vue?vue&type=style&index=0&lang=sass& (./node_modules/css-loader/dist/cjs.js??ref--9-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--9-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--9-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=style&index=0&lang=sass&)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Invalid CSS after " ": expected 1 selector or at-rule, was "{"
on line 1 of /Users/MatthewBell/GitHub/pollify/client/src/App.vue
>> {
^
Clearly it says the error is in App.vue and seems like a misplaced curly brace.
But if check in that file there aren't even any curly braces there:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link>|
<router-link to="/about">About</router-link>
</div>
<router-view />
</div>
</template>
<style lang="sass">
#app
#extend %global-styles
</style>
..And the file of class being extended.. main.sass is shown below. None of the imported sass sheets have curly braces either, so I'm sitting here very confused about the error message.
// Importing all our globally accessible stylesheets
#import ./reset
#import ./variables
#import ./mixins_and_placeholders
%global-styles
font-family: $font
-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
background-color: $grey-3
color: $text-black
I also searched this question on StackOverflow and some people seem to say it can be an issue with your config file, but I cant find any issues with my vue.config.js:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
// pass options to sass-loader
// #/ is an alias to src/
// so this assumes you have a file named `src/variables.sass`
// Note: this option is named as "data" in sass-loader v7
sass: {
prependData: `
#import "#/styles/main.sass"
`
}
}
}
};
This was working fine before so it's not an issue with the prepend data path.
As Phil mentioned in the comments. The indented #import "#/styles/main.sass" in my config file vue.config.js was causing the issue, since backticks preserve indentation. The following syntax solves it:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
// pass options to sass-loader
// #/ is an alias to src/
// so this assumes you have a file named `src/variables.sass`
// Note: this option is named as "data" in sass-loader v7
sass: {
prependData: `#import "#/styles/main.sass"`
}
}
}
};

Using Vuetify classes within SASS

I would like to use some of the existing Vuetify classes in my own sass file, but I can't seem to figure out how to do it. I have a Vue-CLI3 project with the latest Vue/Vuetify, and have the following code:
main.sass
#import '~vuetify/src/styles/styles.sass'
.myTest
#extend .mr-1
#extend .shrink
I also have the vue.config.js setup to correctly reference the sass/scss files:
export default {
css: {
loaderOptions: {
sass: {
data: `#import "path/to/main.sass"`
},
scss: {
data: `#import "path/to/main.scss";`
},
}
}
}
When I compile, I get The target selector was not found, and it points to .mr-1 and .shrink. Am I doing this incorrectly?
All other CSS in my main.sass file works as expected, so I believe the wiring is correct.
It seems the spacing helper classes (including .mr-1) are only found when importing vuetify/src/styles/main.sass instead of styles.sass. The .shrink class is found in vuetify/src/components/VGrid/_grid.sass.
So your main.sass should look like this:
#import '~vuetify/src/styles/main.sass'
#import '~vuetify/src/components/VGrid/_grid.sass' // for .shrink
.myTest
#extend .mr-1
#extend .shrink
sass-loader config
The original question is probably using an older version of sass-loader, given the sass.data config. If using version 8 or newer, the loader option is sass.additionalData:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
sass: {
// sass-loader >= 8
additionalData: `#import "~#/path/to/main.sass"`
// sass-loader < 8
data: `#import "~#/path/to/main.sass"`
}
}
},
}
Prepending global styles
With the sass-loader config above, importing vuetify/src/styles/main.sass in your project's root main.sass (as done in the original question) causes an error. The workaround is to copy the contents of Vuetify's main.sass into your own. However, if your app uses any Vuetify components, you'll see the same error for _grid.sass, and the same workaround applies:
// #import '~vuetify/src/styles/main.sass' ❌ SassError: This file is already being loaded.
#import '~vuetify/src/styles/tools/_index'
#import '~vuetify/src/styles/settings/_index'
#import '~vuetify/src/styles/generic/_index'
#import '~vuetify/src/styles/elements/_index'
#import '~vuetify/src/styles/utilities/_index'
// #import '~vuetify/src/components/VGrid/_grid.sass' ❌ SassError: This file is already being loaded.
.shrink
flex-grow: 0 !important
flex-shrink: 1 !important
.myTest
#extend .mr-1
#extend .shrink
This approach gets unwieldy the more you need to extend the component-specific styles.
Also, since this prepends the contents of your main.sass to all Sass entry points, you may notice a significant delay in build/dev times (hampering developer experience), and a sizable vendor CSS chunk in your build output.
Better alternatives
You could avoid the caveats above by importing your main.sass in main.js:
import '#/main.sass'
demo 1
On the other hand, if you only need these styles in a specific component, use local styles instead:
<script>
import '#/main.sass'
</script>
demo 2
<!-- or -->
<style lang="sass">
#import '~#/main.sass'
</style>
demo 3
<!-- or -->
<style lang="sass">
#import '~vuetify/src/styles/main.sass'
#import '~vuetify/src/components/VGrid/_grid.sass' // for .shrink
.myTest
#extend .mr-1
#extend .shrink
</style>
demo 4
So, I achieved to do it thanks to Vue CLI and some documentation. Here is my github repo, here is the codesandbox.
Basically, the setting was as follows:
// src/plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'
Vue.use(Vuetify)
export default new Vuetify({
theme: {
options: { customProperties: true }, // interesting part
},
})
I'm not sure about the vue.config.js nor the webpack.config.js configurations since it also depends on your versions of node-sass and sass-loader but you said that you handled it well by yourself, so no big worries I guess.
I made the example in the App.vue file in which I wrote
<div id="priority" class="medium">hello, this is working !</div>
There is a global.sass file that will target it's div tag and apply color: var(--v-warning-base).
There is a global.scss file that will target it's .medium class and apply color: var(--v-accent-base).
Finally, the component itself will target it's #priority id and apply color: var(--v-error-base).
I found the answer thanks to this post, give it a thumbs up too !

Vue Cli 3 Local fonts not loading

When trying to load custom local fonts in Vue CLI 3 the fonts still will not appear. I am not receiving any error messages. The inspector shows the correct rule being loaded, but fonts are falling back to serif on #app. Fonts are not showing up in my dist folder anywhere.
I have tried adding loaders in vue.config.js, changing url paths, and moving the #font-face rules around to different locations, changing the public path to ' ' and '/', importing scss into main.js.
Font loading:
#font-face {
font-family: 'OpenSans-Regular';
src: url('/assets/fonts/OpenSans-Regular.eot');
src: url('/assets/fonts/OpenSans-Regular.eot?#iefix') format('embedded-opentype'),
url('/assets/fonts/OpenSans-Regular.otf') format('font-opentype'),
url('/assets/fonts/OpenSans-Regular.woff') format('font-woff'),
url('/assets/fonts/OpenSans-Regular.ttf') format('font-truetype'),
url('/assets/fonts/OpenSans-Regular.svg#OpenSans-Regular') format('svg');
font-weight: normal;
font-style: normal;
}
And use within App.vue:
<style lang="scss">
#app {
font-family: 'OpenSans-Regular', serif;
}
</style>
That styling is placed within my main.scss file. The file structure as follows:
src
assets
fonts
OpenSans-Regular.eot
OpenSans-Regular.woff
etc
styles
main.scss
App.vue
vue.config.js
vue.config.js file is as follows:
module.exports = {
publicPath: '/',
css: {
sourceMap: true,
loaderOptions: {
sass: {
data: `#import "#/styles/main.scss";`
}
}
},
configureWebpack: {
module: {
rules: [{
test: /\.(ttf|otf|eot|woff|woff2)$/,
use: {
loader: "file-loader",
options: {
name: "fonts/[name].[ext]",
},
},
}]
}
}
}
I have also tried a chainWebpack in vue.config.js to no avail:
chainWebpack: config => {
config
.module
.rule("file")
.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/,)
.use("url-loader")
.loader("url-loader")
.options({
limit: 10000,
name: 'assets/fonts/[name].[ext]'
})
.end();
}
Did you try
#font-face {
font-family: 'OpenSans-Regular';
src: url('~#/assets/fonts/OpenSans-Regular.eot');
src: url('~#/assets/fonts/OpenSans-Regular.eot?#iefix') format('embedded-opentype'),
url('~#/assets/fonts/OpenSans-Regular.otf') format('font-opentype'),
url('~#/assets/fonts/OpenSans-Regular.woff') format('font-woff'),
url('~#/assets/fonts/OpenSans-Regular.ttf') format('font-truetype'),
url('~#/assets/fonts/OpenSans-Regular.svg#OpenSans-Regular') format('svg');
font-weight: normal;
font-style: normal;
}
Works for me Vue CLI 3, no vue.config.js settings.
I'm loading my styles like this:
import Vue from 'vue';
import router from './router';
import store from './store';
// eslint-disable-next-line
import styles from './scss/app.scss';
import App from './App.vue';
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app');
Not sure if that is good practice.
What I ended up doing was moving to a file loader method to get the fonts to package over and set the the public path.
vue.config.js
module.exports = {
assetsDir: 'assets/',
publicPath: '/', // Base directory for dev
css: {
sourceMap: true,
loaderOptions: {
sass: {
data: `#import "#/styles/main.scss";`
}
}
},
chainWebpack: config => {
config.module
.rule("fonts")
.test(/\.(ttf|otf|eot|woff|woff2)$/)
.use("file-loader")
.loader("file-loader")
.tap(options => {
options = {
// limit: 10000,
name: '/assets/fonts/[name].[ext]',
}
return options
})
.end()
}
};
File-loader doesn't see the files unless called in the js so I imported them in main.js The console log is to navigate around the linter flagging unused imports
// Fonts need to be called in js for webpack to see and copy over
import OpenSansReg from './assets/fonts/OpenSans-Regular.ttf';
import OpenSansLight from './assets/fonts/OpenSans-Light.ttf';
import OpenSansBold from './assets/fonts/OpenSans-Bold.ttf';
console.log(OpenSansReg, OpenSansBold, OpenSansLight);
then in one of my scss files
#font-face {
font-family: 'OpenSans-Regular';
src: url('/assets/fonts/OpenSans-Regular.eot?#iefix') format('embedded-opentype'),
url('/assets/fonts/OpenSans-Regular.otf') format('opentype'),
url('/assets/fonts/OpenSans-Regular.woff') format('woff'),
url('/assets/fonts/OpenSans-Regular.ttf') format('truetype'),
url('/assets/fonts/OpenSans-Regular.svg#OpenSans-Regular') format('svg');
font-weight: normal;
font-style: normal;
}
For me, I just took out that 'format()' thing and works... Finally..
I stuck my custom icon-font in the head tags of my initial index.html page Which also has a custom font import. The same page that you would stick your <div id="vue-app"></div>. All the other pages /components can use the font-family for me.
<head>
...
<link rel="stylesheet" href="icon-font/styles.css" />
</head>
But if i try any other location in the project it fails. and the Scss doesnt even compile.
This helped me
In src folder main.js just added:
import '../src/fonts/fonts.css'
in the font the following code:
#font-face {
font-family: 'Conv4240';
src: url('~#/fonts/Conv4240/4240.eot');
src: local('☺'),
url('~#/fonts/Conv4240/4240.woff') format('woff'),
url('~#/fonts/Conv4240/4240.ttf') format('truetype'),
url('~#/fonts/Conv4240/4240.otf') format('opentype'),
url('~#/fonts/Conv4240/4240.svg') format('svg');
font-weight: normal;
font-style: normal;
}
And everything started to work