{
test: /\.module\.scss$/,
use: [
{ loader: MiniCssExtractPlugin.loader, options: { publicPath: '../' } },
{
loader: 'css-loader',
options: {
modules: { localIdentName: '[local]---[hash:base64:5]' }
}
},
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: './src/css/_variables.scss'
}
}
]
},
{
test: /\.scss$/,
exclude: /\.module\.scss$/,
use: [
{ loader: MiniCssExtractPlugin.loader, options: { publicPath: '../' } },
'css-loader',
'sass-loader'
]
},
...
plugins: [
new MiniCssExtractPlugin({
filename: 'css/bundle.css'
})
]
I am creating a single css file that includes some vanilla sass styles and some css module styles. Is there a way to control this so that the module css comes AFTER the regular css in the outputted bundle.css file? It's always before it right now.
I've tried reordering them in the package.json. I've tried using oneOf.
I had this issue in my React app and after a lot of banging my head against the wall, realized it was the order of my App and components relative to the other css import. In hindsight this was very obvious, but it took me a while to get there.
// Imports css-modules in App and components in App first
// followed by global styles
import App from '$containers/App';
import '$scss/global.css';
...
render((
<App />
), document.getElementById('root'));
// Imports global styles first
// followed by css-modules in App and components in App
import '$scss/global.css';
import App from '$containers/App';
...
render((
<App />
), document.getElementById('root'));
You just need to import by the order and you should be good like this
#import "~bootstrap/scss/bootstrap";
#import "~font-awesome/scss/font-awesome";
#import "~toastr/toastr";
#import "~react-select/dist/react-select.css";
#import "~react-bootstrap-table/dist/react-bootstrap-table-all.min.css";''
My webpack config
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
],
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
minimize: true,
sourceMap: true
}
},
{
loader: "sass-loader"
}
]
}
]
}
You can view my full webpack here
Related
I am trying to split code of styles into smaller chunks due to the size of generated output. I am developing using react so i solved javascript loading with React.lazy().
Lets say that there is one big application with 50 different views you can open. Not all views are available to all users.
What i did in my router is:
...
const view = React.lazy(() => import("./views/view"));
...
...
<view />
...
What this did is divided entire application to 50 separate js files that are dynamically loaded which is good.
It however did not divide styles the same way. So lets look into one of the views:
import React, { Component } from "react";
import "../../scss/view.scss";
class view extends Component {
...
}
export default view;
So each view has its own scss files dedicated for this view, which makes them virtually standalone. The problem is that webpack is still producing only one big style[hash].css file.
Webpack config:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html"
});
const extractTextPlugin = new ExtractTextPlugin({
filename: "css/style.[hash:8].css",
allChunks: true
});
module.exports = {
output: {
filename: "js/main.[hash:8].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.(png|jpg|gif|ico|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 25000,
outputPath: "/assets/",
name: "[name].[hash:8].[ext]"
}
},
{
test: /\.(scss|sass|css)$/i,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{ loader: "css-loader" },
{ loader: "postcss-loader", options: { sourceMap: true } },
{ loader: "sass-loader", options: { sourceMap: true } }
]
})
}
]
},
resolve: {
extensions: [".js", ".jsx", ".json"]
},
plugins: [htmlPlugin, extractTextPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }]
}
}
};
Is there any way to make styles also produced and loaded dynamically respective to their js file, so for example if i open view 10 it loads 10.main[hash].js and 10.style[hash].css ?
Answer to this problem is to replace deprecated extract-text-webpack-plugin package that is actually missing this functionality (splitting styles into respective chunks).
Instead mini-css-extract-plugin should be used and it automatically works.
updated working webpack config file:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html",
});
const miniCssExtractPlugin = new MiniCssExtractPlugin({
filename: "css/style.[hash:8].css",
chunkFilename: "css/[id].style.[hash:8].css",
});
module.exports = {
output: {
filename: "js/main.[hash:8].js",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.(png|jpg|jpeg|gif|ico|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 25000,
outputPath: "/assets/",
name: "[name].[hash:8].[ext]",
},
},
{
test: /\.(scss|sass|css)$/i,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
resolve: {
extensions: [".js", ".jsx", ".json"],
},
plugins: [htmlPlugin, miniCssExtractPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }],
},
},
};
I am using these three css imports from various packages:
// want to do import 'path/to/css.css'
import slickCss from "slick-carousel/slick/slick.css"
import slickCssTheme from "slick-carousel/slick/slick-theme.css"
import leafcss from 'leaflet/dist/leaflet.css'
console.log(`Slick Css: `, slickCss)
console.log(`Slick Theme Css: `, slickCssTheme)
console.log(`leaf css: `, leafcss)
If I log those out they are all empty objects:
Slick Css: {}
Slick Theme Css: {}
leaf css: {}
I assume that something is going wrong with how I am using the loader for webpack. For the most part that I can see everything else is working as far as the react bundle goes. For now I will attach my webpack to not over complicate things. If there is no problem with the webpack I will start adding the necessary files. I tried the alias and still got the same result.
var path = require(`path`)
module.exports = {
mode: `development`,
entry: `./scripts/inject.js`,
output: {
path: path.resolve(__dirname, `dist`),
filename: `bundle.js`,
},
resolve: {
extensions: [`.html`, `.js`, `.json`, `.scss`, `.css`],
alias: {
leafModule: __dirname + `/node_modules/leaflet/dist/leaflet.css`,
},
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: `file-loader`,
},
],
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: `file-loader`,
options: {
name: `[name].[ext]`,
outputPath: `fonts/`,
},
},
],
},
{
test: /\.css$/i,
use: [`style-loader`, `css-loader`],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: `babel-loader`,
options: {
presets: [`#babel/preset-env`],
},
},
},
],
},
}
I'm not sure your setup is able to collect your style properly. From my point of view, you can use mini-css-extract-plugin to help you collect your css. Here is additional code you may add to your webpack.config.js:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
// ...
modules: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: `css-loader`,
options: {
// Enable css as module so we can import
modules: true,
},
},
],
},
],
},
plugins: [
// ...
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
]
}
However, keep in mind that if you switch css to module, it won't inject automatically anymore since each class name will be renamed so you have to import and add manually like:
import css from "path/to/css";
<div classSName={css.headerClass} />
As a result of that, you will have trouble with 3rd packages which have css files to import as your case.
I started to using a webpack bundler, and I got a little issue with slick slider.
Slick fonts and gif doesn't load properly
It looks like webpack skips main folder, where my project is, and looking for files in d:/node_modules instead of d:/main_folder/node_modules
I was trying to fix this by creating slick-fix.scss and set font and loader path
but it doesn't work properly
This is the error screenshot:
slick-fix.scss
$slick-loader-path: "/node_modules/slick-carousel/slick/" !default;
$slick-font-path: "/node_modules/slick-carousel/slick/fonts/" !default;
main.scss
#import "slick-fix";
#import "~slick-carousel/slick/slick.scss";
#import "~slick-carousel/slick/slick-theme.scss";
main.js
require('./styles/main.scss');
require('jquery');
import 'slick-carousel/slick/slick';
$('.slider').slick();
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const webpack = require('webpack');
const $ = require('jquery');
module.exports = {
context: path.resolve(__dirname),
entry: './src',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
]
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
}
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.$': 'jquery',
'window.jQuery': 'jquery'
})
]
}
You cannot access local paths from your http server. In other words, you cannot load files from your harddrive directly. They have to be served by the server.
I'm new to React and Webpack and all this stuff. I've created a React app with Webpack and I used webpack-dev-server to create and debug my app.
So in my webpack.config.js file I have this code:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
context: path.join(__dirname, "src"),
devtool: debug ? "inline-sourcemap" : false,
entry: "./js/client.js",
module: {
loaders: [
{
test: /\.js?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-decorators-legacy', 'transform-class-properties'],
}
},
{
test: /\.scss$/,
use: debug ? [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}] : ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" })
}
]
},
output: {
path: __dirname + "/src/",
filename: "client.min.js"
},
plugins: debug ? [] : [
new ExtractTextPlugin('style.min.css'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
],
externals: {
"jquery": "jQuery",
"react": "React",
"react-dom": "ReactDOM",
"animejs": "anime"
}
};
When I use webpack-dev-server --content-base src --inline --hot, I see my app working in localhost:8080 but now I want to make the app ready for production. so I ran these codes in my terminal:
$: NODE_ENV=production
$: webpack
It doesn't change anything! So first question: what is wrong with NODE_ENV=production? When I change the first line of my webpack to var debug = process.env.NODE_ENV === "production"; //false it works.
There are other problems!
I'm using sass and When debug === false and I open my index.html file in browser, my styles aren't compiled! Just all of my sass code is copied to style.min.css file The problem should be with this part of code:
{
test: /\.scss$/,
use: debug ? [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}] : ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" })
}
And the last problem is with absolute paths! I have this code in my app:
<img src="/images/avatar.jpg">
It works when I use webpack-dev-server but when I use webpack, the image is not found as it tries to open it from the root of my linux.
So these are my questions:
why NODE_ENV=production doesn't work?
How should I compile sass and put the css in style.min.css?
How can I use absolute paths in my app?
thanks in advance
How should I compile sass and put the css in style.min.css?
Try following config
{
test: /\.scss$/,
use: debug ? [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}] : ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: "css-loader",
options: {
modules: true,
},
},
{
loader: "sass-loader",
options: {
modules: true,
},
},
],
}),
},
How can I use absolute paths in my app?
A better way to import images in react app is using file loader in webpack and then directly importing images in application like you import other modules. First add file-loader in webpack like this
{
test: /\.(jpg|png)$/,
loader: "file-loader",
},
and then the public path of your server in webpack
output: {
path: __dirname + "/src/",
publicPath: "http://localhost:3000/static", // Your server public path
filename: "client.min.js"
},
Then in directly import image and put in src like this
import avatar from "../images/avatar.jpg";
<img src={avatar} />
in my react app I want to use fontawesome css files with webpack and the css loaders. my configuration looks like this:
webpack config
module: {
rules: [
{
test: /\.js?$/,
loader: 'babel-loader',
options: {
presets: [
["es2015", { modules: false }],
"stage-2",
"react"
],
plugins: [
"transform-node-env-inline"
],
env: {
development: {
plugins: ["react-hot-loader/babel"]
}
}
}
}, {
test: /\.(eot|ttf|woff2?|otf|svg|png|jpg)$/,
loaders: ['file']
},
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: "[name]--[local]--[hash:base64:8]"
}
},
"postcss-loader" // has separate config, see postcss.config.js nearby
]
},
]
in index.js I have this:
import 'font-awesome/css/font-awesome.css';
and in the render method i have this:
<li><NavLink to="/dashboard" className="fa fa-bars" activeClassName="activeSidebar"
aria-hidden="true"></NavLink></li>
There are noe errors, but also no icons displayed ... whats my mistake?
Thanks
You may need to add a name argument to the loader that handles the font files.
eg:
...
{
test: /\.(eot|ttf|woff2?|otf|svg|png|jpg)$/,
loader: 'file-loader?name=./[name].[hash].[ext]'
},
...
If you're working with Webpack 2, you should always add the -loader suffix after each loader's name. Here's my portion of code that works correctly in my webpack.config.js:
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
use:[{
loader: 'url-loader',
options:{
limit: 100000,
name: 'assets/resources/[name].[ext]'
}
}]
}
I'm using url-loader, but in this case it should work with file-loader too.
well, in my case, I shall add a small pattern after the extension for the url-loader and some include / exclude instructions.
This is because we want to have different tools for our css and imported ones.
The pattern added in url-loader is to handle import from font-awesome.css because they look like : src: url('../fonts/fontawesome-webfont.eot?v=4.7.0');
Here is the extract of my webpack.config.js file :
{
test: /\.css/,
loaders: [
'style-loader',
`css-loader?${JSON.stringify({
sourceMap: isDebug,
// CSS Modules https://github.com/css-modules/css-modules
modules: true,
localIdentName: isDebug ? '[name]_[local]_[hash:base64:3]' : '[hash:base64:4]',
// CSS Nano http://cssnano.co/options/
minimize: !isDebug,
camelCase: 'dashes',
})}`,
'postcss-loader',
],
exclude: [
path.resolve(__dirname, './node_modules/font-awesome'),
],
},
// ...
{
test: /\.css/,
loaders: [
'style-loader',
'css-loader',
],
include: [
path.resolve(__dirname, './node_modules/font-awesome'),
],
},
// ...
{
test: /\.(png|jpg|jpeg|gif|woff|woff2)(\?.*$|$)/,
loader: 'url-loader?limit=10000',
},
Solution that worked for me is to add the css files in my www/index.html
then I can use the css like this:
<div className={`row`}>
Same with bootstrap and fontawesome