116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
import { Plugin } from "$fresh/server.ts";
|
|
import { ensureDir } from "$std/fs/ensure_dir.ts";
|
|
import { join } from "$std/path/join.ts";
|
|
import { parse } from "$std/path/parse.ts";
|
|
import { dirname } from "$std/path/dirname.ts";
|
|
|
|
// External Less compiler for Deno
|
|
const LESS_CDN = "https://esm.sh/less@4.2.0";
|
|
|
|
export interface LessPluginOptions {
|
|
path: string;
|
|
outDir: string;
|
|
}
|
|
|
|
export default function lessPlugin(options: LessPluginOptions): Plugin {
|
|
let watcher: Deno.FsWatcher | null = null;
|
|
const combinedCssPath = join(options.outDir, "styles.combined.css");
|
|
let less: any;
|
|
|
|
// Compile a Less file and return its CSS
|
|
async function compileLessFile(path: string): Promise<string> {
|
|
try {
|
|
const lessContent = await Deno.readTextFile(path);
|
|
const { css } = await less.render(lessContent);
|
|
return css;
|
|
} catch (err) {
|
|
console.error(`Error compiling ${path}:`, err);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// Combine all compiled CSS into a single file
|
|
async function combineAndWriteCss(paths) {
|
|
try {
|
|
const compiledCssArray: string[] = [];
|
|
|
|
for (const path of paths) {
|
|
const css = await compileLessFile(path);
|
|
compiledCssArray.push(css);
|
|
}
|
|
|
|
const combinedCss = compiledCssArray.join("\n");
|
|
await Deno.writeTextFile(combinedCssPath, combinedCss);
|
|
console.log(`Combined CSS written to ${combinedCssPath}`);
|
|
} catch (err) {
|
|
console.error("Error combining CSS:", err);
|
|
}
|
|
}
|
|
|
|
// Start watching the style directory
|
|
async function startWatcher() {
|
|
try {
|
|
// Determine directory to watch (assuming first path is representative)
|
|
const watchDir = dirname(options.path);
|
|
|
|
console.log(`Starting watcher on ${watchDir}`);
|
|
watcher = Deno.watchFs(watchDir);
|
|
|
|
(async () => {
|
|
for await (const event of watcher!) {
|
|
if (event.kind === "modify" || event.kind === "create") {
|
|
const lessFiles = event.paths.filter(p => p.endsWith(".less"));
|
|
if (lessFiles.length > 0) {
|
|
console.log(`Less files changed: ${lessFiles.join(", ")}`);
|
|
await combineAndWriteCss(lessFiles);
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
} catch (err) {
|
|
console.error("Error starting watcher:", err);
|
|
}
|
|
}
|
|
|
|
return {
|
|
name: "less",
|
|
async buildStart() {
|
|
try {
|
|
// Import the Less compiler
|
|
const lessModule = await import(LESS_CDN);
|
|
less = lessModule.default;
|
|
|
|
// Ensure the output directory exists
|
|
await ensureDir(options.outDir);
|
|
|
|
// Initial compilation
|
|
await combineAndWriteCss();
|
|
|
|
// Start the file watcher
|
|
await startWatcher();
|
|
} catch (err) {
|
|
console.error("Error initializing Less plugin:", err);
|
|
}
|
|
},
|
|
|
|
render(ctx) {
|
|
// Generate a link to the combined CSS file
|
|
const href = "/css/styles.combined.css"
|
|
ctx.render();
|
|
return {
|
|
links: [{ rel: "stylesheet", href }],
|
|
};
|
|
},
|
|
|
|
async buildEnd() {
|
|
// Clean up watcher when build ends
|
|
if (watcher) {
|
|
try {
|
|
watcher.close();
|
|
} catch (err) {
|
|
console.error("Error closing watcher:", err);
|
|
}
|
|
}
|
|
},
|
|
};
|
|
} |