Webpack, Scss - add cdn server path before compilation - npm

How do I add a cdn path variable into the styles.scss before compilation? I have a webpack 4 configuration that works fine for JS. The JS/CSS files are loaded correctly from the desired cdn url.
What I want to achieve is, that the project running on localhost will use a different cdn url for images/icons/fonts than the same web running on production.
My webpack config has these lines for setting the cdn domain:
if (process.env.NODE_ENV === 'production') {
webUrl = 'https://cdn.project.com/';
}
else if (process.env.NODE_ENV === 'development') {
webUrl = 'http://localcdn.localhost/';
}
This code works well for JS/CSS files, but CSS always loads backgrounds/fonts using a relative path, which of course is the main domain and not the cdn.
Maybe just open the styles.scss and update the file manually before webpack compilation? Isn't there a better way?

After hours of trial and error I found this solution for webpack 4. It may help someone trying to solve the same issue.
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options : {
url : false,
sourceMap: devMode
}
},
{
loader: 'sass-loader',
options : {
processCssUrls : false,
sourceMap: devMode,
data : "$cdnFolder: 'http://cdn.myweb.net/';"
}
}
],
},
This is a part of webpack.config.js, in the section:
module : {
rules : {
This configuration makes the scss variable $cdnFolder available in every scss file. CDN link can be changed based on the current mode dev/prod/stage.

For webpack 5, the config changed a little:
{
loader: 'sass-loader',
options : {
additionalData : "$cdnFolder: '" + cdnUrl + "';"
}
}

Related

In NuxtJS How to configure different paths for publicPath, outputDir, and indexPath

I have situation when i deploy NuxtJS App for production that I need put files in different paths.
I used this configurations before in Vue App in vue.config.js and it’s works fine:
module.exports = {
publicPath:'/assets/my_app/my_page/',
outputDir: path.resolve('../my_app/public/my_page'),
indexPath: path.resolve('../my_app/www/my_page.html'),
devServer: {
allowedHosts: ["my_site.com"],
proxy: {
'^/api': serverProxy,
'^/assets': serverProxy,
'^/files': serverProxy
}
}
};
How can do the same configurations in NuxtJS?
I tried this in nuxt.config.js but it not working:
build: {
publicPath:'/assets/my_app/my_page/',
// outputDir: path.resolve('../my_app/public/my_page'),
},
generate: {
dir: path.resolve('../my_app/www/my_page.html'),
},
there are different Dir properties that you can use in nuxt.config. I think
buildDir ,rootDir or srcDir can help you. However, you can access vue configuration and use your old solution by :
nuxt.config vue.config property

VueJS build started throwing Error: Conflict: Multiple assets emit to the same filename

My app used to work fine until I updated VueJS this morning. Now when I build, it shows the following error:
Error: Conflict: Multiple assets emit to the same filename img/default-contractor-logo.0346290f.svg
There's only one file like this in the repo.
Here's my vue.config.js:
module.exports = {
baseUrl: '/my/',
outputDir: 'dist/my',
css: {
loaderOptions: {
sass: {
data: `
#import "#/scss/_variables.scss";
#import "#/scss/_mixins.scss";
#import "#/scss/_fonts.scss";
`
}
}
},
devServer: {
disableHostCheck: true
}
};
I tried webpack fixes recommended in similar cases, but non helped.
I had the same error when importing SVG files using dynamically generated path in the require statement:
const url = require("../assets/svg/#{value}");
<img src={{url}} />
In this case file-loader processes all SVG files and saves them to the output path. My file-loader options were:
{
loader: "file-loader",
options: { name: "[name].[ext]" }
}
The folders structure has duplicate file names, something like this:
assets
|__ one
|____ file.svg
|__ two
|____ file.svg
In this case file-loader saves both file.svg files to the same output file: build/assets/file.svg - hence the warning.
I managed to fix it by adding [path] to the name option:
{
loader: "file-loader",
options: { name: "[path][name].[ext]" }
}
The answer by #ischenkodv is definitely correct, but because of my inexperience with webpack, I needed a little more context to use the information to fix the problem.
For the benefit of anyone else in the same situation, I'm adding the following details which I hope will be useful.
This section of the Vue.js documentation was particularly helpul:
VueJS - Modifying Options of a Loader
For the TL;DR fix, here is the relevant chunk of my vue.config.js:
// vue.config.js
module.exports = {
// ---snip---
chainWebpack: config =>
{
config.module
.rule('svg')
.test(/\.svg$/)
.use('file-loader')
.tap(options =>
{
return { name: "[path][name].[ext]" };
});
}
// ---snip---
};
In my project it was the flag-icon-css NPM package that was causing the Multiple assets emit to the same filename conflict errors. The above update to the vue.config.js file resolved the problem for me.
I suspect that the regular expression in the test could be tightened up to target just the items in the flag-icon-css package rather than matching all SVG files, but I haven't bothered since it's not causing any adverse effects so far.

Image URLs don't resolve in Vue component

My problem :
Path generated for images are the same for images used in css or in a vue component.
Images are correctly loaded from CSS files, but are not found when declared in a vue component.
Version of webpack : 3.6.0
Here is the webpack configuration
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
publicPath: '../../',
limit: 1000,
name: utils.assetsPath('images/[name].[hash:7].[ext]')
}
},
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
name: utils.assetsPath('css/[name].[ext]'),
}
},
]
}
sourceMap is enabled and publicPath is './'
All works correctly if files are deployed in server root directory, but it is deployed in a subdirectory, it doesn't.
Let's say I deploy my files in a 'dev' subdirectory.
Images in CSS files will be search in /dev/static/images/
Images in vue components will be searched in /static/images/, where they won't be found...
I can't figure out what I am doing wrong... Any help or advice is appreciated.
Thanks !

responsive-loader with nuxt.js

I want to integrate responsive-loader into my Nuxt.js project which runs in SPA mode. (Optional I want to add Vuetify Progressive Image support also).
It will be a static hosting with Netlify.
Versions:
"nuxt": "^2.3.4"
"responsive-loader": "^1.2.0"
"sharp": "^0.21.1"
I found some solutions how to do it (https://stackoverflow.com/a/51982357/8804871) but this is not working for me.
When I run npm run build
I get an error message: "TypeError: Cannot set property 'exclude' of undefined"
My build section looks the following:
build: {
transpile: [/^vuetify/],
plugins: [
new VuetifyLoaderPlugin()
],
extractCSS: true,
/*
** Run ESLint on save
*/
extend(config, { isDev, isClient, isServer }) {
// Default block
if (isDev && isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
if (isServer) {
config.externals = [
nodeExternals({
whitelist: [/^vuetify/]
})
]
}
// Default block end
// here I tell webpack not to include jpgs and pngs
// as base64 as an inline image
config.module.rules.find(
rule => rule.loader === "url-loader"
).exclude = /\.(jpe?g|png)$/;
/*
** Configure responsive-loader
*/
config.module.rules.push({
test: /\.(jpe?g|png)$/i,
loader: "responsive-loader",
options: {
min: 350,
max: 2800,
steps: 7,
placeholder: false,
quality: 60,
adapter: require("responsive-loader/sharp")
}
});
}
}
The error is probably found in this section:
config.module.rules.find(
rule => rule.loader === "url-loader"
).exclude = /\.(jpe?g|png)$/;
Like said I get this error message: "TypeError: Cannot set property 'exclude' of undefined".
I run this project along with vuetify. I also would like to enable the Progressive image support together with responsive loader. Does anybody know how to setup both rules together?
https://github.com/vuetifyjs/vuetify-loader#progressive-images
The easiest way to integrate responsive-loader into a Nuxt.js project is to use this module: https://www.npmjs.com/package/nuxt-responsive-loader
Disclaimer: I created the module
The problem with your config that it relies on rule.loader property but rule can be defined in use or oneOf config sections as well.
Another one problem is that nuxt internal config has several rules with url-loader(for images, videos, fonts ...).
In your case the rule, you tried to find, has use section and url-loader is defined there, that's why your find function found nothing and threw this error:
{
"test": /\.(png|jpe?g|gif|svg|webp)$/,
"use": [{
"loader": "url-loader",
"options": {
"limit": 1000,
"name": "img/[hash:7].[ext]"
}
}]
}
About responsive-loader, you should remove extensions you want to process with responsive-loader from url-loader rule to avoid unexpected behavior and conflicts, here is extend function working example:
extend(config, ctx) {
let imgTest = '/\\.(png|jpe?g|gif|svg|webp)$/';
// find by reg ex string to not rely on rule structure
let urlRule = config.module.rules.find(r => r.test.toString() === imgTest);
// you can use also "oneOf" section and define both loaders there.
// removed images from url-loader test
urlRule.test = /\.(svg|webp)$/;
config.module.rules.push({
test: /\.(png|jpe?g|gif)$/,
loader: "responsive-loader",
options: {
// place generated images to the same place as url-loader
name: "img/[hash:7]-[width].[ext]",
min: 350,
max: 2800,
steps: 7,
placeholder: false,
quality: 60,
adapter: require("responsive-loader/sharp")
}
})
}
Yes, it looks dirty, but I think it's only way for now to change some loader.
What about vuetify - I think both loaders will conflict with each other and probably the solution is to use single loader that will work with your images.
Hope it helps.
Update for Nuxt >= 2.4.0:
They modified the rules array please update the following line:
let imgTest = '/\\.(png|jpe?g|gif|svg|webp)$/i';
Then the code should work normally again.

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/.