@cedx/php-minifier
Version:
Minify PHP source code by removing comments and whitespace.
88 lines (87 loc) • 2.9 kB
JavaScript
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));
});
});
}
}