vite-plugin-preload
Version:
[](https://badge.fury.io/js/vite-plugin-preload)
138 lines (134 loc) • 4.4 kB
JavaScript
// src/options.ts
var defaultOptions = {
includeJs: true,
includeCss: true,
format: true,
mode: "preload",
shouldPreload: () => true
};
// src/index.ts
import { createFilter } from "@rollup/pluginutils";
// src/dom-utils.ts
import { JSDOM } from "jsdom";
import { normalize } from "path";
var createDom = (source) => new JSDOM(source);
var createModulePreloadLinkElement = (dom, path) => {
const link = dom.window.document.createElement("link");
link.rel = "modulepreload";
link.href = path;
return link;
};
var createPrefetchLinkElement = (dom, path) => {
const link = dom.window.document.createElement("link");
link.rel = "prefetch";
link.href = path;
return link;
};
var createStylesheetLinkElement = (dom, path) => {
const link = dom.window.document.createElement("link");
link.rel = "stylesheet";
link.href = path;
return link;
};
var getExistingLinks = (dom) => {
const existingLinks = [];
dom.window.document.querySelectorAll("script").forEach((s) => {
if (!s.src) {
return;
}
existingLinks.push(s.src);
});
dom.window.document.querySelectorAll("link").forEach((l) => existingLinks.push(normalize(l.href)));
return existingLinks;
};
var appendToDom = (dom, link) => dom.window.document.head.appendChild(link);
// src/index.ts
import prettier from "prettier";
import { resolve } from "url";
import { normalize as normalize2 } from "path";
var jsFilter = createFilter(["**/*-*.js"]);
var cssFilter = createFilter(["**/*-*.css"]);
function VitePluginPreloadAll(options) {
let viteConfig;
const mergedOptions = { ...defaultOptions, ...options };
return {
name: "vite:vite-plugin-preload",
enforce: "post",
apply: "build",
configResolved(config) {
viteConfig = config;
},
transformIndexHtml: {
order: "post",
handler: (html, ctx) => {
if (!ctx.bundle) {
return html;
}
const base = viteConfig.base ?? "";
const dom = createDom(html);
const existingLinks = getExistingLinks(dom);
let additionalModules = [];
let additionalStylesheets = [];
for (const bundle of Object.values(ctx.bundle)) {
const path = normalize2(resolve(base, bundle.fileName));
if (existingLinks.includes(path) || !mergedOptions.shouldPreload(bundle)) {
continue;
}
if (mergedOptions.includeJs && bundle.type === "chunk" && jsFilter(bundle.fileName)) {
additionalModules.push(path);
}
if (mergedOptions.includeCss && bundle.type === "asset" && cssFilter(bundle.fileName)) {
additionalStylesheets.push(path);
}
}
additionalModules = additionalModules.sort(
(a, z) => a.localeCompare(z)
);
additionalStylesheets = additionalStylesheets.sort(
(a, z) => a.localeCompare(z)
);
if (mergedOptions.mode === "preload") {
for (const additionalModule of additionalModules) {
const element = createModulePreloadLinkElement(
dom,
additionalModule
);
appendToDom(dom, element);
}
for (const additionalStylesheet of additionalStylesheets) {
const element = createStylesheetLinkElement(
dom,
additionalStylesheet
);
appendToDom(dom, element);
}
} else if (mergedOptions.mode === "prefetch") {
for (const additionalModule of additionalModules) {
const element = createPrefetchLinkElement(dom, additionalModule);
appendToDom(dom, element);
}
for (const additionalStylesheet of additionalStylesheets) {
const element = createPrefetchLinkElement(
dom,
additionalStylesheet
);
appendToDom(dom, element);
}
} else {
throw new Error(`Unsupported "mode" option: ${mergedOptions.mode}`);
}
const unformattedHtml = dom.serialize();
if (mergedOptions.format === false) {
return unformattedHtml;
}
return prettier.format(unformattedHtml, {
...typeof mergedOptions.format === "object" ? mergedOptions.format : {},
parser: "html"
});
}
}
};
}
export {
VitePluginPreloadAll as default
};