Thanks for the awesome work.
I created (like half a year ago) a theme for an application. The theme css is compiled using scss (node-sass). The content of the main scss file is like this:
// based on https://getbootstrap.com/docs/4.0/getting-started/theming/#importing
@import "~bootstrap/scss/_functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
// setting variables like $theme-colors, etc
@import "~bootstrap/scss/bootstrap";
@import "customtheme"
// ...
So after I tried to recompile it recently, I got the following error message:
ERROR in ./theme.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
@if str-index($string, "data:image/svg+xml") {
^
Argument `$string` of `str-index($string, $substring)` must be a string
in /Users/d4rkmindz/code/node_modules/bootstrap/scss/_functions.scss (line 55, column 7)
at runLoaders (/Users/d4rkmindz/code/node_modules/webpack/lib/NormalModule.js:316:20)
at /Users/d4rkmindz/code/node_modules/loader-runner/lib/LoaderRunner.js:367:11
at /Users/d4rkmindz/code/node_modules/loader-runner/lib/LoaderRunner.js:233:18
at context.callback (/Users/d4rkmindz/code/node_modules/loader-runner/lib/LoaderRunner.js:111:13)
at Object.render [as callback] (/Users/d4rkmindz/code/node_modules/sass-loader/dist/index.js:89:7)
at Object.done [as callback] (/Users/d4rkmindz/code/node_modules/neo-async/async.js:8067:18)
at options.error (/Users/d4rkmindz/code/node_modules/node-sass/lib/index.js:294:32)
@ ./styles/theme.test.js 1:0-32
My webpack file looks like this:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: {
theme: path.join(__dirname, 'styles', 'theme.js'), // this file basically just imports the theme.scss file
},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
{
test: /\.js$/,
exclude: /(node_modules)/,
use: 'babel-loader',
},
],
},
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin({}),
new TerserPlugin({
parallel: true,
terserOptions: {
ecma: 6,
},
}),
],
splitChunks: {
cacheGroups: {
common: {
test: /node_modules/,
name: 'vendors',
chunks: 'all',
},
},
},
},
output: {
// output stuff into code/webroot/ folder
filename: path.join('js', '[name].min.js'),
chunkFilename: path.join('js', '[name].min.js'),
path: path.resolve(__dirname, 'webroot'),
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
Alert: 'exports-loader?Alert!bootstrap/js/dist/alert',
Button: 'exports-loader?Button!bootstrap/js/dist/button',
Carousel: 'exports-loader?Carousel!bootstrap/js/dist/carousel',
Collapse: 'exports-loader?Collapse!bootstrap/js/dist/collapse',
Dropdown: 'exports-loader?Dropdown!bootstrap/js/dist/dropdown',
Modal: 'exports-loader?Modal!bootstrap/js/dist/modal',
Popover: 'exports-loader?Popover!bootstrap/js/dist/popover',
Scrollspy: 'exports-loader?Scrollspy!bootstrap/js/dist/scrollspy',
Tab: 'exports-loader?Tab!bootstrap/js/dist/tab',
Tooltip: 'exports-loader?Tooltip!bootstrap/js/dist/tooltip',
Util: 'exports-loader?Util!bootstrap/js/dist/util',
}),
new MiniCssExtractPlugin({
filename: path.join('css', '[name].min.css'),
}),
],
};
So after having a look at the bootstrap code, i realized, that the method escape-svg (L54, _functions.scss)
uses the $escaped-characters variable which is not set by the moment of import (the recommended order is functions, then variables, where it is defined).
It might be a problem, that I always updated the dependencies, but missed out to recompile the theme. The last compilation might have been at version 4.2 or less (the escape-svg method didn't exist back then).
Now my question is: How do I get this to work again?
Used versions
@twbs/css-review
You're importing the whole Bootstrap after importing functions, variables and mixins: they're imported twice.
Please read carefully our "Importing" documentation and try again, with either importing the whole Bootstrap or only part of itβand share your result if that doesn't fix your issue :)
Closing per previous comment.
Please read carefully our "Importing" documentation and try again, with either importing the whole Bootstrap or only part of itβand share your result if that doesn't fix your issue :)
I followed the documentation and removed all imports. Now the file looks (original file) something similar like this
// Your variable overrides
$body-bg: #000;
$body-color: #111;
// Bootstrap and its default variables
@import "../node_modules/bootstrap/scss/bootstrap";
I still receive the error as described above. Somehow, if I rearrange the code like below, it compiles, but (obviously) no changes are applied
// Bootstrap and its default variables
@import "../node_modules/bootstrap/scss/bootstrap";
// Your variable overrides
$body-bg: #000;
$body-color: #111;
@D4rkMindz Could you please share the exact variables you're trying to overwrite?
The error message is pretty clear, you're trying to replace a variable that's called in our escape-svg() function with something that the function cannot handle (it requires string, as the message says). Maybe you're dropping or nullifying a required variable, or using a color where Bootstrap expects a string.
@ffoodd I created a gist with all the used variables here.
I added a @debug "string value contains: #{$string}"; statement at scss/_functions.scss:55 and placed the output in the gist too.
The last debug output line contains the same value as set in the $body-bg variable. If I rename this variable, absolutely nothing changes.
I also checked all my scss files for following variables to be used/written somewhere else than in the bootstrap file.
Method escape-svg($string)
| Variable | Read | Write |
| --------- | ----- | ------ |
| $string | β | β |
| $char | β | β |
| $encoded | β | β |
| $escaped-characters | β | β |
Method str-replace($string, $search, $replace: "") used in escape-svg($string)
| Variable | Read | Write |
| --------- | ----- | ------ |
| $string | β | β |
| $search | β | β |
| $replace | β | β |
| $index | β | β |
So I guess I was right: you're overriding $navbar-dark-toggler-icon-bg with a color, where Bootstrap uses a string that's passed through escape-svg() to be used as background-image.
This cannot work. I think if you drop this variable, everything should be fine.
@mdo @MartijnCuppens I understand this is quite confusing, we should probably find a way to mention this? Not sure though, thniking out loud.
@ffoodd Thank you so much. This actually resolved my problem.
@mdo @MartijnCuppens The variables are pretty good named and really clear what they're standing for. But it still might be a good thing to document it. I mean most other framework have an (automatically generated) API documentation for all its methods/variables.
This might help. It's also better to have a documentation instead of just having to look through the code and "manually debug" it.
Still great work though and thank you for that.
Most helpful comment
So I guess I was right: you're overriding
$navbar-dark-toggler-icon-bgwith a color, where Bootstrap uses a string that's passed throughescape-svg()to be used asbackground-image.This cannot work. I think if you drop this variable, everything should be fine.
@mdo @MartijnCuppens I understand this is quite confusing, we should probably find a way to mention this? Not sure though, thniking out loud.