Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: add support for nuxt 3/nuxt bridge #94

Merged
merged 14 commits into from
Jul 22, 2022
Merged

Conversation

ricardogobbosouza
Copy link
Collaborator

@ricardogobbosouza ricardogobbosouza commented Jul 7, 2022

This PR enables this module to work for Nuxt Bridge & Nuxt 3.

🔥 Notable changes

  • Uses @nuxt/module-builder to build module
  • Refactor structure using @nuxt/kit
  • Update docs (docs: migrate to docus #95)
  • Re-enable e2e test suite

src/module.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@danielroe danielroe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! Main issue is differences between vue-meta & vueuse/head. (Which may not be an issue with this module - partial support is better than none at all, and a console log may be enough to let user know until upstream features land.)

src/module.ts Outdated Show resolved Hide resolved
src/module.ts Outdated Show resolved Hide resolved
@CKGrafico
Copy link

CKGrafico commented Jul 15, 2022

This is in draft but checking your todo list seems ready to be used, can we have an alpha version or something to don't use a github "link" in our package json?

EDIT: Meanwhile we wait for a version this is how I was able to make it work...
package.json

"@nuxtjs/google-fonts": "github:nuxt-community/google-fonts-module#refactor-use-kit",

nuxt.config.ts

  modules: ['./modules/fonts'],
  ...
  googleFonts: {
    families: {
      Roboto: true,
      Lato: [100, 300],
      Raleway: {
        wght: [100, 400],
        ital: [100]
      }
    }

modules/fonts.ts (first attempt)

import fonts from '@nuxtjs/google-fonts/src/module';

export default fonts;

The result is an error because the original package json is not exporting this file.

modules/fonts.ts (second attempt)

// Waiting a version: https://github.com/nuxt-community/google-fonts-module/pull/94
// File imported from '@nuxtjs/google-fonts/src/module';

import { defineNuxtModule, isNuxt2, resolvePath, useLogger } from '@nuxt/kit';
import { constructURL, download, DownloadOptions, GoogleFonts, isValidURL, merge, parse } from 'google-fonts-helper';
import { resolve } from 'pathe';
const name = '@nuxtjs/google-fonts';
const version = '2.0.1';

export interface ModuleOptions extends DownloadOptions, GoogleFonts {
  prefetch?: boolean;
  preconnect?: boolean;
  preload?: boolean;
  useStylesheet?: boolean;
  download?: boolean;
  inject?: boolean;
}

const logger = useLogger('nuxt:google-fonts');

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name,
    version,
    configKey: 'googleFonts'
  },
  defaults: {
    families: {},
    display: undefined, // set to 'swap' later if no preload or user value
    subsets: [],
    text: undefined,
    prefetch: true,
    preconnect: true,
    preload: false,
    useStylesheet: false,
    download: true,
    base64: false,
    inject: true,
    overwriting: false,
    outputDir: 'node_modules/.cache/nuxt-google-fonts',
    stylePath: 'css/nuxt-google-fonts.css',
    fontsDir: 'fonts',
    fontsPath: '../fonts'
  },
  async setup(options, nuxt) {
    // If user hasn't set the display value manually and isn't using
    // a preload, set the default display value to 'swap'
    if (options.display === undefined && !options.preload) {
      options.display = 'swap';
    }

    const fontsParsed = [];

    // merge fonts from valid head link
    if (isNuxt2()) {
      nuxt.options.head = nuxt.options.head || {};
      nuxt.options.head.link = nuxt.options.head.link || [];
      fontsParsed.push(
        ...nuxt.options.head.link.filter((link) => isValidURL(link.href)).map((link) => parse(link.href))
      );
    } else {
      nuxt.options.app.head.link = nuxt.options.app.head.link || [];
      fontsParsed.push(
        ...nuxt.options.app.head.link.filter((link) => isValidURL(link.href)).map((link) => parse(link.href))
      );
    }

    // construct google fonts url
    const url = constructURL(merge(options, ...fontsParsed));

    if (!url) {
      logger.warn('No provided fonts.');

      return;
    }

    // remove fonts
    if (isNuxt2()) {
      nuxt.options.head = nuxt.options.head || {};
      nuxt.options.head.link = nuxt.options.head.link || [];
      nuxt.options.head.link = nuxt.options.head.link.filter((link) => !isValidURL(link.href));
    } else {
      nuxt.options.app.head.link = nuxt.options.app.head.link || [];
      nuxt.options.app.head.link = nuxt.options.app.head.link.filter((link) => !isValidURL(link.href));
    }

    // download
    if (options.download) {
      const outputDir = await resolvePath(options.outputDir);

      try {
        const downloader = download(url, {
          base64: options.base64,
          overwriting: options.overwriting,
          outputDir,
          stylePath: options.stylePath,
          fontsDir: options.fontsDir,
          fontsPath: options.fontsPath
        });

        await downloader.execute();

        if (options.inject) {
          nuxt.options.css.push(resolve(outputDir, options.stylePath));
        }

        // Add the nuxt google fonts directory
        nuxt.options.nitro = nuxt.options.nitro || {};
        nuxt.options.nitro.publicAssets = nuxt.options.nitro.publicAssets || [];
        nuxt.options.nitro.publicAssets.push({ dir: outputDir });
      } catch (e) {
        logger.error(e);
      }

      return;
    }

    if (isNuxt2()) {
      nuxt.options.head = nuxt.options.head || {};
      nuxt.options.head.link = nuxt.options.head.link || [];
      nuxt.options.head.script = nuxt.options.head.script || [];
      nuxt.options.head.noscript = nuxt.options.head.noscript || [];
      nuxt.options.head.__dangerouslyDisableSanitizersByTagID =
        nuxt.options.head.__dangerouslyDisableSanitizersByTagID || {};

      // https://developer.mozilla.org/en-US/docs/Web/Performance/dns-prefetch
      if (options.prefetch) {
        nuxt.options.head.link.push({
          hid: 'gf-prefetch',
          rel: 'dns-prefetch',
          href: 'https://fonts.gstatic.com/'
        });
      }

      // https://developer.mozilla.org/en-US/docs/Web/Performance/dns-prefetch#Best_practices
      if (options.preconnect) {
        nuxt.options.head.link.push(
          // connect to domain of font files
          {
            hid: 'gf-preconnect',
            rel: 'preconnect',
            href: 'https://fonts.gstatic.com/',
            crossorigin: 'anonymous'
          },

          // Should also preconnect to origin of Google fonts stylesheet.
          {
            hid: 'gf-origin-preconnect',
            rel: 'preconnect',
            href: 'https://fonts.googleapis.com/'
          }
        );
      }

      // https://developer.mozilla.org/pt-BR/docs/Web/HTML/Preloading_content
      // optionally increase loading priority
      if (options.preload) {
        nuxt.options.head.link.push({
          hid: 'gf-preload',
          rel: 'preload',
          as: 'style',
          href: url
        });
      }

      // append CSS
      if (options.useStylesheet) {
        nuxt.options.head.link.push({
          hid: 'gf-style',
          rel: 'stylesheet',
          href: url
        });

        return;
      }

      // JS to inject CSS
      nuxt.options.head.script.push({
        hid: 'gf-script',
        innerHTML: `(function(){var l=document.createElement('link');l.rel="stylesheet";l.href="${url}";document.querySelector("head").appendChild(l);})();`
      });

      // no-JS fallback
      nuxt.options.head.noscript.push({
        hid: 'gf-noscript',
        innerHTML: `<link rel="stylesheet" href="${url}">`
      });

      // Disable sanitazions
      nuxt.options.head.__dangerouslyDisableSanitizersByTagID['gf-script'] = ['innerHTML'];
      nuxt.options.head.__dangerouslyDisableSanitizersByTagID['gf-noscript'] = ['innerHTML'];

      return;
    }

    nuxt.options.app.head.link = nuxt.options.app.head.link || [];
    nuxt.options.app.head.script = nuxt.options.app.head.script || [];

    // https://developer.mozilla.org/en-US/docs/Web/Performance/dns-prefetch
    if (options.prefetch) {
      nuxt.options.app.head.link.push({
        rel: 'dns-prefetch',
        href: 'https://fonts.gstatic.com/'
      });
    }

    // https://developer.mozilla.org/en-US/docs/Web/Performance/dns-prefetch#Best_practices
    if (options.preconnect) {
      nuxt.options.app.head.link.push(
        // connect to domain of font files
        {
          rel: 'preconnect',
          href: 'https://fonts.gstatic.com/',
          crossorigin: 'anonymous'
        },

        // Should also preconnect to origin of Google fonts stylesheet.
        {
          rel: 'preconnect',
          href: 'https://fonts.googleapis.com/'
        }
      );
    }

    // https://developer.mozilla.org/pt-BR/docs/Web/HTML/Preloading_content
    // optionally increase loading priority
    if (options.preload) {
      nuxt.options.app.head.link.push({
        rel: 'preload',
        as: 'style',
        href: url
      });
    }

    // append CSS
    if (options.useStylesheet) {
      nuxt.options.app.head.link.push({
        rel: 'stylesheet',
        href: url
      });

      return;
    }

    // JS to inject CSS
    nuxt.options.app.head.script.unshift({
      'data-hid': 'gf-script',
      children: `(function(){
        var h=document.querySelector("head");
        var m=h.querySelector('meta[name="head:count"]');
        if(m){m.setAttribute('content',Number(m.getAttribute('content'))+1);}
        else{m=document.createElement('meta');m.setAttribute('name','head:count');m.setAttribute('content','1');h.append(m);}
        var l=document.createElement('link');l.rel='stylesheet';l.href='${url}';h.appendChild(l);
      })();`
    });

    /*
    // no-JS fallback
    // waiting https://github.com/vueuse/head/pull/71
    /* nuxt.options.app.head.noscript.push({
      children: `<link rel="stylesheet" href="${url}">`
    })
    */
  }
});

Copy link
Contributor

@danielroe danielroe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! I think you could possibly simplify things slightly by wrt nuxt 2/3 and injecting head, maybe with a helper function, if you wanted to. But that's only a nitpick.

@ricardogobbosouza ricardogobbosouza marked this pull request as ready for review July 22, 2022 13:24
@ricardogobbosouza ricardogobbosouza merged commit fbe5d77 into main Jul 22, 2022
@ricardogobbosouza ricardogobbosouza deleted the refactor-use-kit branch July 22, 2022 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants