Webpack - Setting up relative path with mini-css-extract-plugin - css

In order to output my css file using mini-css-extract-plugin to a directory I did something like the following:
context: path.resolve(__dirname, "src"),
entry: {
"main": "./js/index.js"
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash].js',
},
module: {
rules: [
{
test: /\.(png|jpg)/,
use: [
{
loader: "file-loader",
options: {
name: "images/[hash].[ext]"
}
},
]
},
{
test: /\.css$/,
use: ['MiniCss.loader', 'css-loader', 'postcss-loader']
},
plugins: [
new MiniCss({
filename: '[name].[hash].css',
})
]
}
and in css I have something like:
background: url(img/fold.svg) right 30% / 100% no-repeat;
Now the problem is that all images are referenced from css/dist instead of dist. I can solve the problem by setting a publicPath: '../' on MiniCss.loader, but then all images are referenced from .././images which works by virtue of relative path, but doesn't look "natural". Now my question is there a cleaner way to achieve this?

Related

Configure fonts in webpack

I have a slight problem with webpack here; I'm somewhat unable to load fonts.
This is my webpack.config.js
const nodeExternals = require('webpack-node-externals');
const path = require('path');
const devMode = true;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry:
[
'./src/main.js',
'./scss/main.scss'
],
output: {
filename: "main.min.js",
chunkFilename: '[name].bundle.min.js?bust=[chunkhash]',
path: path.resolve(__dirname, 'static_root'),
publicPath: "/assets/"
},
target: "node",
externals: [nodeExternals()],
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].css',
outputPath: 'css/'
}
},
{
loader: 'extract-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
hmr: process.env.NODE_ENV == 'development',
}
},
],
},
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[ext]'
}
}
]
}
};
This builds my css although then my local fonts aren't included / aren't rendered.. This also copies my Font to /static_root (which is where the css gets built to).
so I end up with this directory structure:
public/static_root/css/main.css
public/static_root/BebasNeue-Regular.ttf
public/static_root/main.min.js
I thought about just adjusting the path to the font in my scss file unfortunately though this lets the build process fail, since my working dir and the output root aren't the same.
My scss/font-directory is structured like so:
/public/scss/fonts/_fonts.scss
/public/scss/fonts/BebasNeueRegular.ttf
/public/scss/main.scss
So how can I achieve the inclusion of the font or how is this usually done since I found lots of different approaches online, that sadly didn't work out for me.
Any help would be greatly appreciated.
Greetings,
derelektrischemoench
So I found out what was causing the problems. It had to do something with the loader for the fonts (I was using an older one). I tried the whole thing with the url-loader like so:
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[ext]'
}
}
... which got it going. It was just kinda confusing, since I found a bazillion of tutorials on the web on how to achieve this, of which the most part was deprecated.
Thanks for the responses.
hey #derelektrischemoench, I think the example in Webpack official website is pretty good, you could follow the webpack config and its file structure:
https://webpack.js.org/guides/asset-management/#loading-fonts

Webpack 4: mini-css-extract-plugin + file-loader not loading assets

I'm trying to move assets (images and fonts) used in one of my .scssfiles, but it seems that they get ignored:
This is my .scss file:
#font-face {
font-family: 'myfont';
src: url('../../assets/fonts/myfont.ttf') format('truetype');
font-weight: 600;
font-style: normal;
}
body {
color: red;
font-family: 'myfont';
background: url('../../assets/images/bg.jpg');
}
And this is my webpack.config.js:
const path = require('path');
const { CheckerPlugin } = require('awesome-typescript-loader');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
target: 'node',
entry: path.resolve(__dirname, 'server.tsx'),
output: {
filename: 'server_bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: '/build'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
module: {
rules: [{
test: /\.(tsx|ts)?$/,
loader: 'awesome-typescript-loader',
options: {
jsx: 'react'
}
},
{
test: /\.(scss|sass|css)$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { url: false, sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } },
]
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
loader: 'file-loader',
options: { outputPath: 'public/images' }
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: { outputPath: 'public/fonts' }
}
]
},
plugins: [
new CheckerPlugin(),
new MiniCssExtractPlugin({
filename: 'public/styles_bundle.css',
chunkFilename: "public/styles/[id].css"
})
]
}
I'm getting this .css file in my browser as the output (Note the name of the image):
body {
color: red;
background: url("../../assets/images/myimage.jpg");
}
And in my public directory I get this:
public/
styles_bundle.css
There are two problems here:
Fonts are not compiled (No public/fonts/etc...)
Images are not compiled
I've been trying everything, but I don't know what may be happening here... Any Ideas?
I have just fixed a similar issue. If you change the url option to true, you might see failed image URL references.
{ loader: 'css-loader', options: { url: false, sourceMap: true } },
Or you can manual check whether the path reference is correct.
url('../../assets/images/bg.jpg')
I think the images folder doesn't get created because all the image resource links are incorrect.
For the problem I was fixing, the references were all wrong and I couldn't fix them so I just used this webpack copy plugin to copy files to the right dist folder location.
you need url-loader
{
test: /\.(jpg|png|gif|woff|eot|ttf|svg)/,
use: {
loader: 'url-loader', // this need file-loader
options: {
limit: 50000
}
}
}
try the below configuration
{
test: /\.s[ac]ss$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: ''
}
},
{
loader: "css-loader",
options: { sourceMap: true}
},{
loader: "sass-loader",
options: { sourceMap: true }
}
]
},
{
test: /\.(png|jpg|jpeg|gif)$/i,
loader: 'file-loader',
options: { outputPath: 'assets/images', publicPath: '../images', useRelativePaths: true }
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
loader: 'file-loader',
options: { outputPath: 'assets/fonts', publicPath: '../fonts', useRelativePaths: true }
}
After this my scss file started accepting the relative URL and the compiled files also mapped accordingly using relative path.
The mini-css-extract-plugin has a 'publicPath' option (see here). It basically tells the generated css where the external resources like fonts, images, etc are to be found. In my case, setting it to '../' and configuring all the file loaders to their proper directories, this worked perfectly.
Basically looks like:
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/public/path/to/', // <-- This is what was helping.
},
},
'css-loader',
],
},
],
I had this issue too. I was using the following versions:
package.json
"mini-css-extract-plugin": "^0.10.1",
"webpack": "^5.3.1",
For me everything was compiling just fine until I added the following into a scss file:
.xmas {
background-image: url("./img/Xmas2020/SurveyBanner.png");
height: 150px;
}
The backgound-image url was the problem. When I changed it to an absolute path it worked:
.xmas {
background-image: url("/img/Xmas2020/SurveyBanner.png");
height: 150px;
}
webpack.config.js
This is just to show how I was putting images into the output directory. I guess there are different ways to do this, but I was using CopyWebpackPlugin.
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: './src/static/img', to: './img', force: true },
]
}),
]
This link helped me https://github.com/webpack-contrib/mini-css-extract-plugin/issues/286#issuecomment-455917803
Had the exact problem with webpack 5. The answer is in Asset Modules
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
assetModuleFilename: 'images/[hash][ext][query]' //set the pattern for your filename here
},
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource' //replaces file-loader, url-loader etc
}
]
},
};

How to config the file path in webpack?

I'm new to webpack. I want to ask how can I custom a file path in webpack.
Here is the code I've tested:
(function () {
var webpack = require('webpack'),
path = require('path'),
BabiliPlugin = require('babili-webpack-plugin'),
ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: {
'site': ['./assets/js/site']
},
output: {
publicPath: '/assets/',
path: path.join(__dirname, 'wwwroot/assets/js'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/i,
use: [{
loader: 'babel-loader',
query: {
presets: ['es2015', 'stage-1'],
compact: false
}
}]
},
{
test: /(\.(ttf|eot|svg)(\?[\s\S]+)?$)|(\.woff2?(\?v=\d+\.\d+\.\d+)?$)/,
use: [{
loader: 'file-loader',
options: {
name: '../fonts/[name].[ext]'
}
}]
},
{
test: /\.(png|jpe?g|bmp|gif|ico)/,
use: [{
loader: 'file-loader',
options: {
name: '../images/[name].[ext]'
}
}]
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract(['css-loader'])
}
]
},
plugins: [
new BabiliPlugin({}, { test: /\.min\.js$/ }),
new webpack.ProvidePlugin({
$: 'jquery'
}),
new ExtractTextPlugin('../css/bundle.css')
]
};
}());
I want to ask about these lines:
use: [{
loader: 'file-loader',
options: {
name: '../fonts/[name].[ext]'
}
}]
When I set the name starts with ../, it compiles exactly right except the url which is inside the file bundle.css, like this snapshot:
Then, I've tried to remove the characters ../ from the name, the fonts folder was created inside js folder (it's not my goal). But the url inside the file bundle.css folder is right (I want this path - /assets/fonts/...).
How can I edit it?
p/s: May you embed the two images to my question? it doesn't appear now. Thank you!
You may need to set a context in your loader's options. By default the current working directory is used.
I'm not sure what your src directory structure is, so I'm taking a guess.
use: [{
loader: 'file-loader',
options: {
name: 'assets/fonts/[name].[ext]',
context: './src/assets/fonts/'
}
}]

Webpack creates unnecessary .js file for my CSS stylesheet

I have this Webpack config for compiling CSS, JavaScript and HTML
{
entry: {
main: ['babel-polyfill', path.join(__dirname, 'clientside', 'client.js')],
styles: path.join(__dirname, 'clientside', 'styles.css')
},
output: {
path: path.join(__dirname, 'public'),
filename: '[name].js'
},
module:
{
loaders: [
{ test: /\.js$/,
loader: 'babel',
query: { presets:['es2015', 'stage-0'] }
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
}
],
},
plugins: [
new ExtractTextPlugin('./styles.css'),
new webpack.optimize.UglifyJsPlugin({ minimize: true }),
new HtmlWebpackPlugin({
template: 'clientside/index.html',
inject: 'body',
chunks: ['main'],
minify: htmlMinifierObj
})
],
}
The problem with this config is it creates an unnecessary styles.js file, I don't need it.
I also know I can include styles.css inside my JS file but I don't think it's a good idea, because I want to keep JavaScript and CSS separated.
So, my question is: how can I edit my config to get rid of this unnecessary file?

webpack : css points to wrong image folder in prod

When I build my project for production I get this structure :
build/static/
js/bundle.js
css/bundle.css
media/ *all my images*
All the images are extracted fine and work except for the images extracted from the css like :
cursor: url(../assets/myImage.png)
It is copied to the right folder static/media/myImage.png
but the url in the css points to static/css/static/media/myImage.png
Here is my webpack config for prod :
entry: {
app: path.join(__dirname, 'src/App.js'),
vendor: ["react", "react-dom"],
},
output: {
path: "./build/",
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js'
},
module: {
loaders: [
{
test: /\.sass$/,
loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss!sass')
},
{
test: /\.(jpg|png|svg)(\?.*)?$/,
loader: 'file',
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
]
},
plugins: [
new ExtractTextPlugin('static/css/[name].[contenthash:8].css',
{allChunks: true}, {publicPath: './'})
]
};
The css is extracted to static/css but when it extracts the images it nests the paths in the code so instead of pointing to static/media/ it gets nested and produces static/css + static/media
How can I get the correct path in my css ?
Thank you.

Resources