I'm using webpack to compile my sass files.
I have a font-face that looks like this:
#font-face
font-family: "Alef"
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.eot")
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.eot?#iefix") format("embedded-opentype"), url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.woff") format("woff"), url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.ttf") format("truetype"), url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.svg#alefbold") format("svg")
font-weight: bold
font-style: normal
and this is how the loaders in my webpack config file looks like
{
test: /\.html$/,
loader: 'html'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?[a-z0-9=&.]+)?$/,
loader: 'file?name=assets/[name].[hash].[ext]'
},
{
test: /\.sass$/,
exclude: /node_modules/,
loader: 'raw-loader!sass-loader'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw'
}
but, i'm getting 404 on the ttf and woff, so this font appears only in chrome (doesn't appear in firefox and edge)
thanks!
Solved! I separated the srcs, like that:
#font-face
font-family: "Alef"
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.eot")
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.eot?#iefix") format("embedded-opentype")
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.woff") format("woff")
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.ttf") format("truetype")
src: url("..\..\public\fonts\Alef\Alef-Webfont\Alef-Bold.svg#alefbold") format("svg")
font-weight: bold
font-style: normal
Related
I need to import into my project some CSS files with Webpack 5 and I need to inline all these resources (it's a requirement sadly). Inside the CSS there are some fonts and images with relative URI, like this:
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Regular.ttf) format("truetype"); font-weight: normal;}
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Bold.ttf) format("truetype"); font-weight: bold;}
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Italic.ttf) format("truetype"); font-weight: normal; font-style: italic;}
#font-face { font-family: "MyFont"; src: url(./fonts/Roboto-BoldItalic.ttf) format("truetype"); font-weight: bold; font-style: italic;}
#font-face { font-family: 'Material Icons'; font-style: normal; font-weight: 400; src: url(./fonts/material-icons.woff2) format('woff2'); }
#font-face { font-family: 'Material Icons Outlined'; font-style: normal; font-weight: 400; src: url(./fonts/material-icons-outlined.woff2) format('woff2'); }
* { font-family: "MyFont", "Roboto-Light", "Noto Sans CJK SC", "DejaVu Sans"; }
.UICheckbox { width:80px; height:89px; background-image:url("img/checkboxOFF.png"); background-repeat:no-repeat; }
.UICheckbox.checked { background-image:url("img/checkboxON.png"); }
Since I need to import as base64 the CSS files I cannot actually process automatically the resources found inside of them (contrary to how it is done with PostCSS or similiars).
My current webpack configuration is the following but it just ignores the url() statements:
{
test: /\.(png|jpg|gif)$/i,
type: "asset/inline",
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: "asset/inline",
},
{
test: /\.css$/i,
type: "asset/inline",
},
Is there a better way to handle this?
I found a solution that is not really generic or solid but does the job, at least in my case scenario.
The imports are relatives to a fixed source path so the idea is to read the resources found inside the url() rules and process it as DataURI in base64 encoding.
I found quite useful the use of datauri which provides a way to include data in-line as if they were external resources and manages the mimetypes automatically.
npm install datauri --save
Then I had to modify the generator handler inside webpack.config.js to process the resources manually exploiting the datauri package.
const path = require("path");
const Datauri = require("datauri/sync");
const EXTERNAL_ROOT_PATH = "./src/external/dev/";
module.exports = {
...
module: {
rules: [
{
test: /\.css$/i,
type: "asset/inline",
generator: {
dataUrl: (content) => {
content = content.toString();
// Get the resource paths inside the CSS url() rules
let asset_urls = [];
let match,
regex = /url\((.*?)\)/gi;
while ((match = regex.exec(content))) {
asset_urls.push(match[1]);
}
// console.log(asset_urls);
// Convert the resource to a DataURI and replace it inside url()
asset_urls.forEach((file_path) => {
// Sanitize the file path first
sanitized_file_path = file_path.replace(/[\"\']/g, "").replace(/^(?:\.\.\/)+/, "");
const data_uri = Datauri(path.join(EXTERNAL_ROOT_PATH, sanitized_file_path));
// console.log(data_uri.content); //=> "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
// console.log(data_uri.mimetype); //=> "image/png"
// console.log(data_uri.base64); //=> "iVBORw0KGgoAAAANSUhEUgAA..."
// console.log(data_uri.buffer); //=> file buffer
content = content.replace(file_path, data_uri.content);
});
return "data:text/css;base64," + Buffer.from(content).toString("base64");
},
},
},
],
},
};
I'm using css modules with sass. So i try to load them like this:
#font-face {
font-family: 'Book Antiqua';
src: url(#/assets/fonts/book_antiqua.ttf) format('truetype');
font-weight: 400;
font-style: normal;
}
#font-face {
font-family: 'Montserrat';
src: url(#/assets/fonts/Montserrat/Montserrat-Regular.ttf) format('truetype');
font-weight: 400;
font-style: normal;
}
The most interesting path is that they actually loaded by the browser.
So inline css looks like this:
#font-face {
font-family: 'Book Antiqua';
src: url("http://localhost:8080/static/media/book_antiqua.d8ae129c.ttf") format("truetype");
font-weight: 400;
font-style: normal; }
#font-face {
font-family: 'Montserrat';
src: url("http://localhost:8080/static/media/Montserrat-Regular.2bb14503.ttf") format("truetype");
font-weight: 400;
font-style: normal; }
But they do not work( So i understand nothing. Browser loaded fonts, font-face syntax looks OK, but they do not trigger.
My webpack config's loaders:
rules: [
{
exclude: [
/\.html$/,
/\.(js|jsx|ts|tsx)$/,
/\.css$/,
/\.json$/,
/\.bmp$/,
/\.gif$/,
/\.jpe?g$/,
/\.png$/,
/\.scss$/,
],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000',
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]',
},
},
'postcss-loader',
],
}),
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
},
},
'sass-loader',
],
}),
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
loader: 'ts-loader',
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]',
},
},
},
}]
I never import fonts from my assets, I always use services like google fonts to get mine, they have montserrat there and I import it like this
#import url('https://fonts.googleapis.com/css?family=Montserrat');
But that's just a band-aid, another place were a problem could be found is where do you use that font, how do you add that font to a certain class is important, for example for montserrat you should do it like this
font-family: 'Montserrat', sans-serif;
I'm trying to use custom fonts in a Project website with angular4.
This is my Project structure
This is my webpack.config.js
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, include: /ClientApp/, use: ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' },
// Font Definitions
{ test: /\.svg$/, loader: 'url?limit=65000&mimetype=image/svg+xml&name=font/[name].[ext]' },
{ test: /\.woff$/, loader: 'url?limit=65000&mimetype=application/font-woff&name=font/[name].[ext]' },
{ test: /\.woff2$/, loader: 'url?limit=65000&mimetype=application/font-woff2&name=font/[name].[ext]' },
{ test: /\.[ot]tf$/, loader: 'url?limit=65000&mimetype=application/octet-stream&name=font/[name].[ext]' },
{ test: /\.eot$/, loader: 'url?limit=65000&mimetype=application/vnd.ms-fontobject&name=font/[name].[ext]' }
]
},
plugins: [new CheckerPlugin()]
};
This is my css with #font-face
#font-face {
font-family: "FuturaMaxiLight";
src: url('/fonts/FuturaMaxi/Futura-Maxi-Light.eot') format('embedded-opentype'), /*for IE */
url('/fonts/FuturaMaxi/Futura-Maxi-Light.ttf') format('truetype'), /* for CSS3 browsers */
url('/fonts/FuturaMaxi/Futura-Maxi-Light.woff') format('woff');
font-weight: normal;
font-style: normal;
}
#font-face {
font-family: "FuturaMaxiDemi";
src: url('/fonts/FuturaMaxi/Futura-Maxi-Demi.eot') format('embedded-opentype'), /*for IE */
url('/fonts/FuturaMaxi/Futura-Maxi-Demi.ttf') format('truetype'), /* for CSS3 browsers */
url('/fonts/FuturaMaxi/Futura-Maxi-Demi.woff') format('woff');
font-weight: normal;
font-style: normal;
}
#font-face {
font-family: "FuturaMaxiBold";
src: url('/fonts/FuturaMaxi/Futura-Maxi-Bold.eot') format('embedded-opentype'), /*for IE */
url('/fonts/FuturaMaxi/Futura-Maxi-Bold.ttf') format('truetype'), /* for CSS3 browsers */
url('/fonts/FuturaMaxi/Futura-Maxi-Bold.woff') format('woff');
font-weight: normal;
font-style: normal;
}
This is the error when I try like that
If I change the css and try to include a dot before the import.
1 dot gives errors.
2 dots breaks the app.
#font-face {
font-family: "FuturaMaxiBold";
src: url('./fonts/FuturaMaxi/Futura-Maxi-Bold.eot') format('embedded-opentype'), /*for IE */
url('./fonts/FuturaMaxi/Futura-Maxi-Bold.ttf') format('truetype'), /* for CSS3 browsers */
url('./fonts/FuturaMaxi/Futura-Maxi-Bold.woff') format('woff');
font-weight: normal;
font-style: normal;
}
Your loaders are specifying name=font/[name].[ext] and your css is looking at /fonts/FuturaMaxi/[name].[ext].
Try changing the loaders to use name=[path][name].[ext] or name=fonts/FuturaMaxi/[name].[ext]
You need resolve-url-loader to resolve the correct path in your build.
See https://github.com/bholloway/resolve-url-loader
Install resolve-url-loader
npm install --save-dev resolve-url-loader
Modify your Webpack CSS rule:
{
test: /\.css$/,
use: [
'to-string-loader',
isDevBuild ? 'css-loader' : 'css-loader?minimize',
'resolve-url-loader' // Add this
]
}
Use relative paths in your CSS files
#font-face {
font-family: "FuturaMaxiLight";
src: url('../fonts/FuturaMaxi/Futura-Maxi-Light.eot') format('embedded-opentype'), /*for IE */
url('../fonts/FuturaMaxi/Futura-Maxi-Light.ttf') format('truetype'), /* for CSS3 browsers */
url('../fonts/FuturaMaxi/Futura-Maxi-Light.woff') format('woff');
font-weight: normal;
font-style: normal;
}
I am working on a react application and trying to implement CSS + Fonts.
In my react component CSS file I have regular CSS and at the very top I import my mixins
#import '../../mixins.css';
/*CSS*/
Inside my mixin file I have
mixin.css
#font-face {
font-family: 'SourceSansPro-Black';
src: url("./SourceSansPro-Black.ttf") format('truetype');
font-weight: normal;
font-style: normal;
}
Webpack throws an error
Error: Cannot resolve 'file' or 'directory' ./SourceSansPro-Black.ttf
This is my webpack config module loadres
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
include: [
path.resolve(__dirname, 'src/app')
]
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, 'src/app/styles'),
path.resolve(__dirname, 'src/app/components')
],
loader: combineLoaders([
{
loader: 'style'
},
{
loader: 'css',
query: {
modules: true,
sourceMap: true,
localIdentName: '[folder]__[local]--[hash:base64:10]'
}
},
{
loader: 'postcss'
}
])
},
// Font Definitions
{
test: /\.ttf$/,
include: [
path.resolve(__dirname, 'src/app/assets/fonts')
],
loader: 'url',
query: {
limit: 50000,
mimetype: 'application/octet-stream',
name: './fonts/[name].[ext]'
}
}
]
},
and the postcss
postcss: (_webpack) => {
return [
require('postcss-import')({
addDependencyTo: _webpack,
path: [ 'styles', 'components'],
root: path.resolve(__dirname, 'src/app'),
skipDuplicates: true
}),
require('postcss-cssnext')()
];
},
I dont' understand why the url isn't resolving correctly.
UPDATE
I have a font.css file that looks like this
#font-face {
font-family: 'SourceSansPro-Bold';
src: url('./SourceSansPro-Bold.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
#font-face {
font-family: 'SourceSansPro-Regular';
src: url('./SourceSansPro-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
#font-face {
font-family: 'SourceSansPro-Light';
src: url('./SourceSansPro-Light.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
I then import the font.css into a mixins.css file
#import '../fonts/fonts.css';
:root {
--regular: {
font-family: 'SourceSansPro-Regular';
font-style: normal;
font-weight: normal;
}
}
Then in my react component I have this:
#import 'styles/mixins.css';
.regular {
#apply --regular;
}
There is no error (or warning) that states any issues with loading the fonts via the url().
webpack.config
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
include: [
path.resolve(__dirname, 'src/app')
]
},
{
test: /\.css$/,
include: [
path.resolve(__dirname, 'src/app/assets/fonts'),
path.resolve(__dirname, 'src/app/assets/styles'),
path.resolve(__dirname, 'src/app/components')
],
loader: combineLoaders([
{
loader: 'style',
},
{
loader: 'css',
query: {
modules: true,
sourceMap: true,
localIdentName: '[folder]__[local]--[hash:base64:10]'
}
},
{
loader: 'resolve-url',
query: {
sourceMap: true,
silent: false,
fail: true,
keepQuery: true
}
},
{
loader: 'postcss',
query: {
sourceMap: true
}
}
])
},
// Font Definitions
{
test: /\.ttf$/,
include: [
path.resolve(__dirname, 'src/app/assets/fonts')
],
loader: 'url',
query: {
limit: 100000,
mimetype: 'application/octet-stream',
name: './fonts/[name].[ext]'
}
}
]
}
An interesting thing is that if I use the ExtractTextWebpackPlugin on the CSS the above works, the fonts get rendered. If I do it this way the tradeOff is there is no CSS hot reloading.
Any suggestions on how to get the fonts to load without the extract-text plugin?
I am using Grunt to watch and compile my CSS from numerous partial SCSS files. So when I update any of my SCSS files the watch generates an updated main.css file. this is okay but I have noticed that all classes seem to be wrapped with the following code, for example
#media -sass-debug-info{filename{font-family:file\:\/\/\/Users\/username\/Projects\/my-gitclone\/projectname\/src\/htdocs\/an\/app\/styles\/utilities\/_display\.scss}line{font-family:\0000354}}
.u-body-noscroll {
overflow: hidden;
}
I don't understand why the watch is inserting this #media -sass-debug-info{filename{}line{font-family:\0000XXX}}, I assumed it may be due to an error in my _fonts.scss file but this is fine and the url values are relative:
#font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
src: url('fonts/Merriweather.woff2') format('woff2'),
url('fonts/Merriweather.woff') format('woff'),
url('fonts/Merriweather.ttf') format('truetype');
}
#font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
src: url('fonts/MerriweatherBold.woff2') format('woff2'),
url('fonts/MerriweatherBold.woff') format('woff'),
url('fonts/MerriweatherBold.ttf') format('truetype');
}
I also thought my _icon-font.scss may be the source of the problem but this is correct? Could the IDE or Grunt be adding this #media -sass-debug-info?
I am using Grunt for my watch/task-runner and IntelliJ as my IDE, has anyone came across this issue?
I think I found an answer... in my Grunt file I added debugInfo: false to the compass.dist and compass.server tasks.
// Compiles Sass to CSS and generates necessary files if requested
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '<%= yeoman.app %>/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: './bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false,
assetCacheBuster: false,
raw: 'Sass::Script::Number.precision = 10\n'
},
dist: {
options: {
generatedImagesDir: '<%= yeoman.dist %>/images/generated',
debugInfo: false
}
},
server: {
options: {
debugInfo: false
}
}
},