Refactoring: moved caddy packages to juicy/juicy, flat packages

pull/77/head
Milan Felix Šulc 4 years ago
parent fcf478d1f6
commit f113d8e1ea
No known key found for this signature in database
GPG Key ID: F85201150685F830

3
.gitignore vendored

@ -2,5 +2,8 @@
/node_modules
/packages/**/package-lock.json
# App
/dist
# Vercel
.vercel

@ -1,10 +1,24 @@
.PHONY: install build test-unit
.PHONY: install build test publish canary
install:
npx lerna exec npm install
npm install
build:
npx lerna exec npm run build
npm run build
test-unit:
npm run test-unit
build-watch:
npm run watch
test:
npm run test
test-watch:
npm run test-watch
publish:
rm -rf ./dist
npm publish --access public --tag latest
canary:
rm -rf ./dist
npm publish --access public --tag canary

@ -3,13 +3,11 @@ module.exports = {
verbose: true,
testEnvironment: "node",
testMatch: [
"**/packages/*/test/spec/**/*.js",
"**/test/spec/**/*.js",
],
testPathIgnorePatterns: [
"/build/",
"/docs/",
"/errors/",
"/examples/",
"/dist/",
"/node_modules/",
]
}

@ -1,8 +0,0 @@
{
"version": "0.0.0",
"npmClient": "npm",
"hoist": true,
"packages": [
"packages/*"
]
}

7800
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,18 +1,42 @@
{
"name": "vercel-php-monorepo",
"name": "vercel-php",
"description": "Vercel PHP runtime",
"version": "0.1.0",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://github.com/juicyfx/vercel-php",
"repository": {
"type": "git",
"url": "https://github.com/juicyfx/vercel-php.git"
},
"keywords": [
"vercel",
"zeit",
"now",
"php",
"builder",
"runtime",
"serverless",
"deployment"
],
"scripts": {
"test-unit": "jest --config unit.jest.config.js"
"watch": "tsc --watch",
"build": "tsc",
"test": "jest",
"test-watch": "jest --watch",
"prepublishOnly": "tsc"
},
"files": [
"dist"
],
"dependencies": {
"@libphp/amazon-linux-2-v74": "^0.0.6"
},
"devDependencies": {
"@now/build-utils": "^2.2.0",
"@types/glob": "^7.1.1",
"@types/node": "^13.9.5",
"async-retry": "^1.3.1",
"buffer-replace": "^1.0.0",
"fs-extra": "^9.0.0",
"@vercel/build-utils": "^2.4.0",
"@types/glob": "^7.1.2",
"@types/node": "^12.12.47",
"jest": "^26.0.1",
"lerna": "^3.20.2",
"node-fetch": "^2.6.0",
"typescript": "^3.8.3"
"typescript": "^3.9.5"
}
}

@ -1,5 +0,0 @@
# TS
/dist
# Node
/node_modules

@ -1,16 +0,0 @@
publish:
rm -rf ./dist
npm publish --access public --tag latest
publish-canary:
rm -rf ./dist
npm version --no-git-tag-version prerelease
npm publish --access public --tag canary
publish-experimental:
rm -rf ./dist
npm version --no-git-tag-version prerelease
npm publish --access public --tag experimental
test:
yarn test

@ -1,9 +0,0 @@
0.0.0.0:8000
# HTTPS
tls off
# PHP
fastcgi / 127.0.0.1:9000 php {
root /var/task/user
}

Binary file not shown.

@ -1,31 +0,0 @@
{
"name": "@now-php/caddy",
"description": "Caddy is part of now-php",
"version": "0.0.2-canary.1",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://github.com/juicyfx/now-php",
"repository": {
"type": "git",
"url": "https://github.com/juicyfx/now-php.git"
},
"scripts": {
"watch": "tsc --watch",
"build": "tsc",
"prepublishOnly": "tsc"
},
"files": [
"dist",
"native"
],
"dependencies": {
"now-php": "0.0.10"
},
"devDependencies": {
"@now/build-utils": "^0.9.4",
"@types/glob": "^7.1.1",
"@types/node": "^10.0.0",
"jest": "^26.0.1",
"typescript": "^3.5.3"
}
}

@ -1,67 +0,0 @@
import { parse as urlParse } from 'url';
import { join as pathJoin } from 'path';
export const getUserDir = (): string => pathJoin(process.env.LAMBDA_TASK_ROOT || '/', 'user');
export const getPhpDir = (): string => pathJoin(process.env.LAMBDA_TASK_ROOT || '/', 'php');
export const isDev = (): boolean => process.env.NOW_PHP_DEV === '1';
export function normalizeEvent(event: Event): AwsRequest {
if (event.Action === 'Invoke') {
const invokeEvent = JSON.parse(event.body);
const {
method, path, host, headers = {}, encoding,
}: InvokedEvent = invokeEvent;
let { body } = invokeEvent;
if (body) {
if (encoding === 'base64') {
body = Buffer.from(body, encoding);
} else if (encoding === undefined) {
body = Buffer.from(body);
} else {
throw new Error(`Unsupported encoding: ${encoding}`);
}
}
return {
method,
path,
host,
headers,
body,
};
}
const {
httpMethod: method, path, host, headers = {}, body,
} = event;
return {
method,
path,
host,
headers,
body,
};
}
export async function transformFromAwsRequest({
method, path, host, headers, body,
}: AwsRequest): Promise<PhpInput> {
const { pathname, search } = urlParse(path);
const filename = pathJoin(
getUserDir(),
process.env.NOW_ENTRYPOINT || pathname || '',
);
const uri = pathname + (search || '');
return { filename, path, uri, host, method, headers, body };
}
export function transformToAwsResponse({ statusCode, headers, body }: PhpOutput): AwsResponse {
return { statusCode, headers, body: body.toString('base64'), encoding: 'base64' };
}

@ -1,74 +0,0 @@
import path from "path";
import {
createLambda,
shouldServe,
rename,
FileFsRef,
BuildOptions,
FileBlob
} from '@now/build-utils';
import {
getPhpLibFiles,
getIncludedFiles
} from 'now-php/dist/utils';
// ###########################
// EXPORTS
// ###########################
export const version = 3;
export async function build({
files,
entrypoint,
workPath,
config = {},
meta = {},
}: BuildOptions) {
const includedFiles = await getIncludedFiles({ files, entrypoint, workPath, config, meta });
const userFiles = rename(includedFiles, name => path.join('user', name));
const bridgeFiles: Files = {
...await getPhpLibFiles(),
...{
'launcher.js': new FileFsRef({
fsPath: path.join(__dirname, 'launcher.js'),
}),
'helpers.js': new FileFsRef({
fsPath: path.join(__dirname, 'helpers.js'),
}),
'caddy': new FileFsRef({
mode: 0o755,
fsPath: path.join(__dirname, '../native/caddy'),
}),
'Caddyfile': new FileFsRef({
fsPath: path.join(__dirname, '../native/Caddyfile'),
}),
}
};
if (process.env.NOW_PHP_DEBUG === '1') {
console.log('🐘 Entrypoint:', entrypoint);
console.log('🐘 Config:', config);
console.log('🐘 Work path:', workPath);
console.log('🐘 Meta:', meta);
console.log('🐘 User files:', Object.keys(userFiles));
console.log('🐘 Bridge files:', Object.keys(bridgeFiles));
console.log('🐘 PHP: php.ini', (bridgeFiles['php/php.ini'] as FileBlob).data.toString());
}
const lambda = await createLambda({
files: { ...userFiles, ...bridgeFiles },
handler: 'launcher.launcher',
runtime: 'nodejs12.x',
environment: {
NOW_ENTRYPOINT: entrypoint,
NOW_PHP_DEV: meta.isDev ? '1' : '0'
},
});
return { output: lambda };
};
export { shouldServe };

@ -1,177 +0,0 @@
import { normalizeEvent, transformFromAwsRequest, transformToAwsResponse, isDev, getPhpDir, getUserDir } from "./helpers";
import { ChildProcess, spawn, SpawnOptions } from "child_process";
import http from 'http';
import net from 'net';
let connFpm: ChildProcess;
let connCaddy: ChildProcess;
async function startFpm() {
if (connFpm) {
console.log(`🐘 PHP FPM is already running`);
return;
}
console.log(`🐘 Spawning: PHP-FPM`);
// php spawn options
const options: SpawnOptions = {
stdio: ['pipe', 'pipe', 'pipe'],
env: process.env
};
// now vs now-dev
if (!isDev()) {
options.env!.PATH = `${getPhpDir()}:${process.env.PATH}`;
options.cwd = getPhpDir();
} else {
options.cwd = getUserDir();
}
const fpm = spawn(
'php-fpm',
['-c', 'php.ini', '--fpm-config', 'php-fpm.ini', '--nodaemonize'],
options
);
fpm.on('close', function (code, signal) {
console.log(`🐘 PHP-FPM process closed code ${code} and signal ${signal}`);
});
fpm.on('error', function (err) {
console.error(`🐘 PHP-FPM process errored ${err}`);
});
process.on('exit', () => {
fpm.kill();
})
await whenPortOpens(9000, 400);
connFpm = fpm;
}
async function startCaddy() {
if (connCaddy) {
console.log(`🚀 Caddy is already running`);
return;
}
console.log(`🚀 Spawning Caddy`);
const caddy = spawn(
'./caddy',
['-conf', 'Caddyfile', '-root', '/var/task/user'],
{
stdio: 'inherit',
cwd: '/var/task',
},
);
caddy.on('close', function (code, signal) {
console.log(`🚀 Caddy process closed code ${code} and signal ${signal}`);
});
caddy.on('error', function (err) {
console.error(`🚀 Caddy process errored ${err}`);
});
process.on('exit', () => {
caddy.kill();
})
await whenPortOpens(8000, 400);
connCaddy = caddy;
}
function whenPortOpensCallback(port: number, attempts: number, cb: (error?: string) => void) {
const client = net.connect(port, '127.0.0.1');
client.on('error', (error: string) => {
if (!attempts) return cb(error);
setTimeout(() => {
whenPortOpensCallback(port, attempts - 1, cb);
}, 50);
});
client.on('connect', () => {
client.destroy();
cb();
});
}
function whenPortOpens(port: number, attempts: number): Promise<void> {
return new Promise((resolve, reject) => {
whenPortOpensCallback(port, attempts, (error?: string) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
async function query({ uri, headers, method, body }: PhpInput): Promise<PhpOutput> {
if (!connFpm || !connCaddy) {
await Promise.all([
startFpm(),
startCaddy()
]);
}
return new Promise(resolve => {
const options = {
hostname: '127.0.0.1',
port: 8000,
path: `${uri}`,
method,
headers,
};
const req = http.request(options, (res) => {
const chunks: Uint8Array[] = [];
res.on('data', (data) => {
chunks.push(data);
});
res.on('end', () => {
resolve({
statusCode: res.statusCode || 200,
headers: res.headers,
body: Buffer.concat(chunks)
});
});
});
req.on('error', (error) => {
console.error('🚀 Caddy HTTP errored', error);
resolve({
body: Buffer.from(`🚀 Caddy HTTP error: ${error}`),
headers: {},
statusCode: 500
});
});
if (body) {
req.write(body);
}
req.end();
});
}
async function launcher(event: Event): Promise<AwsResponse> {
const awsRequest = normalizeEvent(event);
const input = await transformFromAwsRequest(awsRequest);
const output = await query(input);
return transformToAwsResponse(output);
}
exports.launcher = launcher;
// (async function() {
// console.log(await launcher({
// httpMethod: 'GET',
// path: '/index.php'
// }));
// })();

@ -1,62 +0,0 @@
type Headers = { [k: string]: string | string[] | undefined };
interface Files {
[filePath: string]: import('@now/build-utils').File;
}
interface MetaOptions {
meta: import('@now/build-utils').Meta;
}
interface PhpIni {
[k: string]: any,
}
interface AwsRequest {
method: string,
path: string,
host: string,
headers: Headers,
body: string,
}
interface AwsResponse {
statusCode: number,
headers: Headers,
body: string,
encoding?: string
}
interface Event {
Action: string,
body: string,
httpMethod: string,
path: string,
host: string,
headers: Headers,
encoding: string | undefined | null,
}
interface InvokedEvent {
method: string,
path: string,
host: string,
headers: Headers,
encoding: string | undefined | null,
}
interface PhpInput {
filename: string,
path: string,
uri: string,
host: string,
method: string,
headers: Headers,
body: string,
}
interface PhpOutput {
statusCode: number,
headers: Headers,
body: Buffer,
}

@ -1,11 +0,0 @@
const helpers = require('../../dist/helpers');
test('transform to AWS response', () => {
const response = helpers.transformToAwsResponse({
statusCode: 200,
headers: [],
body: "foo"
});
expect(response.body).toBe("foo");
});

@ -1,25 +0,0 @@
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"lib": [
"esnext"
],
"target": "esnext",
"module": "commonjs",
"outDir": "dist",
"sourceMap": false,
"declaration": true,
"typeRoots": [
"./node_modules/@types"
]
},
"include": [
"src/**/*"
],
"exclude": [
"dist",
"node_modules",
"test"
]
}

@ -1,5 +0,0 @@
# TS
/dist
# Node
/node_modules

@ -1,12 +0,0 @@
.PHONY: test
publish:
rm -rf ./dist
npm publish --access public --tag latest
publish-canary:
rm -rf ./dist
npm publish --access public --tag canary
test:
yarn test

@ -1,40 +0,0 @@
{
"name": "vercel-php",
"description": "Vercel PHP runtime",
"version": "0.1.0",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://github.com/juicyfx/vercel-php",
"repository": {
"type": "git",
"url": "https://github.com/juicyfx/vercel-php.git"
},
"keywords": [
"vercel",
"zeit",
"now",
"php",
"builder",
"runtime",
"serverless",
"deployment"
],
"scripts": {
"watch": "tsc --watch",
"build": "tsc",
"prepublishOnly": "tsc"
},
"files": [
"dist"
],
"dependencies": {
"@libphp/amazon-linux-2-v74": "^0.0.6"
},
"devDependencies": {
"@vercel/build-utils": "^2.4.0",
"@types/glob": "^7.1.2",
"@types/node": "^12.12.47",
"jest": "^26.0.1",
"typescript": "^3.9.5"
}
}

@ -6,7 +6,7 @@ import {
BuildOptions,
PrepareCacheOptions,
glob,
} from '@now/build-utils';
} from '@vercel/build-utils';
import {
getPhpFiles,
getLauncherFiles,
@ -69,8 +69,6 @@ export async function build({
await modifyPhpIni({ config, runtimeFiles, userFiles });
}
console.log('!', userFiles);
// Show some debug notes during build
if (process.env.NOW_PHP_DEBUG === '1') {
console.log('🐘 Entrypoint:', entrypoint);

@ -6,7 +6,7 @@ test('PHP is not installed', async () => {
log: jest.fn()
};
utils.ensureLocalPhp = jest.fn();
utils.ensureLocalPhp = jest.fn(() => false);
await builder.build({
files: [],

@ -26,6 +26,7 @@
"src/**/*.ts"
],
"exclude": [
"errors",
"dist",
"node_modules",
"test"
Loading…
Cancel
Save