How to load a Font from node_modules with Vite? - vue.js

I'm trying to load a company font from a node_modules folder which only includes fonts and icons, it was working locally. At first, I thought it was because Vite/Rollup don't have the ~ by default, so I added an alias in vite config, but actually what I think really happens is that Rollup simply disregard (doesn't include) my node_modules/#company because I'm not importing any JS/TS code from it (it's just fonts/icons), so I assume that Rollup is probably skipping or ignoring that in the tree shaking process during the prod build because the only time it's reference is through the #import in my scss file which is probably not enough.
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [
Vue({
reactivityTransform: true,
template: { transformAssetUrls },
}),
],
resolve: {
alias: {
'~#company': path.resolve(__dirname, 'node_modules/#company'),
'#': `${path.resolve(__dirname, './src')}`,
},
},
}
this only works locally, it doesn't work from a build (I get 404)
/* scss file */
#font-face {
font-family: 'comp-icon';
src: url('~#company/icons/fonts/comp-icon.woff2') format('woff2'), url('~#company/icons/fonts/comp-icon.woff') format('woff');
font-weight: normal;
font-style: normal;
}
So like I said, I think Rollup is ignoring my node_modules/#company folder completely during the prod build tree shaking process.
I looked for why it doesn't work and came across this post in a similar issue, that person used rollup-plugin-copy lib to copy the font into the public assets folder and that seems to work for me but is not ideal since it copies font from one place to another on every build.
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [
Vue({
reactivityTransform: true,
template: { transformAssetUrls },
}),
copy({
targets: [{ src: './node_modules/#company/icons/fonts/**/*', dest: 'public/assets/fonts'
}],
}),
],
resolve: {
alias: {
'~#company': path.resolve(__dirname, 'node_modules/#company'),
'#': `${path.resolve(__dirname, './src')}`,
},
},
}
and using it with
/* scss file */
#font-face {
font-family: 'comp-icon';
src: url('fonts/comp-icon.woff2') format('woff2'), url('fonts/comp-icon.woff') format('woff');
font-weight: normal;
font-style: normal;
}
It seems to work but I think it's just an ugly patch, I don't really wish to keep this copy process unless I really have to. My project is a Vue 3 + Vite + Vitest, however I assume that my problem is stricly a Vite/Rollup problem.
What is the correct way to load custom company fonts from a node_modules that I believe gets excluded from Rollup at the tree shaking process? What do I need to do to get this working and expect Rollup to include all my fonts files (woff, woff2, ttf) in my final prod build?
EDIT
Creating an alias like this SO that was provided in the comments did help with my use case. However in my case I wanted to keep # as an alias to src so I added a ~ alias, it's similar to how it works in WebPack except that I need to add a trailing slash after the tilda, it would be nice to find how to make it the same as WebPack (path.join is suppose to help but that didn't work) but for now it's acceptable
resolve: {
alias: {
'~': path.resolve(__dirname, './node_modules'),
'#': `${path.resolve(__dirname, './src')}`,
},
},
#font-face {
font-family: 'se-icon';
src: url('~/#company/icons/fonts/se-icon.woff2') format('woff2'), url('~/#company/icons/fonts/se-icon.woff') format('woff');
font-weight: normal;
font-style: normal;
}

Referencing files from within node_modules folder works for me in Vite 4.0.1
Might be that it's because I'm using tailwind, IDK.
#import "#openfonts/ubuntu_latin-ext/index.css";

Related

Snowpack built-in optimization removes comments from scss

I have a small project where I am trying to use Snowpack built-in optimization instead of #snowpack/plugin-webpack (docs).
When running a build process, comments from scss file are removed. What can I do to keep my comments?
This is what I am using in snowpack.config.mjs file:
optimize: {
bundle: true,
minify: false,
sourcemap: false,
target: 'es2015',
},
plugins: [
'#snowpack/plugin-sass',
'#snowpack/plugin-postcss'
],
I tested it in a simple index.scss file:
/* ------------ Comment example ---------- */
body {
font-family: sans-serif;
color: pink;
}
The resulted index.css file doesn't have my comment, but a different one:
/* build/index.css */
body {
font-family: sans-serif;
color: pink;
}
I don't need this new comment, but would like to keep mine.

Using #use "sass:math" in a Vue component

In a Nuxt project i have created a button component with the following style:
<style lang="scss">
.my-button {
// lots of cool styles and stuff here
$height: 28px;
height: $height;
border-radius: $height / 2;
}
</style>
The problem is the border-radius: $height / 2; line gives this warning:
╷
182 │ border-radius: $height / 2;
│ ^^^^^^^^^^^
╵
components/MyButton.vue 182:20 button-size()
components/MyButton.vue 186:5 root stylesheet
: Using / for division is deprecated and will be removed in Dart Sass
2.0.0.
Recommendation: math.div($height, 2)
It also links to this page describing the deprecation.
However if i add #use "sass:math" to the top of my style tag like so:
<style lang="scss">
#use "sass:math";
//Cool styles and stuff
$height: 28px;
height: $height;
border-radius: math.div($height, 2);
</style>
I get this error:
[Vue warn]: Error in render: "Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): 12:13:59
SassError: #use rules must be written before any other rules.
╷
102 │ #use "sass:math";
│ ^^^^^^^^^^^^^^^^
╵
components/MyButton.vue 102:1 root stylesheet"
I think i need to add the import of #use "sass:math" somewhere in nuxt.config.js file to load it in all components or similar, but i am not able to figure out where.
The css related blocks in my nuxt.config.js currently looks like:
build: {
postcss: {
plugins: {
'postcss-easing-gradients': {},
},
},
},
styleResources: {
scss: [
'~/assets/global-inject.scss',
],
},
css: [
'~/assets/base.scss',
'~/assets/reset.scss',
],
Updating #nuxtjs/style-resources to above version 1.1 and using hoistUseStatements fixed it.
I changed the styleResources object in nuxt.config.js to:
styleResources: {
scss: [
'~/assets/global-inject.scss',
],
hoistUseStatements: true,
},
and added #use "sass:math"; to the top of global-inject.scss.
Updated answer
What if you try this in your nuxt.config.js file?
{
build: {
loaders: {
scss: {
additionalData: `
#use "#/styles/colors.scss" as *;
#use "#/styles/overrides.scss" as *;
`,
},
},
...
}
Or you can maybe try one of the numerous solutions here: https://github.com/nuxt-community/style-resources-module/issues/143
Plenty of people do have this issue but I don't really have a project under my belt to see what is buggy. Playing with versions and adding some config to the nuxt config is probably the way to fix it yeah.
Also, if it's a warning it's not blocking so far or does it break your app somehow?
Old answer
My answer here can probably help you: https://stackoverflow.com/a/68648204/8816585
It is a matter of upgrading to the latest version and to fix those warnings.

Vue PWA plugin adjusting iconPaths and manifest destination

I have attached 2 screenshots, one of my vue.config.js and another of a section of the unminified output my build is producing.
Whats happening is this: I want to change the icon paths and the path to the manifest. For whatever reason the official way of changing this is not working. Right now they are blank spaces, however it was not working when it was anything else either ( just tried with 'foo/bar' as the path as I was typing this to triple check ).
I am confused because I seem to be doing everything exactly as I should according to the official docs. Is there anything another set of eyes can spot that I am missing?
Greetings Erik White
At some point I had the same difficulty and solved it as follows:
Copy the images into the "public" folder
example:
We add the folder "favicon" to "public", "favicon" contains 5 images
[project]/public/favicon/favicon-32x32.png
[project]/public/favicon/favicon-16x16.png
[project]/public/favicon/apple-touch-icon-152x152.png
[project]/public/favicon/safari-pinned-tab.svg
[project]/public/favicon/msapplication-icon-144x144.png
To add images in your html: modify the "vue.config.js" and add.
// Inside vue.config.js
module.exports = {
  // ... other vue-cli plugin options ...
  pwa: {
  // ...
    iconPaths: {
      favicon32: 'favicon/favicon-32x32.png',
      favicon16: 'favicon/favicon-16x16.png',
      appleTouchIcon: 'favicon/apple-touch-icon-152x152.png',
      maskIcon: 'favicon/safari-pinned-tab.svg',
      msTileImage: 'favicon/msapplication-icon-144x144.png'
    }
  // ...
  }
}
To change the path and name of "manifest.json" modify the "vue.config.js" and add:
// Inside vue.config.js
module.exports = {
  // ... other vue-cli plugin options ...
  pwa: {
  // ...
    manifestPath: 'my_new_manifest.json',
  // ...
  }
}
To change the properties of the "manifest.json", (name, images, color, etc) modify the "vue.config.js" and add:
// Inside vue.config.js
module.exports = {
// ... other vue-cli plugin options ...
pwa: {
// ...
manifestOptions: {
name: 'etc ..',
short_name: 'etc ..',
theme_color: '# f44647',
background_color: '# f44647',
start_url: 'index.html',
display: 'standalone',
orientation: 'portrait',
icons: [
{
src: './favicon/favicon-32x32.png',
sizes: '32x32',
type: 'image/png'
},
{
src: './favicon/favicon-16x16.png',
sizes: '16x16',
type: 'image/png'
},
{
src: './favicon/apple-touch-icon-152x152.png',
sizes: '152x152',
type: 'image/png'
},
{
src: './favicon/safari-pinned-tab.svg',
sizes: '942x942',
type: 'image/svg+xml'
},
{
src: './favicon/msapplication-icon-144x144.png',
sizes: '144x144',
type: 'image/png'
},
]
},
// ...
}
}
NOTE
chucks is not a supported parameter.
excludeChucks is not a supported parameter.
If you need to test a service worker locally, build the application and run a simple HTTP-server from your build directory. It's recommended to use a browser incognito window to avoid complications with your browser cache.
Remember to see the VUE documentation, it is very detailed, I leave you a link below #vue/cli-plugin-pwa
Nevermind, solved by updating my dependencies.
guessing this was fixed in a patch i didnt catch

Nuxt - Custom icon-font not served from _nuxt folder

I have successfully used the webfonts-loader package to generate a font and class-definitions for icons, but it isn't served by my nuxt dev server. There is a styletag in my head with:
#font-face {
font-family: "TopLoggerIcons";
src: url("/myfont.eot?#iefix") format("embedded-opentype"), url("/myfont.woff2") format("woff2");
}
But the requested http://localhost:3010/myfont.woff2 gives a 404. I had this working in the nuxt version before 2.0 (and before webpack 4), where the file is served from http://localhost:3010/_nuxt/myfont.woff2. The font is currently also served from there, but the path in the font-face declaration is wrong. I'm wondering what has changed here removing the (required?) _nuxt part in the path.
In my nuxt.config.js file I have:
build: {
extend(config, ctx) {
config.module.rules.push({
test: /plugins\/icons\.js$/,
use: ['vue-style-loader', 'css-loader', 'webfonts-loader'],
})
},
}
Now according to the example on the webfonts-loader lib I need to use the MiniCssExtractPlugin.loader instead of the vue-style-loader, but that doesn't work. I read here that it is internally used by nuxt, but i don't know how to add it here.
Hope anyone has an idea where to look...
Ok, just figured it out: you have to use the publicPath option of the webfonts-loader package:
extend(config, ctx) {
config.module.rules.push({
test: /plugins\/icons\.js$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'webfonts-loader',
options: {
publicPath: config.output.publicPath,
},
}
],
})
}
The config.output.publicPath is /_nuxt/.

Two compile cases with Webpack, Vue.js, and Sass

I'm using Webpack (v4), Sass and Vue.js (v2) in my project.
In some cases, I'd like to compile sass code into .css files. (This is for the .scss files that are mentioned in webpack.config.js as "entry" points)
In some other cases I'd like to have the compiled sass code injected into a html tag. (This is for the <style lang="sass"> included in my .vue single file components)
Is it possible to have both at the same time? How should I configure Webpack?
You can use sass-loader to include scss files anywhere and compile them:
https://github.com/webpack-contrib/sass-loader
To include scss in a single-file-component, you don't have to do anything specific, just write your styles into a style tag specifying lang="scss".
Here is a detailed example for both cases:
https://medium.com/hong-kong-tech/use-sass-scss-of-webpack-in-vuejs-8dde3a83611e
You can only leave scss files for webpack to process. You can't get them processed during build time and inject them into your single components, as stated here "In some other cases I'd like to have the compiled sass code injected into a html tag. (This is for the included in my .vue single file components)".
You have to leave to webpack the burden to compile all your scss files into css. Then you choose to either extract them or leave them in the html style tag.
Sorry PlayMa256 & Máté, for being so long before answering your replies.
In the end I found the solution of using two different configurations for my two cases. Webpack allows it through its multi-compiler feature.
So here is what my webpack.config.js now looks like:
module.exports = [ // notice that we are handling an array of configurations here
// In this first config, I manage the first of my use cases:
// Compilation of .scss files into .css files
{
name: "css",
entry: { /* ... */ },
output: { /* ... */ },
/* ... */
module: {
rules: [
{
test: /\.scss$/,
use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader' ],
}
]
},
plugins: [ /* ... */]
},
// In this other config, I manage the other of my use cases:
// injection of the <style> blocks of my .vue files into the DOM
{
name: "main", // name for first configuration
entry: { /* ... */ },
output: { /* ... */ },
/* ... */
module: {
rules: [
// Vue single file components loader
{
test: /\.vue$/,
loader: 'vue-loader',
},
// Injection of <style> elements into the DOM,
// for both plain `.css` files and `<style>` blocks in `.vue` files
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
// Compilation of sass code,
// (This actually works both for `.css` files and `<style>` blocks in `.vue` files,
// but I don't have any `.css` as entry for this config.)
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
}
]
},
plugins: [ /* ... */]
}
];