Disable resolving for CSS/SASS/SCSS/LESS URLs in Webpack 5 - javascript

In SASS, I have a CSS rule with a URL that looks like:
.eSearchFAQsAccord-q {
&::after {
content: url("./images/caret.svg");
}
}
By default, Webpack will resolve this (though it chokes on my SVG). I want it to NOT resolve. I want the browser to load this image separately, from my static directory.
I'm not sure what to say about what I've tried so far. I've tried a lot of settings from around the web in my Webpack config that didn't work...
Here's my Webpack config, which I think is pretty out-of-the-box:
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
mode: "development",
entry: {
index: `./src/index.js`,
},
target: "web",
output: {
path: `${__dirname}/dist`,
filename: "[name].js",
},
plugins: [
new CopyWebpackPlugin({
patterns: [{ from: "static" }],
}),
],
devServer: {
hot: true,
inline: true,
host: "localhost",
port: 8080,
watchOptions: {
poll: true,
},
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
{
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
},
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
},
],
},
};
I'm sure my issue is because I don't have intimate knowledge of Webpack, but the documentation I don't think is particularly intuitive at a glance.

I think Webpack 5 css-loader resolves this url() calls by default, and you need to disable it manually:
loader: "css-loader",
options: {
// Add this option
url: false,
},
More in the docs
Maybe there are same options for your other loaders, but I'm pretty sure you just need to disable it for css-loader only

Related

Webpack breaking change

I am trying to build a react app but each time I run npm start, I am greeted with this message
Module not found: Error: Can't resolve 'buffer' in '/Users/abdus/Documents/GitHub/keywords-tracker/node_modules/buffer-equal-constant-time'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
It gives the same message for a few different modules. I have tried npm installing these modules but the error persists
this is my webpack set up that works. you should install all the packages that listed in fallback:
// const path = require("path");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const webpack = require("webpack");
module.exports = {
mode: "development",
target: "web",
entry: ["regenerator-runtime/runtime", "./src/index.js"],
output: {
filename: "bundle.js",
path: path.join(__dirname, "dist"),
publicPath: "/",
},
resolve: {
extensions: [".js", ".css"],
alias: {
// add as many aliases as you like!
components: path.resolve(__dirname, "src/components"),
},
fallback: {
// path: require.resolve("path-browserify"),
fs: false,
assert: require.resolve("assert/"),
os: require.resolve("os-browserify/browser"),
constants: require.resolve("constants-browserify"),
stream: require.resolve("stream-browserify"),
crypto: require.resolve("crypto-browserify"),
http: require.resolve("stream-http"),
https: require.resolve("https-browserify"),
},
},
// devtool: "eval-cheap-source-map",
devtool: "eval",
module: {
rules: [
{ test: /\.(js|jsx)/, loader: "babel-loader", exclude: /node_modules/ },
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
// {
// test: /\.m?js/,
// resolve: {
// fullySpecified: false
// }
// },
{
test: /\.(woff(2)?|ttf|eot|jpg|jpeg|png|gif)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[contenthash].[ext]",
outputPath: "fonts/",
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: "svg-url-loader",
options: {
limit: 10000,
},
},
],
},
{
test: /\.json5$/i,
loader: "json5-loader",
type: "javascript/auto",
options: {
esModule: true,
},
},
],
},
devServer: {
contentBase: path.join(__dirname, "build"),
historyApiFallback: true,
overlay: true,
},
plugins: [
new HtmlWebpackPlugin({
title: "NFT",
template: "src/index.html",
}),
// new CopyWebpackPlugin({
// patterns: [{ from: "assets", to: "assets" }],
// }),
],
};
you can get this webpack5-Boilerplate
Since there are too many polyfills, instead of manually installing all, you can use node-polyfill-webpack-plugin package. instead of fallback property
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
plugins: [
new HtmlWebpackPlugin({
title: "esBUild",
template: "src/index.html",
}),
// instead of fallback
new NodePolyfillPlugin(),
// new webpack.ProvidePlugin({
// process: "process/browser",
// Buffer: ["buffer", "Buffer"],
// React: "react",
}),
],
It seems like you are using a front-end react app and some dependency is internally using the buffer module which is only available in target: node under webpack. So you will need to add a polyfill for the same.
module.exports = {
resolve: {
fallback: {
buffer: require.resolve('buffer'),
}
},
}
You can check the docs here at webpack: https://webpack.js.org/configuration/resolve/#resolvefallback
From Webpack 5 onwards, webpack doesn't polyfill for browser-based applications.

Webpack 5 HMR throws Uncaught TypeError: cannot set property <filename> of undefined at self.webpackHotUpdate

After upgrading to Webpack 5, HMR has stopped working on our React project.
Current versions of modules are:
#webpack-cli/serve#1.5.1, html-webpack-plugin#5.3.2, webpack#5.50.0, webpack-cli#4.7.2
webpack-dev-server#4.0.0-rc.0
(note, it was failing exactly the same way with earlier non-rc version of webpack-dev-server)
The browser console reports:
Uncaught TypeError: Cannot set property
'./resources/assets/js/screens/LandingPage/LandingPage.js' of undefined
at self.webpackHotUpdate (jsonp chunk loading:44)
at bundle.7fe3c7a98c4f94dbfe6d.hot-update.js:2
The above happens when the code is changed - the watch detects it, and the recompile takes place, but the above error is thrown preventing the browser reloading. Manual reload on the browser works fine.
Running
webpack-cli serve --config=webpack.dev.config.js
Config file is:
module.exports = {
mode: 'development',
entry: {
[bundleNames.js]: path.join(__dirname, `${assetsDir}/js/app.js`),
[bundleNames.css]: path.join(__dirname, `${assetsDir}/less/styles.less`)
},
output: {
filename: '[name].js',
path: path.join(__dirname, publicPath),
publicPath: '/',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.jsx?$/,
use: 'babel-loader',
include: [path.resolve(__dirname, `${assetsDir}/js`)],
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.png$|\.xml$|\.ico$|\.svg$/,
use: ['file-loader?name=[name].[ext]'],
include: [path.resolve(__dirname, `${assetsDir}/favicons`)],
},
{
test: /\.json$/,
use: ['file-loader?name=[name].[ext]'],
type: 'javascript/auto',
include: [path.resolve(__dirname, `${assetsDir}/favicons`)],
},
{
test: /\.woff2?$|\.ttf$|\.eot$|\.svg$|\.png$|\.jpe?g$|\.gif$/,
use: [
{
loader: 'file-loader',
options: {
esModule: false,
name: './static/[name].[ext]',
},
},
],
},
{
test: /\.js$/,
use: ['file-loader?name=static/[name].[ext]'],
include: [path.resolve(__dirname, `${assetsDir}/static`)],
},
],
},
plugins: [
new webpack.DefinePlugin({
'LOCALE_HASH': `'${LOCALE_HASH}'`,
}),
new webpack.HotModuleReplacementPlugin({}),
],
resolve: {
extensions: ['.js'],
fallback: {
"fs": false
}
},
devServer: {
hot: true,
host: '0.0.0.0',
port: 3000,
proxy: {
'*': {
target: config.WEBPACK_PROXY_URL,
changeOrigin: true
}
},
headers: {
'Access-Control-Allow-Origin': '*'
},
historyApiFallback: false,
}
};
The solution was:
Remove the CSS line from Webpack config:
entry: {
[bundleNames.js]: path.join(__dirname, `${assetsDir}/js/app.js`),
--> [bundleNames.css]: path.join(__dirname, `${assetsDir}/less/styles.less`)
},
instead import the Less directly in app.js:
import '../less/styles.less';

Optimizing webpack build time

I have a problem compiling a project after saving a change in the files; the compilation time of the files takes 2 or more minutes.
To fix the problem, I took the following steps:
1.In babel-loader from the documentation in the option object for properties cacheDirectory set to true, cacheComprassion to false
2. In the ts-loader from the documentation in the option object for the properties transpileOnly and happyPackMode set to true
3.dev-tool disabled for better performance
4. ForkTsCheckerWebpackPlugin connected to check types in typescript
5. Code splitting customized
Webpack config file
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const webpack = require('webpack');
// eslint-disable-next-line import/no-extraneous-dependencies
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: [
path.resolve(__dirname, 'src/index.tsx'),
],
mode: 'development',
module: {
rules: [
{ parser: { requireEnsure: false } },
{
test: /\.(ts|tsx)$/,
exclude: /(node_modules)/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
},
},
{
loader: 'ts-loader', options: {
transpileOnly: true,
happyPackMode: true
},
},
],
},
{
test: /\.scss$/,
use: [
{
// creates style nodes from JS strings
loader: 'style-loader',
},
{
// translates CSS into CommonJS
loader: 'css-loader',
},
{
// compiles Sass to CSS
loader: 'sass-loader',
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
// eslint-disable-next-line global-require
require('autoprefixer'),
],
},
},
],
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'less-loader'],
}),
},
{
test: /\.css$/,
use: [
{
// creates style nodes from JS strings
loader: 'style-loader',
},
{
// translates CSS into CommonJS
loader: 'css-loader',
},
],
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
},
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
],
},
// devtool: 'source-map',
optimization: {
runtimeChunk: {
name: 'app',
},
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
minimize: true,
},
resolve: { extensions: ['*', '.js', '.jsx', '.ts', '.tsx', 'scss'], modules: ['node_modules'] },
output: {
// path: `${__dirname}/dist`,
// filename: 'app.js',
publicPath: 'http://localhost:3000/hmr/',
chunkFilename: '[id].js?v=[chunkhash]',
},
devServer: {
stats: {
// assets: true,
// cachedAssets: true,
// performance: true,
// entrypoints: true,
// chunkGroups: true,
// chunks: true,
// chunkModules: true,
// show modules contained in each chunk
// chunkOrigins: true,
// show the origin of a chunk (why was this chunk created)
// chunkRelations: true,
// show relations to other chunks (parents, children, sibilings)
// dependentModules: true,
},
disableHostCheck: true,
host: '127.0.0.1',
port: 3000,
publicPath: '/hmr/',
filename: 'app.js',
// hot: true,
// hotOnly: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ForkTsCheckerWebpackPlugin({
typescript: {
diagnosticOptions: {
semantic: true,
syntactic: true,
},
},
async: true,
}),
new ESLintPlugin({
eslintPath: 'eslint',
fix: true,
quiet: true,
extensions: ['ts', 'tsx'],
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
};
Please tell me how you can reduce the compilation time of files in the project after saving the files?
Solved the issue. The problem turned out to be in the eslint-loader-webpack plugin. If you install the old version of eslint-loader, then everything works fine.
How to solve the issue of the eslint-loader-webpack plugin slow?

Webpack doesn't emit css sourcemap (with sourcemap: true)

I can't make my webpack to emit css sourcemap. I've put sourcemap: true everywhere where possible, and no effect, and all the solutions online suggest either this or some other plugin configuration, but I don't have any other plugin, it's super simple webpack.config.js
This is my webpack.config.js:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var path = require("path");
module.exports = {
entry: "./main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: "/",
sourceMapFilename: '[file].map'
},
devtool: 'source-map',
module: {
rules: [{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["es2015"],
sourceMap: true
}
}
},
{
test: /\.scss$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/',
sourceMap: true,
hmr: process.env.NODE_ENV === 'development',
},
},
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true
},
}
]
},
{
test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/,
use: [{
loader: 'url-loader',
options: {
name: 'images/[hash]-[name].[ext]'
}
}]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
sourceMap: true
}),
],
};
I need this source map in dev mode, but only two files get emited main.css and bundle.js.
For those who also struggle with this, the below webpack.config.js is a proper configuration for having style's sourcemap in dev mode. Bundle.js needs to be included when in dev mode, and custom.min.css needs to be added to the HTML document in production mode.
Edit: Unfortunately this can be also wrong. Right now without any change to webpack or node, the sourcemap is not generating :/ sometimes it works, and sometimes it doesn't. There is some bug in webpack, or in some plugins, either way it's a serious bug, but it's webpack so I am not surprised...
Edit 2: Now I see that the problem is only in Firefox, Chrome and Opera have the correct map.
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var path = require("path");
module.exports = {
entry: "./main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: "/"
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: "babel-loader",
options: { presets: ["es2015"] }
}
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
},
{
loader: "css-loader" ,
options: {
sourceMap: true
}// translates CSS into CommonJS
},
{
loader: "sass-loader",
options: {
sourceMap: true
} // compiles Sass to CSS
}
]
},
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg)$/,
use: [{
loader: 'url-loader',
options: {
name: 'images/[hash]-[name].[ext]'
}
}] }
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '../css/custom.min.css'
})
]
};

Webpack externals failing to resolve in parent project

I have a library, this library is React component library so it depends on react and react-dom. It also depends on react-router-dom (and transitively react-router).
These are packages the parent project provides. I don't want them in the bundle. This library is generated using webpack so I have added them to the externals configuration in the libraries webpack configuration, which is below (Webpack v4.4)
const webpack = require("webpack");
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "commonjs",
},
externals: {
"react-router": {
"commonjs": "react-router",
"commonjs2": "eact-router",
"amd": "react-router",
"root": "react-router"
},
"react-router-dom": {
"commonjs": "react-router-dom",
"commonjs2": "react-router-dom",
"amd": "react-router-dom",
"root": "react-router-dom"
},
"react": {
"commonjs": "react",
"commonjs2": "react",
"amd": "react",
"root": "React"
},
"react-dom": {
"commonjs": "react-dom",
"commonjs2": "react-dom",
"amd": "react-dom",
"root": "ReactDOM"
}
},
// devtool: "cheap-eval-source-map",
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env", "#babel/preset-react"],
plugins: [
"#babel/plugin-transform-flow-strip-types",
"#babel/plugin-proposal-object-rest-spread",
"transform-class-properties",
],
},
},
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{ loader: "css-loader", options: { minify: true } },
"sass-loader",
],
}),
},
{
// Match woff2 in addition to patterns like .woff?v=1.1.1.
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: "url-loader",
options: {
// Limit at 50k. Above that it emits separate files
limit: 50000,
// url-loader sets mimetype if it's passed.
// Without this it derives it from the file extension
mimetype: "application/font-woff",
// Output below fonts directory
name: "./fonts/[name].[ext]",
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: "svg-inline-loader",
options: {
removeSVGTagAttrs: false,
},
},
],
},
{
test: /\.(png|jp(e*)g)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8000, // Convert images < 8kb to base64 strings
name: 'images/[hash]-[name].[ext]'
}
}]
},
],
},
plugins: [
new ExtractTextPlugin("styles.css"),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.optimize\.css$/g,
cssProcessor: require("cssnano"),
cssProcessorOptions: { discardComments: { removeAll: true } },
canPrint: true,
}),
new webpack.optimize.AggressiveMergingPlugin(),
],
};
However, when I include the output of the library in the parent project it complains during the build phase that
ERROR in ../moss/dist/bundle.js
Module not found: Error: Can't resolve 'react-router' in '/Users/ubermouse/code/moss/dist'
# ../moss/dist/bundle.js 19655:223-261
# ./matai/static_src/js/containers/App.js
# ./matai/static_src/js/containers/Root.js
# ./matai/static_src/js/index.js
# multi ./matai/static_src/js/utils/polyfills.js ./matai/static_src/js/index.js
I get the above error for both react-router and react-router-dom. I do not get it for react or react-dom.
What is going on here? Am I using externals wrong? Why does it work for react/react-dom? Are they just not required yet? Can externals not pull dependencies from the parents node_modules? I've been tearing my hair out over this for hours :(
One thing I have noticed, react-router/react-router-dom have a module property in their package.json so their ESModule gets loaaded. react/react-router does not. I don't know if this changes anything, but it is something.
Our parent projects webpack config for completeness
const webpack = require('webpack');
const path = require('path');
const config = require('./frontend.config');
/**
* Base Webpack config, defining how our code should compile.
*/
module.exports = {
entry: {
vendor: [
"moment",
"react",
"react-dom",
"react-intl",
"react-intl-redux",
"react-redux",
"react-leaflet",
"react-router",
"react-router-dom",
"react-router-redux",
"redux",
"redux-observable",
"rxjs",
],
matai: [
path.join(config.paths.js, 'utils', 'polyfills.js'),
path.join(config.paths.js, 'index.js'),
],
},
output: {
path: path.join(config.paths.build_js),
filename: '[name].js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity,
// (with more entries, this ensures that no other module
// goes into the vendor chunk)
}),
],
module: {
rules: [
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{
test: /\.js$/,
enforce: 'pre',
use: ['eslint-loader'],
include: path.join(config.paths.js),
},
{
test: /\.js$/,
use: ['babel-loader'],
exclude: [/node_modules/],
},
],
},
stats: {
// Set the maximum number of modules to be shown
maxModules: 3,
// Add chunk information (setting this to `false` allows for a less verbose output)
chunks: false,
// Add the hash of the compilation
hash: false,
// `webpack --colors` equivalent
colors: true,
// Add information about the reasons why modules are included
reasons: false,
// Add webpack version information
version: false,
},
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
},
};

Categories