This topic could be considered as a continuation of my previous question related to webpack & ts-loader
Now I am trying to understand how to use sass-loader with ts-loader and ExtractTextPlugin. After hours of digging it seems that ExtractTextPlugin is parsing node_modules and hence fails.
In the code example below you can see the commented part (the old style loader part) and new one which I'm trying to make work with guidance from sass-loader docs.
Currently I am stuck on this (and dozens of other similar parsing issues from node_modules):
webpack.config.js
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin"); // <-- as soon as this is imported, the build fails
const extractSass = new ExtractTextPlugin({
filename: "[name].[contenthash].css",
disable: process.env.NODE_ENV === "development"
});
module.exports = env => {
return {
devtool: "inline-source-map",
entry: "./src/index.tsx",
output: {
path: path.resolve(__dirname, "/public"),
filename: "build/app.js"
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json", ".scss"],
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: path.resolve(__dirname, "/node_modules"),
loader: "ts-loader",
},
{
test: /\.scss$/,
exclude: path.resolve(__dirname, "/node_modules"),
use: extractSass.extract({
use: [
{
loader: "style-loader",
exclude: path.resolve(__dirname, "/node_modules")},
{
loader: "css-loader",
exclude: path.resolve(__dirname, "/node_modules")},
{
loader: "sass-loader",
exclude: path.resolve(__dirname, "/node_modules"),
options: {
includePaths: [path.resolve(__dirname, "/src")],
}
},
],
}),
}
// {
// test: /\.scss$/,
// loader: 'style-loader!css-loader!sass-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
// }
],
},
plugins: [
extractSass,
]
}
}
N.B. Without ExtractTextPlugin I get an empty object when importing .scss into a .tsx file. So if you can help me solve also this issue, I would be glad (and able to continue coding) :)
import * as styles from "./Main.scss"; // <-- styles is {/* empty object */}
Related
I have a small React app that I'm minifying with Webpack, and I noticed that ~80% of my minified index.js file is just Bootstrap css that I'm not using, plus Webpack warns me that my entry file is too big (~900kb vs ~250kb recommended). I found a few answers here from a long time ago that said to remove parts of bootstrap.min.css file that I don't need, and I'm wondering if that's still the recommended solution for a React app using react-bootstrap?
This is my production webpack config:
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
module.exports = {
entry: '/src/index.tsx',
output: {
path: path.resolve(__dirname, 'prod'),
},
mode: 'production',
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
},
},
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules/react-toastify/dist'),
path.resolve(
__dirname,
'node_modules/bootstrap/dist/css/bootstrap.min.css'
),
path.resolve(
__dirname,
'node_modules/react-grid-layout/css/styles.css'
),
path.resolve(
__dirname,
'node_modules/react-resizable/css/styles.css'
),
],
use: ['style-loader', 'css-loader'],
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: 'ts-loader',
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
}),
new FaviconsWebpackPlugin('./src/logo.png'),
],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
}
And at the top of my App.tsx file I have
import 'bootstrap/dist/css/bootstrap.min.css'
Ok so I was able to (I think) accomplish what I was asking. I first tried to follow the instructions here:
https://medium.com/dwarves-foundation/remove-unused-css-styles-from-bootstrap-using-purgecss-88395a2c5772
So running purgecss --css [path to bootstrap css] ---content src/index.html --output public did create very minified CSS files, but either I did something wrong or purgecss removed too much, because the bootstrap styles didn't seem to be applied to anything.
Instead, I installed MiniCssExtractPlugin, and pointed webpack to the full bootstrap.min.css file. Running webpack with the below (updated) webpack.prod.js config file reduced the entry file size from ~900kb to ~360kb, which is still above the recommended limit but is about 1/3 the size of the entry before these changes.
Edit: and it also seems good that now the css styles are in their own actual main.css file, rather than for some reason being inside main.js, which is how it was before adding MiniCssExtractPlugin.
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: '/src/index.tsx',
output: {
path: path.resolve(__dirname, 'prod'),
},
mode: 'production',
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
},
},
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'public')
],
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: 'ts-loader',
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: './src/index.html',
}),
new MiniCssExtractPlugin({filename: "[name].css", chunkFilename: "[id].css"}),
new FaviconsWebpackPlugin('./src/logo.png'),
],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
}
So I was trying to use Bulma and got a can't import _varibales.sass, which I have in my src folder. So I thought it was because I didn't configure webpack to support Sass.
So I followed the configuration instructions from this tutorial, but then I got a loader error. This is my first time using raw webpack as opposed to CRA. I did this because I wanted to understand Webpack and Babel more.
Another thing I have tried is the Webpack configuration found on the dart-sass configuration.
My error right now is:
[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
configuration.module.rules[2] should be one of these:
["..." | object { compiler?, dependency?, descriptionData?, enforce?, exclude?, generator?, include?, issuer?, issuerLayer?, layer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceFragment?, resourceQuery?, rules?, sideEffects?, test?, type?, use? }, ...]
-> A rule.
Details:
* configuration.module.rules[2].loader should be a non-empty string.
And my webpack.config.js looks like this:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const isDevelopment = process.env.NODE_ENV === 'development'
module.exports = {
mode: 'development',
entry: path.resolve(__dirname, 'src', 'index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ["#babel/preset-env", "#babel/preset-react"]
}
},
{
test: /\.module\.s(a|c)ss$/,
loader: [
isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: isDevelopment
}
},
{
loader: 'sass-loader',
options: {
sourceMap: isDevelopment
}
}
]
},
{
test: /\.s(a|c)ss$/,
exclude: /\.module.(s(a|c)ss)$/,
loader: [
isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'sass-loader',
options: {
sourceMap: isDevelopment
}
}
]
}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'src', 'index.html') }),
new Dotenv(),
new MiniCssExtractPlugin({
filename: isDevelopment ? '[name.css]' : '[name].[hash].css',
chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css'
})
],
resolve: {
extensions: [".js", ".jsx", ".sass", ".scss"]
}
};
You use WebPack version 5+. Downgrade to a lower version of WebPack to assure compatibility.
"webpack": "^4.41.5"
In case you need to stick with the 5+ version or to learn more about the error in the webpack.config.json configuration file, refer to Webpack v4 to v5 migration.
Actuall, I had the same issue which draw me back to this question and I found the answer here (downgrading was not working as too many dependencies...) : https://webpack.js.org/loaders/sass-loader/
Instead of loader, it's 'use' that need to be used, like:
{
test: /\.s(a|c)ss$/,
use: ['style-loader','css-loader', 'sass-loader'
},
I have been looking everywhere for a place to tell me how to add tsx compilers to an existing react project. This was not a create-react-app. Is it possible to use both TSX and JSX files in the same project? I don't want to do everything in TSX, but I definitely want to get some practice in and don't want to convert the whole thing. Do you guys have any places I can go look for this? Here is my webpack.config for reference (if you know a way I can add lmk)
Version: "react": "^16.8.1",
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
devtool: 'inline-source-map',
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: "./index.html"
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "/static/cs/styles.css",
chunkFilename: "styles.css"
})
],
entry: './src/index.js',
output: {
path: path.join(__dirname, 'build'),
filename: 'static/js/bundle.js'
},
module: {
rules: [
{
test: /\.s?css$/,
use: [
"style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
{
use: { loader: 'babel-loader' },
test: /\.js$/,
exclude: /node_modules/
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: '',
},
}
]
},
]
},
devServer: {
contentBase: path.join(__dirname, 'build'),
},
}
I try to upgrade my app from webpack 2 to webpack 4.16.5.
Because I want not again end up in a hard to understand some hundreds line config, I start with a minimal config. This is my current:
const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const context = path.resolve(__dirname, "app");
module.exports = {
entry: {
home: "./index.js"
},
context,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.(css|sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader"
},
{
loader: "postcss-loader"
},
{
loader: "sass-loader"
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
resolve: {
extensions: [".js", ".jsx", ".css", "json"],
modules: [path.resolve(__dirname, "node_modules"), context]
}
};
But I run in problems importing the CSS files from react-toolbox i.e.:
import Dialog from 'react-toolbox/lib/dialog';
in a js file and also
#import "react-toolbox/lib/button/theme.css";
causes errors like this:
ERROR in ../node_modules/react-toolbox/lib/switch/theme.css (../node_modules/css-loader!../node_modules/postcss-loader/src!../node_modules/sass-loader/lib/loader.js!../node_modules/react-toolbox/lib/switch/theme.css)
Module build failed (from ../node_modules/css-loader/index.js):
Error: composition is only allowed when the selector is single: local class name not in ".disabled", ".disabled" is weird
Does anyone have a working application with wbpack4 and react-toolbox? Also, any hints on what may cause these errors are welcome!
I'm learning react.js with the js stack from scratch tutorial and try to using react-toolbox components.
Finnaly, i have a working demo with webpack 4 and the react-toolbox, it's based on the react-toolbox-example.
This is my settings:
add css-modules related packages
$ npm install postcss postcss-cssnext postcss-import postcss-loader css-loader style-loader
add a postcss.config.js
module.exports = {
plugins: {
'postcss-import': {
root: __dirname,
},
'postcss-cssnext': {}
},
};
add a webpack rule
...
{ test: /\.css$/, use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]--[local]--[hash:base64:8]'
}
},
'postcss-loader'
]},
...
add cmrh.conf.js - Using the css-modules-require-hook for SSR(Optional)
module.exports = {
generateScopedName: '[name]--[local]--[hash:base64:8]'
}
You can see all the settings in here, hope it will work for you.
I am trying out ReactJS with Webpack, hot updating, and React-Router. Below is my
webpack.config.js code. For some reason there are a bunch of json files being created at the very top of the file tree. For example, fb43026df6c9e1823c07.hot-update.json
Files end with .hot-update.json
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:5000',
'webpack/hot/dev-server',
'./scripts/index'
],
output: {
path: __dirname,
filename: 'bundle.js',
publicPath: '/static/'
},
resolve: {
extensions: ['', '.js']
},
devtool: 'eval-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel-loader']
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
},
{
test: /\.jsx?$/,
loaders: ['babel'],
include: path.join(__dirname, 'scripts')
}
]
}
};
This is the file that Webpack's hotModuleReplacementPlugin is reading from every time you make a change and save it. It's making new bundles of your app for your front end to receive.