Compile sass files to hashed css using webpack - css

to compile my .scss files I use webpack.
What i want to achieve is to get for example
styles.b0eda78ad870282c8cb9fd58884415d7.css
instead of
styles.css
When I add to webpack option [hash] (now commented in source) - then every change in .scss files generate new .css files. For example 3 changes in .scss will generate 3 new files with different hashes:
themeA.b0eda78ad870282c8cb9fd58884415d7.css
themeA.2c0521243fe51696a6d08ae5443a6721.css
themeA.6ebd2d65f4d311fbac8441141826a9a8.css
I want only to update one css file with new hash and do not create new files.
My webpack configuration
const themeA = `${mainDirectory}/commons/themeA.scss`;
const themeB = `${mainDirectory}/commons/scss/shop/themeB.scss`;
const themeC = `${mainDirectory}/commons/themeC.scss`;
const themeD = `${mainDirectory}/commons/scss/shop/themeD.scss`;
let sassFiles;
const themeMap = new Map([
['a', themeA],
['b', themeB],
['c', themeC],
['d', themeD],
]);
if (theme === undefined) {
sassFiles = [...themeMap.values()];
} else {
sassFiles = [
`${mainDirectory}/commons/${theme}.scss`,
`${mainDirectory}/commons/scss/shop/${theme}_shop.scss`,
];
}
module.exports = {
entry: [...sassFiles],
mode: 'development',
output: {
path: path.resolve(mainDirectory, 'commons'),
filename: 'hot/sassBundle.js',
publicPath: '/',
},
module: {
rules: [
{
test: /\.scss$/,
sideEffects: true,
use: [
{
loader: 'file-loader',
options: {
minimize: true,
name: '[name].css',
// hashed css
// name: '[name].[hash].css',
outputPath: '/css',
},
},
{
loader: 'extract-loader',
},
{
loader: 'css-loader',
options: {
url: false,
sourceMap: !buildMode,
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: !buildMode,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: !buildMode,
convertToAbsoluteUrls: false,
},
},
],
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
},
{
test: /\.(woff|woff2|eot|ttf)$/,
loader: 'url-loader?limit=100000',
},
],
},
plugins: [
new webpack.SourceMapDevToolPlugin({}),
new ReplaceInFileWebpackPlugin([
{
dir: `${mainDirectory}/commons/css/`,
test: [/\.css$/],
rules: [
{
search: /\/\*# sourceURL.+\\*/g,
replace: '',
},
],
},
]),
],
};

Related

SVG in CSS is interpreted via webpack with "module.exports = 'data:...'" instead of valid svg

I use webpack to compile scss. The scss also contains url to svg files, which I need to process and link to css with correct url.
However, instead of a valid svg, I get a file (eebc108eb2b00c4b2784.svg) with the following content:
module.exports = "data:image/svg+xml,%3csvg width='30px' height='30px' xmlns=...'
which is linked to css like:
background-image: url(../eebc108eb2b00c4b2784.svg);
That is what i want basically, but svg obviously dont show. This SVG is not used anywhere in JS only in CSS.
My webpack config looks like this:
const webpack = require("webpack");
const path = require("path");
const AssetsPlugin = require("assets-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
let config = {
watch: true,
entry: {
appAdmHomepage: "./_devapp/AppAdmHomepage.js",
cssStyle: "../css/primary/style.scss",
cssAdm: "../css/primary/administrace.scss",
cssPrint: "../css/primary/print.scss",
cssObjProces: "../css/primary/objednavkovy_proces.scss",
cssDesign: "../css/primary/design.scss",
},
output: {
filename: "[name].bundle.js",
chunkFilename: "[name].[contenthash].js",
path: path.resolve(__dirname, "assets", "bundle")
},
resolve: {
extensions: [".js", ".jsx", ".json", ".ts", ".tsx", ".css", ".scss"]
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: path.resolve(__dirname, "node_modules"),
use: {
loader: "babel-loader",
options: {
presets: [
"#babel/preset-env",
["#babel/preset-react",{
"runtime": "automatic"
}]
],
plugins : [
["#babel/plugin-proposal-decorators", { version: "legacy" }],
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-private-methods",
]
}
},
}, {
test: /\.svg$/,
use: [
{
loader: "svg-url-loader",
options: {
name: "./image/[name]--.[ext]"
},
},
],
}, {
test: /\.scss$/,
include: [
path.resolve(__dirname, "../css/primary/")
],
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
url: true,
import: true
}
},
"sass-loader"
]
}, {
test: /\.css$/, //pro datepicker
use: [
"style-loader",
{
loader: "css-loader",
options: {
url: true
}
}
]
}
],
},
plugins: [
new webpack.DefinePlugin({
"__DEV__" : JSON.stringify(true),
"__API_HOST__" : JSON.stringify("http://127.0.0.1:8080/www/eshop/www"),
"__PATH_HOST__" : JSON.stringify("/www/eshop/www"),
}),
new AssetsPlugin({
prettyPrint: true,
removeFullPathAutoPrefix: true,
fullPath: true
}),
new MiniCssExtractPlugin({
filename: "./css/[name].min.css"
}),
new CleanWebpackPlugin()
]
};
module.exports = config;
Is there a way to link correct form of SVG or am i making a mistake somewhere? Thanks for help

Bootstrap not applying CSS using Webpack

I'm using Bootstrap with webpack, but when I run my app, no Bootstrap and no CSS is applied.
This is my webpack.config.js :
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
var OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
// mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
publicPath: '',
filename: 'bundle.js'
},
devServer: {
contentBase: path.join(__dirname, './build'),
compress: true,
port: 3000
},
performance: {
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
module: {
rules: [
{
test: /\.s?css$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].css"
}
},
{
loader: "extract-loader"
},
{
loader: "css-loader",
},
{
loader: "sass-loader"
}
]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ["file-loader"]
},
{
test: /\.(woff(2)?|ttf|otf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}
]
},
//remove comments from JS files
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
output: {
comments: false,
},
},
}),
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
}
})
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css"
}),
new ManifestPlugin(),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve('./public/index.html'),
}),
]
};
I have this kind of error in brower console :
Uncaught Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/css-loader/dist/cjs.js):
CssSyntaxError
(192:1) Unknown word
I don't have an idea where this error comes from.
Below two versions of dev/prod and all the code you can see here webpack-boilerplate
Dev:
{
test: /\.(css|sass|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
}
],
},
Prod:
{
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},

webpack not getting seperate css file for extract text plugin

Hi everyone I am using web-pack to try to replace a gulp build that was overly complicated. but was running into some issues when it came to the Css. We are using sass. We also have a project structure that has the sass files right by each of the the angular component so that means for every class there is a separate folder. Currently our gulp magically goes into the folders and downloads the sass.
But I can't get the extract-text-webpack-plugin to output me a separate Css file the source I am using for trying to do this is.
https://itnext.io/sharing-sass-resources-with-sass-resources-loader-and-webpack-ca470cd11746
here is my code
const config = {
entry: {
'app': './app/app.js',
// 'vendor': './src/vendor.module.js'
},
devtool: 'source-map',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist/dev')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: [ 'ng-annotate-loader', 'babel-loader' ]
},
// for fixing of loading bootstrap icon files
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
loader: 'url-loader?limit=10000',
options: {
name: './fonts/[name].[ext]'
}
},
{
test: /\.(eot|ttf)$/,
loader: 'file-loader',
options: {
name: './fonts/[name].[ext]'
}
},
{
test: /\.html$/,
loader: 'html-loader',
options: {
attrs: [ 'attrs=false' ]
}
},
{
test: /\.scss$/,
use: ExtractTextWebpackPlugin.extract({
fallback: 'style-loader',
filename: path.resolve(__dirname, 'dist/dev') + 'app.css',
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
},
{
loader: 'sass-resources-loader',
options: {
resources: require(path.join(process.cwd(), './app/appscss.js'))
}
}
]
}),
},
/* ,
{
test: /\.(scss)$/,
use: ExtractTextWebpackPlugin.extract({
use: [
{
loader: "css-loader",
options: {
minimize: true
}
},
{
loader: "sass-loader"
}
]
})
} */
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
comments: false,
sourceMap: true,
}),
new ExtractTextWebpackPlugin('app.css', {
allChunks: true
}),
new webpack.DefinePlugin({
GULP_REPLACE_ENV_URL: JSON.stringify(environementUrl())
})
],
devServer: {
port: 5000,
contentBase: path.resolve(__dirname, 'dist/dev'),
historyApiFallback: true,
// needed since we set api to something other than host
// http://flummox-engineering.blogspot.com/2017/10/webpack-dev-server-invalid-host-header-host-0.0.0.0-not-working-npm-dev-server.html
disableHostCheck: true
}
};
module.exports = config;
Any help would be much appreciated.

Wrong CSS rules order compiled with webpack

I have an issue with css order that compiles with webpack.
I currently use these packages in dependencies:
"css-loader": "^0.28.4",
"style-loader": "^0.18.2",
"sass-loader": "^6.0.6",
"sass-resources-loader": "^1.3.0",
"webpack": "^3.5.5",
Here is my webpack.config.js
const { alias } = require('./webpack/common.js');
const path = require('path');
const webpack = require('webpack');
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const nodeEnv = process.env.NODE_ENV || 'development';
const isProd = nodeEnv === 'production';
const sourcePath = path.join(__dirname, './src');
const staticPath = path.join(__dirname, './dist');
const commonCssOptions = {
sass: {
loaders: ['sass-loader', 'sass-resources-loader'],
},
context: path.resolve(__dirname, '.'),
output: {
path: 'dist',
},
};
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor.bundle.js',
}),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify(nodeEnv) },
}),
new webpack.NamedModulesPlugin(),
new ExtractTextPlugin({ filename: 'css/bundle.css', disable: false, allChunks: true }),
new webpack.ContextReplacementPlugin(
/moment[/\\]locale/,
/(en-gb)\.js/
),
];
if (isProd) {
plugins.push(
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false,
options: commonCssOptions,
})
);
} else {
const dashboard = new Dashboard();
plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.LoaderOptionsPlugin({
options: commonCssOptions,
}),
new DashboardPlugin(dashboard.setData)
);
}
module.exports = {
devtool: isProd ? false : 'cheap-module-source-map',
entry: {
js: './src/index.js',
vendor: [
'babel-polyfill',
'bootstrap-loader',
'classnames',
'react',
'react-dom',
'react-redux',
'redux',
'react-router',
'react-router-dom',
// 'moment',
],
},
output: {
path: staticPath,
publicPath: '/',
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: 'file-loader',
query: {
name: '[name].[ext]',
},
},
},
{
test: /\.s?css$/,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true,
localIdentName: '[name]__[local]_[hash:base64:5]',
},
},
{
loader: 'sass-loader',
options: {
includePaths: [
path.join(__dirname, './components-lib/src/assets/styles'),
],
},
},
{
loader: 'sass-resources-loader',
options: {
resources: [
'./components-lib/src/assets/styles/_variables.scss',
'./components-lib/src/assets/styles/_mixins.scss',
],
},
},
'postcss-loader',
],
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
'babel-loader',
],
},
{
test: /\.(woff|woff2|eot|ttf|svg)(\?.*$|$)/,
loader: 'file-loader',
query: {
name: '[name].[ext]',
},
},
],
},
resolve: {
extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.jsx', '.js'],
modules: [
'node_modules',
sourcePath,
],
alias,
},
plugins,
devServer: {
contentBase: './src',
historyApiFallback: true,
host: '0.0.0.0',
port: 3000,
compress: isProd,
inline: !isProd,
hot: !isProd,
quiet: true,
stats: {
assets: true,
children: false,
chunks: false,
hash: false,
modules: false,
publicPath: false,
timings: true,
version: false,
warnings: false,
colors: {
green: '\u001b[32m',
},
performance: {
hints: false,
},
},
},
externals: {
cheerio: 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true,
},
};
On initial load I have wrong css order
But on hot reload the order becomes correct
My component library is a git submodule (if it is important)
I've noticed that including HotModuleReplacementPlugin will change CSS order on occasion, still trying to figure out why.
I think because of the way things get re-written, the ordering is bound to change i.e. the new stuff will be at the bottom. I've also noticed Webpack not being able to guarantee the order of css. I wasn't able to find a 'webpack' solution and i'm not sure if there is one. Probably bot what you wanted to hear, sorry!
The only way i've solved it was by either using smaccs/BEM notation and/or ensuring writing css rarely/never over-writes other css. For example, if you need to use a 'modifier' to change a background from white to red, then that is actually two modifiers and the default 'base' class doesn't have a background set at all. This way you can guarantee ordering doesn't matter. TBH, this turned out to be a more readable and maintainable way of writing css, but i digress!

Getting webpack style loader to let me import css within my components

I'm currently messing around with https://github.com/sahat/megaboilerplate and trying to get it such that I can import css from within my components.
Here's my config:
const path = require('path');
const webpack = require('webpack');
var config = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'./app/main'
],
output: {
path: path.join(__dirname, 'public', 'js'),
filename: 'bundle.js',
publicPath: '/js'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
],
module: {
loaders: [
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
],
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
plugins: [
['react-transform', {
transforms: [
{
transform: 'react-transform-hmr',
imports: ['react'],
locals: ['module']
}, {
transform: 'react-transform-catch-errors',
imports: ['react', 'redbox-react']
}
]
}]
]
}
}
]
}
};
if (process.env.NODE_ENV === 'production') {
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compressor: {
screw_ie8: true,
warnings: false
}
})
);
}
module.exports = config;
As you can see from the original config:
https://github.com/sahat/megaboilerplate/blob/master/webpack.config.js
I've added:
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
],
But when I run the server, I get:
/megaboiler/node_modules/spectre.css/dist/spectre.min.css:1
(function (exports, require, module, __filename, __dirname) { /*! Spectre.css | MIT License | github.com/picturepan2/spectre */html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}hr{box-sizing:content-box;height:0;overflow:visible}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input
SyntaxError: Unexpected token {
What am I missing?
Your test: /\.css$/ is now.
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
],
Seems that you may miss some loaders which can handle your files correctly, remember each loader has it's limits what it can process.
use: [
'raw-loader',
'style-loader',
'css-loader',
'postcss-loader',
'resolve-url-loader',
]

Resources