import { PurgeCSS, purgeHtml } from "../deps/purgecss.ts";
import { merge } from "../core/utils/object.ts";
import { concurrent } from "../core/utils/concurrent.ts";
import { getExtension, matchExtension } from "../core/utils/path.ts";
import type Site from "../core/site.ts";
import type { Page } from "../core/file.ts";
import type { RawContent, UserDefinedOptions } from "../deps/purgecss.ts";
export interface Options {
/** The list of page extensions loaded as content. */
contentExtensions?: string[];
/** Options for purgecss */
options?: Partial;
}
// Default options
export const defaults: Options = {
contentExtensions: [".html", ".js"],
options: {
extractors: [],
},
};
/**
* A plugin to remove unused CSS
*/
export function purgecss(userOptions?: Options) {
const options = merge(defaults, userOptions);
options.options.extractors!.push({
extractor: purgeHtml,
extensions: ["html"],
});
return (site: Site) => {
site.process([".css"], async function processPurgeCSS(pages, allPages) {
const content: RawContent[] = [];
for (const page of allPages) {
if (!matchExtension(options.contentExtensions, page.outputPath)) {
continue;
}
const pageContent = page.content;
if (typeof pageContent !== "string") {
return;
}
content.push({
raw: pageContent,
extension: getExtension(page.outputPath).slice(1),
});
}
await concurrent(pages, async (page: Page) => {
const pageContent = page.content;
if (typeof pageContent !== "string") {
return;
}
const purgeOptions: UserDefinedOptions = {
...options.options,
content: (options.options.content || []).concat(content),
css: [
{
raw: pageContent,
},
],
};
const result = await new PurgeCSS().purge(purgeOptions);
page.content = result[0].css;
});
});
};
}
export default purgecss;