Webpack sass loader does not recognize global variables file - javascript

i have this sass directory:
- _vars.scss
- main.scss
//vars.scss
$base-container: 1400px;
//main.scss
#import './vars';
In other js file i have:
require('./some-module-sass-file');
//some-module-sass-file.scss
.container {
width: $base-container;
}
The problem is i have global variables in the vars file and the some-module-sass-file not recognize them and throw an error:
undefined variable $base-container

Without using sass-resources-loader:
Thanks to #Arseniy-II for helping me get to this answer, in conjunction with this thread:
https://github.com/webpack-contrib/sass-loader/issues/218
Using loader options in your webpack module rules, you can assign a data property to sass-loader, you should then be able to use all sass functions as expected:
module: {
rules: [
// Apply loader
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
data: '#import "path/to/global.scss";',
includePaths:[__dirname, 'src']
},
},
],
},
],
}

You have to import the vars file into every Sass partial that uses those variables, because every partial is compiled on its own; none of the files will 'know about' the others unless you specifically import them.
If you don't want to have to type the imports in every Sass file, you can look at baggage-loader, which will automatically add them for you.

Note that you need to use " and ; at the end
{
loader: 'sass-loader',
options: {
additionalData:'#import "path/to/general.sass";',
},
},

If you have Webpack 5 you have to use additionalData, the other options are not valid now:
{
loader: 'sass-loader',
options: {
additionalData: '#import path/to/general.sass',
}
},
If you do like this your general sass or scss file will get prepended

Webpack 4 solution:
{
loader: 'sass-loader', options: {
sourceMap: true,
prependData: '#import "pathto/vars";'
},
}
In order #import "pathto/vars"; to work you need Webpack to configure to resolve such imports. So it simply prepends the line.
This solution is good because you have no issues with sourcemaps like with using sass-resources-loader

You can use text-transform-loader package.
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'text-transform-loader',
options: {
prependText: `#import "${path.resolve(__dirname, './base.scss')}";`,
}
}
]
}

Related

Loading FontAwesome via Webpack: Fonts do not load

I'm trying to understand how to load fonts via fontawsome when loading them through a scss file:
this is my webpack config:
const path = require('path');
const webpack = require('webpack');
const UrlLoader = require('url-loader');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
publicFolder = path.resolve(__dirname, 'public');
// appFolder = path.resolve(__dirname, 'app');
module.exports = {
entry: {
// Selects main js file
main: './public/es6/index.js'
},
output: {
// Main path for the js folder
path: path.resolve(__dirname, 'public/js/'),
// Select teh name the main js file (after compression)
filename: 'bundle.js',
// Public path
// publicPath: 'http://localhost:8080',
publicPath: '/public/js/',
// Name the chunkFile (in case of external scripts)
chunkFilename: '[name].[contenthash].js'
},
module: {
rules: [ // Vue Files
{
test: /\.vue$/,
exclude: /node_modules/,
loader: 'vue-loader',
options: {
loader: {
scss: 'vue-style-loader!css-loader!sass-loader',
css: 'vue-style-loader!css-loader'
}
}
},
// JS files
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
// CSS / SASS files
{
test: /\.(sa|sc|c)ss$/,
// test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
url: false,
minimize: true,
sourceMap: true
}
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
minimize: true
}
}
]
},
// Forgot why I need this...
{
test: /\.(png|gif|jpe|jpg|woff|woff2|eot|ttf|svg)(\?.*$|$)/,
use: [{
loader: 'url-loader',
options: {
limit: 100000
}
}]
}
]
},
plugins: [
// Load jQuery globally
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
// Hot module
// new webpack.HotModuleReplacementPlugin(),
// BrowserSync: Load page automatically on change
new BrowserSyncPlugin({
proxy: 'https://potato.mywebsite.com/',
port: 3000,
files: [
'**/*.php'
],
ghostMode: {
clicks: false,
location: false,
forms: false,
scroll: false
},
minify: false,
injectChanges: true,
logFileChanges: true,
logLevel: 'debug',
logPrefix: 'webpack',
notify: true,
reloadDelay: 0
}),
// Provides a way to customize how progress is reported during a compilation
new webpack.ProgressPlugin(),
// Loads Vue
new VueLoaderPlugin(),
// For webpack-dev-server (currently not in use)
// new webpack.HotModuleReplacementPlugin(),
// Handle css in different files (scss file in login.js for example to a hashed login.css file)
new MiniCssExtractPlugin({ filename: '../css/[name].css' }),
// CSS assets during the Webpack build and will optimize \ minimize the CSS
new OptimizeCSSAssetsPlugin({}),
// Not sure if needed yet
new webpack.NamedModulesPlugin()
],
devServer: {
// https: true,
headers: { 'Access-Controll-Allow-Origin': '*' },
compress: true,
quiet: true,
hot: true,
inline: true
}
};
And this is my SCSS file where I load FontAwesome (and others)..
#import 'variable';
// Colors
#import 'colors/default';
#import 'colors/green';
#import 'colors/megna';
#import 'colors/purple';
#import 'colors/red';
#import 'colors/blue';
#import 'colors/blue-dark';
#import 'colors/default-dark';
#import 'colors/green-dark';
#import 'colors/red-dark';
#import 'colors/megna-dark';
#import 'colors/purple-dark';
// Import Bootstrap source files
#import "../../node_modules/bootstrap/scss/bootstrap";
// This is for the icons
#import '../assets/icons/font-awesome/css/fontawesome-all.css';
#import '../assets/icons/simple-line-icons/css/simple-line-icons.css';
#import '../assets/icons/weather-icons/css/weather-icons.min.css';
#import '../assets/icons/themify-icons/themify-icons.css';
#import '../assets/icons/flag-icon-css/flag-icon.min.css';
#import "../assets/icons/material-design-iconic-font/css/material-design-iconic-font.min.css";
// This is the core files
#import 'core/core';
#import 'widgets/widgets';
#import 'responsive';
// In This scss you can write your scss
#import 'custom';
When running npm run dev (or others) i don't get any error mentioning fonts.
When loading my website I get these URLS refrences in the "network" pannel:
https://mywebsite.potato.com/public/webfonts/fa-regular-400.woff
https://mywebsite.potato.com/public/fonts/Simple-Line-Icons.ttf?-i3a2kk
pointing on font files that don't even exist in my directory (or at least do't get created..)
How do I load fonts properly?
EDIT:
Adding this for #FabioCosta
{
test: /\.(png|gif|jpe|jpg|woff|woff2|eot|ttf|svg)(\?.*$|$)/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
// name: '[path][name].[ext]',
outputPath: '/public/fonts/',
publicPath: '/public/fonts/'
}
}
]
}
Adding the full module part:
module: {
rules: [ // Vue Files
{
test: /\.vue$/,
exclude: /node_modules/,
loader: 'vue-loader',
options: {
loader: {
scss: 'vue-style-loader!css-loader!sass-loader',
css: 'vue-style-loader!css-loader'
}
}
},
// JS files
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
// CSS / SASS files
{
test: /\.(sa|sc|c)ss$/,
// test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
url: false,
minimize: true,
sourceMap: true
}
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
minimize: true
}
}
]
},
{
test: /\.(png|gif|jpe|jpg|woff|woff2|eot|ttf|svg)(\?.*$|$)/,
use: [
{
loader: 'file-loader',
options: {
// name: '[path][name].[ext]',
name: '[name].[ext]',
outputPath: '/public/fonts/',
publicPath: '/public/fonts/'
}
}
]
}
Tried following: https://chriscourses.com/blog/loading-fonts-webpack
and doesn't seem to work.
Adding CSS screentshot
UPDATE
With base on the github files, you are targeting the unchanged css on the php file. That will not be parsed by webpack, remove it.
<link rel="stylesheet" type="text/css" href="css/main.css">
If you run npm run build your entry point is the JS file, this will be the parsed JS file though webpack that will generate all your files and will need to be included.
Then you are using mini css extract plugin to copy your css to somewhere, you need to load that file.
By your current configuration it is saving one level up on a css folder:
new MiniCssExtractPlugin({ filename: '../css/[name].css' }),
Whatever this file outputs is what you should be loading not the original main.css, so by your current folder structure this file would be on one level UP path. Not in the public/css that you are probably expecting, if I am not mistaken if you use ./css/[name].css it should output to where you are expecting.
As a side note here, it seems you are using the same folder for the source and output. Try to move to separated folders just so you don't overwrite anything unwillingly.
Finally the fonts:
The test of the loader needs to match your font
src: url("../webfonts/fa-brands-400.eot");
does not match the test:
test: /\.(png|gif|jpe|jpg|woff|woff2|eot|ttf|svg)(\?.*$|$)/,
You probably want to make that last part optional
test: /\.(png|gif|jpe|jpg|woff|woff2|eot|ttf|svg)(\?.*$|$)?/,
also your css-loader has url=false so the font resolver would never be invoked. Remove the url: false from your loader. Then is just a case of playing with the options of the file-loader, you can change the public-path to go to whatever you store your files and they would be replaced on the generated css and output path to copy them to the desired location.
So to summarise:
Check if you are importing the right css file, rename the file and see where it lands if you need assurance
If you want the url and the loader to be replaced , remove the url:false from css-loader and ensure the fonts files regex is matching them.
To avoid confusion store all the output on separated folder and check what lays where.
First answer:
If you are already using font-awesome and webpack I would suggest you use the font-awesome-loader.
That would be the easiest way to load them but a deeper explanation is that basically for every file extension webpack requires a loader to handle it. It will handle the file appropriately and put its contents somewhere.
So the steps to make webpack load the fontawesome fonts are:
Install the font awesome package in your project (or have the assets on some fixed place).
Load the font files using some loader like below
module.exports = {
module: {
loaders: [
// the file-loader will copy the file and fix the appropriate url
{
test: /\.(ttf|eot|svg|woff(2)?)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "fonts/",
publicPath: "../fonts/"
}
}
]
}
};
Load the appropriate CSS/SCSS/LESS from font-awesome on your css.
So analysing your code on this part:
// Forgot why I need this...
{
test: /\.(png|gif|jpe|jpg|woff|woff2|eot|ttf|svg)(\?.*$|$)/,
use: [{
loader: 'url-loader',
options: {
limit: 100000
}
}]
}
You decided to load all these extensions through url-loader so they would become base64 URIs.
You loaded all font awesome css here
#import '../assets/icons/font-awesome/css/fontawesome-all.css';
If you check the CSS it is referencing the files by a given path and you choose the url-loader so the path will not match. If you change to the file-loader and make the options match the appropriate path it will copy the files there and you should be all set to go.
I've just posted a detailed answer on another similar question like this. That could help you and also includes another possible solution with the new way of using FontAwesome5 with SVG+JS. With that there's no need for font files, Webpack loaders, etc... Just a few extra lines in your JavaScript code.
(I hope posting an answer like this is not against the rules. That another is a long writing, I don't want to copy-paste it. Should I? I don't think the duplicate flag could be used here...)

VueJS/Webpack - Not exporting sass file to css file

So I'm facing this problem that in my project I want to use sass as well as Vue but it wont compile.
So far I'm using vue-cli and have to init a normal project(vue init webpack project) and followed the guide here for global https://vue-loader.vuejs.org/en/configurations/pre-processors.html
And I wand the SCSS file to compile to a CSS and place itself in a folder.
After I've done that nothing happens it runs but without CSS.
Basically I want this -> src/asset/css/style.scss
To compile to this location -> static/css/style.css <- and then be a CSS
file because then I can load it into main.html
This is the webpack.base.conf file
{
test: /\.scss$/,
use: [
'sass-loader',
'style-loader',
'css-loader',
'postcss-loader',
{
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, '../src/assets/css/layout.scss')
},
},
],
},
This is the utils file
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass').concat(
{
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, '../src/assets/css/layout.scss')
}
}
),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
How will I be able to fix this?

nextJS/webpack: How to handle SASS files with font

I'm trying to configure webpack of my nextJS application to handle some SASS files, which looks like this:
#font-face
font-family: 'Marcellus'
font-style: normal
font-weight: 400
src: local('Marcellus-Regular'), url('/fonts/marcellus/Marcellus-Regular.ttf') format('truetype')
The # gives me an unexpected token error. So I tried to add some custom webpack configuration:
module.exports = {
webpack: function (config) {
config.module = {
rules: [
{ test: /(\.sass$)/, loaders: ['sass-loader'] },
{ test: /(\.css$)/, loaders: ['style-loader', 'css-loader', 'postcss-loader'] },
{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' }
]
}
return config
}
}
With this the *.js files aren't recognized anymore and I'm not quite sure if the SASS files are loaded correctly. I'm very unexperienced with webpack.
You need to add multiple loaders for the SASS file:
test: /\.sass$/,
use: [{
loader: 'style-loader', // creates style nodes from JS strings
}, {
loader: 'css-loader', // translates CSS into CommonJS
}, {
loader: 'sass-loader', // compiles Sass to CSS
}],
Source: Sass-loader

How to include images from CSS (backgrounds and etc.) to build folder using webpack?

I'm trying to use file loader to process images and include them into my build folder.
Images which are inside html files appear in build but images from styles not.
I keep my webpack config splitted into 2 files and use webpack merge module to merge them.
This is how i configure css processing:
exports.loadCSS = function (paths) {
return {
module: {
rules: [{
test: /\.scss$/,
include: paths.app,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
root: paths.root
}
},
'postcss-loader',
'sass-loader'
]
}]
}
};
};
And this is file loader configuration:
{
test: /\.(jpg|png|svg)$/,
loader: 'file-loader?name=[path][name].[hash].[ext]'
}
Piece of scss:
.img-from-styles {
width: 100px;
height: 100px;
background: url('/imgs/imgInStyles.jpg');
}
Here is project itself containing full configuration
You need to use url-loader
Install it
npm install url-loader --save-dev
How use it
{
test: /\.(png|jpg|jpeg|gif)$/,
loader: 'url-loader?limit=10000'
}
Now webpack will be able to resolve your url from your styles
Update
Webpack (css-loader) need exact file path so it can resolve the file or url for you.

Unable to load/require any css files in Node

I have a ReactJS application based off of this boilerplate.
I am simply trying to load and require or import a css file (to be embedded in <style> tag, as opposed to css link). Below are the two methods I have tried, and not ever both at the same time.
Method 1: Configure loaders in Webpack
These are all the loader configurations I have tried, but still resulted in this error: [require-hacker] Trying to load "something.css" as a "*.js"
dev.config.js
module: {
loaders: [
// loaders in here
]
}
{ test: /\.css$/, loader: "style!css" }
{ test: /\.css$/, loader: 'style-loader!css-loader'} from here
{ test: /\.css$/, loader: 'style!css!postcss' }
{ test: /\.css$/, loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]!postcss' }
{ test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
}
{
test: /\.css$/,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
},
Method 2: Use loaders directly
If I remove the css loaders altogether, and instead call require('style!css!./something.css'), I get this error:
Error: Cannot find module 'style!css!./something.css'
---- # NOTE: ----
I am able to properly require my .scss files and its webpack loader configuration is below. But for some reason my css files don't want to play that way too.
{ test: /\.scss$/,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap' }
change extensions: ['less','scss'] to extensions: ['less','scss','css'] in webpack-isomorphic-tools.js at line 65.for more details you can see this

Categories

Resources