Related
I'm following Next's guide to optimize fonts
I added the font export:
src/style/fonts.ts
import { Montserrat } from '#next/font/google';
export const montserrat = Montserrat({
weight: ['500', '600', '700'],
display: 'swap',
preload: true,
subsets: ['latin'],
});
What I get in the network request response for the css includes this:
#font-face {
font-family: __Montserrat_4a3ba4;
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(/_next/static/media/df4ba022c23c08de.woff2) format("woff2");
unicode-range: U+0460-052f,U+1c80-1c88,U+20b4,U+2de0-2dff,U+a640-a69f,U+fe2e-fe2f
}
#font-face {
font-family: __Montserrat_4a3ba4;
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(/_next/static/media/b1464bad92c88a2d.woff2) format("woff2");
unicode-range: U+0301,U+0400-045f,U+0490-0491,U+04b0-04b1,U+2116
}
#font-face {
font-family: __Montserrat_4a3ba4;
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(/_next/static/media/8ed0c04f7e5d7b36.woff2) format("woff2");
unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01a0-01a1,U+01af-01b0,U+1ea0-1ef9,U+20ab
}
#font-face {
font-family: __Montserrat_4a3ba4;
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(/_next/static/media/c528baaebca50056.woff2) format("woff2");
unicode-range: U+0100-024f,U+0259,U+1e??,U+2020,U+20a0-20ab,U+20ad-20cf,U+2113,U+2c60-2c7f,U+a720-a7ff
}
#font-face {
font-family: __Montserrat_4a3ba4;
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(/_next/static/media/1060bab20f18b5c2.p.woff2) format("woff2");
unicode-range: U+00??,U+0131,U+0152-0153,U+02bb-02bc,U+02c6,U+02da,U+02dc,U+2000-206f,U+2074,U+20ac,U+2122,U+2191,U+2193,U+2212,U+2215,U+feff,U+fffd
}
These have unicode ranges that correspond to subsets not included in fonts.tsx. They also point to src urls non-existant (non-latin ones). Perhaps it's some issue with SASS, I'm not sure. My question is, shouldn't all but latin be removed as specified in subsets in fonts.ts?
I tried all methods described in Next's documentation yielding the same results. This might not necessarily be an issue, but since CSS files sizes affect SEO I imagined that those code blocks shouldn't be there as part of Next's optimization. Specially since they are pointing to files that don't exist.
Dependencies in case they are relevant:
"dependencies": {
"#apollo/client": "^3.5.5",
"#elastic/elasticsearch": "^8.4.0",
"#newrelic/next": "^0.3.1",
"#next/font": "^13.0.2",
"#sentry/nextjs": "^7.16.0",
"#snowplow/browser-tracker": "^3.2.1",
"#types/react-scroll": "^1.8.3",
"#types/styled-components": "^5.1.15",
"apollo-link-timeout": "^4.0.0",
"apollo-upload-client": "^16.0.0",
"date-fns": "^2.29.3",
"dayjs": "^1.11.3",
"email-validator": "^2.0.4",
"expo-jwt": "^1.4.1",
"express": "^4.18.1",
"firebase": "^9.6.1",
"graphql": "^16.0.1",
"grommet": "^2.19.1",
"i18next": "^21.5.5",
"ioredis": "^5.2.3",
"js-base64": "^3.7.2",
"lodash.flatten": "^4.4.0",
"lodash.uniqby": "^4.7.0",
"lru-cache": "^7.14.0",
"newrelic": "^9.3.0",
"next": "^13.0.0",
"polished": "^4.1.3",
"react": "^18.2.0",
"react-cookie": "^4.1.1",
"react-dom": "^18.2.0",
"react-hook-form": "^7.24.1",
"react-hot-toast": "^2.4.0",
"react-i18next": "^11.14.3",
"react-icons": "^4.3.1",
"react-intersection-observer": "^8.33.1",
"react-loading-skeleton": "^3.0.1",
"react-scroll": "^1.8.4",
"react-slick": "^0.29.0",
"react-transition-group": "^4.4.2",
"sass": "^1.43.4",
"shortid": "^2.2.16",
"styled-components": "^5.3.3",
"uuid": "^8.3.2",
"winston": "^3.8.2",
"winston-elasticsearch": "^0.17.1"
}
I'm having an issue, we needed to get rid of links to external resources in html file(as google api font and material icons). So I self hosted it, on localhost in network font is received and works fine, but on production stand there's even no requests in network to get this font.It seems that on production stand it doesn't event try to plug font or import css does not work in production.
Here's my index.css
#font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('KFOlCnqEu92Fr1MmWUlfBBc4AMP6lQ.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
body {
font-family: 'Roboto';
}
#font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url('MaterialIcons-Regular.ttf') format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}
This is App.tsx:
import * as React from 'react';
import { Provider } from 'react-redux';
import { hot } from 'react-hot-loader/root';
import CssBaseline from '#material-ui/core/CssBaseline'; // CSS Reset
import { ThemeProvider } from '#material-ui/core/styles';
import NotifierProvider from 'components/NotifierProvider';
import { MuiPickersUtilsProvider } from '#material-ui/pickers';
import DateFnsUtils from '#date-io/date-fns';
import ruLocale from 'date-fns/locale/ru';
import { Router } from 'react-router';
import { initAxios } from 'security';
import store from '../../store';
import MainRouting from '../MainRouting';
import theme from './theme';
import history from '../../historyRouting';
import GlobalCss from '../GlobalCss';
import '../../assets/font/index.css';
// инициализируем аксиос с авторизацией
initAxios();
export const App: React.FC = () => (
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={ruLocale}>
<CssBaseline />
<Router history={history}>
<ThemeProvider theme={theme}>
<GlobalCss />
<Provider store={store}>
<NotifierProvider>
<MainRouting />
</NotifierProvider>
</Provider>
</ThemeProvider>
</Router>
</MuiPickersUtilsProvider>
);
export default hot(App);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
and maybe issue is in webpack, so here's my styles config:
module.exports = function () {
return {
module: {
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
}
};
};
and coommon rules:
module.exports = function () {
return {
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: { minimize: true }
}
]
},
{
test: /\.(pdf|jpg|png|gif|ico|)$/,
exclude: /font/,
use: [
{
loader: 'url-loader?limit=20480&name=assets/img/[name]-[hash].[ext]',
options: {
esModule: false,
}
}
]
},
{
test: /\.svg$/,
use: ['#svgr/webpack', 'svg-url-loader'],
},
{
test: /\.(ttf|eot|woff|woff2)$/,
exclude: /img/,
loader: 'file-loader?name=assets/font/[name].[ext]'
}
]
}
};
};
I guess paths are correct as it work on localhost.
please, help me, I spent hours to figure what's wrong...(
Finally fixed this problem!:) But maybe for someone who has the same issue it'll be helpful, because I spent whole day to figure this out.
Apparently there's a problem with "sideEffects": false in package.json file and you have to either delete this, either write "sideEffects": ["*.css"]. More information here
The Problem
No matter what i do, there is no way to make iOS Simulator load the custom fonts.
I've tested everything I've found across different Ionic versions and all platforms and the current setup works perfectly in Google Chrome Browser, Safari Browser, Android Device and Android Emulator but not in iOS Simulator (could not test it in iOS Device since i don't have one yet).
Expected Behavior
Current Behavior
No custom font dependent component is shown except when commenting its font styling (second image).
Code
Angular-Ionic mandatory global.scss (with repeated styling just to test if its correctly loaded only from certain sources)
// http://ionicframework.com/docs/theming/
#import '~#ionic/angular/css/core.css';
#import '~#ionic/angular/css/normalize.css';
#import '~#ionic/angular/css/structure.css';
#import '~#ionic/angular/css/typography.css';
#import '~#ionic/angular/css/padding.css';
#import '~#ionic/angular/css/float-elements.css';
#import '~#ionic/angular/css/text-alignment.css';
#import '~#ionic/angular/css/text-transformation.css';
#import '~#ionic/angular/css/flex-utils.css';
#import '~animate.css/animate.min';
#font-face {
font-family: "Gotham";
src: local('GothamMedium'), local('GothamMedium'),
url('assets/GothamMedium.eot') format('embedded-opentype'),
url('assets/GothamMedium.woff2') format('woff2'),
url('assets/GothamMedium.woff') format('woff'),
url('assets/GothamMedium.ttf') format('truetype'),
url('assets/GothamMedium.svg#GothamMedium') format('svg');
font-weight: normal;
font-style: normal;
}
#font-face {
font-family: "Gotham";
src: local('GothamBold'), local('GothamBold'),
url('assets/GothamBold.eot') format('embedded-opentype'),
url('assets/GothamBold.woff2') format('woff2'),
url('assets/GothamBold.woff') format('woff'),
url('assets/GothamBold.ttf') format('truetype'),
url('assets/GothamBold.svg#GothamBold') format('svg');
font-weight: bold;
font-style: normal;
}
#mixin font($weight, $size: false, $shadow: false, $align: false) {
font-family: "Gotham" !important;
font-weight: $weight;
#if $weight==regular {
#if $shadow {
text-shadow: 1px 1px 1px #aaaa;
}
}
#if $weight==bold {
#if $shadow {
text-shadow: 1px 2px 4px #aaaa;
}
}
#if $size {
font-size: $size !important;
}
#if $align {
text-align: $align !important;
}
}
//...
/*:root[mode=ios] .gotham,
:root[mode=md] .gotham{
--ion-font-family: 'Gotham' !important;
font-family: 'Gotham' !important;
}*/
}
.subtitulo {
#include font(normal, 3.5vw, false, center);
margin: auto !important;
}
ion-card-title,
h1 {
top: -10px;
#include font(bold, 9vw, true);
color: var(--ion-color-primary);
}
Ionic mandatory theming variables.scss
// Ionic Variables and Theming. For more info, please see:
// http://ionicframework.com/docs/theming/
/** Ionic CSS Variables **/
:root {
// --ion-font-family: "GothamMedium", "Roboto";
// font-family: var(--ion-font-family) !important;
--ion-font-family: 'Gotham' !important;
font-family: 'Gotham' !important;
//... other non-related theming variables
}
Ionic-suggested fonts.scss (i was going to deprecate it if the globals.scss code block functioned correctly, or the inverse). I do use mixins to make styling faster.
#font-face {
font-family: "Gotham";
src: local('GothamMedium'), local('GothamMedium'),
url('../assets/GothamMedium.eot') format('embedded-opentype'),
url('../assets/GothamMedium.woff2') format('woff2'),
url('../assets/GothamMedium.woff') format('woff'),
url('../assets/GothamMedium.ttf') format('truetype'),
url('../assets/GothamMedium.svg#GothamMedium') format('svg');
font-weight: normal;
font-style: normal;
}
#font-face {
font-family: "Gotham";
src: local('GothamBold'), local('GothamBold'),
url('../assets/GothamBold.eot') format('embedded-opentype'),
url('../assets/GothamBold.woff2') format('woff2'),
url('../assets/GothamBold.woff') format('woff'),
url('../assets/GothamBold.ttf') format('truetype'),
url('../assets/GothamBold.svg#GothamBold') format('svg');
font-weight: bold;
font-style: normal;
}
#mixin font($weight, $size: false, $shadow: false, $align: false) {
font-family: "Gotham" !important;
font-weight: $weight;
#if $weight==regular {
#if $shadow {
text-shadow: 1px 1px 1px #aaaa;
}
}
#if $weight==bold {
#if $shadow {
text-shadow: 1px 2px 4px #aaaa;
}
}
#if $size {
font-size: $size !important;
}
#if $align {
text-align: $align !important;
}
}
Configuration
angular.json
{
"$schema": "./node_modules/#angular-devkit/core/src/workspace/workspace-schema.json",
"version": 1,
"defaultProject": "app",
"newProjectRoot": "projects",
"projects": {
"app": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "www",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
{
"glob": "**/*",
"input": "src/assets/",
"output": "assets/"
},
{
"glob": "**/*.woff2",
"input": "src/assets/",
"output": "assets/"
},
{
"glob": "**/*.svg",
"input": "node_modules/ionicons/dist/ionicons/svg",
"output": "./svg"
},
{
"glob": "**/*.svg",
"input": "node_modules/ionicons/dist/ionicons/svg",
"output": "./svg"
}
],
"styles": [
{
"input": "src/theme/fonts.scss"
},
{
"input": "src/theme/variables.scss"
},
{
"input": "src/global.scss"
},
//...
package.json
{
"name": "app",
"version": "0.1.0",
"author": "",
"homepage": "",
"scripts": {
"ng": "ng",
"start": "ng serve --host 0.0.0.0",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"android:dev": "ionic cordova run android --external --debug",
"android:prod": "ionic cordova run android -l --ssl --external --prod",
"ios:dev": "ionic cordova run ios --prod",
"ios:prod": "ionic cordova run ios -l --ssl --external --prod",
},
"private": true,
"dependencies": {
"#angular/common": "^10.1.5",
"#angular/core": "^10.1.5",
"#angular/forms": "^10.1.5",
"#angular/platform-browser": "^10.1.5",
"#angular/platform-browser-dynamic": "^10.1.5",
"#angular/router": "^10.1.5",
"#ionic-native/bluetooth-serial": "^5.28.0",
"#ionic-native/core": "5.22.0",
"#ionic-native/device": "^5.28.0",
"#ionic-native/diagnostic": "^5.28.0",
"#ionic-native/firebase-x": "^5.26.0",
"#ionic-native/in-app-browser": "^5.26.0",
"#ionic-native/native-storage": "^5.26.0",
"#ionic-native/splash-screen": "5.22.0",
"#ionic-native/status-bar": "^5.22.0",
"#ionic/angular": "^5.0.4",
"#ionic/storage": "^2.2.0",
"#keyframes/core": "^2.0.10",
"#teamhive/lottie-player": "^1.0.0",
"animate.css": "^3.7.2",
"cordova": "^10.0.0",
"cordova-android-firebase-gradle-release": "^4.0.0",
"cordova-plugin-bluetooth-serial": "^0.4.7",
"cordova-plugin-device": "^2.0.3",
"cordova-plugin-enable-multidex": "^0.2.0",
"cordova-plugin-inappbrowser": "^4.0.0",
"cordova-plugin-ionic-keyboard": "^2.2.0",
"cordova-plugin-ionic-webview": "^5.0.0",
"cordova-plugin-nativestorage": "^2.3.2",
"cordova-plugin-splashscreen": "^5.0.3",
"cordova-plugin-statusbar": "^2.4.3",
"cordova-plugin-whitelist": "^1.3.4",
"core-js": "^3.6.4",
"firebase": "^7.14.5",
"howler": "^2.1.3",
"keyframes": "^2.3.0",
"lodash": "^4.17.19",
"native-run": "^1.0.0",
"ng-payment-card": "0.0.8",
"npm-check-updates": "^4.0.4",
"rxjs": "^6.5.4",
"zone.js": "^0.10.2"
},
"devDependencies": {
"#angular-devkit/architect": "^0.900.5",
"#angular-devkit/build-angular": "^0.1001.6",
"#angular-devkit/core": "^10.1.6",
"#angular-devkit/schematics": "^10.1.6",
"#angular/cli": "^10.1.6",
"#angular/compiler": "^10.1.5",
"#angular/compiler-cli": "^10.1.5",
"#angular/language-service": "^10.1.5",
"#ionic/angular-toolkit": "^2.2.0",
"#ionic/lab": "^3.1.6",
"#types/jasmine": "^3.5.8",
"#types/jasminewd2": "^2.0.8",
"#types/lodash": "^4.14.149",
"#types/node": "^13.7.7",
"codelyzer": "^5.2.1",
"cordova-android": "^9.0.0",
"cordova-ios": "^6.1.1",
"cordova-plugin-androidx": "^2.0.0",
"cordova-plugin-androidx-adapter": "^1.1.1",
"cordova-plugin-firebasex": "10.2.0-cli",
"jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^4.4.1",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^2.1.1",
"karma-jasmine": "^3.1.1",
"karma-jasmine-html-reporter": "^1.5.2",
"protractor": "^5.4.3",
"ts-node": "^8.6.2",
"tslint": "~6.1.0",
"typescript": "^4.0.3"
},
"description": "Crucijuegos Salas App",
"cordova": {
"plugins": {
"cordova-plugin-whitelist": {},
"cordova-plugin-statusbar": {},
"cordova-plugin-device": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-ionic-webview": {
"ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+"
},
"cordova-plugin-ionic-keyboard": {},
"cordova-plugin-local-notification": {},
"cordova-plugin-background-mode": {},
"cordova-plugin-nativestorage": {},
"cordova-android-firebase-gradle-release": {
"FIREBASE-CORE": "17.0.0",
"FIREBASE-ADS": "18.0.0",
"FIREBASE-ANALYTICS": "17.0.0",
"FIREBASE-APPINDEXING": "19.0.0",
"FIREBASE-AUTH": "18.0.0",
"FIREBASE-FIRESTORE": "20.0.0",
"FIREBASE-FUNCTIONS": "18.0.0",
"FIREBASE-MESSAGING": "19.0.0",
"FIREBASE-STORAGE": "18.0.0",
"FIREBASE-CRASH": "16.2.1",
"CRASHLYTICS": "2.10.1",
"FIREBASE-DYNAMIC-LINKS": "18.0.0",
"FIREBASE-INVITES": "17.0.0",
"FIREBASE-INAPPMESSAGING": "18.0.1",
"FIREBASE-INAPPMESSAGING-DISPLAY": "18.0.1",
"FIREBASE-ML-VISION": "21.0.0",
"FIREBASE-ML-VISION-IMAGE-LABEL-MODEL": "18.0.0",
"FIREBASE-ML-VISION-FACE-MODEL": "18.0.0",
"FIREBASE-ML-VISION-OBJECT-DETECTION-MODEL": "17.0.0",
"FIREBASE-ML-NATURAL-LANGUAGE": "20.0.0",
"FIREBASE-ML-NATURAL-LANGUAGE-LANGUAGE-ID-MODEL": "20.0.0",
"FIREBASE-ML-NATURAL-LANGUAGE-TRANSLATE-MODEL": "20.0.0",
"FIREBASE-ML-NATURAL-LANGUAGE-SMART-REPLY-MODEL": "20.0.0",
"FIREBASE-ML-MODEL-INTERPRETER": "20.0.0",
"FIREBASE-ML-VISION-AUTOML": "17.0.0",
"FIREBASE-PERF": "18.0.0",
"FIREBASE-DATABASE": "18.0.0",
"FIREBASE-CONFIG": "18.0.0"
},
"cordova-plugin-enable-multidex": {},
"cordova-plugin-inappbrowser": {},
"cordova-plugin-ble-central": {
"BLUETOOTH_USAGE_DESCRIPTION": " "
},
"cordova-plugin-bluetooth-serial": {},
"cordova-plugin-firebasex": {
"FIREBASE_ANALYTICS_COLLECTION_ENABLED": "true",
"FIREBASE_PERFORMANCE_COLLECTION_ENABLED": "true",
"FIREBASE_CRASHLYTICS_COLLECTION_ENABLED": "true"
}
},
"platforms": [
"ios",
"android"
]
}
}
Env
Mac development station
74-80-245-21:cruci-app user922954$ ionic info
Ionic:
Ionic CLI : 6.11.12 (/usr/local/lib/node_modules/#ionic/cli)
Ionic Framework : #ionic/angular 5.3.3
#angular-devkit/build-angular : 0.901.12
#angular-devkit/schematics : 9.1.12
#angular/cli : 9.1.12
#ionic/angular-toolkit : 2.3.3
Cordova:
Cordova CLI : 10.0.0
Cordova Platforms : ios 6.1.1
Cordova Plugins : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 5.0.0, (and 15 other plugins)
Utility:
cordova-res : 0.15.1
native-run (update available: 1.2.2) : 1.1.0
System:
ios-sim : 8.0.2
NodeJS : v12.16.2 (/usr/local/bin/node)
npm : 6.14.4
OS : macOS Catalina
Xcode : Xcode 12.0.1 Build version 12A7300
Linux development station (for reference)
⟩ ionic info
Ionic:
Ionic CLI : 6.11.8 (/usr/local/lib/node_modules/#ionic/cli)
Ionic Framework : #ionic/angular 5.3.3
#angular-devkit/build-angular : 0.1001.6
#angular-devkit/schematics : 10.1.6
#angular/cli : 10.1.6
#ionic/angular-toolkit : 2.3.3
Cordova:
Cordova CLI : 10.0.0
Cordova Platforms : android 9.0.0
Cordova Plugins : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 4.1.3, (and 16 other plugins)
Utility:
cordova-res : not installed
native-run (update available: 1.2.2) : 1.1.0
System:
Android SDK Tools : 26.1.1 (/home/praetors/Android/Sdk/)
NodeJS : v12.13.0 (/home/praetors/.nvm/versions/node/v12.13.0/bin/node)
npm : 6.12.0
OS : Linux 4.19
I would like to switch from gulp to webpack totally but I still I am looking for a good solution.
What this gulp task achieve :
Takes all svgs in src/assets/icons/**/*
Create fonts (ttf, eot, woff...)
Generate thanks to src/assets/css/icons_template.scss a icons.scss file creating classes for each icon
My Gulpfile
var gulp = require('gulp');
var iconfont = require('gulp-iconfont');
var iconfontCss = require('gulp-iconfont-css');
gulp.task('icons', function () {
return gulp.src('src/assets/icons/**/*')
.pipe(iconfontCss({
fontName: 'myapp-icons',
path: 'src/assets/css/icons_template.scss',
fontPath: '../fonts/icons/',
targetPath: '../../css/icons.scss',
cssClass: 'mu-icon'
}))
.pipe(iconfont({
fontName: 'myapp-icons',
formats: ['ttf', 'eot', 'woff', 'woff2', 'svg'],
normalize: true,
centerHorizontally: true
}))
.pipe(gulp.dest('src/assets/fonts/icons'))
});
gulp.task('default', function () {
gulp.start('icons');
});
The template i use :
//src/assets/css/icons_template.scss
#font-face {
font-family: "<%= fontName %>";
src: url(<%= fontPath %><%= fontName %>.eot);
src: url(<%= fontPath %><%= fontName %>.eot?#iefix) format('eot'),
url(<%= fontPath %><%= fontName %>.woff2) format('woff2'),
url(<%= fontPath %><%= fontName %>.woff) format('woff'),
url(<%= fontPath %><%= fontName %>.ttf) format('truetype'),
url(<%= fontPath %><%= fontName %>.svg#<%= fontName %>) format('svg');
}
#mixin <%= cssClass%>-styles {
font-family: "<%= fontName %>";
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-style: normal;
font-variant: normal;
font-weight: normal;
// speak: none; // only necessary if not using the private unicode range (firstGlyph option)
text-decoration: none;
text-transform: none;
}
%<%= cssClass%> {
#include <%= cssClass%>-styles;
}
#function <%= cssClass%>-char($filename) {
$char: "";
<% _.each(glyphs, function(glyph) { %>
#if $filename == <%= glyph.fileName %> {
$char: "\<%= glyph.codePoint %>";
}<% }); %>
#return $char;
}
#mixin <%= cssClass%>($filename, $insert: before, $extend: true) {
&:#{$insert} {
#if $extend {
#extend %<%= cssClass%>;
} #else {
#include <%= cssClass%>-styles;
}
content: <%= cssClass%>-char($filename);
}
}
<% _.each(glyphs, function(glyph) { %>.<%= cssClass%>-<%= glyph.fileName %> {
#include <%= cssClass%>(<%= glyph.fileName %>);
}
<% }); %>
Here is what I managed to do with webpack :
Use webfonts-loader
Add a myapp.font.js file
module.exports = {
'files': [
'./icons/*.svg'
],
'cssTemplate': './fonts/myapp_icons_template.css.tpl',
'fontName': 'myapp-icons',
'classPrefix': 'myapp-icon-',
'baseSelector': '.myapp-icon',
'types': ['eot', 'woff', 'woff2', 'ttf', 'svg'],
'fileName': 'myapp-icons.[ext]'
};
Add this to my webpack loaders after imported the previous file:
{
test: /\.font\.js/,
loaders: [
'style-loader',
'css-loader',
'webfonts-loader'
]
},
And then the style is directly copied ton index.html
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;
}