Unable to inline styles with `sass-loader` - css

I have a project setup where I use ExtractTextPlugin to create a CSS file. I'm trying to create a dev Webpack config with the styles injected onto the page using style-loader, css-loader, and sass-loader.
As far as I am aware the default behaviour is to inject the styles into a <style /> tag and I've removed all traces of ExtractTextPlugin but it still doesn't want to inject the styles.
Does anybody know what might cause the styles to be lost? My Webpack config is below.
Config:
const webpack = require('webpack')
module.exports = config => Object.assign({}, {
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
new webpack.SourceMapDevToolPlugin({
filename: 'bundle.js.map'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
]
}, config)
Called with:
module.exports = require('../../dev')({
name: 'Onboarding',
entry: './src/apps/components/Onboarding/index.js'
})

I was able to get it working by rewriting most of my Webpack config. I had already tried the css-loader options below, so I'm not sure why they worked now but not before.
This is my new dev-only config:
const webpack = require('webpack')
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = config => {
const { out, libraryTarget, name = 'main' } = config
const filename = `${name}.js`
delete config.out
return Object.assign({}, {
output: {
path: path.resolve(__dirname, '../../../' + out),
filename,
libraryTarget,
publicPath: '/assets/js/'
},
devtool: 'source-map',
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
query: {
importLoaders: 1,
modules: true,
localIdentName: '[name]_[local]_[hash:base64:5]'
}
},
'sass-loader']
}
]
},
plugins: [
new HTMLWebpackPlugin({
title: 'App Name',
filename: '../../index.html',
template: './test-lambda/template-dev.html',
inject: 'body'
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.SourceMapDevToolPlugin({
filename: `${filename}.map`
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
]
}, config)
}

Related

I Get An Error When I Use mapbax-gl.css with react/typescript

When i built a map with mapbox-gl by using react/typescript, i got an error where i imported css file for the mapbox-gl "import 'mapbox-gl/dist/mapbox-gl.css';"
i cant figure out what kind of loader do i still need cuz in "webpack.config.js" ive already imported css-loader....
error
ERROR in ./node_modules/mapbox-gl/dist/mapbox-gl.css 1:0
Module parse failed: Unexpected token (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
webpack.config.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const dotenv = require('dotenv');
module.exports = () => {
const env = dotenv.config().parsed;
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
return {
mode: 'development',
entry: path.resolve(__dirname, './src/index.tsx'),
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader'
]
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
new webpack.DefinePlugin(envKeys)
],
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json']
},
devtool: 'inline-source-map',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
historyApiFallback: true,
inline: true,
hot: true,
port: 5000,
open: true
},
}
};
```
You didn't match the css-loader on the correct extension.
Use it against .css files instead, by adding a new rule :
rules: [
{
test: /\.css$/,
use: [
'css-loader',
]
},
{
test: /\.scss$/,
use: [
'style-loader',
'postcss-loader',
'sass-loader'
]
},

Rearrange style order in ccs bundle

After a migration from grunt, the styles are not working as intended with webpack. All the styles were concatenated in the gruntfile like this:
target: {
files: {
"all.css": [
"node_modules/bootstrap/dist/css/bootstrap.css",
"bower_components/toastr/toastr.css",
"bower_components/angular-ui-select/dist/select.css",
"node_modules/font-awesome/font-awesome.css",
"bower_components/angular-loading-bar/build/loading-bar.css",
"bower_components/angular-ui-tree/dist/angular-ui-tree.css",
"content/styles/awesome-bootstrap-checkbox.css",
"content/styles/tradesolution.css",
"content/styles/site.css",
"content/styles/ts.css",
"content/styles/nyKladd.css"
]
}
}
My current config in webpack:
var webpack = require('webpack');
var globby = require('globby');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
var AssetsPlugin = require('assets-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var DashboardPlugin = require('webpack-dashboard/plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const extractCSS = new ExtractTextPlugin('[name].css');
const extractLESS = new ExtractTextPlugin('[name].css');
module.exports = {
entry: {
app: globby.sync(['./app/app.js','./app/app.run.js', './app/app.config.js', './app/**/*.js']),
Ztyles: globby.sync(['./content/styles/less/*.less']),
styles: globby.sync(['./content/styles/*.css']),
images: globby.sync(['./content/images/**/*.*']),
vendor: [
// removed to save space
],
},
output: {
filename: './scripts/[name].bundle.js',
path: path.join(__dirname, "public")
},
devServer: {
port: 1384,
contentBase: './public/'
},
// Enable sourcemaps for debugging webpack's output.
devtool: (() => {
if(NODE_ENV = "devlopment") return 'source-map'
else return 'cheap-module-eval-source-map'
}) (),
module: {
rules: [
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [/node_modules/]
},
{
test: /\.css$/,
loader: extractCSS.extract(
{ fallback: 'style-loader', use: 'css-loader' }
),
//'style-loader', 'css-loader'
},
{ test: /\.less$/,
use: extractLESS.extract(
{fallback:'style-loader', use: ['css-loader','less-loader']}
)
//'style-loader', 'css-loader!less-loader'
},
{
test: /\.(ico)$/,
loader: "url-loader?name=./[name].[ext]",
include: path.resolve(__dirname, "content", "images")
},
{
test: /\.(jpg|jpeg|gif|png|PNG|tiff|svg)$/,
loader: 'file-loader?name=/[path]/[name].[ext]',
include: path.resolve(__dirname, "content", "images"),
},
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff&name=./fonts/[name].[ext]' },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader?name=./fonts/[name].[ext]' },
{
test: require.resolve('adal-angular/lib/adal'),
loader: 'expose-loader?AuthenticationContext'
},
{
test: /\.js$/,
enforce: "pre",
loader: 'source-map-loader'
}
],
},
plugins: [
new webpack.DefinePlugin({
ADMIN_API_URL: JSON.stringify('http://localhost:41118/api/'),
API_URL: JSON.stringify('http://epdapi.tradesolution.no/'),
GLOBAL_ADMIN_URL: JSON.stringify('https://adminapi.tradesolution.no/')
}),
new HtmlWebpackPlugin({
template: './app/layout.html',
filename: 'index.html'
}),
extractCSS,
extractLESS,
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: './scripts/vendor.bundle.js' }),
new ExtractTextPlugin({ filename: './[name].bundle.css' }),
new AssetsPlugin({
filename: 'webpack.assets.json',
path: './public',
prettyPrint: true
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
"window.AuthenticationContext": "AuthenticationContext",
_: 'underscore'
}),
new CopyWebpackPlugin([
{from: './app/**/*.html', to: './'}
]),
new DashboardPlugin()
],
externals: [
{ xmlhttprequest: '{XMLHttpRequest:XMLHttpRequest}' }
],
}
From this picture you can see that the default bootstrap styles are overriding the styles written for the nav-bar.
What i have done so far is to implement all the other css files into one less file, like this:
#import "../tradesolution.css";
#import "../site.css";
#import "../nykladd.css";
#import "for";
#import "kladd.less";
#import "~bootstrap/less/bootstrap";
#import "~bootstrap/less/alerts.less";
#import "~bootstrap/less/mixins/buttons.less";
#import "~font-awesome/less/font-awesome.less";
Then the less file is compiled to css and loaded in the Ztyles.css , but regardless of where I put the imports, my styles are still overridden. I have also tried changing the order of the webpack rules and the order of extractCSS and extractLESS in plugins
I dont think my intended solution is good practice, so any approach to solving this issue is very welcome.
After a while i stumbled over a new css framework postcss they have all kinds of plugins, and with this configuration I got it to work:
{
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { modules: true, importLoaders: 1 },
loader: 'postcss-loader',
},
]
},
{ test: /\.less$/,
use: extractLESS.extract(
{fallback:'style-loader', use: ['css-loader', 'less-loader']}
)
},
Here are some resources that helped:
https://github.com/postcss/postcss
https://webdesign.tutsplus.com/tutorials/using-postcss-together-with-sass-stylus-or-less--cms-24591
https://github.com/Crunch/postcss-less

Webpack: extract css to its own bundle

I'm using webpack on a project. I use style-loader so I can import "my.css".
The css gets bundled with the javascript and will be rendered in a <style> tag when component mount, ok.
However, I would like to keep that import syntax and make webpack build a css bundle for every entry point.
So webpack output should be [name].bundle.js AND [name].bundle.css.
Is this something I can achieve ?
var config = {
entry: {
'admin': APP_DIR + '/admin.entry.jsx',
'public': APP_DIR + '/public.entry.jsx'
},
output: {
path: BUILD_DIR,
filename: '[name].bundle.js'
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
plugins: [],
devtool: 'cheap-source-map',
module: {
loaders: [{
test: /(\/index)?\.jsx?/,
include: APP_DIR,
loader: 'babel-loader'
},
{
test: /\.scss$/,
loaders: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: ['./src/styles/constants.scss']
},
}
]
}
],
}
};
along with this babel.rc:
{
"presets" : ["es2015", "react"],
"plugins": ["transform-decorators-legacy", "babel-plugin-root-import"]
}
Yes, you need to use extract-text-webpack-plugin. You might want to do it only on your production config. Config looks like this:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: ['css-loader', 'sass-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin('style.css')
//if you want to pass in options, you can do so:
//new ExtractTextPlugin({
// filename: 'style.css'
//})
]
}

Less module build failed in webpack after migrating from grunt

I can't figure out how to compile my less files to css and then include them in my build folder, without the app failing to run. Trying to build/run the application returns the following error:
ERROR in ./content/styles/less/ts.less
Module build failed:
#import "node_modules/bootstrap/less/mixins/buttons.less";
#import "node_modules/Font-awesome/less/font-awesome.less";
^
Can't resolve './node_modules/Font-awesome/less/font-awesome.less' in '/home/thinkpad/work/EPD.SPA/EpdSPA/content/styles/less'
in /home/thinkpad/work/EPD.SPA/EpdSPA/content/styles/less/ts.less (line 4, column 0)
# multi ./content/styles/less/for.less ./content/styles/less/kladd.less ./content/styles/less/ts.less
To clarify: These files have already proved to be working with grunt. The webpack migration triggered these errors.
I'm using the webpack config examples from here. My config file:
var webpack = require('webpack');
var globby = require('globby');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
var AssetsPlugin = require('assets-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
const extractLESS = new ExtractTextPlugin('stylesheets/[name]-two.css');
module.exports = {
entry: {
app: globby.sync(['./app/app.js','./app/app.run.js', './app/app.config.js', './app/**/*.js']),
styles: globby.sync(['./content/styles/*.css']),
lessStyles: globby.sync(['./content/styles/less/*.less']),
images: globby.sync(['./content/images/**/*.*']),
vendor: [
// removed to save space
]
},
output: {
filename: './scripts/[name].bundle.js',
path: path.join(__dirname, "public")
},
devServer: {
port: 1384,
contentBase: './public/'
},
// Enable sourcemaps for debugging webpack's output.
devtool: 'source-map',
module: {
rules: [
{ test: /\.less$/,
use: extractLESS.extract([ 'css-loader', 'less-loader' ])
},
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [/node_modules/]
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }),
},
{
test: /\.(ico)$/,
loader: "url-loader?name=./[name].[ext]",
include: path.resolve(__dirname, "content", "images")
},
{
test: /\.svg$/,
loader: 'svg-loader'
},
{
test: /\.(jpg|jpeg|gif|png|PNG|tiff|svg)$/,
loader: 'file-loader?name=/[path]/[name].[ext]',
include: path.resolve(__dirname, "content", "images"),
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?minetype=application/font-woff&name=./fonts/[name].[ext]'
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader?name=./fonts/[name].[ext]'
},
{
test: require.resolve('adal-angular/lib/adal'),
loader: 'expose-loader?AuthenticationContext'
},
{
test: /\.js$/,
enforce: "pre",
loader: 'source-map-loader'
}
],
},
plugins: [
new HtmlWebpackPlugin({
template: './app/layout.html',
filename: 'index.html'
}),
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: './scripts/vendor.bundle.js' }),
new ExtractTextPlugin({ filename: './[name].bundle.css' }),
/*
new CleanWebpackPlugin(['./public'], {
verbose: false
}),
*/
new AssetsPlugin({
filename: 'webpack.assets.json',
path: './public/scripts',
prettyPrint: true
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
"window.AuthenticationContext": "AuthenticationContext",
_: 'underscore'
}),
new CopyWebpackPlugin([
{from: './app/**/*.html', to: './'}
]),
extractLESS // including the less files here
],
externals: [
{ xmlhttprequest: '{XMLHttpRequest:XMLHttpRequest}' }
]
}
Here you can see that the less files have been compiled to css and included in the public(build) folder. Why do i get errors, if the config file executes as intended?
Here it also shows that all the files are included in the application in the browser as well. I have checked all my dependencies and they are all running latest versions.
The path for the imports in the less files, were incorrect. Here is the working references:
#import "~bootstrap/less/variables.less";
#import "~bootstrap/less/mixins/buttons.less";
#import "~font-awesome/less/font-awesome.less";
I think the problem is with your font_awesome path.
Try to change import to (font_awesome instead of Font_awesome)
#import "node_modules/font-awesome/less/font-awesome.less";

Webpack: wrong absolute path in compiled CSS

I'm migrating an Angular 1 project in order to be able to deploy everything with Webpack.
So far, I managed to configure almost everything but I'm having issues trying to export the static assets (fonts and images mostly).
I've configured the ExtractTextPlugin as below
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader','css-loader', {allChunks: true}) }
and in the compiled CSS the paths are replaced but the resulting absolute path is wrong. In fact the resulting path is /assetsweb/assets/.. while I expect it to be /assets/...
I cannot understand where the /assetsweb part is coming from.
Here's the Webpack configuration I'm using
var webpack = require("webpack");
var path = require("path");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
context: __dirname + "/src",
entry:{
web: "./web/wayonara.js",
mobile: "./mobile/wayonara.js"
},
output:{
path: __dirname + "/dist",
filename: "/[name]/bundle.js",
publicPath: "/assets"
},
plugins:[
new webpack.DefinePlugin({
ENV: JSON.stringify('dev')
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
EXIF: "exif-js",
"window.EXIF":"exif-js"
}),
new ExtractTextPlugin("/[name]/assets/css/bundle.css")
],
module:{
loaders: [
{
loader: "babel-loader",
test: /\.js?$/,
exclude: [/node_modules/, /bower_components/],
query: {
presets: ['es2015']
}
},
{ test: /\.html$/, loader: "html" },
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader','css-loader', {allChunks: true}) },
{
test: /\.(jpg|jpeg|png|svg)$/,
loader: "file-loader?name=[path][name].[ext]"
},
{
test: /\.(woff|woff2|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?/,
loader: 'file-loader?name=[path][name].[ext]'
}
]
}
};
Can you help me? Thanks in advance,
Best,
Maurizio

Resources