file-loader for fonts configuration in Webpack - path

Project structure
/dev
-/fonts
-/css
-/vendors
-/fontawesome
-/webfonts
/dist
-/my-project
-/fonts
With file-loader for Webapck, I´m trying to compile all sass/scss with url path and moved all font files into dist/my-project/fonts/.
webpack.config.js
module.exports = env => {
...
return{
...
output: {
path: path.resolve(__dirname, 'dist/'),
},
module: {
rules: [
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: './my-project/fonts/',
context: './fonts/'
}
}
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: './my-project/fonts/',
context: 'css/vendors/'
}
}
]
}
]
}
}
}
This config manage to copy files at the right place but in the css, I got this:
#font-face{
font-family:'Font Awesome 5 Brands';
font-style:normal;
font-weight:normal;
font-display:auto;
src:url(my-project/fonts/fa-brands-400.eot); //<--instead of fonts/fa-brands-400.eot
...
}
So how to compile the right url font path in css files keeping this outPath ?

The solution is to use :
publicPath to compile path in css url font
outPath to move font files in the right directory
So...
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
publicPath: './fonts/', //<--resolve the path in css files
outputPath: './my-project/fonts/', //<-- path to place font files
context: 'css/vendors/'
}
}
]
}

Related

webpack Failed to load resource using outputPath in assets/resource

I'm not very familiar with webpack.
My goal was to put all the assets inside my HTML in a specific folder.
For that, I set a new option under the rule that deals with the `type: assets/resource:
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option setted
}
}
It does actually work. webpack creates the folder after compiling and brings those files inside it. The problem is that the HTML file compiled doesn't understand that the assets files are inside assets/ folder.
How can I fix it?
Here is my webpack.config.js
const path = require('path')
const { merge } = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
const stylesHandler = MiniCssExtractPlugin.loader
const base = {
entry: {
bundle: [
'./js/main.js',
'./css/style.scss'
]
},
output: {
path: path.resolve(__dirname, 'docs')
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
scriptLoading: 'module',
inject: 'body'
}),
new MiniCssExtractPlugin()
],
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [stylesHandler, 'css-loader', 'postcss-loader', 'sass-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option setted
}
},
{
test: /\.html$/i,
use: ['html-loader']
}
]
}
}
const dev = {
devServer: {
open: false,
host: 'localhost',
watchFiles: ['./index.html']
}
}
const prod = {
output: {
clean: true
}
}
module.exports = (env, args) => {
switch (args.mode) {
case 'development':
return merge(base, dev)
case 'production':
return merge(base, prod)
default:
throw new Error('No matching configuration was found!')
}
}
So I discover it by myself, and it was kinda obvious.
Well, when webpack compiles your index.html file, it won't understand if you just give a new path for your assets final destiny.
For example, like I did:
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option set
}
}
In order this to work you need to specify the publicPath:
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option set
publicPath: 'assets/'
}
}
You're telling webpack:
Put all the assets inside outputPath.
Hey HTML, when you look for the assets, please include the publicPath before looking for it.

Webpack-4 CSS-Loader error unknown word at module.export

I'm new at webpack and have been trying to implement it for a legacy site. No matter how many solutions I try I always get 'Unknown word' error on build using sass/raw/css/loaders. The error seems to happen at 'module.export' which is, I guess, added as a result of importing a style sheet in .js file. Here is my webpack.config.js:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: { presets: ["env"] }
}
},
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
use: [
'css-loader',
'raw-loader',
'sass-loader'
],
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [ 'file-loader' ]
}
]
}
In index.js:
`import '../css/global.scss';`
The global.scss file consists of a list of #import statements.
Here is the error I get:
ERROR in ./css/analytics/global.scss
Module build failed: Unknown word (1:1)
> 1 | module.exports = ".custom {\n (...)
It seems that no matter what is on the global.scss file, the appended 'module.exports' appears to break the build.
I have tried many suggestions on the internet but none have worked.
Thanks in advance!
I figured out what I was doing wrong. The raw-loader wasn't the right loader for this situation, though it 'looked' like it had solved the issue of getting urls resolved. I replaced it with resolve-url-loader, plus a few more tweaks. Here is the result:
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: { presets: ["env"] }
}
},
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'resolve-url-loader',
'sass-loader?sourceMap'
],
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[path][name].[hash].[ext]",
},
},
},
{
test: /\.svg$/,
use: "file-loader",
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: PATH_CONFIGS.global_path + '/fonts'
}
}]
}
]
So I am guessing the 'unknown word' error is a somewhat generic response that can point to many possible issues. Hope this helps someone who is in a similar situation.

Adding autoprefixer to webpack 2.2.1

I'm trying to add autoprefixer to webpack 2.2.1 and having issues seeing the prefixes.
I installed postcss-loader https://github.com/postcss/postcss-loader as this seems to be the listed way to handle postcss in webpack.
I'm currently using scss files which I'm importing into my react files.
example: import styles from '../../styles/header.scss';
This is handled in webpack using sass-loader.
I'm not getting any error with my setup but I'm also not seeing any autopre-fixing going on to my files ? I presume this only needs to be added in development not production ?
Here is my dev setup webpack config.
const path = require('path')
const webpack = require('webpack')
const ROOT_DIR = path.resolve(__dirname, '../app')
module.exports = {
devtool: 'eval',
entry: [
`${ROOT_DIR}/js/index`,
'webpack-hot-middleware/client'
],
output: {
path: path.resolve(__dirname, '../public'),
filename: 'bundle.js',
publicPath: '/public/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
"config.ASSET_URL": JSON.stringify(process.env.ASSETS_URL),
"config.GA_TRACKING_ID": JSON.stringify(process.env.GA_TRACKING_ID)
})
],
module: {
loaders: [
{ test: /\.js?$/,
loader: 'babel-loader',
include: path.join(__dirname, '../app'),
exclude: /node_modules/
},
{ test: /\.scss?$/,
include: path.join(__dirname, '../app', 'styles'),
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: { plugins: [
require('autoprefixer')
] }
},
{
loader: 'sass-loader',
options: {
data: "$assetPath: '" + process.env.ASSETS_URL + "';"
}
}
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
include : path.join(__dirname, '../app', 'images'),
loader : 'file-loader?limit=30000&name=[name].[ext]'
},
{
test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
include : path.join(__dirname, '../app', 'fonts'),
loader: 'file-loader?name=fonts/[name].[ext]'
}
]
}
}
I had a to deal with sometime similar recently. Check if it works if you create a separate postcss.config.js file in the directory of your scss files with this in it
//postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
and in your webpack config
{ test: /\.scss?$/,
include: path.join(__dirname, '../app', 'styles'),
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "postcss-loader"},
{loader: "sass-loader",
options: {
data: "$assetPath: '" + process.env.ASSETS_URL + "';"
}
}
]
},

Webpack error 'Error: Final loader didn't return a Buffer or String' when trying to compile React server side components using ReactJS.NET and MVC 5

I am getting the following error - 'Module build failed: Error: Final loader didn't return a Buffer or String' when trying to compile JSX components for server-side rendering using Webpack 2 and ReactJS.NET. I have followed the examples as described here as well as in this example.
My folder structure is similar to the Github example, I have one React component, an index.js file and a server.js file. Here are the contents:
/Content/components/TestComponent.jsx
var React = require('react');
class Test extends React.Component {
getInitialState() {
return { data: this.props.greeting };
}
render() {
return (
<div>
<h1>{this.props.greeting}</h1>
</div>);
}
}
module.exports = Test;
/Content/components/index.js
module.exports = {
Test: require('./TestComponent.jsx')
}
/Content/server.js
var Components = require('expose?Components!./components');
And here is my full webpack.config.js:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './Content/server',
output: {
path: __dirname + '/resources/dev/scripts/server',
filename: 'test.js'
},
module: {
rules: [
{
test: /\.js$|.jsx$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['env', 'react'],
}
}
{
test: require.resolve('react'),
loader: 'expose?React'
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
externals: {
react: 'React'
}
}
I have created an example project here with the same problem.
The solution was to do away with the /Content/server.js file, and instead use the expose-loader in webpack. Here is the updated webpack.config.js:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './Content/components/index',
output: {
path: __dirname + '/resources/dev/scripts/server',
filename: 'test.js'
},
module: {
rules: [
{
test: /\.js$|.jsx$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['env', 'react'],
}
},
{
test: require.resolve('./Content/components/index'),
use: [{
loader: 'expose-loader',
options: 'Components'
}]
},
{
test: require.resolve('react'),
use: [{
loader: 'expose-loader',
options: 'React'
}]
}
]
},
resolve: {
extensions: ['.js', '.jsx']
}
}

webpack: Inline css for a splash screen (above the fold css)

Im trying to figure out why a css segment will not run through 'style-ext-html-webpack-plugin'.
Currently I have a .CSS file with rules for the splash screen.
It's being extracted using 'extract-text-webpack-plugin' and injected to the template's <head> with 'extract-text-webpack-plugin'.
problem is, the file never gets run through 'style-ext-html-webpack-plugin' and I can't wrap my head around how to debug it.
(Ideally, I'd like to have a .SCSS file so it can be themeable through a .env file. i.e: have splash.scss exclusively extracted and inlined in the <head> after being injected with some theme colors)
webpack.config.js:
....
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //used for above-the-fold css (such as splash-screen)
const StyleExtHtmlPlugin = require('style-ext-html-webpack-plugin');
const extractSplashCSS = new ExtractTextPlugin('splash.css');
module.exports = {
entry: {...},
output: {...},
resolve: {...},
plugins: [
...,
new HtmlWebpackPlugin({
title: enviroments.TITLE,
splashScreenTitle: enviroments.SPLASH_SCREEN_TITLE,
template: 'src/index.html',
cache: true,
favicon: enviroments.FAVICON || './src/assets/images/favicon.ico',
inject: 'body'
}),
extractSplashCSS,
new StyleExtHtmlPlugin('splash.css')
],
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{
test: /\.css$/,
loader: 'style-loader!css-loader!resolve-url-loader?import=false',
exclude: [path.join(path.resolve('./src'), 'common/app/splash.css')]
},
{
test: /\.css$/,
loader: extractSplashCSS.extract({
use: 'css-loader'
}),
include: [path.join(path.resolve('./src'), 'common/app/splash.css')]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader?importLoaders=1',
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')];
}
}
},
'resolve-url-loader?sourceMap',
{
loader: 'sass-loader?sourceMap',
options: {
includePaths: path.resolve('./src'),
data: `
$color-primary: ${theme.PRIMARY};
....
`
}
}
]
},
....
]
}
};
index.js:
...
// above the fold css
import 'common/app/splash.css';
Needed to update html-webpack-plugin to 2.29.0.
I've managed to solve this issue, using a sass file that can be themeable with variables from .env file:
I had to explicitly exclude the splash file from the normal sass flow and create another loader definition explicitly for it:
...
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //used for above-the-fold css (such as splash-screen)
const StyleExtHtmlWebpackPlugin = require('style-ext-html-webpack-plugin');
module.exports = {
...
plugins: [
...
new HtmlWebpackPlugin({
...
}),
new ExtractTextPlugin('splash.css'),
new StyleExtHtmlWebpackPlugin('splash.css'),
],
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.css$/, loader: 'style-loader!css-loader!resolve-url-loader?import=false' },
{
test: /\.scss$/,
exclude: [path.join(path.resolve('./src'), 'common/app/splash.scss')],
use: [
.....
]
},
{
test: /\.scss$/,
include: [path.join(path.resolve('./src'), 'common/app/splash.scss')],
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {minimize: true}
},
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')];
}
}
},
{
loader: 'sass-loader',
options: { data: `$color-primary: ${theme.PRIMARY};` }
}
]
})
},
]
}
};

Resources