webpack scss background image path error - sass

I have the following rule on line 258 of my style.scss file:
background: url(img/bg-light-grey.gif)
I then run the command webpack and it successfully builds. I go to my webpage but I see I don't see the image included on my webpage. I open up chrome debugger and it says that line 258 of my style.scss has:
background: url(build/4932049asdfjaoi3j234.gif)
In my Chrome debugger, I replace that line with absolute url
background: url(http://localhost:8080/experiment/build/4932049asdfjaoi3j234.gif)
And now the image appears.
How do I get webpack to compile the file paths properly for my images? Alternatively, I don't mind stringify or base64encode these things into my bundle.js file. Whatever it takes to get these images to render properly.

I found the answer here:
Webpack - background images not loading
I had to make a change in my webpack.config.js from
{ test: /\.scss$/, loaders: [ 'style', 'css?sourceMap', 'sass?sourceMap' ]},
to
{ test: /\.scss$/, loaders: [ 'style', 'css', 'sass' ]},

Related

How to make Laravel Vite copy static assets versioned to build folder

I'm experimenting with Laravel Vite but can't seem to figure out how to have the build command move static assets. Instead, it embeds the images "in" the css file trough base64.
So far I've figured out that you need to reference your images relative to the source .css / .scss file.
Like so in /resources/app.css;
.arrow {
background-image: url('../img/icons/arrow.png');
}
When I run npm run build the end result is a css file containing the image as a base64;
.arrow {
background-image: url(data:image/png;base64,xxxxxxxxxxxxxxxxxxxx);
}
My desired end result, however, would be that Vite would copy and version that exact image into /public/build/assets/img/icons/arrow.xxxxxxxxxx.png and the processed css would be;
.arrow {
background-image: url('/build/assets/img/icons/arrow.xxxxxxxxxx.png);
}
Figured it out.
Turns out it's actually a feature where Vite inlines images < 4kb by default. The setting can be overwritten by defining build.assetsInlineLimit
export default defineConfig({
build: {
assetsInlineLimit: 0,
},
plugins: [
laravel([
'resources/css/app.scss',
]),
],
});
As stated in the docs;
Assets smaller in bytes than the assetsInlineLimit option will be inlined as base64 data URLs.
https://vitejs.dev/guide/assets.html
https://vitejs.dev/config/build-options.html#build-assetsinlinelimit

Tailwind css installation, rebuild won't stop

I try to install Tailwind CSS following the instructions on the official page.
But as I tried to input the following instruction which starts the Tailwind CLI build process, the following occurred.
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
enter image description here
And it's still rebuilding even after ten minutes.
I have no idea what is going on.
Thank you in advance!
The --watch command will make it run continiously. To put an end to it just press and hold CTRL then C
In tailwind.config.js, stick to the essential folders, mine had to check thousands of plugin files before building, so updated it to limit the files to check
module.exports = {
content: [
"../views/**/*.{php,js,html}",
"../js/app/**/*.{php,js}"
],
theme: {
extend: {},
},
plugins: [],
}

Webpack dev-server doesn't show the inline image

I'm trying to understand how webpack is working. For this I created a very simple example:
Folder structure
webpack.config.js
const path = require('path');
module.exports = {
entry: ['./src/index.js'],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
devtool: 'source-map',
};
index.html
<body>
<div>
<img src="../src/images/lion.png" alt="">
</div>
<script src="./bundle.js"></script>
</body>
As you can see the index.html is inside the dist folder. If I open the index.html in browser, it shows the images.
But if I run the dev-server, it starts the browser, shows the index.html but cannot find the image.
And the console shows this error:
Does any one know why webpack cannot show the image?
You need to use html-loader https://webpack.js.org/loaders/html-loader/ so that it require()s for you every url from <img src="<url>"> correctly at compile time, otherwise your browser will try to access the path it cannot reach during runtime.
Also when using html-loader, since it will require img urls for you, you will need a specific loader that understands image format, for which you can use https://webpack.js.org/loaders/url-loader/ or https://webpack.js.org/loaders/file-loader/
Otherwise you will need to copy all your images to a dist folder where you can access them publicly during runtime in browser from your html without html-loader or require calls. But the copying itself can be done again through another loader https://webpack.js.org/plugins/copy-webpack-plugin/ .
And still you cannot access the compile level paths like ../src, since when webpack is running it's compiling everything into a final public folder where you only have your main js file and all of it's require()ed dependencies that are put into the same final(dist) folder based on the rules from loaders or plugins property in webpack config.

Setup Laravel Mix with SASS and PostCSS critical CSS splitting

I want to setup Laravel Mix with mix.sass AND PostCss Critical CSS splitting. In the end I want two files: app.css and app-critical.css.
Unfortunately I can get this to work. One of the setups (webpack.mix.js) I did try:
mix
.js('templates/src/js/app.js', 'web/assets/dist/')
.js('templates/src/js/home.js', 'web/assets/dist/')
.extract(['vue','axios','lazysizes','svgxuse', 'fontfaceobserver'], 'web/assets/dist/vendor.js')
.sass('templates/src/scss/app.scss', 'web/assets/dist/')
.sourceMaps()
.options({
postCss: [
require('postcss-critical-css')({
preserve: false,
minify: false
})
]
})
.browserSync({
proxy: '127.0.0.1:8080',
files: [
'templates/**/*.twig',
'templates/src/js/**/*',
'templates/src/scss/**/*'
]
});
if (mix.inProduction()) {
console.log("In production");
mix.version();
}
When I run the script via 'npm run watch' I get an error:
10% building modules 0/1 modules 1 active ...ign-tools/templates/src/scss/app.scssWithout `from` option PostCSS could generate wrong source map and will not find Browserslist config. Set it to CSS file path or to `undefined` to prevent this warning.
Also, my file is just copying over all the critical styling. The file grows bigger and bigger, expanding the duplicate code everytime the input SCSS/CSS-file changes.
I did try to set up Laravel Mix + mix.sass + one of the following plugins:
https://github.com/zgreen/postcss-critical-css
https://www.npmjs.com/package/postcss-critical-split
Without success :(
Anybody with a working setup or link to an example repository?
Thanks,
Teun

How to #import external SCSS properly with webpack and Vue.js?

As in Material Component Web's example, I want to be able to import SCSS from my node_modules like this:
#import '#material/elevation/mdc-elevation';
However, I'm getting this error message when trying to run the webpack build:
File to import not found or unreadable: #material/elevation/mdc-elevation.
#import './~/#material/elevation/mdc-elevation.scss'; doesn't work either.
I'm pretty sure the issue is somewhere in my webpack config, but I can't figure out where.
What did they do in Material Components Web's Vue.js example in order to make it work?
Here's my npm-debug.log in case you need it.
And here's the corresponding Git repository: sk22/spg-tinf-sem03/proj01
Thanks in advance!
Edit: I want to be able to import the scss files, not the compiled css.
Got it.
here's a part of my webpack 2 config's module.rules:
{
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
includePaths: [path.resolve(__dirname, 'node_modules')],
},
},
],
},
So what did I do wrong?
My options object was placed in the rule directly, not the loader.
The old webpack config rule looked like this:
{
test: /\.(sass|scss)$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
options: { includePaths: [path.resolve(__dirname, './node_modules')] },
},
See the difference? Instead of the 'sass-loader' string, I extended it to an object, containing the loader name and the options object, because the options only apply to the sass-loader.
(You could also drop the path.resolve and only write 'node_modules', but it might be safer to leave it.)
Check out this documentation page for further information. https://webpack.js.org/configuration/module/#rule-use
Without that loader, you must prefix each import with a ~, which webpack converts to the node_modules folder, at least with my previous configuration.
But this will break 3rd party SCSS frameworks like Material Components Web, because they use #import statements without a leading ~ themselves, for example here.
Inside .vue files
This will not work in .vue files, as vue-loader just uses sass-loader without any options by default.
So if you want that to work, you probably need to make use of vue-loader's own options, as described in its documentation.
(I'm unable to get it to work for some reason I don't know...)
EDIT: Webpack has a section on sass-loader now: https://webpack.js.org/loaders/sass-loader/ also mentioning includepaths.
I had the same issue with #material and Vue. I managed to resolve the problem without adjusting the use property directly.
Solution
Step 1: First create a default Vue 2.1 project using the CLI.
Your file structure will have a ./build directory.
Step 2: Open the file 'utils' you will see a cssLoaders() function which returns an object/map for the languages vue-loader supports.
You will see both sass and scss in that map.
Step 3: Change the values of sass and scss to:
sass: generateLoaders('sass', {
indentedSyntax: true,
includePaths: [path.resolve(__dirname, '../node_modules')]
}),
scss: generateLoaders('sass', {
includePaths: [path.resolve(__dirname, '../node_modules')]
}),
Step 4: Go to the .vue file you're using and change the lang attribute in your <style> element to either sass or scss.
Step 5: After you've done that go to the terminal/console and install sass-loader with:
npm install sass-loader node-sass webpack --save-dev
Step 6: Then run npm run dev and it should work.
Why does this work?
Libraries
I dug around a bit and it turns out sass-loader uses node-sass which has some options such asincludePaths one mentioned by #22samuelk. IncludePaths tells node-sass or rather the underlying library LibSass to include sass files from that directory/path.
Vue
Sass-loader options
By default Vue expects your assets to be in your projects src/assets folder (correct me if I'm wrong). You can however use ~ to indicat you want to start at your projects root which would look like `~/node_modules/#material/smth/mdc-smth.scss.
Now if you want your sass-loader to use something other than those options you need to explicitly tell them.
Hence path.resolve(__dirname, '../node_modules' since the utils file is in ./build and you need to use an absolute path for sass-loader to understand where to look.
Vue-loader config
This is not really specific to the question but the vue-loader config defined in vue-loader.conf.js works as follows:
It uses the map returned by cssLoaders() to build the loaders expected by webpack.
The returned map ({key:value}) is then used by providing key as a file extension used in test: for a loader object. The value is used as the loader object.
Which would like like this:
{
test: /\.(key)$/,
use: [
{
loader: '//ld//-loader',
options: {
/*Options passed to generateLoaders('//ld//', options)*/
},
},
],
}
Where key is the file extention. In this case that would be either sass or scss. And //ld//is the loader you which to use. Which is shown in Step 3 as 'sass'.
Hopefully this clears up some stuff. Took me a while because I just started using Vue.

Resources