From 8d65f2f4ff7872c1c759bdd8bdb7a7b384092315 Mon Sep 17 00:00:00 2001 From: Thorn Walli Date: Mon, 30 Oct 2023 19:56:46 +0100 Subject: [PATCH] fix(preload): ignore other urls --- .vscode/launch.json | 138 +++++++------------------------ src/hookFunctions/nitro/init.mjs | 100 ++++++++++++++++++++++ src/utils/preload.mjs | 96 +-------------------- 3 files changed, 134 insertions(+), 200 deletions(-) create mode 100644 src/hookFunctions/nitro/init.mjs diff --git a/.vscode/launch.json b/.vscode/launch.json index d5d96dbce8..354524dceb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,125 +2,49 @@ "version": "0.2.0", "configurations": [ { - "type": "node", + "presentation": { + "group": "nuxt" + }, + "command": "npm run dev", + "name": "Debug: dev", "request": "launch", - "name": "Express-Server (build/dist)", - "runtimeVersion": "19.5.0", - "program": "${workspaceFolder}/tools/express-server", - "outputCapture": "std", - "args": [ - "--dist", - "playground/.nuxt/nuxt-custom-elements/dist" - ] + "type": "node-terminal" }, { - "type": "node", + "presentation": { + "group": "nuxt" + }, + "command": "npm run build", + "name": "Debug: build", "request": "launch", - "name": "Debug (nuxi:generate)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxi", - "outputCapture": "std", - "args": [ - "generate", - "playground", - "--target", - "static" - ] + "type": "node-terminal" }, { - "type": "node", + "presentation": { + "group": "nuxt" + }, + "command": "npm run generate", + "name": "Debug: generate", "request": "launch", - "name": "Debug (nuxi:build)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxi", - "outputCapture": "std", - "args": [ - "build", - "playground" - ] + "type": "node-terminal" }, { - "type": "node", + "presentation": { + "group": "tests" + }, + "command": "npm run vitest:dev", + "name": "Debug: vitest:dev", "request": "launch", - "name": "Debug (nuxi:dev)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxi", - "outputCapture": "std", - "args": [ - "dev", - "playground" - ] + "type": "node-terminal" }, { - "type": "node", + "presentation": { + "group": "others" + }, + "command": "npm run start", + "name": "Serve (dist)", "request": "launch", - "name": "Debug (nuxt:generate)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxt", - "outputCapture": "std", - "args": [ - "generate", - "playground", - "--target", - "static" - ] - }, - { - "type": "node", - "request": "launch", - "name": "Debug (nuxt:build)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxt", - "outputCapture": "std", - "args": [ - "build", - "playground" - ] - }, - { - "type": "node", - "request": "launch", - "name": "Debug (nuxt:dev)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxt", - "outputCapture": "std", - "args": [ - "dev", - "playground" - ] - }, - { - "type": "node", - "request": "launch", - "name": "Debug (nuxi:prepare)", - "runtimeVersion": "19.5.0", - "runtimeArgs": [ - "--inspect" - ], - "program": "${workspaceFolder}/node_modules/.bin/nuxt", - "outputCapture": "std", - "args": [ - "prepare", - "playground" - ] - }, + "type": "node-terminal" + } ] } diff --git a/src/hookFunctions/nitro/init.mjs b/src/hookFunctions/nitro/init.mjs new file mode 100644 index 0000000000..b8b9885bcc --- /dev/null +++ b/src/hookFunctions/nitro/init.mjs @@ -0,0 +1,100 @@ +import { promises as fsPromises } from 'fs'; +import { basename, dirname, join, resolve } from 'path'; +import { parseDocument } from 'htmlparser2'; +import { load } from 'cheerio'; +import { render } from 'dom-serializer'; +import { logger } from '../../utils.mjs'; + +export default (nuxt, disableNuxtCritters = true) => + nitro => { + nitro.hooks.hook('prerender:generate', async route => { + if (!route.fileName?.endsWith('.html') || !route.contents) { + return; + } + + const document = parseDocument(route.contents); + const $ = load(document); + + $('[rel="modulepreload"][as="script"]').remove(); + $('[rel="prefetch"][as="script"]').remove(); + + $('[rel="preload"][as="style"]').remove(); + $('[rel="prefetch"][as="style"]').remove(); + + // embed css files + try { + const css = await Promise.all( + Array.from($('link[rel="stylesheet"]')) + .map(el => $(el)) + .map(async $el => { + const dir = dirname($el.attr('href')); + + // https://nuxt.com/docs/guide/directory-structure/output + const publicDir = join( + nuxt.options.rootDir, + '.output/public', + nuxt.options.vite.build.assetsDir + ); + const filepath = join(publicDir, basename($el.attr('href'))); + const fileContent = await fsPromises.readFile(filepath, 'utf-8'); + + let urls = getUrlValues(fileContent); + urls = prepareUrls(urls, dir); + + if (disableNuxtCritters) { + const css = urls.reduce( + (result, [a, b]) => result.replace(a, b), + fileContent + ); + + $el.remove(); + logger.info( + `Embed CSS File \`${basename($el.attr('href'))}\`; Route: \`${ + route.route + }\`` + ); + return css; + } else { + const matches = fileContent.match( + /\/\*! speedkit-font-faces start \*\/(.*)\/\*! speedkit-font-faces end \*\// + ); + if (matches) { + logger.info( + `Embed Font-Faces CSS \`${basename( + $el.attr('href') + )}\`; Route: \`${route.route}\`` + ); + return matches[1].replace(/url\(.\//g, `url(${dir}/`); + } + } + }) + ); + if (css.length) { + $('head').append(``); + } + } catch (error) { + logger.error("can't embed css file.", error); + } + + route.contents = render(document); + }); + }; + +function getUrlValues(css) { + return css.match(/url\(([^)]+)\)/g); +} + +function prepareUrls(urls, relativeDir) { + return urls + .map(url => { + const value = url + .trim() + .replace(/^url\((.*)\)$/, '$1') + .trim(); + if (value.startsWith('http') || value.startsWith('data')) { + return false; + } + return [url, `url(${resolve(relativeDir, value)})`]; + }) + .filter(Boolean); +} diff --git a/src/utils/preload.mjs b/src/utils/preload.mjs index db1033209c..567083da4e 100644 --- a/src/utils/preload.mjs +++ b/src/utils/preload.mjs @@ -1,11 +1,6 @@ -import { promises as fsPromises } from 'fs'; -import { basename, dirname, join, resolve } from 'path'; -import { parseDocument } from 'htmlparser2'; -import { load } from 'cheerio'; -import { render } from 'dom-serializer'; -import { isViteBuild, logger } from '../utils.mjs'; +import initHook from '../hookFunctions/nitro/init.mjs'; +import { isViteBuild } from '../utils.mjs'; -// eslint-disable-next-line sonarjs/cognitive-complexity export function optimizePreloads(moduleOptions, nuxt) { const disableNuxtCritters = moduleOptions.disableNuxtCritters; @@ -18,90 +13,5 @@ export function optimizePreloads(moduleOptions, nuxt) { nuxt.options.experimental.inlineSSRStyles = false; - nuxt.hook('nitro:init', nitro => { - nitro.hooks.hook('prerender:generate', async route => { - if (!route.fileName?.endsWith('.html') || !route.contents) { - return; - } - - const document = parseDocument(route.contents); - const $ = load(document); - - $('[rel="modulepreload"][as="script"]').remove(); - $('[rel="prefetch"][as="script"]').remove(); - - $('[rel="preload"][as="style"]').remove(); - $('[rel="prefetch"][as="style"]').remove(); - - // embed css files - try { - const css = await Promise.all( - Array.from($('link[rel="stylesheet"]')) - .map(el => $(el)) - .map(async $el => { - const dir = dirname($el.attr('href')); - - // https://nuxt.com/docs/guide/directory-structure/output - const publicDir = join( - nuxt.options.rootDir, - '.output/public', - nuxt.options.vite.build.assetsDir - ); - const filepath = join(publicDir, basename($el.attr('href'))); - const fileContent = await fsPromises.readFile(filepath, 'utf-8'); - - let urls = getUrlValues(fileContent); - urls = prepareUrls(urls, dir); - - if (disableNuxtCritters) { - const css = urls.reduce( - (result, [a, b]) => result.replace(a, b), - fileContent - ); - - $el.remove(); - logger.info( - `Embed CSS File \`${basename($el.attr('href'))}\`; Route: \`${ - route.route - }\`` - ); - return css; - } else { - const matches = fileContent.match( - /\/\*! speedkit-font-faces start \*\/(.*)\/\*! speedkit-font-faces end \*\// - ); - if (matches) { - logger.info( - `Embed Font-Faces CSS \`${basename( - $el.attr('href') - )}\`; Route: \`${route.route}\`` - ); - return matches[1].replace(/url\(.\//g, `url(${dir}/`); - } - } - }) - ); - if (css.length) { - $('head').append(``); - } - } catch (error) { - logger.error("can't embed css file.", error); - } - - route.contents = render(document); - }); - }); -} - -function getUrlValues(css) { - return css.match(/url\(([^)]+)\)/g); -} - -function prepareUrls(urls, relativeDir) { - return urls.map(url => { - return [ - url, - `url(${resolve(relativeDir, url.replace(/^url\((.*)\)$/, '$1'))})` - ]; - }); + nuxt.hook('nitro:init', initHook(nuxt, disableNuxtCritters)); }