How do I compress inline css in the webpack bundle - css

I have an SPA using vanilla webcomponents, and I am struggling with compressing the inline css in the bundled js webpack output. Here's the module part of my webpack config:
module: {
rules: [
{
test: /\.html$/i,
loader: "html-loader",
exclude: path.resolve(__dirname, "./src/index.html")
},
{
test: /\.css$/i,
exclude: /node_modules/,
loader: 'css-loader'
}
],
}
In my components I import css like this:
import css from "./entityPage.css";
In my component css e.g. ./entityPage.css I refer to the "outer css" like this
#import "../../style.css";
Here is an extract of the inline css in the webpack bundle output:
c.push([e.id,"#h2puIrptVrtsTvV8FGBM{\r\n width: 40%;\r\n min-width: 614px; /*48 x the character w with font-size 1rem ;) */\r\n border: solid 1px black;\r\n\r\n}\r\n\r\n#eKOgREy00yPONhrgY8Zg{\r\n font-weight: bold;\r\n
As seen whitespace, lineshifts and even comments are preserved.
I have tried multiple combinations of mini-css-extract-plugin, css-minimizer-webpack-plugin, postcss-loader without luck, so a working example of the css rule setup in webpack config would be really appreciated. (with eventual plugins / optimization setup if appropriate)
Thx.

Check out CSSO (https://github.com/css/csso). You can use this with Webpack. There some documentation there on how to set it up with WebPack.
An alternative way is to let the IDE compile this for you automatically.
What I do is to code in SCSS - which will automatically compile to CSS when I change the file. This is set up in PHPStorm File Watchers. PHPStorm detects external changes in CSS (as it was generated from SCSS) and it applies Autoprefixer and CSSO optimizer to minimize the CSS.
I also made my own CLI tool to automatically compile that CSS to native JavaScript module for better performance and quicker compiling - so I don't need Webpack to do this. You can get my CLI tool here: https://www.npmjs.com/package/csshtml-module
This should also work well with Webpack as the end result is native JS/TS. And you get the benefit of SCSS compiling and optimization outside of your JS library as well.
Similar approach can be done in VSCode, and probably other IDE's as well.

postcss / postcss-loader was the way to go in my context.
The webpack.config module rule for my css files looks like this:
{
test: /\.css$/i,
exclude: /node_modules/,
use: [
{
loader: 'css-loader',
options: {
importLoaders: 1,
}
},
{
loader: 'postcss-loader'
}
]
}

Related

How can I make a sass file global instead of importing it in every file and bloating bundle size?

Question
How can I globally import variables.scss 1. without importing them in every file and 2. by referencing instead of duplicating them in my build?
Setup
I use Vue2 and laravel-mix and I have index.scss imported in my main.js
variables.scss
$--test: #ff0000;
index.scss
#import 'variables';
.dashboard-title {
color: $--test;
}
This colors the title red. But when I try to do the same thing inside of the component, it doesnt work:
<style scoped lang="scss">
.dashboard-title {
color: $--test;
}
</style>
This doesn't work, but I proved that index.scss is global in my first example. How is
variables.scss not global, when I import it in my global index.scss?
I can fix the error by importing the variables file in the component, but by doing this, I essentially duplicate the whole variables.scss file every time I import it in a vue component.
I found this out by analyzing my bundle with a webpack bundle analyzer, this is the output:
webpack bundle analysis image (all blue crossed parts are increased in size because the variables file is imported, this isn't a big problem now, but this will exponentially increase my bundle size with time)
It would reduce my bundle size by atleast 20% right now...
How can I reference the variables.scss file instead of duplicating its content?
What I've tried:
https://css-tricks.com/how-to-import-a-sass-file-into-every-vue-component-in-an-app/ (I wasn't able to "migrate" this to a laravel-mix config)
I've also tried using purgeCss to remove duplicate css, this just completely messed up my styles but reduced the bundle size by 50% lol
Adding this to the webpack.mix.js
mix.webpackConfig({
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'sass-loader',
options: {
//this might be "data" or "prependData" depening on your version
additionalData: `#import "./resources/js/styles/variables.scss";`
}
}
]
}
]
}
})
This does make the variables global, but imports(duplicates) them for every vue component, even if they aren't being used.
Edit: This only is an issue, when the imported file is relatively big. In my project, the imported file itsself imported a theme scss (to get access to the themes variables), which ultimately copied this whole thing everywhere I needed the variables.
I fixed this by defining my custom variables in a seperate file and using those variables in the "overwriting-variables" file, something like this:
custom-variables.scss
$red: #ff0000;
overwriting-variables.scss
import 'theme.scss'; //this bloated my project
import 'custom-variables';
$--theme-red: $red
And when I needed this theme color in my vue components I just imported the custom-variables.scss instead of overwriting-variables.scss.
This does fix my bloating issue, but doesn't fully solve the problem, I still have multiple instances of the custom-variables.scss in my project, it just doesn't matter (yet) because its really small. So I'd be still happy to hear about other solutions!
If you import every .scss in your index.scss, then every variable should work. Try this in your vue.config
css: {
loaderOptions: {
// by default the `sass` option will apply to both syntaxes
// because `scss` syntax is also processed by sass-loader underlyingly
// but when configuring the `data` option
// `scss` syntax requires an semicolon at the end of a statement, while `sass` syntax requires none
// in that case, we can target the `scss` syntax separately using the `scss` option
scss: {
prependData: `#import "#/style/index.scss"`
}
}
},
So I got it working with laravel-mix like this:
mix.webpackConfig({
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: 'sass-loader',
options: {
//this might be "data" or "prependData" depening on your version
additionalData: `#import "./resources/js/styles/variables.scss";`
}
}
]
}
]
}
})
Not sure yet if this prevents the duplication though
Edit: It does not prevent duplication, it does increase the bundle size in every vue component. So I now have a 150% bigger bundle, because the variables file is imported in every single vue component. Even if the variable isn't even used.

How can I add a namespace to all my .less files in a project?

I am working with two web applications in the same repository, and need a way to 'namespace' the CSS class names for each application.
I am using LESS as my style preprocessor, and and using webpack to bundle all the LESS files into a single .css file which then gets loaded into the webpage via HTML.
What I am currently doing is manually prepending every CSS class with my namespace like so:
// mylessfile.less
.nmsp {
&__some-class-name {
color: blue;
}
}
this is annoying and not very maintainable.
Would something like this scale?:
// global.less
#my_namespace="nmsp";
// mylessfile.less
#import "global.less";
#my_namespace {
&__some-class-name {
color: blue;
}
}
Is there a way to do this via LESS or even Webpack?
Ideally I would like to use a namespace for app1, app2, and a "common" styles namespace for all the styles that both applications share.
SASS and LESS both support namespacing out of the box.
.app1-styles {
#import (app1) url("app1.css");
}
Webpack supports CSS Modules as a way to scope an app. Using CSS Modules gets you namespacing as well.
In your webpack config:
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
}
Stuff inside the [ ] should be customized to your app.
Here's a demo project repo

how to use less & bootstrap in angular 6 project?

I have edit the angular.json styleext for using less
"schematics": {
"#schematics/angular:component": {
"prefix": "app",
"styleext": "less"
},
"#schematics/angular:directive": {
"prefix": "app"
}
}
I create a component and test the less it works. But now i want to mix the component css/less with the bootgstrap classes.
For example I want all button in my component to have .mx-1
I type in my less:
.btnmx-1{
.btn();
.mx-1();
}
but it failed. I tried to import :
#import "../../../../node_modules/bootstrap/dist/css/bootstrap.min.css";
.btnmx-1{
.btn();
.mx-1();
}
this one also failed to compile with error : .btn is undefined
How to fix this ? I want all buttons in my component to have margin left and right 1px inherited from bootstrap
For Bootsrap:
npm install bootsrap --save
in angular.json:
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.css",
"src/styles.scss"
],
For less:
add less file type instead css (by default)
comp.component.less
in angular.json.
Set the property defaults.styleExt to less.
Here's how I use bootstrap in my project
Download bootstrap Source files from link: https://getbootstrap.com/docs/4.0/getting-started/download/
create styles folders in your project copy scss folder from resource to it and rename it to bootstrap to more clearly
create your own mixin and import it bootstrap.scss file(below all of the existing imports)
import bootstrap.scss to style.scss(or in angular.json)
In my case, I just want to use bootstrap utils classes like padding, margin,heading...so I just keep these files in my boostrap scss folder
If you need all just keep all or remove some modules that need bootstrap js to run like carousel....

how to upgrade css-loader from v0.28 to v1.0.0?

In css-loader v0.28, I used root option ,but In css-loader v1.0.0,the option was removed,I checked the changelog(https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md) and Found this:
remove root option, use postcss-loader with postcss-url plugin
but I could not integrate postcss-url very well.
for example,my previous css-loader option was:
{
loader: 'css-loader',
options: {
root: 'static',
minimize: true
}
}
So when I wrote some css snippet like that :
background-image: url("/mobile/img/logo-new.png");
after css-loader parsed,it would changed to:
background-image: url("/static/mobile/img/logo-new.png");
I like previous style but maybe we should upgrade css-loader,so should use postcss-url.I could not use it very well,the docs also could not give me more info,so I came here and hope someone could help me.
what postcss-url option should I use to get the correct answer?

Using Webpack to compile scss in a separate css file while keeping original urls for images

I've learned how to include scss files inside a javascript using file Webpack but now I want to generate a css file from a scss. I'm using ExtractTextPlugin to do this and I could generate a css file but the problem is that inside my scss file, I'm setting some background images like:
background: url("../img/test.jpg") no-repeat center center;
Now, I realized that when extracting into a separate css file, the images are incorporated in that file, increasing the size from 6 kb to 400 kb for the different images so I can't load the styles quickly.
I want to ignore including the images inside the generated css file and just keep the url like they are so that they could be requested like they would normally do from a css file. I've read some articles related to that but I still can't figure it out.
The loaders I'm using are:
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass')
},
{
test: /\.(png|jpg)$/,
loader: "url-loader"
},
Thank you very much!
I could figure it out how to solve the problem, we just need to use file-loader instead of url-loader and set the context like:
{
test: /\.(png|jpg)$/,
loader: "file-loader?emitFile=false&name=[path][name].[ext]&context=src/"
}
With the context query, all the url paths keep like they should be.

Resources