Webpack can not load font file: Unexpected Token - css

I have a style.css file that makes use of a font file, and I'm having trouble getting the font file loaded using Webpack. Here is my loader configuration:
loaders : [
{
test : /\.(js|jsx)$/,
exclude : /node_modules/,
loader : 'react-hot!babel-loader'
}, {
test : /\.styl/,
loader : 'style-loader!css-loader!stylus-loader'
}, {
test : /\.css$/,
loader : 'style-loader!css-loader'
}, {
test : /\.(png|jpg)$/,
loader : 'url-loader?limit=8192'
}, {
test : /\.(ttf|eot|svg|woff(2))(\?[a-z0-9]+)?$/,
loader : 'file-loader'
}
/*}, {
test : /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader : 'url-loader?limit=10000&minetype=application/font-woff'*/
]
The errors that I receive is
ERROR in ./src/fonts/icon/fonts/mf-font.woff?lt4gtt
Module parse failed: /PATH/src/fonts/icon/fonts/mf-font.woff?lt4gtt Line 1: Unexpected token ILLEGAL
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
# ./~/css-loader!./src/fonts/icon/style.css 2:293-331
It looks to me that Webpack is taking it as a CSS file when it's not. But I'm pretty sure the test expression passes for the font file

The regex in your test expression has a small mistake. woff(2) means that it always looks for woff2 and just captures the 2 in a separate group. If you add a ? after it, webpack should be able to recognize woff as well:
test : /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader : 'file-loader'
Please let me know if this worked.

This did the trick for me:
{ 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" },

Related

How can I import CSS Modules in a TypeScript file?

I've made some edits which are listed below.
I am working with a combination of React (18.2.0), Typescript (4.8.4), and Webpack (5.75.0). I am attempting to add some styling to my application, and am trying to use CSS modules. I have tried a few Webpack configurations, and none of them are causing Webpack to use the correct loader. I have tried a few other variants of loaders (as seen in the commented out sections), and none of them are working.
I am using an approach similar to this answer to import the stylesheets (declaring a src/Globals.d.ts, setting the typescript-plugin-css-modules compiler plugin for tsc, and importing as import * as styles from './styles.module.css')
Stylesheet import
import * as styles from './ResultCount.module.css'
export const ResultCount = () => {
const orders = useSelector((state: ReducedState) => state.all.orders)
console.log('result count style name', styles.results) // always undefined
return <p className={styles.results}>
src/Globals.d.ts
declare module '*.module.css'
This is the error that I get, regardless of the loader configuration that I use
cached modules 1.59 MiB (javascript) 27.4 KiB (runtime) [cached] 131 modules
./src/components/Order/styles.module.css 96 bytes [built] [1 error]
ERROR in ./src/components/Order/styles.module.css 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .order {
...
Would someone be able to tell me what I am doing wrong in my webpack.config.ts file?
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
transpileOnly: true
},
exclude: /dist/
},
{
test: /\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: true,
importLoaders: 1,
localIdentName: "[name]_[local]_[hash:base64]",
sourceMap: true,
minimize: true
}
}
]
},
// {
// test: /\.css$/,
// include: path.join(__dirname, 'src/components'),
// loader: 'css-loader',
// //use: ['style-loader', 'css-loader']
// // use: [
// // 'style-loader',
// // {
// // loader: 'typings-for-css-modules-loader',
// // options: {
// // modules: true,
// // namedExport: true
// // },
// // },
// // 'css-loader',
// // ],
// },
]
},
Edit
I've found out that webpack serve must be restarted for these sorts of changes to take affect (even with reloading turned on). The new issue is: although Webpack successfully builds, but any import of the classes in the .ts files returns an undefined. So none of the styles are applied. I've update the title to reflect the new issue.
What's strange is that my language server (tsserver) can auto complete the classes defined in the .css file from import * as styles from './styles.module.css', but if I console.log() it before I return my TSX, I always see an undefined value. I've confirmed that the mangled CSS modules names are in the final rendered page by finding the inline styles in the browser inspector. I've also tried declaring a styles.module.css.d.ts file (even though I shouldn't need to due to the Typescript plugin) just in case, but that still did not fix the issue. I've also tried (from this answer) to rename from styles.module.css to <component name here>.module.css but that also did not work.
Does anyone know what could be causing this?
import * as styles from "module-path"; is semantically different to import styles from "module-path";. Basically don't assume these non-javascript made-up modules follow any advanced module rules and always default import them.

webpack: understanding source maps when working with CSS

Introduction
I have already setup bundling for my Javascript files with webpack in my project. Now I am in the process of adding CSS files to the webpack configuration. So far, I have been including the CSS files manually in the HTML header by adding <link> elements for every CSS file I depend on (e.g. bootstrap, my own css, etc.). Obviously this is not very elegant and using webpack would be much better, so I would like to replace the link elements and bundle them via webpack.
This should be easy, everything is pretty much documented in the webpack documentation. After reading the documentation and experimenting a bit with webpack I have arrived at the configuration below which already works.
Problem
The problem with my current setup is that I would like to have proper source map support and that does not seem to work. By proper, I mean that I expect that when I run a development build with webpack and I inspect some element in Chrome DevTools, that I will see from which file and which line in the file a certain CSS class originated and that I can click on the CSS rules and the browser jumps to that file.
I do not want to have inline styles in the head element, because then the browser will show something like .foobar { <style>..</style>, rather then .foobar { app.css:154.
With my current setup I have all CSS files combined (but not minified) into one app.css file. This means that if I inspect a bootstrap class such as .btn then it appears as .btn { app.css:3003. However, what I want to achieve is that the browser shows it as .btn { bootstrap.css:3003.
So now I am trying to understand how webpack and the different plugins such as css-loader and min-css-extract-plugin apply CSS source maps, and how I can configure them to achieve a proper debugging experience.
I am not sure how relevant this is, but when I navigate in DevTools under Sources to webpack://./bootstrap/dist/css/bootstrap.css I see that it only contains a single line:
// extracted by mini-css-extract-plugin.
Webpack Setup
index.js:
window.jQuery = require('jquery/dist/jquery');
require('bootstrap/dist/css/bootstrap.css');
require('bootstrap/dist/js/bootstrap');
/* other dependencies */
webpack.config.js:
const devMode = process.env.NODE_ENV !== 'production';
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{ /* Javascript rules excluded */ },
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
plugins: [
new UglifyJSPlugin (),
new HtmlWebpackPlugin({
template: 'app/index.tpl.html'
}),
new MiniCssExtractPlugin({ filename: devMode ?
'[name].css' :
'[name].[hash].css'
})
],
Conclusion
It seems I just passed the rubber duck test. While I was writing this I arrived at a solution. I will still publish the question, maybe it can help others.
The problem was that I was also using the mini-css-extract-plugin for development and not just for production. I thought that I needed to do that, because when at first I was using the style-loaded I would get styles included in the header and the browser would show me all styles as .foobar { <style>..</style>.
However, the actual problem seemed to be, that I was not using devtools. So the solution was to add devtool: devMode ? 'cheap-module-eval-source-map' : 'source-map', to the webpack configuration to conditionally use the style-loader plugin during development builds and mini-css-extract-plugin during production builds.
webpack.config.js
{
test: /\.css$/,
use: [
{
- loader: MiniCssExtractPlugin.loader,
+ loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
/* ... */
+ devtool: devMode ? 'cheap-module-eval-source-map' : 'source-map',

How do you configure Create React App to use CSS Blocks?

CSS blocks just went open source and I wanted to incorporate it into my React app while still using the boilerplate CRA webpack because I want to keep all the other functionality.
From what I understand the majority of the configuration is simply adding another babel-loader with the css-block plugin.
So instead of just:
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
You follow it with:
{
test: /\.[j|t]s(x?)$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve("babel-preset-react-app")],
cacheDirectory: true,
compact: true,
}
},
// Run the css-blocks plugin in its own dedicated loader because the react-app preset
// steps on our transforms' feet. This way, we are guaranteed a clean pass before any
// other transforms are done.
{
loader: require.resolve('babel-loader'),
options: {
plugins: [
require("#css-blocks/jsx/dist/src/transformer/babel").makePlugin({ rewriter: CssBlockRewriter }),
],
cacheDirectory: true,
compact: true,
parserOpts: {
plugins: [
"jsx",
"doExpressions",
"objectRestSpread",
"decorators",
"classProperties",
]
}
}
},
But, I cannot for the life of me get the second bit to parse anything. It's like it doesn't even exist and my CSS modules are just being referenced inside the class. Result ends up being like:
<div class="/src/test.css">
instead of
<div class="a b cD">
If anyone has any pointers of where I should try to look I would greatly appreciate it!
P.S. For reference I'll include links to the docs below since it's very new
http://css-blocks.com/
https://github.com/linkedin/css-blocks/blob/master/packages/%40css-blocks/website/config/webpack.config.dev.js
I get the example from Linkedin example /website and works fine with react-create-app scripts.
Fallow boilerplate extracted from CSS Blocks by me ralfting/boilerplate-css-blocks... Maybe this help you.

CSS Background image not loading with webpack

I've read through almost all of the posts here about CSS background images not loading, and I'm convinced I have (yet another) special case.
I've set up my webpack configuration like so (just the relevant parts):
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'file-loader',
}
]
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
}
]
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
}
]
},
{
test: /\.less$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader"
},
{
loader: "less-loader",
options: {
includePaths: [
path.resolve(__dirname, "assets", "less")
]
},
}
],
exclude: /node_modules/
}
I have my public path set as follows:
output: {
path: path.resolve(__dirname, "public"),
filename: "bundle.js",
publicPath: "public/"
},
When I build the webpack file everything gets moved to my /public directory just fine and my styles are rewritten properly. I can even manually find the image that is not loading in the public directory. However, this style is goofed up:
.section-intro {
background: url(public/76d7fa525cc5b3d641b9f774b7a79c92.png) center center no-repeat;
background-size: cover;
}
I thought maybe it wasn't getting set correctly, however hovering over the style in chrome seems to imply it is working - it shows localhost:8080/public/76d7fa525cc5b3d641b9f774b7a79c92.png.
Other things, such as fonts seem to load correctly. However, I did notice that manually going to localhost:8080/public/76d7fa525cc5b3d641b9f774b7a79c92.png gives me a 404. Which I find weird.
In my express server I have the following line:
this.app.use(express.static(path.resolve(__dirname, "..", "public")));
which should allow me to see the images, right?
I'm not sure if this is on the express side, or the webpack side, but it is causing me to pull my hair out. I hope someone can help.
Thank you!
I don't want to call this a fix, so I won't mark my own answer correct until someone else can confirm.
However, changing file-loader to url-loader for the png matcher fixed. It, I don't think this fully fixes the problem though. The only difference is url-loader can pass a data URL if the file is small enough. Chances are my images are small enough to make this a "fix", but if I put a larger image in I'm sure it'll break again.
I'd love to see a more complete solution.

How to have multiple output files in gruntfile.js when running requirejs

In Gruntfile.js for grunt-contrib-requirejs I can only register one task and I can only have one output file i.e. home_scripts.pack.js. However, I want to have as many as I want output files based on different 'include' criteria. For example, home_scripts.pack.js, checkout_scripts.pack.js, product_scripts.pack.js etc. This way each page will only load JS that is using:
This is invalid, however I want to do something similar:
requirejs: {
compile1: {
options: {
baseUrl: 'C:/project/js',
mainConfigFile: 'C:/project/js/app.js',
name: 'app',
paths: {
requireLib: 'C:/project/js/require.min'
},
*include: ['requireLib', 'home_page_internal.js'],*
*out: 'C:/project/js/home_scripts.pack.js'*
}
}
},
compile2: {
options: {
baseUrl: 'C:/project/js',
mainConfigFile: 'C:/project/js/app.js',
name: 'app',
paths: {
requireLib: 'C:/project/js/require.min'
},
*include: ['requireLib', 'checkout_internal.js'],*
*out: 'C:/project/js/checkout_scripts.pack.js'*
}
}
}
}
The code with asterisk above is the code I want to generate output files different for each page. However, if there is a more efficient way to generate and load large number of JS plugin files and modules through requireJS optimizer using grunt, I'm open to suggestions.
Thanks,
You need to take a look at RequireJS Multipage Example
It depicts how to use concatenation on basis of need of the page.
So your options will look like.
requirejs : {
compile : {
"baseUrl": "app",
"dir": "app/built",
"include": "main.js",
"paths": {
"angular": "bower_components/angular/angular.min",
"css" : "bower_components/require-css/css.min",
"text" : "bower_components/requirejs-text/text",
"css-builder" : "bower_components/require-css/css-builder",
"normalize" : "bower_components/require-css/normalize"
},
"modules" : [
{
"name" : "app",
"include" : ["text", "css"]
},
{
"name" : "modules/module1",
"include" : [],
"exclude" : ["app"]
},
{
"name" : "modules/module2",
"include" : [],
"exclude" : ["app"]
},
{
"name" : "modules/module3",
"include" : [],
"exclude" : ["app"]
} ]
}
}
Ignore other config and check modules config. It's an array which takes multiple AMD module and each will be concatenated in its own file.
In case of SPA, if you need to exclude any common modules which you dont want to be included in subsequent modules. In this case app module incorporates all the library layer and hence it is excluded from the subsequent modules.

Resources