UNPKG

@cedx/php-minifier

Version:

Minify PHP source code by removing comments and whitespace.

88 lines (87 loc) 2.9 kB
import { spawn } from "node:child_process"; import { createServer } from "node:net"; import { join, normalize, resolve } from "node:path"; import { setTimeout } from "node:timers"; /** * Removes comments and whitespace from a PHP script, by calling a Web service. */ export class FastTransformer { /** * The path to the PHP executable. */ #executable; /** * The port that the PHP process is listening on. */ #port = -1; /** * The underlying PHP process. */ #process = null; /** * Creates a new fast transformer. * @param executable The path to the PHP executable. */ constructor(executable = "php") { this.#executable = normalize(executable); } /** * Releases any resources associated with this object. * @returns Resolves when this object is finally disposed. */ [Symbol.asyncDispose]() { return this.close(); } /** * Closes this transformer. * @returns Resolves when the transformer has been closed. */ close() { this.#process?.kill(); this.#process = null; return Promise.resolve(); } /** * Starts the underlying PHP process and begins accepting connections. * @returns The TCP port used by the PHP process. */ async listen() { if (this.#process) return Promise.resolve(this.#port); this.#port = await this.#getPort(); return new Promise((fulfill, reject) => { const args = ["-S", `127.0.0.1:${this.#port}`, "-t", join(import.meta.dirname, "../www")]; this.#process = spawn(this.#executable, args, { stdio: ["ignore", "pipe", "ignore"] }) .on("error", reject) .on("spawn", () => setTimeout(() => fulfill(this.#port), 1_000)); }); } /** * Processes a PHP script. * @param file The path to the PHP script. * @returns The transformed script. * @throws `Error` when an error occurred while processing the script. */ async transform(file) { const port = await this.listen(); const url = new URL(`http://127.0.0.1:${port}/index.php`); url.searchParams.set("file", resolve(file)); const response = await fetch(url); if (response.ok) return await response.text(); throw Error(`An error occurred while processing the script: ${file}`); } /** * Gets an ephemeral TCP port chosen by the system. * @returns The TCP port chosen by the system. */ #getPort() { return new Promise((fulfill, reject) => { const server = createServer().unref().on("error", reject); server.listen({ host: "127.0.0.1", port: 0 }, () => { const { port } = server.address(); server.close(() => fulfill(port)); }); }); } }