├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── renovate.json └── workflows │ └── check.yml ├── .gitignore ├── .nvmrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src └── index.tsx └── tsconfig.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: joe-bell 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Smartphone (please complete the following information):** 33 | 34 | - Device: [e.g. iPhone6] 35 | - OS: [e.g. iOS8.1] 36 | - Browser [e.g. stock browser, safari] 37 | - Version [e.g. 22] 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>joe-bell/renovate-config"] 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | os: 16 | - ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Read .nvmrc 21 | run: echo ::set-output name=NVMRC::$(cat .nvmrc) 22 | id: nvm 23 | 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v2.1.5 26 | with: 27 | node-version: "${{ steps.nvm.outputs.NVMRC }}" 28 | - run: npm ci --ignore-scripts 29 | - run: npx prettier . --check 30 | - run: npm run build 31 | env: 32 | CI: true 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.16.1 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [2.2.0](https://github.com/joe-bell/next-google-fonts/compare/v2.1.0...v2.2.0) (2020-03-30) 7 | 8 | ### Features 9 | 10 | - Add keys to `` tags to prevent duplicates ([e0caed5](https://github.com/joe-bell/next-google-fonts/commit/e0caed540c45655dd38f42665a00094ec58e086e)) 11 | - Add `data-next-google-fonts-*` attributes for debugging ([dd7cc13](https://github.com/joe-bell/next-google-fonts/commit/dd7cc13b2501cf739c9bc24e1b1b7ddd05099e31)) 12 | 13 | ## [2.1.0](https://github.com/joe-bell/next-google-fonts/compare/v2.0.0...v2.1.0) (2020-03-15) 14 | 15 | ### Features 16 | 17 | - add "no-js" fallback ([4f45eb2](https://github.com/joe-bell/next-google-fonts/commit/4f45eb2974f8829c56b9d7cd2a72f2989693bd42)) 18 | > In the unlikely event that a visitor has intentionally disabled JavaScript, fall back to the original method. The good news is that, although this is a render-blocking request, it can still make use of the preconnect which makes it marginally faster than the default. 19 | > 20 | > [Harry Roberts](https://csswizardry.com/2020/05/the-fastest-google-fonts/#google-fonts-async-snippet) 21 | 22 | ## [2.0.0](https://github.com/joe-bell/next-google-fonts/compare/v1.3.0...v2.0.0) (2020-02-26) 23 | 24 | ### Refactor 25 | 26 | - switches to named `GoogleFonts` export ([8fdb19d](https://github.com/joe-bell/next-google-fonts/commit/8fdb19d78b58b3eceba8a2c5973b30bb4583ddd4)) 27 | 28 | ### Features 29 | 30 | - upgrade peerDeps to latest `next` and `react` versions ([8fdb19d](https://github.com/joe-bell/next-google-fonts/commit/8fdb19d78b58b3eceba8a2c5973b30bb4583ddd4)) 31 | 32 | ## [1.3.0](https://github.com/joe-bell/next-google-fonts/compare/v1.2.1...v1.3.0) (2020-02-25) 33 | 34 | ### Features 35 | 36 | - add named export of `GoogleFonts` ([f9e17b5](https://github.com/joe-bell/next-google-fonts/commit/f9e17b52d2cfd66ee3be5a1a1f77810b0d1fd77e)) 37 | 38 | ## [1.2.1](https://github.com/joe-bell/next-google-fonts/compare/v1.2.0...v1.2.1) (2020-07-08) 39 | 40 | ### Reverts 41 | 42 | - remove react-google-fonts until tested ([f9096dd](https://github.com/joe-bell/next-google-fonts/commit/f9096dd68d11aa10a473e007ae244b766d0f6c63)) 43 | 44 | ## [1.2.0](https://github.com/joe-bell/next-google-fonts/compare/v1.1.0...v1.2.0) (2020-07-08) 45 | 46 | ### Features 47 | 48 | - introduce react-google-fonts ([aea5b19](https://github.com/joe-bell/next-google-fonts/commit/aea5b198e1073a2be062515b964cc5850e853614)) 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Joe Bell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | ⚠️ 3 |

4 | 5 |

6 | THIS PROJECT HAS BEEN DEPRECATED 7 |

8 | 9 |

10 | As of Next.js 10.2, Google Fonts are automatically optimized 🎉 11 |

12 | 13 |

14 | Thanks for all your love and support for this project, 15 |
16 | Joe 17 |

18 | 19 | --- 20 | 21 |
22 | 23 |

next-google-fonts

24 | 25 |

26 | A tiny next/head helper for loading Google Fonts fast and asynchronously ⏩ 27 |

28 | 29 |

30 | 31 | NPM Version 32 | 33 | 34 | Types Included 35 | 36 | 37 | Minizipped Size 38 | 39 | 40 | MIT License 41 | 42 | 43 | NPM Downloads 44 | 45 | 46 | Follow @joebell_ on Twitter 47 | 48 |

49 | 50 |
51 | 52 | > Using Next.js 10? See ["How does this compare to Next.js font optimization?"](#how-does-this-compare-to-nextjs-font-optimization) before continuing. 53 | 54 | ## Table of Contents 55 | 56 | 1. [Setup](#setup) 57 | 2. [FAQs](#faqs) 58 | 59 | ## Setup 60 | 61 | In this example, we're going to add [`Inter`](https://fonts.google.com/specimen/Inter) (specifically weights `400` and `700`) to a Next.js app. 62 | 63 | See [joebell.co.uk](https://joebell.co.uk) for a working example. 64 | 65 | 1. Add the package to your Next.js project: 66 | 67 | ```sh 68 | npm i next-google-fonts 69 | ``` 70 | 71 | 2. Create a custom `Head` component. 72 | 73 | It's important to acknowledge that `next-google-fonts` is a small [`next/head`][next/head] component and should **not** be nested inside [`next/head`][next/head]. To solve this, wrap both components with a `Fragment`. 74 | 75 | ```jsx 76 | // components/head.js 77 | import * as React from "react"; 78 | import NextHead from "next/head"; 79 | import { GoogleFonts } from "next-google-fonts"; 80 | 81 | export const Head = ({ children, title }) => ( 82 | 83 | 84 | 85 | 86 | 90 | 91 | 92 | {title} 93 | 94 | {children} 95 | 96 | 97 | ); 98 | ``` 99 | 100 | 3. Add the requested Google Font/s to your styles with a sensible fallback. 101 | It really doesn't matter whether you're using CSS or Sass or CSS-in-JS: 102 | 103 | ```css 104 | body { 105 | font-family: "Inter", sans-serif; 106 | } 107 | ``` 108 | 109 | 4. [Run your Next.js app](https://nextjs.org/docs/api-reference/cli#build) to see the results in action! 110 | 111 | You should expect to see the fallback font first, followed by a switch to the Google Font/s without any render-blocking CSS warnings. Your font/s will continue to display until your app is re-hydrated. 112 | 113 | If JS is disabled, only the fallback font will display. 114 | 115 | ## FAQs 116 | 117 | - [How does this compare to Next.js font optimization?](#how-does-this-compare-to-nextjs-font-optimization) 118 | - [Why?](#why) 119 | 120 | ### How does this compare to Next.js font optimization? 121 | 122 | Next.js 10 introduced [automatic Google Font optimization](https://github.com/vercel/next.js/pull/14746), you can make a decision on which solution to use based on the following criteria: 123 | 124 | - "My fonts are **not priority** and can be loaded **asynchronously**" - use `next-google-fonts`. 125 | - "My fonts **are priority** and should **not** be loaded **asynchronously**" - use `Next.js` font optimization. 126 | 127 | For further reading, see the [Next.js issue discussion](https://github.com/vercel/next.js/issues/16065). 128 | 129 | ### Why? 130 | 131 | `next-google-fonts` aims to make the process of using Google Fonts in Next.js more consistent, faster and painless: it preconnects to font assets, preloads and asynchronously loads the CSS file. 132 | 133 | In the current iteration of [`next/head`][next/head], we can't make use of the familiar "media hack" method of asynchronous Google font loading: 134 | 135 | ```html 136 | 137 | 143 | ``` 144 | 145 | If you'd like to track this issue in Next.js, you can follow it here: [Next.js#12984](https://github.com/zeit/next.js/issues/12984). 146 | 147 | [next/head]: https://nextjs.org/docs/api-reference/next/head 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-google-fonts", 3 | "version": "2.2.0", 4 | "description": "Load Google Fonts Asynchronously in Next.js", 5 | "source": "src/index.tsx", 6 | "main": "dist/index.js", 7 | "module": "dist/index.esm.js", 8 | "typings": "dist/index.d.ts", 9 | "files": [ 10 | "dist", 11 | "README.md" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/joe-bell/next-google-fonts.git" 16 | }, 17 | "keywords": [ 18 | "next.js", 19 | "google fonts" 20 | ], 21 | "author": "Joe Bell (https://joebell.co.uk)", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/joe-bell/next-google-fonts/issues" 25 | }, 26 | "homepage": "https://github.com/joe-bell/next-google-fonts#readme", 27 | "scripts": { 28 | "prepare": "npm run build", 29 | "build": "microbundle --jsx React.createElement --tsconfig tsconfig.json", 30 | "commit": "git-cz" 31 | }, 32 | "config": { 33 | "commitizen": { 34 | "path": "cz-conventional-changelog" 35 | } 36 | }, 37 | "husky": { 38 | "hooks": { 39 | "pre-commit": "lint-staged" 40 | } 41 | }, 42 | "lint-staged": { 43 | "*.{js,jsx,ts,tsx,json,md,yml}": "prettier --write" 44 | }, 45 | "peerDependencies": { 46 | "next": ">= 10.0.7", 47 | "react": ">= 17.0.1", 48 | "react-dom": ">= 17.0.1" 49 | }, 50 | "devDependencies": { 51 | "@types/node": "14.14.41", 52 | "@types/react": "17.0.3", 53 | "commitizen": "4.2.3", 54 | "cz-conventional-changelog": "3.3.0", 55 | "husky": "4.3.8", 56 | "lint-staged": "10.5.4", 57 | "microbundle": "0.13.0", 58 | "next": "10.1.3", 59 | "prettier": "2.2.1", 60 | "react": "17.0.2", 61 | "react-dom": "17.0.2", 62 | "typescript": "4.2.4" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import Head from "next/head"; 3 | 4 | export interface IGoogleFontsProps { 5 | /** 6 | * URL to your Google Fonts StyleSheet. 7 | * 8 | * Be sure to end with `&display=swap` for best performance. 9 | */ 10 | href: string; 11 | } 12 | 13 | let hydrated = false; 14 | 15 | export const GoogleFonts: React.FC = ({ href }) => { 16 | const hydratedRef = React.useRef(false); 17 | const [, rerender] = React.useState(false); 18 | 19 | React.useEffect(() => { 20 | if (!hydratedRef.current) { 21 | hydrated = true; 22 | hydratedRef.current = true; 23 | rerender(true); 24 | } 25 | }, []); 26 | 27 | return ( 28 | 29 | 36 | 43 | 50 | 58 | 59 | ); 60 | }; 61 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "include": ["src/**/*.ts", "src/**/*.tsx"], 4 | "compilerOptions": { 5 | "target": "es5", 6 | "lib": ["dom", "dom.iterable", "esnext"], 7 | "allowJs": true, 8 | "skipLibCheck": true, 9 | "strict": false, 10 | "forceConsistentCasingInFileNames": true, 11 | "noEmit": true, 12 | "esModuleInterop": true, 13 | "module": "esnext", 14 | "moduleResolution": "node", 15 | "resolveJsonModule": true, 16 | "isolatedModules": false, 17 | "jsx": "preserve" 18 | } 19 | } 20 | --------------------------------------------------------------------------------