Webpack SCSS and autoprefixer do not work together - compilation

Having the following webpack configuration for assets compiling I can't get autoprefixer to work. The extracted css does not get the needed prefixes.
var webpack = require('webpack'),
precss = require('precss'),
autoprefixer = require('autoprefixer'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path');
const sassLoaders = [
'css-loader!autoprefixer-loader?browsers=last 2 version',
'postcss-loader',
'sass-loader?indentedSyntax=sass&includePaths[]=' + path.resolve(__dirname, '.')
]
const config = {
entry: {
//nsb: ['./js/nsb']
dashboard: ['./js/dashboard']
},
module: {
loaders: [
{
test: /\.sass$/,
loader: ExtractTextPlugin.extract('style-loader', sassLoaders.join('!'))
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
},
{
test: /\.docs\.css$/,
loader: "style-loader!css-loader!postcss-loader?pack=cleaner"
},
{
test: /\.css$/,
loader: "style-loader!css-loader!postcss-loader"
},
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }
]
},
postcss: function () {
return {
defaults: [precss, autoprefixer],
cleaner: [autoprefixer({ browsers: [] })]
};
},
output: {
filename: '[name].js',
path: path.join(__dirname, './build'),
publicPath: '/bundles/dashboard/build/'
},
amd: {jQuery: true},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js', Infinity)
],
/* postcss: [
autoprefixer({
browsers: ['last 2 versions']
})
],
*/
resolve: {
alias: {
jquery: 'node_modules/jquery/dist/jquery.js',
magnificPopup: 'node_modules/maginific-popup/dist/jquery.magnific-popup.js' //JQuery Plugin
},
modulesDirectories: ['./js', 'node_modules'],
extensions: ['', '.js', '.sass'],
root: [path.join(__dirname, './')]
}
}
module.exports = config;

The css-loader comes with it's own autoprefixer config you will need to disable this in order for your config to work. So wherever you have css-loader you need to do add to disable the css-loader autoprefixer.
css-loader?-autoprefixer
More info can found here & here
So your config will look like this
var webpack = require('webpack'),
precss = require('precss'),
autoprefixer = require('autoprefixer'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path');
const sassLoaders = [
'css-loader?-autoprefixer!autoprefixer-loader?browsers=last 2 version',
'postcss-loader',
'sass-loader?indentedSyntax=sass&includePaths[]=' + path.resolve(__dirname, '.')
]
const config = {
entry: {
//nsb: ['./js/nsb']
dashboard: ['./js/dashboard']
},
module: {
loaders: [
{
test: /\.sass$/,
loader: ExtractTextPlugin.extract('style-loader', sassLoaders.join('!'))
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
},
{
test: /\.docs\.css$/,
loader: "style-loader!css-loader?-autoprefixer!postcss-loader?pack=cleaner"
},
{
test: /\.css$/,
loader: "style-loader!css-loader?-autoprefixer!postcss-loader"
},
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }
]
},
postcss: function () {
return {
defaults: [precss, autoprefixer],
cleaner: [autoprefixer({ browsers: [] })]
};
},
output: {
filename: '[name].js',
path: path.join(__dirname, './build'),
publicPath: '/bundles/dashboard/build/'
},
amd: {jQuery: true},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js', Infinity)
],
/* postcss: [
autoprefixer({
browsers: ['last 2 versions']
})
],
*/
resolve: {
alias: {
jquery: 'node_modules/jquery/dist/jquery.js',
magnificPopup: 'node_modules/maginific-popup/dist/jquery.magnific-popup.js' //JQuery Plugin
},
modulesDirectories: ['./js', 'node_modules'],
extensions: ['', '.js', '.sass'],
root: [path.join(__dirname, './')]
}
}
module.exports = config;
Also, I think you can remove the autoprefixer-loader that you have inside your sassLoaders since you are using PostCSS with autoprefixer.

You could try the following code, notice the addition of "?-autoprefixer" between css-loader and postcss-loader.
var webpack = require('webpack'),
precss = require('precss'),
autoprefixer = require('autoprefixer'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path');
const sassLoaders = [
'css-loader!autoprefixer-loader?browsers=last 2 version',
'postcss-loader',
'sass-loader?indentedSyntax=sass&includePaths[]=' + path.resolve(__dirname,
'.')
]
const config = {
entry: {
//nsb: ['./js/nsb']
dashboard: ['./js/dashboard']
},
module: {
loaders: [
{
test: /\.sass$/,
loader: ExtractTextPlugin.extract('style-loader', sassLoaders.join('!'))
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
},
{
test: /\.docs\.css$/,
loader: "style-loader!css-loader?-autoprefixer!postcss-loader?pack=cleaner"
},
{
test: /\.css$/,
loader: "style-loader!css-loader?-autoprefixer!postcss-loader"
},
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }
]
},
postcss: function () {
return {
defaults: [precss, autoprefixer],
cleaner: [autoprefixer({ browsers: [] })]
};
},
output: {
filename: '[name].js',
path: path.join(__dirname, './build'),
publicPath: '/bundles/dashboard/build/'
},
amd: {jQuery: true},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js', Infinity)
],
/* postcss: [
autoprefixer({
browsers: ['last 2 versions']
})
],
*/
resolve: {
alias: {
jquery: 'node_modules/jquery/dist/jquery.js',
magnificPopup: 'node_modules/maginific-popup/dist/jquery.magnific-popup.js' //JQuery Plugin
},
modulesDirectories: ['./js', 'node_modules'],
extensions: ['', '.js', '.sass'],
root: [path.join(__dirname, './')]
}
}
module.exports = config;
One more note: In my project's root directory I also have a postcss.config.js with the following content:
module.exports = {
parser: 'postcss-scss',
plugins: [
require('autoprefixer'),
]
}

Related

How to use preload webpack plugin with blade templates

So i have a laravel/vuejs app , i'm trying to preload the css chunks that i have generated upon splitting components, it works fine but it generates an index.html. Is it possible to somehow do it in blade templates? What could be the solution?
Here is my webpack.config.js
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {VueLoaderPlugin} = require("vue-loader");
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require("path");
module.exports = {
entry: {
main: "./resources/js/app.js",
},
output: {
publicPath: '/',
path: path.resolve(__dirname, "public"),
},
plugins: [
new HtmlWebpackPlugin(),
new VuetifyLoaderPlugin(),
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: `components/[name].css`
}),
new PreloadWebpackPlugin({
rel: 'preload',
include: 'asyncChunks', // can be 'allChunks' or 'initial' or see more on npm page
fileBlacklist: [/\.map|.js/], // here may be chunks that you don't want to have preloaded
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader"
]
},
{
test: /\.js$/,
loader: 'babel-loader',
},
{
test: /\.s[ac]ss$/i,
use: [
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
{
test: /\.vue$/,
loader: "vue-loader",
options: {
extractCSS: true
}
},
],
},
resolve: {
extensions: ['.js', '.vue'],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/](vue|axios|jquery|bootstrap)[\\/]/,
name: 'vendor',
chunks: 'all'
}
}
}
}
}
And one final question , is it better to preload/prefetch the js chunks too? ( to optimize the performance )

html loader set wrong path or ignore image from index.html

I have problem in my webpack, when i set attrs: [':data-src'] in my html-loader i have good path in index.html like this: <img src="img/logo.png" width="180" height="96">, but when I use npm run build I haven't images from this index in dist folder. When I have default attrs=img:src i have images, but my path looks like: <img src="../img/../img/logo.png" width="180" height="96">. I tried use attrs: ['data:src', 'img:src'], but it doesn't work.
My config:
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
context: path.join(__dirname, "src"),
entry: "./js/index.js",
output: {
path: __dirname + "/dist/js",
filename: "bundle.min.js"
},
module: {
loaders: [{
test: /\.js?$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['es2015'],
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(html)$/,
use: [{
loader: 'html-loader',
options: {
attrs: ['data:src', 'img:src']
}
}]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: '../img/',
publicPath: '../img/'
}
}]
},
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
mangle: false,
sourcemap: false
}),
new HtmlWebpackPlugin({
filename: '../index.html',
template: './index.html'
}),
],
};

ExtractTextPlugin gives images wrong path

I'm having troubles with compiling sass with Webpack. ExtractTextPlugin gives images wrong path, prepending 'css/' to it. When I change the filename in ExtractTextPlugin options to '/app.css', it puts app.css to the dist/ folder instead of css, but it gives the images correct path. How should I correctly specify the paths in config?
Here is my webpack.config.js:
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const path = require('path')
const autoprefixer = require('autoprefixer')
let isProd = process.env.NODE_ENV == 'production';
let cssDev = [
'style-loader',
'css-loader?sourseMap&importLoaders=2',
'postcss-loader',
'sass-loader'];
let cssProd = ExtractTextPlugin.extract({
allChunks: true,
fallback: "style-loader",
use: [
{
loader: 'css-loader',
options: {
minimize: false,
importLoaders: 2
}
},
{
loader: 'postcss-loader',
options: {
minimize: false
}
},
{
loader: 'sass-loader',
options: {
minimize: false
}
}
]
});
let cssConfig = isProd ? cssProd : cssDev;
module.exports | webpack.config
module.exports = {
entry: {
'js/app': './src/app.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js',
publicPath: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: [ path.resolve(__dirname, 'src/js/') ],
loader: 'babel-loader',
query: {
presets: ['es2015'],
}
},
{
test: /\.sass$/,
use: cssConfig
},
{
test: /\.pug$/,
use: 'pug-loader?pretty=true'
},
{
test: /\.(jpe?g|png|gif|svg)$/,
use: [
'file-loader?name=[name].[ext]&publicPath=img/&outputPath=img/'
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: 'file-loader?name=[name].[ext]&publicPath=fonts/&outputPath=fonts/'
}
]
},
devServer: {
contentBase: __dirname + '/dist',
compress: true,
port: 9000,
open: true,
hot: true,
stats: 'errors-only'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Product Description',
minimize: false,
favicon: false,
hash: true,
template: './src/index.pug'
}),
new HtmlWebpackPlugin({
title: 'Distribution and Channels',
minimize: false,
favicon: false,
hash: true,
filename: 'distrib.html',
template: './src/distrib.pug'
}),
new ExtractTextPlugin({
filename: '/app.css',
publicPath: '/',
disable: !isProd,
allChunks: true
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.LoaderOptionsPlugin({ options:
{ postcss: [
autoprefixer({
browsers: ['last 5 versions'],
supports: true,
flexbox: true
})
] }
})
]
};

Webpack runs, Elixir throws errors - undefined is not a function

After hours of pulling my hair out, I finally got webpack to run on an existing project, that I'm trying to port to Laravel.
When I run webpack it compiles now...
...but when I run gulp in the root, which executes Elixir, I get this error message:
node_modules/webpack/lib/NullFactory.js:9 undefined is not a function
My webpack.config.js looks like this:
var path = require('path');
var webpack = require('webpack');
var debug = process.env.NODE_ENV !== "production";
module.exports = {
devtool: 'source-map',
entry: debug ? [
'webpack-hot-middleware/client',
'./resources/assets/js/client/index'
] : [
'./resources/assets/js/client/index'
],
output: {
path: path.join(__dirname, 'public/js'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: debug ? [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': "'production'"
}
}),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false,warnings: false })
],
resolve: {
root: [
path.resolve('./resources/assets/js/client')
],
alias: {
},
},
module: {
loaders: [
// js
{
test: /\.js$/,
loaders: ['babel'],
include: path.join(__dirname, 'resources/assets/js/client')
},
// CSS
{
test: /\.styl$/,
include: path.join(__dirname, 'resources/assets/js/client'),
loader: 'style-loader!css-loader!stylus-loader'
},
{
test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'
},
{
test: /\.json?$/,
loader: 'json'
},
{ test: /\.html$/, loader: "html" }
/* {
test: /\.jsx?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
cacheDirectory: true,
presets: ['react', 'es2015']
}
}*/
]
}
};
Ok, I have very outdated version of Node... upgrading fixed it.

Webpack, "hot-reload" or "live-reload" sass?

Is there a way to get webpack to "recompile" sass and reload your page on the fly?
I've been searching around but have not found an example.
Here is what I've got:
My folder structure
-app
---public
------dist
---------index.html
---------sass
------------webpack.scss
It seems like my sass only recompiles when I run webpack but it doesn't recompile when I am running the webpack-dev-server
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpack = require('webpack');
module.exports = {
entry: {
app: './app/main.js',
//All 3rd party source
vendor: ['react', 'redux', 'lodash']
},
output: {
path: path.join(__dirname, 'app', 'public', 'dist'),
publicPath: '/app/public/dist/',
filename: 'app.js'
},
module: {
loaders: [
{ test: /\.js$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ },
{ test: /.jsx?$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.css/, loader: ExtractTextPlugin.extract('css') },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('!css!sass?sourceMap') }
]
},
sassLoader: {
includePaths: [ path.resolve(__dirname, './app/public/sass/')]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),
new ExtractTextPlugin('./css/style.css',{
allChunks: true
})
],
debug: true,
//watch: true
};

Resources