Webpack source-map does not resolve sass imports - css

I have webpack configured to transpile scss -> css, but sourcemap generated by webpack does not resolve scss #imports.
webpack.config.js:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const outputPath = path.join(__dirname, 'dist');
module.exports = {
devtool: 'source-map',
entry: ['./src/main.scss'],
target: 'web',
output: {
filename: 'js/[name].bundle.js',
path: outputPath
},
module: {
rules: [
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
loader: ExtractTextPlugin.extract([
{
loader: 'css-loader',
options: {
url: false,
import: true,
minimize: true,
sourceMap: true,
}
},
'sass-loader'
])
},
]
},
plugins: [
new ExtractTextPlugin({ // define where to save the file
filename: 'css/[name].bundle.css',
allChunks: true,
})
]
};
main.scss:
#import 'foo';
_foo.scss:
h1 { color: red; }
However, in Chrome dev tools, I see a reference to main.scss where I expect reference to _foo.scss - see the screenshot below:
Compiled demo: http://store.amniverse.net/webpacktest/

You should not use extractTextPlugin when you are in dev mode.
Please make extra configs for dev and production mode. In production the use of extractTextPlugin is fine but in dev mode it is not necessary and can lead to other features not working. So instead use the style-loader.
Also - I am not sure if that fixes your problem - try to use importLoaders prop on the css loader. Look here for more info:
https://github.com/webpack-contrib/css-loader#importloaders
const path = require('path');
const outputPath = path.join(__dirname, 'dist');
module.exports = {
devtool: 'source-map',
entry: ['./src/main.scss'],
target: 'web',
output: {
filename: 'js/[name].bundle.js',
path: outputPath
},
module: {
rules: [
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
loader: [
{
loader: 'style-loader',
options: {
sourceMap: true
}
},
{
loader: 'css-loader',
options: {
url: false,
import: true,
minimize: true,
sourceMap: true,
importLoaders: 1,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
]
}
};

You have sass-loader there, switch it with:
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
And that would work.

There's nothing wrong with ExtractTextPlugin in dev mode, and what #Omri Aharon posted is correct. However, what you should consider is having source-map enabled only in dev mode.
To build webpack using its default production settings (which uglifies and applies OccurrenceOrderPlugin plugin by default in webpack 2.0+), run the command webpack -p, and then in your webpack.config.js, you can determine if you're in dev mode or not by doing:
const DEBUG = !process.argv.includes('-p');
Add the function
function cssConfig(modules) {
return {
sourceMap: DEBUG,
modules,
localIdentName: DEBUG ? '[name]_[local]_[hash:base64:3]' : '[hash:base64:4]',
minimize: !DEBUG
};
}
in your webpack.config.js, making your scss loader appear as so:
test: /\.(sass|scss)$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: cssConfig(true)
},
{
loader: 'sass-loader',
options: { sourceMap: DEBUG }
}
]
})
},
and my plugins section has
new ExtractTextPlugin('[name].css?[contenthash]'),

Related

Compile CSS and JS in difference files / WEBPACK

For 2 days I have been trying to compile the js and css file to a separate file because now everything is together. Does anyone have any idea how this can be solved?
I would be very grateful for your help.
There is my code webpack.config.js
const path = require('path');
const webpack = require('webpack');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'src/dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
{
loader: "css-loader",
options: {
url: false
}
},
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
]
},
plugins: [
new BrowserSyncPlugin({
// browse to http://localhost:3000/ during development,
// ./public directory is being served
host: 'localhost',
port: 3000,
files: ['./src/*.html'],
server: { baseDir: ['src'] }
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
I think MiniCssExtractPlugin is what you are looking for.
It takes the output of css-loader and create .css bundles. It takes care of downloading them in the browser (by pushing a section of code in webpack runtime code), and also yeah, it minifies the .css :).
Simple usage:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
};
Yes you are right. Style-loader creates javascript snippets that later in runtime creates .css rules and push them to the browser global css scope.

Error importing mobiscroll css styles in webpack

I have a problem with importing mobiscroll css styles in my react project (created by webpack)
Other css files are working well but
This line generates Error:
import '#mobiscroll/react-lite/dist/css/mobiscroll.min.css'
The generated Error:
./node_modules/#mobiscroll/react-lite/dist/css/icons_mobiscroll.ttf?vtxdtu 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
./node_modules/#mobiscroll/react-lite/dist/css/icons_mobiscroll.woff?vtxdtu 1:4
Module parse failed: Unexpected character '�' (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
./node_modules/#mobiscroll/react-lite/dist/css/icons_mobiscroll.woff 1:4
Module parse failed: Unexpected character '�' (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
and my webpack.config.js:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const path = require('path');
const autoprefixer = require('autoprefixer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CSSModuleLoader = {
loader: 'css-loader',
options: {
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
sourceMap: true
}
};
const CSSLoader = { loader: 'css-loader' };
const PostCSSLoader = {
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: false, // turned off as causes delay
plugins: () => [
autoprefixer({
browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9']
})
]
}
};
const StyleLoader = {
loader: 'style-loader'
};
const SassLoader = {
loader: 'sass-loader'
};
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
chunkFilename: '[id].js',
publicPath: ''
},
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}, {
test: /\.html$/,
use: [{loader: 'html-loader'}]
},
{
test: /\.(sa|sc|c)ss$/,
exclude: /\.module\.(sa|sc|c)ss$/,
use: [StyleLoader, CSSLoader, PostCSSLoader, SassLoader]
},
{
test: /\.module\.(sa|sc|c)ss$/,
use: [StyleLoader, CSSModuleLoader, PostCSSLoader, SassLoader]
},
{
test: /\.(svg|png|jpe?g|gif|bmp)$/,
loader: 'url-loader?limit=10000&name=img/[name].[ext]'
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file?name=[name].[ext]'
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [ // for copying the content of 'public/static' folder to 'dist' folder
{ from: path.resolve(__dirname, 'public/static'), to: path.resolve(__dirname, 'dist/static')}
]
}),
new HtmlWebpackPlugin({
template: __dirname + '/public/index.html',
filename: 'index.html',
inject: 'body'
}),
]
};
my webpack configuration is working well for all other css or scss files but can not load that css file. what's the problem?
please help me with this.
I found out my mistake. I haven't defined a loader for font files and that css file was using some fonts.
This solved my Problem:
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
// exclude: /node_modules/,
loader: 'file-loader',
options: {
limit: 1024,
name: '[name].[ext]',
publicPath: 'dist/assets/',
outputPath: 'dist/assets/'
}
}

Combining tailwind css with sass using webpack

I'm struggling a bit getting Tailwind CSS to work with SASS and Webpack. It seems like the postcss configuration for tailwind doesn't really do anything in terms of processing #tailwind preflight, #tailwind components and #tailwind utilities
My set up is as follows:
layout.scss
#import "~tailwindcss/preflight.css";
#import "~tailwindcss/components.css";
.my-class {
#apply text-blue;
#apply border-red;
}
#import "~tailwindcss/utilities.css";
entry.js
import '../css/src/layout.scss';
postcss.config.js
const tailwindcss = require('tailwindcss');
const purgecss = require('#fullhuman/postcss-purgecss');
const cssnano = require('cssnano');
const autoprefixer = require('autoprefixer');
module.exports = {
plugins: [
tailwindcss('./tailwind.js'),
cssnano({
preset: 'default',
}),
purgecss({
content: ['./views/**/*.cshtml']
}),
autoprefixer
]
}
webpack.config.js
// NPM plugins
const autoprefixer = require('autoprefixer');
const WebpackNotifierPlugin = require('webpack-notifier');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: {
main: './scripts/entry.js'
},
output: {
filename: '[name].bundle.js',
publicPath: './'
},
watch: false,
externals: {
jquery: 'jQuery'
},
mode: 'development',
plugins: [
// Notify when build succeeds
new WebpackNotifierPlugin({ alwaysNotify: true }),
// Extract any CSS from any javascript file to process it as LESS/SASS using a loader
new MiniCssExtractPlugin({
fileame: "[name].bundle.css"
}),
// Minify CSS assets
new OptimizeCSSAssetsPlugin({}),
// Use BrowserSync plugin for file changes. I.e. if a CSS/SASS/LESS file changes, the changes will be injected directly in the browser with no page load
new BrowserSyncPlugin({
proxy: 'mysite.local',
open: 'external',
host: 'mysite.local',
port: 3000,
files: ['./dist/main.css', './views', './tailwind.js']
},
{
// disable reload from the webpack plugin since browser-sync will handle CSS injections and JS reloads
reload: false
})
],
module: {
rules: [
{
// Transpile ES6 scripts for browser support
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/,
use: [
{
loader: 'file-loader'
}
]
},
{
// Extract any SCSS content and minimize
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{
loader: 'postcss-loader',
options: {
plugins: () => [autoprefixer()]
}
},
{
loader: 'sass-loader',
options: {
plugins: () => [autoprefixer()]
}
}
]
},
{
// Extract any CSS content and minimize
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader' }
]
}
]
}
};
When I run Webpack, everything runs just fine, but the content of /dist/main.css is:
#tailwind preflight;#tailwind components;#tailwind utilities;.my-class{#apply text-blue;#apply border-red}
I suspect it's related to the (order of) loaders, but I can't seem to figure out why it's not getting processed correctly.
Does anyone know what I'm doing wrong here? :-)
Thanks in advance.
Wow, so after fiddling around with the loaders even more, I made it work :-) For future reference:
I added options: { importLoaders: 1 } to the css-loader for SCSS files and removed: plugins: () => [autoprefixer()] from the postcss-loader in my webpack.config.js file.
Full, updated webpack.config.js file:
// NPM plugins
const autoprefixer = require('autoprefixer');
const WebpackNotifierPlugin = require('webpack-notifier');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: {
main: './scripts/entry.js'
},
output: {
filename: '[name].bundle.js',
publicPath: './'
},
watch: false,
externals: {
jquery: 'jQuery'
},
mode: 'development',
plugins: [
// Notify when build succeeds
new WebpackNotifierPlugin({ alwaysNotify: true }),
// Extract any CSS from any javascript file to process it as LESS/SASS using a loader
new MiniCssExtractPlugin({
fileame: "[name].bundle.css"
}),
// Minify CSS assets
new OptimizeCSSAssetsPlugin({}),
// Use BrowserSync plugin for file changes. I.e. if a CSS/SASS/LESS file changes, the changes will be injected directly in the browser with no page load
new BrowserSyncPlugin({
proxy: 'mysite.local',
open: 'external',
host: 'mysite.local',
port: 3000,
files: ['./dist/main.css', './views', './tailwind.js']
},
{
// disable reload from the webpack plugin since browser-sync will handle CSS injections and JS reloads
reload: false
})
],
module: {
rules: [
{
// Transpile ES6 scripts for browser support
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/,
use: [
{
loader: 'file-loader'
}
]
},
{
// Extract any SCSS content and minimize
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader',
options: {
plugins: () => [autoprefixer()]
}
}
]
},
{
// Extract any CSS content and minimize
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader' }
]
}
]
}
};
There is an extension called tailwindcss-transpiler which compiles your layout.tailwind.scss files into pure CSS files.It also optimizing features.I hope it will be useful.
For VS Code
https://marketplace.visualstudio.com/items?itemName=sudoaugustin.tailwindcss-transpiler
For Atom
https://atom.io/packages/tailwindcss-transpiler

I'm having trouble setting up Autoprefixer in my webpack config

I've tried copying numerous webpack setups, but I can't seem to get the postcss-loader Autoprefixer to work. I use Flexbox heavily in my projects, and I really want to have webpack add the prefixes for older browsers on yarn build. Right now, the SCSS is compiled into CSS, but no prefixes are added. Here is what my webpack config currently looks like:
webpack.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
var autoprefixer = require('autoprefixer');
const baseConfig = require('./base.config.js');
module.exports = merge(baseConfig, {
output: {
filename: 'app.bundle.min.js',
path: path.join(__dirname, '../../assets')
},
module: {
rules: [
{
test: /\.(scss|css)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: { sourceMap: true, minimize: true }
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [require('autoprefixer')]
}
},
{
loader: 'sass-loader',
options: { sourceMap: true, minimize: true }
}
],
fallback: 'style-loader'
})
}
]
},
plugins: [
new ExtractTextPlugin('app.bundle.min.css'),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [autoprefixer()]
}
}),
// Minimize JS
new UglifyJsPlugin({ sourceMap: true, compress: true })
// Minify CSS
/*new webpack.LoaderOptionsPlugin({
minimize: true,
}),*/
]
});
I believe you need to call its constructor i.e require('autoprefixer')()
I'm seeing this in the PostCss Loader README.
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
require('autoprefixer')({...options}), // calls constructor with optional options
...,
]
}
}
]
}

Webpack4 - CSS files imported from less files aren't being minified

I'm putting together a project with webpack 4. Virtually all of it working as it should, I'm just having trouble with minifying CSS.
If in my entrypoint i include a.css or .less file then everything works correctly. It also works correctly if i use #include './myfile.less'. However if I use #include './myfile.css' that section is imported without being minified.
How do I get imported CSS files to work?
webpack.config
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
'app': './src/app/app.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
module: {
rules: [
{
test: /\.html/,
use: 'html-loader'
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
"less-loader"
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader?name=assets/images/[path][name].[ext]?[hash]']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader?name=assets/fonts/[name].[ext]?[hash]'
]
}
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/public/index.html' }),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "[name].bundle.css",
chunkFilename: "[id].css"
}),
]
};
While webpack 5 is likely to come with a CSS minimizer built-in, with webpack 4 you need to bring your own. To minify the output, use a plugin like optimize-css-assets-webpack-plugin. Setting optimization.minimizer overrides the defaults provided by webpack, so make sure to also specify a JS minimizer
webpack.config.js
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
}
}
Reference
I found notes on MiniCssExtractPlugin production usage.
Following these fixed the issue:
specifically adding:
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
...
module.exports = {
...
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
},
}
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
minimize: true
}
}
]

Resources