Webpack not building because CssSyntaxError - javascript

I am trying to run a webpack-dev-server built, but it fails everytime with the following error:
ERROR in ./src/style.css (./node_modules/css-loader/dist/cjs.js!./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./src/style.css)
Module build failed (from ./node_modules/css-loader/dist/cjs.js):
CssSyntaxError
(1:1) Unknown word
> 1 | var api = require("!../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js");
| ^
2 | var content = require("!!../node_modules/css-loader/dist/cjs.js!./style.css");
3 |
My webpack.dev.js looks like this:
const path = require('path');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
entry: './src/index.js',
mode: 'development',
devtool: 'inline-source-map',
optimization: {
usedExports: true,
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
],
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
],
},
});
The error appears on using this in my index.js:
import './style.css';
Many solutions suggest the order of the style-loader and the css-loader, but as far as I know it is in the correct order. What am I doing wrong?

I had the same error when trying to use the style-loader and the MiniCssExtractPlugin simultaneously. Your example uses webpack merge, so I assume that you also have a webpack.common.js somewhere with additional CSS rules?
In my case, what solved it was as following:
I have the following rules in my webpack.dev.config.js:
module: {
rules: [
{
test: /\.(sass|scss)$/,
use: [
"style-loader",
"css-loader",
"postcss-loader",
{
loader: "sass-loader",
options: {
// Prefer `dart-sass`
implementation: require("sass"),
},
},
],
},
],
},
And the following in my webpack.prod.config.js:
module: {
rules: [
{
test: /\.(sass|scss)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
{
loader: "sass-loader",
options: {
// Prefer `dart-sass`
implementation: require("sass"),
},
},
],
},
],
},
You could also use the ternary operator to check if mode === 'production' and leave it in one file but I prefer to have two separate files to keep it more readable in case the webpack configs get too big.
I also tried to move the css-loader, postcss-loader and sass-loader to the same webpack.common.js file but for some reason it didn't work.
Not sure if that might be cause of your error but it fixed it in my use case so now I use the style loader for my dev environment and the plugin to compile for production.
This worked for webpack 5 and node 16

Related

Webpack url() path resolution with css-loader

I am developing a site and using webpack for obvious reasons. The problem I am having is with path resolution for images which are imported into my project via my SCSS files. The issue is that css-loader isn't resolving the correct path. What seems to be happening is the following:
If I allow css-loader to handle the url() imports (leaving the url option to true) it rewrites the file path relative to the output directory specified in ExtractCSSChunksPlugin(), for example:
url('../img/an-image.jpg') should be rewritten to url('http://localhost:3000/assets/img/an-image.jpg'), however, what is actually being outputted is url('http://localhost:3000/assets/css/assets/img/an-image.jpg').
If I change it to false the correct path is resolved but the file-loader isn't able to find the images and then emit them.
I know that the images are being outputted when the css-loader is handling url resolution as I can see the emitted message when the bundle is compiled -- it does not fail.
I can also get the images to display if I manually add import calls to them in the JS entry point, set in the entry: field, and then call the absolute path in SCSS. But this is not desirable as it becomes tedious with the growing project.
I have tried to use resolve-url-loader and changing multiple settings but I just can't seem to get this to work.
I have also tried using the resolve: { alias: { Images: path.resolve(__dirname, 'src/assets/img/' } } option provided by webpack and then calling url('~Images/an-image.jpg') in my SCSS but it just reproduces the same results.
So, overall, my issue is that I need to be able to use relative paths in my SCSS and then have them rewritten to the correct path by one of my loaders.
My current webpack config (outputting the files with file loader but prepending assets/css/ to the start of the url) is as follows:
"use strict";
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common');
const ExtractCSSChunksPlugin = require('extract-css-chunks-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
entry: [
'webpack-hot-middleware/client',
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
}
}
},
{
test: /\.scss$/,
use: [
{
loader: ExtractCSSChunksPlugin.loader,
options: {
hot: true,
}
},
{
loader: 'css-loader',
options: {
sourceMap: true,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
}
}
]
},
{
test: /\.html$/,
use:['html-loader']
},
{
test:/\.(svg|jpg|png|gif)$/,
use: [{
loader:'file-loader',
options: {
publicPath: 'assets/img',
outputPath: 'assets/img',
name: '[name].[ext]',
esModule: false
}
}],
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ExtractCSSChunksPlugin({
filename: 'assets/css/[name].css',
chunkFilename: 'assets/css/[id].css',
}),
]
});
Thank you in advance.
Ok, so it seems I have fixed the issue by resolving the publicPath set in the file loader config field: publicPath: path.resolve(__dirname, '/assets/img').
My config is now:
"use strict";
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');
const ExtractCSSChunksPlugin = require('extract-css-chunks-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
entry: [
'webpack-hot-middleware/client',
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
}
}
},
{
test: /\.scss$/,
use: [
{
loader: ExtractCSSChunksPlugin.loader,
options: {
hot: true,
}
},
{
loader: 'css-loader',
options: {
sourceMap: true,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
}
}
]
},
{
test: /\.html$/,
use:['html-loader']
},
{
test:/\.(svg|jpg|png|gif)$/,
use: [{
loader:'file-loader',
options: {
publicPath: path.resolve(__dirname, '/assets/img'),
outputPath: 'assets/img',
name: '[name].[ext]',
esModule: false
}
}],
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ExtractCSSChunksPlugin({
filename: 'assets/css/[name].css',
chunkFilename: 'assets/css/[id].css',
}),
]
});
I think adding url loader in the webpack configuration would help.
{
test: /\.(jpg|png)$/,
use: {
loader: "url-loader",
options: {
limit: 25000,
},
},
},

Objects called in browser after webpack bundle show undefined

I am new to webpack and I want to debug using console.log in my browser and by calling functions to see what works, but whenever I try to do this after my js files are bundled everything shows up as undefined. Webpack must be changing the names somehow when the files get bundled together so even if I make a simple let x = 'hello', I can't console.log it and I can't even call any functions I made without them being undefined when I use them in the console.
How can I fix this so that I can call the objects that I made in the console? Here is my simple webpack config-
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-source-map',
mode: 'development',
entry: {
app:'./src/js/index.js',
test:'./src/js/test2.js',
create: './src/js/create.js'
},
devtool: 'source-map ',
devServer: {
contentBase: './dist',
compress: true,
port: 8080,
},
plugins: [
new HtmlWebpackPlugin({
title: 'Menu',
template: './src/views/index.ejs',
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.jsnpm$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['#babel/preset-env', {
'debug':true
}]
}
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
},
};
https://webpack.js.org/contribute/debugging/
This would be helpful for getting in depth of debugging webpacks! good documentation for debugging webpacks.
In case you want to use browser for debugging, this may be helpful:
Configure webpack to allow browser debugging
Hope this helps!

Webpack: include specific file instead of package.json specified?

I have a webpack configuration:
var path = require("path");
module.exports = {
entry: {
app: [
'./src/index.js'
]
},
output: {
path: path.resolve(__dirname + '/dist'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader',
]
},
{
test: /\.js$/,
exclude: /node_modules/,
},
{
test: /\.html$/,
exclude: /node_modules/,
loader: 'file-loader?name=[name].[ext]',
},
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
loader: 'elm-webpack-loader?verbose=true&warn=true',
options: {debug: true, warn: true},
},
{
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',
},
],
noParse: /\.elm$/,
},
devServer: {
inline: true,
stats: { colors: true },
},
};
I have a few questions:
According to me the above config says that it should not be looking
for js files in node_modules. However it is still bundling
./node_modules/dexie/dist/dexie.es.js when I call require ("dexie"). (I am just doing this to experiment and understand webpack).
I would rather like to call dexie.js instead of dexie.es.js. How do
I make this happen. I know I can set the mainFields property.
However how do I do this on a prelibrary basis instead of globally.
Not sure if I understand your requirement fully, but an option is to set up aliases in the webpack resolve
module.exports = {
entry: {
...
},
output: {
...
},
module: {
rules: [
...
],
noParse: /\.elm$/,
},
resolve: {
alias: {
dixie: 'node_modules/dexie/dist/dexie.js'
}
},
devServer: {
...
},
};
To your first question please see here. It has already been answered.
No matter what you exclude in your loaders config, the file will be bundled unless you define it as external in your config.
To your second question, you can just require the other file with
require('dexie/dexie.js')
When you just write require('dexie'), webpack will look in your node_modules folder for a folder named 'dexie', read the package.json and resolve the file described by the module property. This is described here.
For more info, please read the webpack docs. They are excellent.

how to ready react app with webpack

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} />

Webpack Sass - cannot resolve images

I am trying to compile my Sass via webpack. Compiling normal sass is fine but I get an error.
Module not found: Error: Can't resolve '../img/twitter.svg' in '/Users/Steve/mywebsite/scss'
# ./~/css-loader!./~/sass-loader/lib/loader.js!./scss/main.scss 6:94501-94530
Is there a way to resolve this? Alternatively is there a way to set the level of the sass compiler to be less strict to just ignore certain errors
Below is my current config.
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
resolve: {
alias: {
masonry: "masonry-layout",
isotope: "isotope-layout",
},
},
entry: "./main.js",
output: {
path: path.resolve(__dirname, "./dist/dist2"),
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.(png|jpg|svg)$/,
include: path.join(__dirname, "/dist/img"),
loader: "url-loader?limit=30000&name=images/[name].[ext]",
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader?presets[]=es2015",
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
use: ["css-loader", "sass-loader"],
}),
},
{
test: /\.vue$/,
loader: "vue-loader",
options: {
loaders: {},
// other vue-loader options go here
},
},
],
},
plugins: [
// new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin("ross.css"),
],
};
I know this is late, but for anyone looking for a workaround this error;
In my case the image was loading perfectly in the template, however, Webpack was returning an error: Module not found: Error: Can't resolve './path/to/assets.png'
Fix/Workaround:
Add ?url=false to your css-loader, that will disable url handling by the css-loader :
...
{
loader: "css-loader?url=false"
},
...
I didn't have any luck with url-loader and file-loaderas suggested in the other answer. I was able to solve it using resolve-url-loader
module: {
rules: [
{ // sass / scss loader for webpack
test: /\.(sass|scss|svg|png|jpe?g)$/, //Make sure to allow all necessary file types here
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: true,
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
},
{
loader: "resolve-url-loader", //resolve-url-loader needs to come *BEFORE* sass-loader
options: {
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
})
}
],
},
This is a breaking change in css-loader 4.x (according to css-loader issue 1136).
You have not specified any loaders for images in your webpack file.
Install url-loader and file-loader to your package.json
via
npm install --save url-loader file-loader
Inside your webpack config file add following -
{
test : /\.(png|jpg|svg)$/,
include : path.join(__dirname, 'img'),
loader : 'url-loader?limit=30000&name=images/[name].[ext]'
}, // inline base64 URLs for <=30k images, direct URLs for the rest
I use this "Disable url resolving using the /* webpackIgnore: true */ comment"
https://webpack.js.org/loaders/css-loader/#disable-url-resolving-using-the--webpackignore-true--comment

Categories

Resources