vite-plugin-php 1.0.71 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,30 +1,60 @@
1
1
  'use strict';
2
2
 
3
- const require$$0$1 = require('fs');
4
- const require$$0 = require('path');
5
- const vite = require('vite');
6
- const http = require('node:http');
7
- const child_process = require('child_process');
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const node_child_process = require('node:child_process');
8
6
  const url = require('url');
9
- const require$$0$2 = require('os');
10
- const require$$0$3 = require('util');
11
- const require$$0$4 = require('stream');
7
+ const node_path = require('node:path');
8
+ const require$$0 = require('os');
9
+ const require$$0$1 = require('path');
10
+ const require$$0$2 = require('util');
11
+ const require$$0$3 = require('stream');
12
12
  const require$$0$5 = require('events');
13
+ const require$$0$4 = require('fs');
14
+ const node_fs = require('node:fs');
15
+ const http = require('node:http');
16
+ const vite = require('vite');
13
17
 
14
18
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
15
19
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
16
20
 
17
- const require$$0__default$4 = /*#__PURE__*/_interopDefaultCompat(require$$0$1);
18
- const require$$0__default$1 = /*#__PURE__*/_interopDefaultCompat(require$$0);
19
- const http__default = /*#__PURE__*/_interopDefaultCompat(http);
20
- const require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0$2);
21
- const require$$0__default$2 = /*#__PURE__*/_interopDefaultCompat(require$$0$3);
22
- const require$$0__default$3 = /*#__PURE__*/_interopDefaultCompat(require$$0$4);
21
+ const require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
22
+ const require$$0__default$1 = /*#__PURE__*/_interopDefaultCompat(require$$0$1);
23
+ const require$$0__default$2 = /*#__PURE__*/_interopDefaultCompat(require$$0$2);
24
+ const require$$0__default$3 = /*#__PURE__*/_interopDefaultCompat(require$$0$3);
23
25
  const require$$0__default$5 = /*#__PURE__*/_interopDefaultCompat(require$$0$5);
26
+ const require$$0__default$4 = /*#__PURE__*/_interopDefaultCompat(require$$0$4);
27
+ const http__default = /*#__PURE__*/_interopDefaultCompat(http);
24
28
 
25
- function makeID() {
26
- return Date.now().toString(36) + Math.random() * 100;
27
- }
29
+ const EPHPError = {
30
+ ERROR: 1,
31
+ WARNING: 2,
32
+ PARSE: 4,
33
+ NOTICE: 8,
34
+ CORE_ERROR: 16,
35
+ CORE_WARNING: 32,
36
+ COMPILE_ERROR: 64,
37
+ COMPILE_WARNING: 128,
38
+ USER_ERROR: 256,
39
+ USER_WARNING: 512,
40
+ USER_NOTICE: 1024,
41
+ STRICT: 2048,
42
+ RECOVERABLE_ERROR: 4096,
43
+ DEPRECATED: 8192,
44
+ USER_DEPRECATED: 16384,
45
+ ALL: 32767
46
+ };
47
+
48
+ const internalParam = "__314159265359__";
49
+ const shared = {
50
+ viteConfig: void 0,
51
+ devConfig: {
52
+ cleanup: true,
53
+ errorLevels: EPHPError.ALL | EPHPError.STRICT
54
+ },
55
+ entries: [],
56
+ tempDir: ".php-tmp"
57
+ };
28
58
 
29
59
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
30
60
 
@@ -113,136 +143,130 @@ picocolors.exports.createColors = createColors;
113
143
  var picocolorsExports = picocolors.exports;
114
144
  const colors = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports);
115
145
 
116
- function resolveEnvPrefix({ envPrefix = "VITE_" }) {
117
- envPrefix = Array.isArray(envPrefix) ? envPrefix : [envPrefix];
118
- if (envPrefix.includes("")) {
119
- throw new Error(
120
- `envPrefix option contains value '', which could lead unexpected exposure of sensitive information.`
121
- );
146
+ function hasViteConfig(input) {
147
+ if (!input) {
148
+ throw new Error("Vite config not initialized!");
122
149
  }
123
- return envPrefix;
124
150
  }
125
- const envPattern = /%(\S+?)%/g;
126
- function initReplaceEnv(config) {
127
- const envPrefix = resolveEnvPrefix({ envPrefix: config.envPrefix });
128
- const env = { ...config.env };
129
- for (const key in config.define) {
130
- if (key.startsWith(`import.meta.env.`)) {
131
- const val = config.define[key];
132
- if (typeof val === "string") {
133
- try {
134
- const parsed = JSON.parse(val);
135
- env[key.slice(16)] = typeof parsed === "string" ? parsed : val;
136
- } catch {
137
- env[key.slice(16)] = val;
138
- }
139
- } else {
140
- env[key.slice(16)] = JSON.stringify(val);
141
- }
142
- }
151
+
152
+ function log(message, { type = "info", prefix = true, ...options } = {}) {
153
+ hasViteConfig(shared.viteConfig);
154
+ let output = "";
155
+ if (prefix) {
156
+ output += colors.bgMagenta(colors.white("\u2009php\u2009")) + " ";
143
157
  }
144
- return function replaceEnv(content, filename) {
145
- return content.replace(envPattern, (text, key) => {
146
- if (key in env) {
147
- return env[key];
148
- } else {
149
- if (envPrefix.some((prefix) => key.startsWith(prefix))) {
150
- const relativeHtml = vite.normalizePath(
151
- require$$0.relative(config.root, filename)
152
- );
153
- config.logger.warn(
154
- colors.yellow(
155
- colors.bold(
156
- `(!) ${text} is not defined in env variables found in /${relativeHtml}. Is the variable mistyped?`
157
- )
158
- )
159
- );
160
- }
161
- return text;
162
- }
163
- });
164
- };
158
+ output += message;
159
+ shared.viteConfig.logger[type](output, options);
165
160
  }
166
-
167
- function writeFile(file, data) {
168
- require$$0$1.mkdirSync(require$$0.dirname(file), { recursive: true });
169
- require$$0$1.writeFileSync(file, data);
170
- }
171
-
172
- const phpTagPattern = /<\?(?:php|).+?(\?>|$)/gis;
173
- function escapePHP({ inputFile, config }) {
174
- const replaceEnv = initReplaceEnv(config);
175
- const input = require$$0$1.readFileSync(inputFile, "utf-8").toString();
176
- const phpCodes = {};
177
- const isJS = inputFile.includes(".js") || inputFile.includes(".ts");
178
- const isML = inputFile.includes(".php") || inputFile.includes(".htm");
179
- const escapedCode = input.replace(phpTagPattern, (match) => {
180
- let token = makeID();
181
- if (isJS) {
182
- token = `/*${token}*/`;
183
- } else if (isML) {
184
- token = `\u2400\u2400${token}\u2400\u2400`;
185
- }
186
- phpCodes[token] = replaceEnv(match, inputFile);
187
- return token;
188
- });
189
- return {
190
- escapedCode,
191
- phpCodes,
192
- write(outputFile) {
193
- writeFile(outputFile, escapedCode);
194
- writeFile(outputFile + ".json", JSON.stringify(phpCodes));
161
+ log.error = function(json, options = {}) {
162
+ let output = json;
163
+ let type = "info";
164
+ try {
165
+ const data = JSON.parse(json);
166
+ output = "";
167
+ switch (data.code) {
168
+ case EPHPError.PARSE:
169
+ case EPHPError.ERROR:
170
+ case EPHPError.CORE_ERROR:
171
+ case EPHPError.COMPILE_ERROR:
172
+ case EPHPError.USER_ERROR:
173
+ type = "error";
174
+ output += colors.bgRedBright(colors.white("Fatal Error"));
175
+ break;
176
+ case EPHPError.WARNING:
177
+ case EPHPError.USER_WARNING:
178
+ case EPHPError.COMPILE_WARNING:
179
+ case EPHPError.RECOVERABLE_ERROR:
180
+ type = "warn";
181
+ output += colors.yellowBright("Warning");
182
+ break;
183
+ case EPHPError.NOTICE:
184
+ case EPHPError.USER_NOTICE:
185
+ type = "info";
186
+ output += colors.bgWhite(colors.black("Notice"));
187
+ break;
188
+ case EPHPError.STRICT:
189
+ type = "info";
190
+ output += colors.yellow("Strict");
191
+ break;
192
+ case EPHPError.DEPRECATED:
193
+ case EPHPError.USER_DEPRECATED:
194
+ type = "info";
195
+ output += colors.cyan("Deprecated");
196
+ break;
197
+ default:
198
+ break;
195
199
  }
196
- };
197
- }
198
- function unescapePHP({ escapedCode, phpCodes }) {
199
- let out = escapedCode;
200
- Object.entries(phpCodes).forEach(([token, code]) => {
201
- out = out.replace(token, (match) => {
202
- return `${code}`;
203
- });
204
- });
205
- return out;
206
- }
200
+ output += " " + data.message + "\r\n";
201
+ output += " In: " + data.file.replace(
202
+ node_path.resolve(shared.tempDir),
203
+ shared.viteConfig?.root
204
+ ) + "\r\n";
205
+ output += " On line: " + data.line;
206
+ } catch (error) {
207
+ }
208
+ log(output, { ...options, type });
209
+ };
207
210
 
211
+ const PHP_Server = {
212
+ binary: "php",
213
+ port: 65535,
214
+ process: void 0,
215
+ start,
216
+ stop
217
+ };
208
218
  function start(root) {
209
- if (!globalThis.php?.pid) {
219
+ if (!PHP_Server.process?.pid) {
210
220
  const routerFileUrl = new URL("./router.php", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
211
- globalThis.php = child_process.spawn(phpServer.binary, [
221
+ PHP_Server.process = node_child_process.spawn(PHP_Server.binary, [
212
222
  "-S",
213
- "localhost:" + phpServer.port,
223
+ "localhost:" + PHP_Server.port,
214
224
  "-t",
215
225
  root,
216
226
  url.fileURLToPath(routerFileUrl)
217
227
  ]).once("spawn", () => {
218
- console.log(
219
- `PHP development server started (PID: ${globalThis.php?.pid})`
220
- );
228
+ log(`Server started (PID: ${PHP_Server.process?.pid})`);
221
229
  }).on("error", (error) => {
222
- console.error("PHP dev-server error: " + error.message);
223
- }).on("close", (code) => {
224
- console.log(`PHP development server stopped (Code: ${code})`);
230
+ log(`Server error: ${error.message})`, {
231
+ type: "error"
232
+ });
233
+ });
234
+ PHP_Server.process.stdout?.on("data", (data) => {
235
+ log("", { timestamp: true });
236
+ `${data}`.trim().split("\r\n").forEach((line) => {
237
+ if (line.startsWith(internalParam + ":")) {
238
+ log.error(
239
+ line.substring((internalParam + ":").length),
240
+ { prefix: false }
241
+ );
242
+ } else {
243
+ log(line);
244
+ }
245
+ });
225
246
  });
226
247
  }
227
248
  }
228
- function stop() {
229
- if (globalThis.php) {
230
- globalThis.php.stdin?.destroy();
231
- globalThis.php.stdout?.destroy();
232
- globalThis.php.stderr?.destroy();
233
- if (globalThis.php.kill()) {
234
- console.log("PHP development server killed");
249
+ function stop(callBack) {
250
+ if (PHP_Server.process) {
251
+ PHP_Server.process.on("close", (code) => {
252
+ log("Ended with: " + code);
253
+ PHP_Server.process = void 0;
254
+ callBack();
255
+ });
256
+ PHP_Server.process.stdin?.destroy();
257
+ PHP_Server.process.stdout?.destroy();
258
+ PHP_Server.process.stderr?.destroy();
259
+ if (PHP_Server.process.kill()) {
260
+ log("Shutting down");
235
261
  } else {
236
- console.error("Attention! Failed to kill PHP development server!");
262
+ log("Failed to send SIGTERM", {
263
+ type: "error"
264
+ });
237
265
  }
266
+ } else {
267
+ callBack();
238
268
  }
239
269
  }
240
- const phpServer = {
241
- binary: "php",
242
- port: 65535,
243
- start,
244
- stop
245
- };
246
270
 
247
271
  var tasks = {};
248
272
 
@@ -6961,7 +6985,8 @@ var out = FastGlob;
6961
6985
 
6962
6986
  const fastGlob = /*@__PURE__*/getDefaultExportFromCjs(out);
6963
6987
 
6964
- function consoleHijack(entries) {
6988
+ function consoleHijack() {
6989
+ const entries = shared.entries;
6965
6990
  ["log", "info", "warn", "error"].forEach((command) => {
6966
6991
  const cx = console[command];
6967
6992
  console[command] = function(...args) {
@@ -6977,307 +7002,458 @@ function consoleHijack(entries) {
6977
7002
  });
6978
7003
  }
6979
7004
 
6980
- const namespacePattern = new RegExp(
6981
- /(.+?)(<\?(?:php|)\s+namespace\s\S+?(?:\s*;|\s*{).+)(<\/.+?>|<.+?\/>)(.+|$)/,
7005
+ function readFile(file) {
7006
+ return node_fs.readFileSync(file, "utf-8").toString();
7007
+ }
7008
+ function writeFile(file, data) {
7009
+ node_fs.mkdirSync(node_path.dirname(file), { recursive: true });
7010
+ node_fs.writeFileSync(file, data);
7011
+ }
7012
+
7013
+ function makeID() {
7014
+ return Date.now().toString(36) + Math.random() * 100;
7015
+ }
7016
+
7017
+ function resolveEnvPrefix({ envPrefix = "VITE_" }) {
7018
+ envPrefix = Array.isArray(envPrefix) ? envPrefix : [envPrefix];
7019
+ if (envPrefix.includes("")) {
7020
+ throw new Error(
7021
+ `envPrefix option contains value '', which could lead unexpected exposure of sensitive information.`
7022
+ );
7023
+ }
7024
+ return envPrefix;
7025
+ }
7026
+ const envPattern = /%(\S+?)%/g;
7027
+ function initReplaceEnv() {
7028
+ hasViteConfig(shared.viteConfig);
7029
+ const { env, define, root, logger } = shared.viteConfig;
7030
+ const envPrefix = resolveEnvPrefix({
7031
+ envPrefix: shared.viteConfig.envPrefix
7032
+ });
7033
+ for (const key in define) {
7034
+ if (key.startsWith(`import.meta.env.`)) {
7035
+ const val = define[key];
7036
+ if (typeof val === "string") {
7037
+ try {
7038
+ const parsed = JSON.parse(val);
7039
+ env[key.slice(16)] = typeof parsed === "string" ? parsed : val;
7040
+ } catch {
7041
+ env[key.slice(16)] = val;
7042
+ }
7043
+ } else {
7044
+ env[key.slice(16)] = JSON.stringify(val);
7045
+ }
7046
+ }
7047
+ }
7048
+ return function replaceEnv(content, filename) {
7049
+ const relativeHtml = vite.normalizePath(node_path.relative(root, filename));
7050
+ return content.replace(envPattern, (text, key) => {
7051
+ if (key in env) {
7052
+ return env[key];
7053
+ } else {
7054
+ if (envPrefix.some((prefix) => key.startsWith(prefix))) {
7055
+ logger.warn(
7056
+ colors.yellow(
7057
+ colors.bold(
7058
+ `(!) ${text} is not defined in env variables found in /${relativeHtml}. Is the variable mistyped?`
7059
+ )
7060
+ )
7061
+ );
7062
+ }
7063
+ return text;
7064
+ }
7065
+ });
7066
+ };
7067
+ }
7068
+
7069
+ var __defProp = Object.defineProperty;
7070
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7071
+ var __publicField = (obj, key, value) => {
7072
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7073
+ return value;
7074
+ };
7075
+ const phpStartPattern = `<\\?(?:php|)`;
7076
+ const phpEndPattern = `\\?>`;
7077
+ const phpTagRegex = new RegExp(
7078
+ `${phpStartPattern}.+?(${phpEndPattern}|$)`,
7079
+ "gis"
7080
+ );
7081
+ class PHP_Code {
7082
+ constructor(code) {
7083
+ __publicField(this, "file", "!!__VIRTUAL__!!.php");
7084
+ __publicField(this, "code");
7085
+ __publicField(this, "mapping", {});
7086
+ this.code = code;
7087
+ return this;
7088
+ }
7089
+ static fromFile(file) {
7090
+ const inst = new this(readFile(file));
7091
+ inst.file = file;
7092
+ return inst;
7093
+ }
7094
+ applyEnv() {
7095
+ const replaceEnv = initReplaceEnv();
7096
+ this.code = replaceEnv(this.code, this.file || "");
7097
+ return this;
7098
+ }
7099
+ escape() {
7100
+ const isJS = this.file.includes(".js") || this.file.includes(".ts");
7101
+ const isML = this.file.includes(".php") || this.file.includes(".htm");
7102
+ this.code = this.code.replace(phpTagRegex, (match) => {
7103
+ let token = makeID();
7104
+ if (isJS) {
7105
+ token = `/*${token}*/`;
7106
+ } else if (isML) {
7107
+ token = `\u2400\u2400${token}\u2400\u2400`;
7108
+ }
7109
+ this.mapping[token] = match;
7110
+ return token;
7111
+ });
7112
+ return this;
7113
+ }
7114
+ write(file, mapping = false) {
7115
+ writeFile(file, this.code);
7116
+ mapping && writeFile(file + ".json", JSON.stringify(this.mapping));
7117
+ }
7118
+ static unescape(code, mapping) {
7119
+ let out = code;
7120
+ Object.entries(mapping).forEach(([token, code2]) => {
7121
+ out = out.replace(token, code2);
7122
+ });
7123
+ return out;
7124
+ }
7125
+ }
7126
+
7127
+ const serve = {
7128
+ rewriteUrl: (url) => url
7129
+ };
7130
+ function tempName(entry) {
7131
+ return `${shared.tempDir}/${entry}`;
7132
+ }
7133
+ const servePlugin = {
7134
+ name: "serve-php",
7135
+ apply: "serve",
7136
+ enforce: "post",
7137
+ configResolved() {
7138
+ function handleExit(signal) {
7139
+ if (signal === "SIGINT") {
7140
+ console.log();
7141
+ }
7142
+ const tempDir = node_path.resolve(shared.tempDir);
7143
+ if (shared.devConfig.cleanup && node_fs.existsSync(tempDir)) {
7144
+ log("Removing temporary files");
7145
+ node_fs.rmSync(tempDir, {
7146
+ recursive: true,
7147
+ force: true
7148
+ });
7149
+ }
7150
+ if (PHP_Server.process && shared.viteConfig?.command === "serve") {
7151
+ PHP_Server.stop(() => {
7152
+ process.exit();
7153
+ });
7154
+ } else {
7155
+ process.exit();
7156
+ }
7157
+ }
7158
+ [
7159
+ "exit",
7160
+ "SIGINT",
7161
+ "SIGUSR1",
7162
+ "SIGUSR2",
7163
+ "uncaughtException",
7164
+ "SIGTERM"
7165
+ ].forEach((eventType) => {
7166
+ new Promise((resolve2) => process.on(eventType, resolve2)).then(
7167
+ handleExit
7168
+ );
7169
+ });
7170
+ const gitIgnoreFile = node_path.resolve(`${shared.tempDir}/.gitignore`);
7171
+ if (!node_fs.existsSync(gitIgnoreFile)) {
7172
+ writeFile(gitIgnoreFile, "*\r\n**/*");
7173
+ }
7174
+ shared.entries.forEach((entry) => {
7175
+ PHP_Code.fromFile(entry).applyEnv().write(tempName(entry));
7176
+ });
7177
+ },
7178
+ configureServer(server) {
7179
+ if (!PHP_Server.process) {
7180
+ PHP_Server.start(server?.config.root);
7181
+ }
7182
+ server.middlewares.use(async (req, res, next) => {
7183
+ try {
7184
+ if (req.url && !["/@vite", "/@fs", "/@id/__x00__", "/node_modules"].some(
7185
+ (path) => req.url.startsWith(path)
7186
+ )) {
7187
+ req.on("error", (error) => {
7188
+ throw error;
7189
+ });
7190
+ const url = new URL(req.url, "http://localhost");
7191
+ if (shared.viteConfig?.server.port) {
7192
+ url.port = shared.viteConfig.server.port.toString();
7193
+ }
7194
+ const requestUrl = url.pathname;
7195
+ if (url.pathname.endsWith("/")) {
7196
+ url.pathname += "index.php";
7197
+ }
7198
+ const routedUrl = serve.rewriteUrl(url);
7199
+ if (routedUrl) {
7200
+ url.pathname = routedUrl.pathname;
7201
+ url.search = routedUrl.search;
7202
+ url.hash = routedUrl.hash;
7203
+ }
7204
+ const entryPathname = url.pathname.substring(1);
7205
+ const entry = shared.entries.find((file) => {
7206
+ return file === entryPathname || file.substring(0, file.lastIndexOf(".")) === entryPathname;
7207
+ });
7208
+ if (entry) {
7209
+ const tempFile = tempName(entry);
7210
+ if (node_fs.existsSync(node_path.resolve(tempFile))) {
7211
+ url.pathname = tempFile;
7212
+ url.port = PHP_Server.port.toString();
7213
+ url.searchParams.set(
7214
+ internalParam,
7215
+ new URLSearchParams({
7216
+ $REQUEST_URI: requestUrl,
7217
+ $PHP_SELF: "/" + entry,
7218
+ temp_dir: shared.tempDir,
7219
+ error_levels: shared.devConfig.errorLevels.toString()
7220
+ }).toString()
7221
+ );
7222
+ const body = await new Promise(
7223
+ (resolve2, reject) => {
7224
+ let data = [];
7225
+ req.on("data", (chunk) => {
7226
+ data.push(chunk);
7227
+ }).on("end", () => {
7228
+ resolve2(Buffer.concat(data));
7229
+ });
7230
+ }
7231
+ );
7232
+ const phpResult = await new Promise(async (resolve2, reject) => {
7233
+ const chunks = [];
7234
+ let statusCode;
7235
+ let incomingHeaders = {};
7236
+ const request = http__default.request(
7237
+ url.toString(),
7238
+ {
7239
+ method: req.method,
7240
+ headers: {
7241
+ ...req.headers,
7242
+ "content-length": Buffer.byteLength(body)
7243
+ }
7244
+ },
7245
+ (msg) => {
7246
+ statusCode = msg.statusCode;
7247
+ incomingHeaders = msg.headers;
7248
+ msg.on("data", (data) => {
7249
+ chunks.push(data);
7250
+ });
7251
+ }
7252
+ ).on("error", (error) => {
7253
+ reject(error);
7254
+ }).on("close", () => {
7255
+ const content = Buffer.concat(chunks).toString(
7256
+ "utf8"
7257
+ );
7258
+ resolve2({
7259
+ statusCode,
7260
+ headers: incomingHeaders,
7261
+ content
7262
+ });
7263
+ });
7264
+ request.write(body, (error) => {
7265
+ if (error) {
7266
+ reject(error);
7267
+ }
7268
+ });
7269
+ request.end();
7270
+ });
7271
+ let out = phpResult.content;
7272
+ if (phpResult.headers["content-type"]?.includes(
7273
+ "html"
7274
+ )) {
7275
+ out = await server.transformIndexHtml(
7276
+ `/${entry}.html`,
7277
+ out,
7278
+ requestUrl
7279
+ );
7280
+ }
7281
+ res.writeHead(
7282
+ phpResult.statusCode || 200,
7283
+ phpResult.headers
7284
+ ).end(out);
7285
+ return;
7286
+ }
7287
+ }
7288
+ }
7289
+ } catch (error) {
7290
+ console.error("Vite-PHP Error: " + error);
7291
+ }
7292
+ next();
7293
+ });
7294
+ },
7295
+ handleHotUpdate({ server, file }) {
7296
+ const entry = shared.entries.find(
7297
+ (entryFile) => node_path.resolve(entryFile) === node_path.resolve(file)
7298
+ );
7299
+ if (entry) {
7300
+ PHP_Code.fromFile(entry).applyEnv().write(tempName(entry));
7301
+ server.moduleGraph.invalidateAll();
7302
+ }
7303
+ if (entry || !file.startsWith(node_path.resolve(shared.tempDir)) && file.includes(".php")) {
7304
+ server.ws.send({
7305
+ type: "full-reload"
7306
+ });
7307
+ }
7308
+ }
7309
+ };
7310
+
7311
+ const assetsPattern = new RegExp(
7312
+ `^(.+?)(${phpStartPattern}\\s+namespace\\s\\S+?(?:\\s*;|\\s*{).+)$`,
6982
7313
  "si"
6983
7314
  );
6984
- function processOutput(input) {
7315
+ const lastTagPattern = new RegExp(`^(.+(?:</.+?>|<.+?/>))(.+|)$`, "si");
7316
+ const closingPattern = new RegExp(`^(.+)(${phpStartPattern}.+)$`, "si");
7317
+ function fixAssetsInjection(input) {
6985
7318
  let out = input;
6986
- out = out.replace(
6987
- namespacePattern,
6988
- (match, assets, contents, lastTag, trailingContent) => contents + lastTag + "\r\n" + assets.trim() + trailingContent
6989
- );
7319
+ let assets = "";
7320
+ out = out.replace(assetsPattern, (match, p1, p2) => {
7321
+ assets = p1.trim();
7322
+ return p2;
7323
+ });
7324
+ const injectAssets = (_, part1, part2) => {
7325
+ let a = assets;
7326
+ if (!(part1.endsWith("\n") || part1.endsWith("\r"))) {
7327
+ a = "\r\n" + a;
7328
+ }
7329
+ if (!(part2.startsWith("\n") || part2.startsWith("\r"))) {
7330
+ a += "\r\n";
7331
+ }
7332
+ assets = "";
7333
+ return `${part1}${a}${part2}`;
7334
+ };
7335
+ if (assets) {
7336
+ out = out.replace(lastTagPattern, injectAssets);
7337
+ }
7338
+ if (assets) {
7339
+ out = out.replace(closingPattern, injectAssets);
7340
+ }
7341
+ if (assets) {
7342
+ out += assets;
7343
+ }
6990
7344
  return out;
6991
7345
  }
6992
7346
 
6993
- const internalParam = "__314159265359__";
7347
+ const buildPlugin = {
7348
+ name: "build-php",
7349
+ apply: "build",
7350
+ enforce: "pre",
7351
+ resolveId(source, importer, options) {
7352
+ if (shared.entries.includes(source)) {
7353
+ return {
7354
+ // Rename ids because Vite transforms only .html files: https://github.com/vitejs/vite/blob/0cde495ebeb48bcfb5961784a30bfaed997790a0/packages/vite/src/node/plugins/html.ts#L330
7355
+ id: `${source}.html`,
7356
+ resolvedBy: "vite-plugin-php",
7357
+ meta: {
7358
+ originalId: source
7359
+ }
7360
+ };
7361
+ }
7362
+ },
7363
+ load(id, options) {
7364
+ const moduleInfo = this.getModuleInfo(id);
7365
+ const entry = moduleInfo?.meta.originalId;
7366
+ if (entry) {
7367
+ const php = PHP_Code.fromFile(entry).applyEnv().escape();
7368
+ return {
7369
+ code: php.code,
7370
+ meta: { phpMapping: php.mapping }
7371
+ };
7372
+ }
7373
+ },
7374
+ generateBundle: {
7375
+ order: "post",
7376
+ handler(options, bundle, isWrite) {
7377
+ Object.entries(bundle).forEach(([key, item]) => {
7378
+ if (item.type === "asset") {
7379
+ const moduleInfo = this.getModuleInfo(item.fileName);
7380
+ if (moduleInfo?.meta.originalId) {
7381
+ const meta = moduleInfo.meta;
7382
+ item.fileName = meta.originalId;
7383
+ if (meta.phpMapping) {
7384
+ item.source = PHP_Code.unescape(
7385
+ item.source.toString(),
7386
+ meta.phpMapping
7387
+ );
7388
+ }
7389
+ item.source = fixAssetsInjection(
7390
+ item.source.toString()
7391
+ );
7392
+ }
7393
+ } else if (item.type === "chunk" && item.facadeModuleId) {
7394
+ const moduleInfo = this.getModuleInfo(item.facadeModuleId);
7395
+ if (moduleInfo) {
7396
+ const meta = moduleInfo.meta;
7397
+ if (meta.phpMapping) {
7398
+ item.code = PHP_Code.unescape(
7399
+ item.code,
7400
+ meta.phpMapping
7401
+ );
7402
+ }
7403
+ item.code = fixAssetsInjection(item.code);
7404
+ }
7405
+ }
7406
+ });
7407
+ }
7408
+ }
7409
+ };
7410
+
6994
7411
  function usePHP(cfg = {}) {
6995
- const {
6996
- binary = "php",
6997
- entry = "index.php",
6998
- rewriteUrl = (requestUrl) => requestUrl,
6999
- tempDir = ".php-tmp",
7000
- cleanup = {}
7001
- } = cfg;
7002
- const { dev: devCleanup = true } = cleanup;
7003
- phpServer.binary = binary;
7004
- let config = void 0;
7005
- let viteServer = void 0;
7006
- let entries = Array.isArray(entry) ? entry : [entry];
7007
- function getTempFileName(file) {
7008
- return `${tempDir}/${file}.html`;
7009
- }
7010
- function cleanupTemp() {
7011
- require$$0$1.rmSync(tempDir, { recursive: true, force: true });
7012
- }
7013
- function onExit() {
7014
- if (config?.command === "serve") {
7015
- phpServer.stop();
7016
- devCleanup && cleanupTemp();
7017
- }
7018
- process.exit();
7019
- }
7020
- [
7021
- "exit",
7022
- "SIGINT",
7023
- "SIGUSR1",
7024
- "SIGUSR2",
7025
- "uncaughtException",
7026
- "SIGTERM"
7027
- ].forEach((eventType) => {
7028
- process.on(eventType, onExit.bind(null));
7029
- });
7412
+ const { entry = "index.php" } = cfg;
7413
+ PHP_Server.binary = cfg.binary ?? PHP_Server.binary;
7414
+ serve.rewriteUrl = cfg.rewriteUrl ?? serve.rewriteUrl;
7415
+ shared.entries = Array.isArray(entry) ? entry : [entry];
7416
+ shared.tempDir = cfg.tempDir ?? shared.tempDir;
7417
+ shared.devConfig = {
7418
+ cleanup: cfg.dev?.cleanup || shared.devConfig.cleanup,
7419
+ errorLevels: cfg.dev?.errorLevels || shared.devConfig.errorLevels
7420
+ };
7030
7421
  return [
7031
7422
  {
7032
- name: "prepare-php",
7423
+ name: "init-php",
7033
7424
  enforce: "post",
7034
- config(config2, env) {
7035
- const gitIgnoreFile = `${tempDir}/.gitignore`;
7036
- if (!require$$0$1.existsSync(gitIgnoreFile)) {
7037
- writeFile(gitIgnoreFile, "*\n**/*.php.html");
7038
- }
7039
- entries = [
7425
+ config(config, env) {
7426
+ shared.entries = [
7040
7427
  ...new Set(
7041
- entries.flatMap(
7428
+ shared.entries.flatMap(
7042
7429
  (entry2) => fastGlob.globSync(entry2, {
7043
7430
  dot: true,
7044
7431
  onlyFiles: true,
7045
7432
  unique: true,
7046
7433
  ignore: [
7047
- tempDir,
7048
- config2.build?.outDir || "dist"
7434
+ shared.tempDir,
7435
+ config.build?.outDir || "dist"
7049
7436
  ]
7050
7437
  })
7051
7438
  )
7052
7439
  )
7053
7440
  ];
7054
- consoleHijack(entries);
7441
+ consoleHijack();
7055
7442
  return {
7056
7443
  build: {
7057
- rollupOptions: { input: entries }
7444
+ rollupOptions: { input: shared.entries }
7058
7445
  },
7059
- optimizeDeps: { entries }
7446
+ optimizeDeps: { entries: shared.entries }
7060
7447
  };
7061
7448
  },
7062
7449
  configResolved(_config) {
7063
- config = _config;
7064
- }
7065
- },
7066
- {
7067
- name: "serve-php",
7068
- apply: "serve",
7069
- enforce: "pre",
7070
- configResolved(_config) {
7071
- config = _config;
7072
- entries.forEach((entry2) => {
7073
- const outputFile = getTempFileName(entry2);
7074
- escapePHP({
7075
- inputFile: entry2,
7076
- config
7077
- }).write(outputFile);
7078
- });
7079
- },
7080
- configureServer(server) {
7081
- viteServer = server;
7082
- phpServer.start(viteServer?.config.root);
7083
- server.middlewares.use(async (req, res, next) => {
7084
- try {
7085
- if (req.url && ![
7086
- "/@vite",
7087
- "/@fs",
7088
- "/@id/__x00__",
7089
- "/node_modules"
7090
- ].some((path) => req.url.startsWith(path))) {
7091
- req.on("error", (error) => {
7092
- throw error;
7093
- });
7094
- res.on("error", (error) => {
7095
- throw error;
7096
- });
7097
- const url = new URL(req.url, "http://localhost");
7098
- if (config?.server.port) {
7099
- url.port = config.server.port.toString();
7100
- }
7101
- const requestUrl = url.pathname;
7102
- if (url.pathname.endsWith("/")) {
7103
- url.pathname += "index.php";
7104
- }
7105
- const routedUrl = rewriteUrl(url);
7106
- if (routedUrl) {
7107
- url.pathname = routedUrl.pathname;
7108
- url.search = routedUrl.search;
7109
- url.hash = routedUrl.hash;
7110
- }
7111
- const entryPathname = url.pathname.substring(1);
7112
- const entry2 = entries.find((file) => {
7113
- return file === entryPathname || file.substring(0, file.lastIndexOf(".")) === entryPathname;
7114
- });
7115
- if (entry2) {
7116
- const tempFile = getTempFileName(entry2);
7117
- if (require$$0$1.existsSync(require$$0.resolve(tempFile))) {
7118
- url.pathname = tempFile;
7119
- url.port = phpServer.port.toString();
7120
- url.searchParams.set(
7121
- internalParam,
7122
- new URLSearchParams({
7123
- REQUEST_URI: requestUrl,
7124
- PHP_SELF: "/" + entry2
7125
- }).toString()
7126
- );
7127
- const body = await new Promise(
7128
- (resolve2, reject) => {
7129
- let data = [];
7130
- req.on("data", (chunk) => {
7131
- data.push(chunk);
7132
- }).on("end", () => {
7133
- resolve2(Buffer.concat(data));
7134
- });
7135
- }
7136
- );
7137
- const phpResult = await new Promise(async (resolve2, reject) => {
7138
- const chunks = [];
7139
- let statusCode;
7140
- let incomingHeaders = {};
7141
- const request = http__default.request(
7142
- url.toString(),
7143
- {
7144
- method: req.method,
7145
- headers: {
7146
- ...req.headers,
7147
- "content-length": Buffer.byteLength(
7148
- body
7149
- )
7150
- }
7151
- },
7152
- (msg) => {
7153
- statusCode = msg.statusCode;
7154
- incomingHeaders = msg.headers;
7155
- msg.on("data", (data) => {
7156
- chunks.push(data);
7157
- });
7158
- }
7159
- ).on("error", (error) => {
7160
- reject(error);
7161
- }).on("close", () => {
7162
- const content = Buffer.concat(
7163
- chunks
7164
- ).toString("utf8");
7165
- resolve2({
7166
- statusCode,
7167
- headers: incomingHeaders,
7168
- content
7169
- });
7170
- });
7171
- request.write(body, (error) => {
7172
- if (error) {
7173
- reject(error);
7174
- }
7175
- });
7176
- request.end();
7177
- });
7178
- let out = phpResult.content;
7179
- if (phpResult.headers["content-type"]?.includes("html")) {
7180
- out = await server.transformIndexHtml(
7181
- requestUrl,
7182
- out,
7183
- "/" + entryPathname
7184
- );
7185
- }
7186
- res.writeHead(
7187
- phpResult.statusCode || 200,
7188
- phpResult.headers
7189
- ).end(out);
7190
- return;
7191
- }
7192
- }
7193
- }
7194
- } catch (error) {
7195
- console.error("Vite-PHP Error: " + error);
7196
- }
7197
- next();
7198
- });
7199
- },
7200
- async handleHotUpdate({ server, file }) {
7201
- const entry2 = entries.find(
7202
- (entryFile) => require$$0.resolve(entryFile) === require$$0.resolve(file)
7203
- );
7204
- if (entry2) {
7205
- const outputFile = getTempFileName(entry2);
7206
- escapePHP({
7207
- inputFile: entry2,
7208
- config
7209
- }).write(outputFile);
7210
- server.moduleGraph.invalidateAll();
7211
- }
7212
- if (entry2 || !file.startsWith(require$$0.resolve(tempDir)) && file.includes(".php")) {
7213
- server.ws.send({
7214
- type: "full-reload"
7215
- });
7216
- }
7450
+ shared.viteConfig = _config;
7217
7451
  }
7218
7452
  },
7219
- {
7220
- name: "build-php",
7221
- apply: "build",
7222
- enforce: "pre",
7223
- resolveId(source, importer, options) {
7224
- if (entries.includes(source)) {
7225
- return {
7226
- // Rename ids because Vite transforms only .html files: https://github.com/vitejs/vite/blob/0cde495ebeb48bcfb5961784a30bfaed997790a0/packages/vite/src/node/plugins/html.ts#L330
7227
- id: `${source}.html`,
7228
- resolvedBy: "vite-plugin-php",
7229
- meta: {
7230
- originalId: source
7231
- }
7232
- };
7233
- }
7234
- },
7235
- load(id, options) {
7236
- const entry2 = this.getModuleInfo(id)?.meta.originalId;
7237
- if (entry2) {
7238
- const { escapedCode, phpCodes } = escapePHP({
7239
- inputFile: entry2,
7240
- config
7241
- });
7242
- return {
7243
- code: escapedCode,
7244
- meta: { phpCodes }
7245
- };
7246
- }
7247
- },
7248
- generateBundle: {
7249
- order: "post",
7250
- handler(options, bundle, isWrite) {
7251
- Object.entries(bundle).forEach(([key, item]) => {
7252
- if (item.type === "asset") {
7253
- const meta = this.getModuleInfo(
7254
- item.fileName
7255
- )?.meta;
7256
- if (meta?.originalId && meta?.phpCodes) {
7257
- item.fileName = meta.originalId;
7258
- item.source = unescapePHP({
7259
- escapedCode: item.source.toString(),
7260
- phpCodes: meta.phpCodes
7261
- });
7262
- item.source = processOutput(item.source);
7263
- }
7264
- } else if (item.type === "chunk" && item.facadeModuleId) {
7265
- const meta = this.getModuleInfo(
7266
- item.facadeModuleId
7267
- )?.meta;
7268
- if (meta?.phpCodes) {
7269
- item.code = unescapePHP({
7270
- escapedCode: item.code,
7271
- phpCodes: meta.phpCodes
7272
- });
7273
- item.code = processOutput(item.code);
7274
- }
7275
- }
7276
- });
7277
- }
7278
- }
7279
- }
7453
+ servePlugin,
7454
+ buildPlugin
7280
7455
  ];
7281
7456
  }
7282
7457
 
7283
- module.exports = usePHP;
7458
+ exports.EPHPError = EPHPError;
7459
+ exports.default = usePHP;