Compare commits

...

26 Commits

Author SHA1 Message Date
Tim Neutkens
ce6f43eae7 Publish
- @now/build-utils@0.4.30-canary.0
 - @now/cgi@0.0.13-canary.0
 - @now/go@0.2.10-canary.0
 - @now/html-minifier@1.0.6-canary.0
 - @now/lambda@0.4.7-canary.0
 - @now/md@0.4.7-canary.0
 - @now/mdx-deck@0.4.16-canary.0
 - @now/next@0.0.79-canary.0
 - @now/node-bridge@0.1.9-canary.0
 - @now/node-server@0.4.24-canary.0
 - @now/node@0.4.26-canary.0
 - @now/optipng@0.4.7-canary.0
 - @now/php@0.4.11-canary.0
 - @now/python@0.0.40-canary.0
 - @now/static-build@0.4.15-canary.0
2018-11-18 14:49:58 +01:00
Tim Neutkens
2cfafe4054 Remove unused comment 2018-11-18 14:49:15 +01:00
Tim Neutkens
b195949881 Bring back canary publish job 2018-11-18 14:47:51 +01:00
Igor Klopov
b7c47fa587 Publish
- @now/build-utils@0.4.29
 - @now/cgi@0.0.12
 - @now/go@0.2.9
 - @now/html-minifier@1.0.5
 - @now/lambda@0.4.6
 - @now/md@0.4.6
 - @now/mdx-deck@0.4.15
 - @now/next@0.0.78
 - @now/node-bridge@0.1.8
 - @now/node-server@0.4.23
 - @now/node@0.4.25
 - @now/optipng@0.4.6
 - @now/php@0.4.10
 - @now/python@0.0.39
 - @now/static-build@0.4.14
2018-11-18 04:44:36 +03:00
Tim Neutkens
f3bcefe822 @now/next exclude package-lock.json / yarn.lock from entry directory (#39)
* @now/next exclude package-lock.json / yarn.lock

* Add typescript to now-next

* Add download and file-fs-ref types

* Add types for now-next

* Remove yarn.lock
2018-11-17 23:10:14 +01:00
Tim Neutkens
7a481c9515 Make PR builds reliable again (#45)
* Run yarn prettier --write --single-quote packages/**/*.js and yarn lint --fix

* Fix tsc error

* Try and make publish-stable only trigger on tag
2018-11-17 22:53:59 +01:00
Igor Klopov
af275c60bf Publish
- @now/node-server@0.4.23-canary.4
 - @now/node@0.4.25-canary.4
2018-11-17 02:37:03 +03:00
Igor Klopov
ded377dfc2 [node] bump ncc 2018-11-17 02:34:51 +03:00
Igor Klopov
0daaa1cf6a Publish
- @now/build-utils@0.4.29-canary.2
 - @now/cgi@0.0.12-canary.1
 - @now/go@0.2.9-canary.1
 - @now/html-minifier@1.0.5-canary.0
 - @now/lambda@0.4.6-canary.0
 - @now/md@0.4.6-canary.0
 - @now/mdx-deck@0.4.15-canary.0
 - @now/next@0.0.78-canary.1
 - @now/node-bridge@0.1.8-canary.1
 - @now/node-server@0.4.23-canary.3
 - @now/node@0.4.25-canary.3
 - @now/optipng@0.4.6-canary.0
 - @now/php@0.4.10-canary.1
 - @now/python@0.0.39-canary.1
 - @now/static-build@0.4.14-canary.0
2018-11-16 22:25:25 +03:00
Igor Klopov
6e928d1a68 run jest tests in parallel 2018-11-16 21:35:54 +03:00
Igor Klopov
791c26fdfe lint fixes to satisfy ci 2018-11-16 21:13:50 +03:00
Igor Klopov
c14451c2c5 Publish
- @now/build-utils@0.4.29-canary.1
 - @now/node-server@0.4.23-canary.2
 - @now/node@0.4.25-canary.2
2018-11-16 20:01:51 +03:00
Igor Klopov
846b229511 [build-utils] apply #38 manually 2018-11-16 19:50:04 +03:00
Igor Klopov
d832658226 [node] erase workPath in prepareCache + bugfix 2018-11-16 18:42:33 +03:00
Igor Klopov
2df09c7742 [node-server] erase workPath in prepareCache 2018-11-16 18:12:56 +03:00
Igor Klopov
e55b84b646 [build-utils] clear cache right away after npmInstall 2018-11-16 17:45:21 +03:00
Igor Klopov
265df1491e Publish
- @now/go@0.2.9-canary.0
 - @now/node-server@0.4.23-canary.1
 - @now/node@0.4.25-canary.1
 - @now/php@0.4.10-canary.0
 - @now/python@0.0.39-canary.0
2018-11-16 05:54:30 +03:00
Igor Klopov
f46c0dc747 [node-server] switch from rollup to ncc 2018-11-16 05:53:00 +03:00
Igor Klopov
1443e5435b [node] switch from rollup to ncc 2018-11-16 05:47:27 +03:00
Nathan Rajlich
b4fa4d35db Add builder config and default maxLambdaSize values (#36)
* Add builder `config` and default `maxLambdaSize` values

* 15mb max lambda zip for `@now/node-server`

* Fix merge weirdness
2018-11-15 17:56:28 -08:00
Igor Klopov
1f565c2570 Publish
- @now/build-utils@0.4.29-canary.0
 - @now/cgi@0.0.12-canary.0
 - @now/next@0.0.78-canary.0
 - @now/node-bridge@0.1.8-canary.0
 - @now/node-server@0.4.23-canary.0
 - @now/node@0.4.25-canary.0
2018-11-16 04:50:58 +03:00
Tim Neutkens
a2d95ae8ee Initial Typescript JSDoc integration (#33)
* Initial typescript jsdoc integration

* Fix trailing comma issue reported by @matheuss

* Add file-ref.js types

* Add BailableError

* Add typescript to lint command
2018-11-16 04:42:55 +03:00
Nathan Rajlich
fe15cc1b2c Add @now/cgi builder 2018-11-15 12:48:59 -08:00
Maarten Van Hoof
e8a9c49949 fix(Next): Fixed typo in environment (#34) 2018-11-15 17:59:42 +01:00
Tim Neutkens
f9233b2e24 Publish
- @now/build-utils@0.4.28
 - @now/go@0.2.8
 - @now/html-minifier@1.0.4
 - @now/lambda@0.4.5
 - @now/md@0.4.5
 - @now/mdx-deck@0.4.14
 - @now/next@0.0.77
 - @now/node-bridge@0.1.7
 - @now/node-server@0.4.22
 - @now/node@0.4.24
 - @now/optipng@0.4.5
 - @now/php@0.4.9
 - @now/python@0.0.38
 - @now/static-build@0.4.13
2018-11-14 16:16:43 +01:00
Tim Neutkens
bfa0c05e5d Install go before publishing 2018-11-14 16:16:06 +01:00
48 changed files with 2193 additions and 434 deletions

View File

@@ -24,26 +24,18 @@ jobs:
- run:
name: Tests
command: yarn test
# publish-canary:
# docker:
# - image: circleci/node:10
# working_directory: ~/repo
# steps:
# - checkout
# - run: yarn install
# - run: yarn bootstrap
# - run:
# name: Saving Authentication Information
# command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
# - run:
# name: Publishing to Canary Channel
# command: yarn run lerna publish from-git --npm-tag canary --yes
publish-stable:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- run:
name: Updating apt-get list
command: sudo apt-get update
- run:
name: Installing the latest version of Go
command: sudo apt-get install golang-go
- run: yarn install
- run: yarn bootstrap
- run:
@@ -52,23 +44,44 @@ jobs:
- run:
name: Publishing to Stable Channel
command: yarn run lerna publish from-git --yes
publish-canary:
docker:
- image: circleci/node:10
working_directory: ~/repo
steps:
- checkout
- run:
name: Updating apt-get list
command: sudo apt-get update
- run:
name: Installing the latest version of Go
command: sudo apt-get install golang-go
- run: yarn install
- run: yarn bootstrap
- run:
name: Saving Authentication Information
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
- run:
name: Publishing to Stable Channel
command: yarn run lerna publish from-git --npm-tag canary --yes
workflows:
version: 2
unscheduled:
build-and-deploy:
jobs:
- build:
filters:
tags:
only: /.*/
- build
- publish-stable:
requires:
- build
filters:
tags:
only: /^.*(\d+\.)(\d+\.)(\*|\d+)$/
# - publish-canary:
# requires:
# - build
# filters:
# tags:
# only: /^.*canary.*($|\b)/
only: /.*\d+\.\d+\.\d+$/
branches:
ignore: /.*/
- publish-canary:
requires:
- build
filters:
tags:
only: /.*-canary.*$/
branches:
ignore: /.*/

View File

@@ -1,10 +1,24 @@
{
"extends": ["airbnb-base", "prettier"],
"extends": ["prettier", "airbnb-base"],
"rules": {
"no-console": 0,
"import/no-unresolved": 0,
"import/no-dynamic-require": 0,
"global-require": 0
}
},
"overrides": [
{
"files": ["test/**"],
"rules": {
"import/no-extraneous-dependencies": 0
},
"globals": {
"describe": true,
"it": true,
"test": true,
"expect": true
}
}
]
}

View File

@@ -1,4 +1,5 @@
module.exports = {
testEnvironment: 'node',
rootDir: 'test',
collectCoverageFrom: ['packages/**/*.{js,jsx}', '!**/node_modules/**'],
};

View File

@@ -13,19 +13,23 @@
"bootstrap": "lerna bootstrap",
"publish-stable": "lerna version",
"publish-canary": "lerna version prerelease --preid canary",
"lint": "eslint .",
"test": "jest",
"lint": "tsc && eslint .",
"test": "jest --runInBand",
"lint-staged": "lint-staged"
},
"pre-commit": "lint-staged",
"lint-staged": {
"*.js": [
"eslint",
"prettier --write --single-quote",
"eslint --fix",
"git add"
]
},
"devDependencies": {
"@types/fs-extra": "^5.0.4",
"@types/glob": "^7.1.1",
"@types/multistream": "^2.1.1",
"@types/node": "^10.12.8",
"eslint": "^5.9.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.1.0",
@@ -33,6 +37,7 @@
"jest": "^23.6.0",
"lint-staged": "^8.0.4",
"pre-commit": "^1.2.2",
"prettier": "^1.15.2"
"prettier": "^1.15.2",
"typescript": "^3.1.6"
}
}

View File

@@ -1,20 +1,38 @@
const assert = require('assert');
const fs = require('fs-extra');
const MultiStream = require('multistream');
const multiStream = require('multistream');
const path = require('path');
const Sema = require('async-sema');
/** @typedef {{[filePath: string]: FileFsRef}} FsFiles */
const semaToPreventEMFILE = new Sema(30);
/**
* @constructor
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {string} options.fsPath
*/
class FileFsRef {
constructor({ mode = 0o100644, fsPath }) {
assert(typeof mode === 'number');
assert(typeof fsPath === 'string');
/** @type {string} */
this.type = 'FileFsRef';
/** @type {number} */
this.mode = mode;
/** @type {string} */
this.fsPath = fsPath;
}
/**
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {NodeJS.ReadableStream} options.stream
* @argument {string} options.fsPath
* @returns {Promise<FileFsRef>}
*/
static async fromStream({ mode = 0o100644, stream, fsPath }) {
assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream
@@ -24,37 +42,45 @@ class FileFsRef {
await new Promise((resolve, reject) => {
const dest = fs.createWriteStream(fsPath);
stream.pipe(dest);
stream.on('error', error => reject(error));
dest.on('finish', () => resolve());
dest.on('error', error => reject(error));
stream.on('error', reject);
dest.on('finish', resolve);
dest.on('error', reject);
});
await fs.chmod(fsPath, mode.toString(8).slice(-3));
return new FileFsRef({ mode, fsPath });
}
/**
* @returns {Promise<NodeJS.ReadableStream>}
*/
async toStreamAsync() {
await semaToPreventEMFILE.acquire();
const release = () => semaToPreventEMFILE.release();
const stream = fs.createReadStream(this.fsPath);
stream.on('end', release);
stream.on('close', release);
stream.on('error', release);
return stream;
}
/**
* @returns {NodeJS.ReadableStream}
*/
toStream() {
let flag;
// eslint-disable-next-line consistent-return
return new MultiStream((cb) => {
if (flag) return cb();
return multiStream((cb) => {
if (flag) return cb(null, null);
flag = true;
this.toStreamAsync().then((stream) => {
cb(undefined, stream);
}).catch((error) => {
cb(error);
});
this.toStreamAsync()
.then((stream) => {
cb(null, stream);
})
.catch((error) => {
cb(error, null);
});
});
}
}

View File

@@ -1,20 +1,42 @@
const assert = require('assert');
const fetch = require('node-fetch');
const MultiStream = require('multistream');
const multiStream = require('multistream');
const retry = require('async-retry');
const Sema = require('async-sema');
/** @typedef {{[filePath: string]: FileRef}} Files */
const semaToDownloadFromS3 = new Sema(10);
class BailableError extends Error {
constructor(...args) {
super(...args);
/** @type {boolean} */
this.bail = false;
}
}
/**
* @constructor
* @argument {Object} options
* @argument {number} [options.mode=0o100644]
* @argument {string} options.digest
*/
class FileRef {
constructor({ mode = 0o100644, digest }) {
assert(typeof mode === 'number');
assert(typeof digest === 'string');
/** @type {string} */
this.type = 'FileRef';
/** @type {number} */
this.mode = mode;
/** @type {string} */
this.digest = digest;
}
/**
* @returns {Promise<NodeJS.ReadableStream>}
*/
async toStreamAsync() {
let url;
// sha:24be087eef9fac01d61b30a725c1a10d7b45a256
@@ -29,34 +51,44 @@ class FileRef {
await semaToDownloadFromS3.acquire();
console.time(`downloading ${url}`);
try {
return await retry(async () => {
const resp = await fetch(url);
if (!resp.ok) {
const error = new Error(`${resp.status} ${resp.statusText}`);
if (resp.status === 403) error.bail = true;
throw error;
}
return resp.body;
}, { factor: 1, retries: 3 });
return await retry(
async () => {
const resp = await fetch(url);
if (!resp.ok) {
const error = new BailableError(
`${resp.status} ${resp.statusText}`,
);
if (resp.status === 403) error.bail = true;
throw error;
}
return resp.body;
},
{ factor: 1, retries: 3 },
);
} finally {
console.timeEnd(`downloading ${url}`);
semaToDownloadFromS3.release();
}
}
/**
* @returns {NodeJS.ReadableStream}
*/
toStream() {
let flag;
// eslint-disable-next-line consistent-return
return new MultiStream((cb) => {
if (flag) return cb();
return multiStream((cb) => {
if (flag) return cb(null, null);
flag = true;
this.toStreamAsync().then((stream) => {
cb(undefined, stream);
}).catch((error) => {
cb(error);
});
this.toStreamAsync()
.then((stream) => {
cb(null, stream);
})
.catch((error) => {
cb(error, null);
});
});
}
}

View File

@@ -1,20 +1,38 @@
const path = require('path');
const FileFsRef = require('../file-fs-ref.js');
/** @typedef {import('../file-ref')} FileRef */
/** @typedef {import('../file-fs-ref')} FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/** @typedef {{[filePath: string]: FileFsRef}|{}} DownloadedFiles */
/**
* @param {FileRef|FileFsRef} file
* @param {string} fsPath
* @returns {Promise<FileFsRef>}
*/
async function downloadFile(file, fsPath) {
const { mode } = file;
const stream = file.toStream();
return FileFsRef.fromStream({ mode, stream, fsPath });
}
/**
* Download files to disk
* @argument {Files} files
* @argument {string} basePath
* @returns {Promise<DownloadedFiles>}
*/
module.exports = async function download(files, basePath) {
const files2 = {};
await Promise.all(Object.keys(files).map(async (name) => {
const file = files[name];
const fsPath = path.join(basePath, name);
files2[name] = await downloadFile(file, fsPath);
}));
await Promise.all(
Object.keys(files).map(async (name) => {
const file = files[name];
const fsPath = path.join(basePath, name);
files2[name] = await downloadFile(file, fsPath);
}),
);
return files2;
};

View File

@@ -3,15 +3,30 @@ const path = require('path');
const vanillaGlob = require('glob');
const FileFsRef = require('../file-fs-ref.js');
/** @typedef {import('fs').Stats} Stats */
/** @typedef {import('glob').IOptions} GlobOptions */
/** @typedef {import('../file-fs-ref').FsFiles|{}} GlobFiles */
/**
* @argument {string} pattern
* @argument {GlobOptions|string} opts
* @argument {string} [mountpoint]
* @returns {Promise<GlobFiles>}
*/
module.exports = function glob(pattern, opts = {}, mountpoint) {
return new Promise((resolve, reject) => {
let options = opts;
if (typeof options === 'string') {
options = { cwd: options };
/** @type {GlobOptions} */
let options;
if (typeof opts === 'string') {
options = { cwd: opts };
} else {
options = opts;
}
if (!options.cwd) {
throw new Error('Second argument (basePath) must be specified for names of resulting files');
throw new Error(
'Second argument (basePath) must be specified for names of resulting files',
);
}
if (!path.isAbsolute(options.cwd)) {
@@ -26,21 +41,27 @@ module.exports = function glob(pattern, opts = {}, mountpoint) {
vanillaGlob(pattern, options, (error, files) => {
if (error) return reject(error);
resolve(files.reduce((files2, relativePath) => {
const fsPath = path.join(options.cwd, relativePath);
const stat = options.statCache[fsPath];
assert(stat, `statCache does not contain value for ${relativePath} (resolved to ${fsPath})`);
if (stat.isFile()) {
let finalPath = relativePath;
if (mountpoint) finalPath = path.join(mountpoint, finalPath);
return {
...files2,
[finalPath]: new FileFsRef({ mode: stat.mode, fsPath }),
};
}
resolve(
files.reduce((files2, relativePath) => {
const fsPath = path.join(options.cwd, relativePath);
/** @type {Stats|any} */
const stat = options.statCache[fsPath];
assert(
stat,
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`,
);
if (stat && stat.isFile()) {
let finalPath = relativePath;
if (mountpoint) finalPath = path.join(mountpoint, finalPath);
return {
...files2,
[finalPath]: new FileFsRef({ mode: stat.mode, fsPath }),
};
}
return files2;
}, {}));
return files2;
}, {}),
);
});
});
};

View File

@@ -1,6 +1,25 @@
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/**
* @callback delegate
* @argument {string} name
* @returns {string}
*/
/**
* Rename files using delegate function
* @argument {Files} files
* @argument {delegate} delegate
* @returns {Files}
*/
module.exports = function rename(files, delegate) {
return Object.keys(files).reduce((newFiles, name) => ({
...newFiles,
[delegate(name)]: files[name],
}), {});
return Object.keys(files).reduce(
(newFiles, name) => ({
...newFiles,
[delegate(name)]: files[name],
}),
{},
);
};

View File

@@ -6,7 +6,9 @@ function spawnAsync(command, args, cwd) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, { stdio: 'inherit', cwd });
child.on('error', reject);
child.on('close', (code, signal) => (code !== 0 ? reject(new Error(`Exited with ${code || signal}`)) : resolve()));
child.on('close', (code, signal) => (code !== 0
? reject(new Error(`Exited with ${code || signal}`))
: resolve()));
});
}
@@ -43,8 +45,10 @@ async function runNpmInstall(destPath, args = []) {
if (await shouldUseNpm(destPath)) {
commandArgs = args.filter(a => a !== '--prefer-offline');
await spawnAsync('npm', ['install'].concat(commandArgs), destPath);
await spawnAsync('npm', ['cache', 'clean', '--force'], destPath);
} else {
await spawnAsync('yarn', ['--cwd', destPath].concat(commandArgs), destPath);
await spawnAsync('yarn', ['cache', 'clean'], destPath);
}
}
@@ -55,7 +59,11 @@ async function runPackageJsonScript(destPath, scriptName) {
await spawnAsync('npm', ['run', scriptName], destPath);
} else {
console.log(`running "yarn run ${scriptName}"`);
await spawnAsync('yarn', ['--cwd', destPath, 'run', scriptName], destPath);
await spawnAsync(
'yarn',
['--cwd', destPath, 'run', scriptName],
destPath,
);
}
} catch (error) {
console.log(error.message);

View File

@@ -25,16 +25,21 @@ async function createLambda({
assert(typeof environment === 'object', '"environment" is not an object');
const zipFile = new ZipFile();
Object.keys(files).sort().forEach((name) => {
const file = files[name];
const stream = file.toStream();
zipFile.addReadStream(stream, name, { mode: file.mode, mtime });
});
Object.keys(files)
.sort()
.forEach((name) => {
const file = files[name];
const stream = file.toStream();
zipFile.addReadStream(stream, name, { mode: file.mode, mtime });
});
zipFile.end();
const zipBuffer = await streamToBuffer(zipFile.outputStream);
return new Lambda({
zipBuffer, handler, runtime, environment,
zipBuffer,
handler,
runtime,
environment,
});
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "0.4.27",
"version": "0.4.30-canary.0",
"dependencies": {
"async-retry": "1.2.3",
"async-sema": "2.1.4",

View File

@@ -0,0 +1,32 @@
root = true
[*]
indent_style = tab
indent_size = 4
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,*.json.example,*.gyp,*.yml}]
indent_style = space
indent_size = 2
[*.py]
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false
# Ideal settings - some plugins might support these.
[*.js]
quote_type = single
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.d,*.cs,*.swift}]
curly_bracket_next_line = false
spaces_around_operators = true
spaces_around_brackets = outside
# close enough to 1TB
indent_brace_style = K&R

2
packages/now-cgi/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
handler

4
packages/now-cgi/build.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
export GOOS=linux
export GOARCH=amd64
go build -o handler main.go

42
packages/now-cgi/index.js Normal file
View File

@@ -0,0 +1,42 @@
const path = require('path');
const { mkdirp, copyFile } = require('fs-extra');
const glob = require('@now/build-utils/fs/glob');
const download = require('@now/build-utils/fs/download');
const { createLambda } = require('@now/build-utils/lambda');
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory');
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({ files, entrypoint }) => {
console.log('downloading files...');
const srcDir = await getWritableDirectory();
const outDir = await getWritableDirectory();
await download(files, srcDir);
const handlerPath = path.join(__dirname, 'handler');
await copyFile(handlerPath, path.join(outDir, 'handler'));
const entrypointOutDir = path.join(outDir, path.dirname(entrypoint));
await mkdirp(entrypointOutDir);
// For now only the entrypoint file is copied into the lambda
await copyFile(
path.join(srcDir, entrypoint),
path.join(outDir, entrypoint),
);
const lambda = await createLambda({
files: await glob('**', outDir),
handler: 'handler',
runtime: 'go1.x',
environment: {
SCRIPT_FILENAME: entrypoint,
},
});
return {
[entrypoint]: lambda,
};
};

152
packages/now-cgi/main.go Normal file
View File

@@ -0,0 +1,152 @@
package main
import (
"os"
"fmt"
"net"
"strings"
"io/ioutil"
"net/http"
"net/http/cgi"
"path/filepath"
"encoding/json"
b64 "encoding/base64"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
type Request struct {
Host string `json:"host"`
Path string `json:"path"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Encoding string `json:"encoding,omitempty"`
Body string `json:"body"`
}
type Response struct {
StatusCode int `json:"statusCode"`
Headers map[string]string `json:"headers"`
Encoding string `json:"encoding,omitemtpy"`
Body string `json:"body"`
}
type ResponseError struct {
Code string `json:"code"`
Message string `json:"message"`
}
type ResponseErrorWrapper struct {
Error ResponseError `json:"error"`
}
type CgiHandler struct {
http.Handler
Dir string
Script string
}
func createErrorResponse(message string, code string, statusCode int) (Response, error) {
obj := ResponseErrorWrapper{
Error: ResponseError{
Code: code,
Message: message,
},
}
body, _ := json.Marshal(obj)
return Response{
StatusCode: statusCode,
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: string(body),
}, nil
}
func (h *CgiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cgih := cgi.Handler{
Path: h.Script,
Root: "/" + h.Script,
Dir: h.Dir,
Env: []string{"SERVER_PORT=443"},
}
cgih.ServeHTTP(w, r)
}
func main() {
l, err := net.Listen("tcp", ":0")
if err != nil {
panic(err)
}
workdir, _ := filepath.Abs(".")
script := os.Getenv("SCRIPT_FILENAME")
h := &CgiHandler{nil, workdir, script}
http.Handle("/", h)
go http.Serve(l, nil)
handler := func(_req events.APIGatewayProxyRequest) (Response, error) {
var req Request
err := json.Unmarshal([]byte(_req.Body), &req)
if err != nil {
fmt.Println(err)
return createErrorResponse("Invalid payload", "bad_request", 400)
}
if req.Encoding == "base64" {
decoded, _ := b64.StdEncoding.DecodeString(req.Body)
req.Body = string(decoded)
}
url := "http://" + l.Addr().String() + req.Path
internalReq, err := http.NewRequest(req.Method, url, strings.NewReader(req.Body))
if err != nil {
fmt.Println(err)
return createErrorResponse("Bad gateway internal req failed", "bad_gateway", 502)
}
for k, v := range req.Headers {
internalReq.Header.Add(k, v)
if strings.ToLower(k) == "host" {
internalReq.Host = v
}
}
client := &http.Client{}
internalRes, err := client.Do(internalReq)
if err != nil {
fmt.Println(err)
return createErrorResponse("Bad gateway internal req Do failed", "bad_gateway", 502)
}
defer internalRes.Body.Close()
resHeaders := make(map[string]string, len(internalRes.Header))
for k, v := range internalRes.Header {
// FIXME: support multiple values via concatenating with ','
// see RFC 7230, section 3.2.2
resHeaders[k] = v[0]
}
bodyBytes, err := ioutil.ReadAll(internalRes.Body)
if err != nil {
return createErrorResponse("Bad gateway ReadAll bytes from response failed", "bad_gateway", 502)
}
resBody := b64.StdEncoding.EncodeToString(bodyBytes)
return Response{
StatusCode: internalRes.StatusCode,
Headers: resHeaders,
Encoding: "base64",
Body: resBody,
}, nil
}
lambda.Start(handler)
}

View File

@@ -0,0 +1,22 @@
{
"name": "@now/cgi",
"version": "0.0.13-canary.0",
"scripts": {
"test": "best -I test/*.js",
"prepublish": "./build.sh"
},
"files": [
"index.js",
"handler"
],
"dependencies": {
"fs-extra": "7.0.0"
},
"devDependencies": {
"@zeit/best": "0.4.3",
"rmfr": "2.0.0"
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}
}

862
packages/now-cgi/yarn.lock Normal file
View File

@@ -0,0 +1,862 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
dependencies:
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
"@nodelib/fs.stat@^1.0.1":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
"@zeit/best@0.4.3":
version "0.4.3"
resolved "http://registry.npmjs.org/@zeit/best/-/best-0.4.3.tgz#eaebdfa8b24121a97b1753501ea8c9330d549b30"
dependencies:
arg "1.0.0"
chalk "2.3.1"
diff "3.5.0"
globby "8.0.0"
signal-exit "3.0.2"
ansi-styles@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
append-type@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/append-type/-/append-type-1.0.1.tgz#e29a6eb22cec0c0b9b93063b3cf6b10d9e0c60f4"
arg@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050"
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
arr-flatten@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
arr-union@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
array-to-sentence@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc"
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
dependencies:
array-uniq "^1.0.1"
array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
array-unique@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
assert-valid-glob-opts@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-valid-glob-opts/-/assert-valid-glob-opts-1.0.0.tgz#ab9b5438ec5e929f5bb08201819affb1227f730a"
dependencies:
glob-option-error "^1.0.0"
validate-glob-opts "^1.0.0"
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
atob@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
dependencies:
cache-base "^1.0.1"
class-utils "^0.3.5"
component-emitter "^1.2.1"
define-property "^1.0.0"
isobject "^3.0.1"
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
dependencies:
arr-flatten "^1.1.0"
array-unique "^0.3.2"
extend-shallow "^2.0.1"
fill-range "^4.0.0"
isobject "^3.0.1"
repeat-element "^1.1.2"
snapdragon "^0.8.1"
snapdragon-node "^2.0.1"
split-string "^3.0.2"
to-regex "^3.0.1"
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
dependencies:
collection-visit "^1.0.0"
component-emitter "^1.2.1"
get-value "^2.0.6"
has-value "^1.0.0"
isobject "^3.0.1"
set-value "^2.0.0"
to-object-path "^0.3.0"
union-value "^1.0.0"
unset-value "^1.0.0"
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
chalk@2.3.1:
version "2.3.1"
resolved "http://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
dependencies:
ansi-styles "^3.2.0"
escape-string-regexp "^1.0.5"
supports-color "^5.2.0"
class-utils@^0.3.5:
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
dependencies:
arr-union "^3.1.0"
define-property "^0.2.5"
isobject "^3.0.0"
static-extend "^0.1.1"
collection-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
dependencies:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
component-emitter@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
define-property@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
dependencies:
is-descriptor "^0.1.0"
define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
dependencies:
is-descriptor "^1.0.0"
define-property@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
dependencies:
is-descriptor "^1.0.2"
isobject "^3.0.1"
diff@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
dir-glob@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
dependencies:
arrify "^1.0.1"
path-type "^3.0.0"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
expand-brackets@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
dependencies:
debug "^2.3.3"
define-property "^0.2.5"
extend-shallow "^2.0.1"
posix-character-classes "^0.1.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.1"
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
dependencies:
is-extendable "^0.1.0"
extend-shallow@^3.0.0, extend-shallow@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
dependencies:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extglob@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
dependencies:
array-unique "^0.3.2"
define-property "^1.0.0"
expand-brackets "^2.1.4"
extend-shallow "^2.0.1"
fragment-cache "^0.2.1"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.1"
fast-glob@^2.0.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.3.tgz#d09d378e9ef6b0076a0fa1ba7519d9d4d9699c28"
dependencies:
"@mrmlnc/readdir-enhanced" "^2.2.1"
"@nodelib/fs.stat" "^1.0.1"
glob-parent "^3.1.0"
is-glob "^4.0.0"
merge2 "^1.2.1"
micromatch "^3.1.10"
fill-range@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
dependencies:
extend-shallow "^2.0.1"
is-number "^3.0.0"
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
fragment-cache@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
dependencies:
map-cache "^0.2.2"
fs-extra@7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
glob-option-error@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/glob-option-error/-/glob-option-error-1.0.0.tgz#57cc65def9c7d5c1461baf13129bb5403cff6176"
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
dependencies:
is-glob "^3.1.0"
path-dirname "^1.0.0"
glob-to-regexp@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
glob@^7.0.5, glob@^7.1.2:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
globby@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.0.tgz#e6f8340ead9a52fa417ec0e75ae664ae0026f5c6"
dependencies:
array-union "^1.0.1"
dir-glob "^2.0.0"
fast-glob "^2.0.2"
glob "^7.1.2"
ignore "^3.3.5"
pify "^3.0.0"
slash "^1.0.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.14"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.14.tgz#1b6e8362ef8c5ecb5da799901f39297e3054773a"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
has-value@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
dependencies:
get-value "^2.0.3"
has-values "^0.1.4"
isobject "^2.0.0"
has-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
dependencies:
get-value "^2.0.6"
has-values "^1.0.0"
isobject "^3.0.0"
has-values@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
has-values@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
dependencies:
is-number "^3.0.0"
kind-of "^4.0.0"
ignore@^3.3.5:
version "3.3.10"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
indexed-filter@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/indexed-filter/-/indexed-filter-1.0.3.tgz#7911439191cac588188464640a8db4f6b324973d"
dependencies:
append-type "^1.0.1"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
inspect-with-kind@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz#fce151d4ce89722c82ca8e9860bb96f9167c316c"
dependencies:
kind-of "^6.0.2"
is-accessor-descriptor@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
dependencies:
kind-of "^3.0.2"
is-accessor-descriptor@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
dependencies:
kind-of "^6.0.0"
is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
dependencies:
kind-of "^3.0.2"
is-data-descriptor@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
dependencies:
kind-of "^6.0.0"
is-descriptor@^0.1.0:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
dependencies:
is-accessor-descriptor "^0.1.6"
is-data-descriptor "^0.1.4"
kind-of "^5.0.0"
is-descriptor@^1.0.0, is-descriptor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
dependencies:
is-accessor-descriptor "^1.0.0"
is-data-descriptor "^1.0.0"
kind-of "^6.0.2"
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
is-extendable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
dependencies:
is-plain-object "^2.0.4"
is-extglob@^2.1.0, is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
is-glob@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
dependencies:
is-extglob "^2.1.0"
is-glob@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
dependencies:
is-extglob "^2.1.1"
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
dependencies:
kind-of "^3.0.2"
is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
dependencies:
isobject "^3.0.1"
is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
isarray@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
dependencies:
isarray "1.0.0"
isobject@^3.0.0, isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
optionalDependencies:
graceful-fs "^4.1.6"
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
dependencies:
is-buffer "^1.1.5"
kind-of@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
dependencies:
is-buffer "^1.1.5"
kind-of@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
kind-of@^6.0.0, kind-of@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
map-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
dependencies:
object-visit "^1.0.0"
merge2@^1.2.1:
version "1.2.3"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
micromatch@^3.1.10:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
braces "^2.3.1"
define-property "^2.0.2"
extend-shallow "^3.0.2"
extglob "^2.0.4"
fragment-cache "^0.2.1"
kind-of "^6.0.2"
nanomatch "^1.2.9"
object.pick "^1.3.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.2"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
dependencies:
for-in "^1.0.2"
is-extendable "^1.0.1"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
define-property "^2.0.2"
extend-shallow "^3.0.2"
fragment-cache "^0.2.1"
is-windows "^1.0.2"
kind-of "^6.0.2"
object.pick "^1.3.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.1"
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
dependencies:
copy-descriptor "^0.1.0"
define-property "^0.2.5"
kind-of "^3.0.3"
object-visit@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
dependencies:
isobject "^3.0.0"
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
dependencies:
isobject "^3.0.1"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
pascalcase@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
dependencies:
pify "^3.0.0"
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
regex-not@^1.0.0, regex-not@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
dependencies:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
repeat-element@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies:
glob "^7.0.5"
rmfr@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/rmfr/-/rmfr-2.0.0.tgz#8a42e81332550b3f0019b8fb8ab245bea81b6d1c"
dependencies:
assert-valid-glob-opts "^1.0.0"
glob "^7.1.2"
graceful-fs "^4.1.11"
inspect-with-kind "^1.0.4"
rimraf "^2.6.2"
safe-regex@^1.1.0:
version "1.1.0"
resolved "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
dependencies:
ret "~0.1.10"
set-value@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
is-plain-object "^2.0.1"
to-object-path "^0.3.0"
set-value@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
dependencies:
extend-shallow "^2.0.1"
is-extendable "^0.1.1"
is-plain-object "^2.0.3"
split-string "^3.0.1"
signal-exit@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
dependencies:
define-property "^1.0.0"
isobject "^3.0.0"
snapdragon-util "^3.0.1"
snapdragon-util@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
dependencies:
kind-of "^3.2.0"
snapdragon@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
dependencies:
base "^0.11.1"
debug "^2.2.0"
define-property "^0.2.5"
extend-shallow "^2.0.1"
map-cache "^0.2.2"
source-map "^0.5.6"
source-map-resolve "^0.5.0"
use "^3.1.0"
source-map-resolve@^0.5.0:
version "0.5.2"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
dependencies:
atob "^2.1.1"
decode-uri-component "^0.2.0"
resolve-url "^0.2.1"
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
dependencies:
extend-shallow "^3.0.0"
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
dependencies:
define-property "^0.2.5"
object-copy "^0.1.0"
supports-color@^5.2.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
dependencies:
has-flag "^3.0.0"
to-object-path@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
dependencies:
kind-of "^3.0.2"
to-regex-range@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
dependencies:
is-number "^3.0.0"
repeat-string "^1.6.1"
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
dependencies:
define-property "^2.0.2"
extend-shallow "^3.0.2"
regex-not "^1.0.2"
safe-regex "^1.1.0"
union-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
dependencies:
arr-union "^3.1.0"
get-value "^2.0.6"
is-extendable "^0.1.1"
set-value "^0.4.3"
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
unset-value@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
dependencies:
has-value "^0.3.1"
isobject "^3.0.0"
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
validate-glob-opts@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/validate-glob-opts/-/validate-glob-opts-1.0.2.tgz#ef9f98977d965537ea4f51fa7d5799e9c6ebca91"
dependencies:
array-to-sentence "^1.1.0"
indexed-filter "^1.0.0"
inspect-with-kind "^1.0.4"
is-plain-obj "^1.1.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"

View File

@@ -17,6 +17,10 @@ async function createGoPathTree(goPath) {
await mkdirp(path.join(goPath, 'pkg', 'linux_amd64'));
}
exports.config = {
maxLambdaSize: '10mb',
};
exports.build = async ({ files, entrypoint }) => {
console.log('downloading files...');
@@ -57,15 +61,25 @@ exports.build = async ({ files, entrypoint }) => {
}
if (handlerFunctionName === '') {
const e = new Error(`Could not find an exported function on "${entrypoint}"`);
const e = new Error(
`Could not find an exported function on "${entrypoint}"`,
);
console.log(e.message);
throw e;
}
console.log(`Found exported function "${handlerFunctionName}" on "${entrypoint}"`);
console.log(
`Found exported function "${handlerFunctionName}" on "${entrypoint}"`,
);
const origianlMainGoContents = await readFile(path.join(__dirname, 'main.go'), 'utf8');
const mainGoContents = origianlMainGoContents.replace('__NOW_HANDLER_FUNC_NAME', handlerFunctionName);
const origianlMainGoContents = await readFile(
path.join(__dirname, 'main.go'),
'utf8',
);
const mainGoContents = origianlMainGoContents.replace(
'__NOW_HANDLER_FUNC_NAME',
handlerFunctionName,
);
// in order to allow the user to have `main.go`, we need our `main.go` to be called something else
const mainGoFileName = 'main__now__go__.go';
@@ -77,12 +91,15 @@ exports.build = async ({ files, entrypoint }) => {
// so now we place `main.go` together with the user code
await writeFile(path.join(entrypointDirname, mainGoFileName), mainGoContents);
console.log('installing dependencies');
// `go get` will look at `*.go` (note we set `cwd`), parse
// the `import`s and download any packages that aren't part of the stdlib
try {
await execa(goBin, ['get'], { env: goEnv, cwd: entrypointDirname, stdio: 'inherit' });
await execa(goBin, ['get'], {
env: goEnv,
cwd: entrypointDirname,
stdio: 'inherit',
});
} catch (err) {
console.log('failed to `go get`');
throw err;
@@ -90,11 +107,17 @@ exports.build = async ({ files, entrypoint }) => {
console.log('running go build...');
try {
await execa(goBin, [
'build',
'-o', path.join(outDir, 'handler'),
path.join(entrypointDirname, mainGoFileName), downloadedFiles[entrypoint].fsPath,
], { env: goEnv, cwd: entrypointDirname, stdio: 'inherit' });
await execa(
goBin,
[
'build',
'-o',
path.join(outDir, 'handler'),
path.join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath,
],
{ env: goEnv, cwd: entrypointDirname, stdio: 'inherit' },
);
} catch (err) {
console.log('failed to `go build`');
throw err;

View File

@@ -1,6 +1,6 @@
{
"name": "@now/go",
"version": "0.2.7",
"version": "0.2.10-canary.0",
"scripts": {
"test": "best -I test/*.js",
"prepublish": "./build.sh"

View File

@@ -1,6 +1,6 @@
{
"name": "@now/html-minifier",
"version": "1.0.3",
"version": "1.0.6-canary.0",
"dependencies": {
"html-minifier": "3.5.21"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@now/lambda",
"version": "0.4.4",
"version": "0.4.7-canary.0",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}

View File

@@ -22,12 +22,17 @@ exports.build = async ({ files, entrypoint, config }) => {
.use(markdown)
.use(remark2rehype)
.use(doc, {
title, language, meta, css,
title,
language,
meta,
css,
})
.use(format)
.use(html);
const result = await FileBlob.fromStream({ stream: stream.pipe(unifiedStream(processor)) });
const result = await FileBlob.fromStream({
stream: stream.pipe(unifiedStream(processor)),
});
console.log(result.data.toString());

View File

@@ -1,6 +1,6 @@
{
"name": "@now/md",
"version": "0.4.4",
"version": "0.4.7-canary.0",
"dependencies": {
"rehype-document": "^2.2.0",
"rehype-format": "^2.3.0",

View File

@@ -19,13 +19,19 @@ exports.build = async ({ files, entrypoint, workPath }) => {
await writeFile(packageJsonPath, JSON.stringify(packageJson));
console.log('running npm install...');
process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = '1'; // TODO opts argument for runNpmInstall
await runNpmInstall(path.dirname(packageJsonPath), ['--prod', '--prefer-offline']);
await runNpmInstall(path.dirname(packageJsonPath), [
'--prod',
'--prefer-offline',
]);
console.log('building...');
const outDir = await getWritableDirectory();
const entrypointFsPath = downloadedFiles[entrypoint].fsPath;
const mountpoint = path.dirname(entrypoint);
const build = require(path.join(workPath, 'node_modules/mdx-deck/lib/build.js'));
const build = require(path.join(
workPath,
'node_modules/mdx-deck/lib/build.js',
));
await build({
html: true,
@@ -48,8 +54,8 @@ exports.prepareCache = async ({ cachePath }) => {
await runNpmInstall(path.dirname(packageJsonPath), ['--prod']);
return {
...await glob('node_modules/**', cachePath),
...await glob('package-lock.json', cachePath),
...await glob('yarn.lock', cachePath),
...(await glob('node_modules/**', cachePath)),
...(await glob('package-lock.json', cachePath)),
...(await glob('yarn.lock', cachePath)),
};
};

View File

@@ -1,6 +1,6 @@
{
"name": "@now/mdx-deck",
"version": "0.4.13",
"version": "0.4.16-canary.0",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}

View File

@@ -4,128 +4,100 @@ const FileFsRef = require('@now/build-utils/file-fs-ref.js');
const FileBlob = require('@now/build-utils/file-blob');
const path = require('path');
const { readFile, writeFile, unlink } = require('fs.promised');
const rename = require('@now/build-utils/fs/rename.js');
const {
runNpmInstall,
runPackageJsonScript
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const glob = require('@now/build-utils/fs/glob.js');
const {
excludeFiles,
validateEntrypoint,
includeOnlyEntryDirectory,
moveEntryDirectoryToRoot,
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
} = require('./utils');
// Exclude certain files from the files object
function excludeFiles(files, matchFn) {
return Object.keys(files).reduce((newFiles, fileName) => {
if (matchFn(fileName)) {
return newFiles;
}
return {
...newFiles,
[fileName]: files[fileName]
};
}, {});
}
/** @typedef { import('@now/build-utils/file-ref').Files } Files */
/** @typedef { import('@now/build-utils/fs/download').DownloadedFiles } DownloadedFiles */
function shouldExcludeFile(entryDirectory) {
return file => {
// If the file is not in the entry directory
if (entryDirectory !== '.' && !file.startsWith(entryDirectory)) {
return true;
}
/**
* @typedef {Object} BuildParamsType
* @property {Files} files - Files object
* @property {string} entrypoint - Entrypoint specified for the builder
* @property {string} workPath - Working directory for this build
*/
// Exclude static directory
if (file.startsWith(path.join(entryDirectory, 'static'))) {
return true;
}
if (file === 'package-lock.json') {
return true;
}
if (file === 'yarn.lock') {
return true;
}
return false;
};
}
exports.build = async ({ files, workPath, entrypoint }) => {
if (
!/package\.json$/.exec(entrypoint) &&
!/next\.config\.js$/.exec(entrypoint)
) {
throw new Error(
'Specified "src" for "@now/next" has to be "package.json" or "next.config.js"'
);
/**
* Read package.json from files
* @param {DownloadedFiles} files
*/
async function readPackageJson(files) {
if (!files['package.json']) {
return {};
}
const packageJsonPath = files['package.json'].fsPath;
return JSON.parse(await readFile(packageJsonPath, 'utf8'));
}
/**
* Write package.json
* @param {string} workPath
* @param {Object} packageJson
*/
async function writePackageJson(workPath, packageJson) {
await writeFile(
path.join(workPath, 'package.json'),
JSON.stringify(packageJson, null, 2),
);
}
/**
* Write .npmrc with npm auth token
* @param {string} workPath
* @param {string} token
*/
async function writeNpmRc(workPath, token) {
await writeFile(
path.join(workPath, '.npmrc'),
`//registry.npmjs.org/:_authToken=${token}`,
);
}
/**
* @param {BuildParamsType} buildParams
* @returns {Promise<Files>}
*/
exports.build = async ({ files, workPath, entrypoint }) => {
validateEntrypoint(entrypoint);
console.log('downloading user files...');
const entryDirectory = path.dirname(entrypoint);
const filesToDownload = excludeFiles(
const filesOnlyEntryDirectory = includeOnlyEntryDirectory(
files,
shouldExcludeFile(entryDirectory)
entryDirectory,
);
const entrypointHandledFilesToDownload = rename(filesToDownload, file => {
if (entryDirectory !== '.') {
return file.replace(new RegExp(`^${entryDirectory}/`), '');
}
return file;
});
let downloadedFiles = await download(
entrypointHandledFilesToDownload,
workPath
const filesWithEntryDirectoryRoot = moveEntryDirectoryToRoot(
filesOnlyEntryDirectory,
entryDirectory,
);
let packageJson = {};
if (downloadedFiles['package.json']) {
console.log('found package.json, overwriting');
const packageJsonPath = downloadedFiles['package.json'].fsPath;
packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
}
packageJson = {
...packageJson,
dependencies: {
...packageJson.dependencies,
'next-server': 'canary'
},
devDependencies: {
...packageJson.devDependencies,
next: 'canary'
},
scripts: {
...packageJson.scripts,
'now-build': 'next build'
}
};
if (!packageJson.dependencies.react) {
console.log(
'"react" not found in dependencies, adding to "package.json" "dependencies"'
);
packageJson.dependencies.react = 'latest';
}
if (!packageJson.dependencies['react-dom']) {
console.log(
'"react-dom" not found in dependencies, adding to "package.json" "dependencies"'
);
packageJson.dependencies['react-dom'] = 'latest';
}
// in case the user has `next` on their `dependencies`, we remove it
delete packageJson.dependencies.next;
await writeFile(
path.join(workPath, 'package.json'),
JSON.stringify(packageJson, null, 2)
const filesWithoutLockfiles = excludeLockFiles(filesWithEntryDirectoryRoot);
const filesWithoutStaticDirectory = excludeStaticDirectory(
filesWithoutLockfiles,
);
let downloadedFiles = await download(filesWithoutStaticDirectory, workPath);
console.log('normalizing package.json');
const packageJson = normalizePackageJson(readPackageJson(downloadedFiles));
await writePackageJson(workPath, packageJson);
if (process.env.NPM_AUTH_TOKEN) {
console.log('found NPM_AUTH_TOKEN in environement, creating .npmrc');
await writeFile(
path.join(workPath, '.npmrc'),
`//registry.npmjs.org/:_authToken=${process.env.NPM_AUTH_TOKEN}`
);
console.log('found NPM_AUTH_TOKEN in environment, creating .npmrc');
await writeNpmRc(workPath, process.env.NPM_AUTH_TOKEN);
}
downloadedFiles = await glob('**', workPath);
console.log('running npm install...');
@@ -137,6 +109,7 @@ exports.build = async ({ files, workPath, entrypoint }) => {
if (process.env.NPM_AUTH_TOKEN) {
await unlink(path.join(workPath, '.npmrc'));
}
downloadedFiles = await glob('**', workPath);
console.log('preparing lambda files...');
@@ -145,7 +118,7 @@ exports.build = async ({ files, workPath, entrypoint }) => {
buildId = await readFile(path.join(workPath, '.next', 'BUILD_ID'), 'utf8');
} catch (err) {
console.error(
'BUILD_ID not found in ".next". The "package.json" "build" script did not run "next build"'
'BUILD_ID not found in ".next". The "package.json" "build" script did not run "next build"',
);
throw new Error('Missing BUILD_ID');
}
@@ -153,30 +126,30 @@ exports.build = async ({ files, workPath, entrypoint }) => {
const dotNextServerRootFiles = await glob('.next/server/*', workPath);
const nodeModules = excludeFiles(
await glob('node_modules/**', workPath),
file => file.startsWith('node_modules/.cache')
file => file.startsWith('node_modules/.cache'),
);
const launcherFiles = {
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') })
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
};
const nextFiles = {
...nodeModules,
...dotNextRootFiles,
...dotNextServerRootFiles,
...launcherFiles
...launcherFiles,
};
if (downloadedFiles['next.config.js']) {
nextFiles['next.config.js'] = downloadedFiles['next.config.js'];
}
const pages = await glob(
'**/*.js',
path.join(workPath, '.next', 'server', 'static', buildId, 'pages')
path.join(workPath, '.next', 'server', 'static', buildId, 'pages'),
);
const launcherPath = path.join(__dirname, 'launcher.js');
const launcherData = await readFile(launcherPath, 'utf8');
const lambdas = {};
await Promise.all(
Object.keys(pages).map(async page => {
Object.keys(pages).map(async (page) => {
// These default pages don't have to be handled as they'd always 404
if (['_app.js', '_error.js', '_document.js'].includes(page)) {
return;
@@ -185,7 +158,7 @@ exports.build = async ({ files, workPath, entrypoint }) => {
const pathname = page.replace(/\.js$/, '');
const launcher = launcherData.replace(
'PATHNAME_PLACEHOLDER',
`/${pathname.replace(/(^|\/)index$/, '')}`
`/${pathname.replace(/(^|\/)index$/, '')}`,
);
const pageFiles = {
@@ -200,31 +173,33 @@ exports.build = async ({ files, workPath, entrypoint }) => {
],
[`.next/server/static/${buildId}/pages/${page}`]: downloadedFiles[
`.next/server/static/${buildId}/pages/${page}`
]
],
};
console.log(`Creating lambda for page: "${page}"...`);
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
files: {
...nextFiles,
...pageFiles,
'now__launcher.js': new FileBlob({ data: launcher })
'now__launcher.js': new FileBlob({ data: launcher }),
},
handler: 'now__launcher.launcher',
runtime: 'nodejs8.10'
runtime: 'nodejs8.10',
});
})
console.log(`Created lambda for page: "${page}"`);
}),
);
const nextStaticFiles = await glob(
'**',
path.join(workPath, '.next', 'static')
path.join(workPath, '.next', 'static'),
);
const staticFiles = Object.keys(nextStaticFiles).reduce(
(mappedFiles, file) => ({
...mappedFiles,
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[file]
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[file],
}),
{}
{},
);
return { ...lambdas, ...staticFiles };
@@ -239,7 +214,7 @@ exports.prepareCache = async ({ files, cachePath, workPath }) => {
console.log('.next folder contents', await glob('.next/**', cachePath));
console.log(
'.cache folder contents',
await glob('node_modules/.cache/**', cachePath)
await glob('node_modules/.cache/**', cachePath),
);
console.log('running npm install...');
@@ -249,6 +224,6 @@ exports.prepareCache = async ({ files, cachePath, workPath }) => {
...(await glob('.next/records.json', cachePath)),
...(await glob('.next/server/records.json', cachePath)),
...(await glob('node_modules/**', cachePath)),
...(await glob('yarn.lock', cachePath))
...(await glob('yarn.lock', cachePath)),
};
};

View File

@@ -1,6 +1,6 @@
{
"name": "@now/next",
"version": "0.0.76",
"version": "0.0.79-canary.0",
"dependencies": {
"@now/node-bridge": "0.1.4",
"execa": "^1.0.0",

151
packages/now-next/utils.js Normal file
View File

@@ -0,0 +1,151 @@
const rename = require('@now/build-utils/fs/rename.js');
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
/** @typedef { import('@now/build-utils/file-fs-ref') } FileFsRef */
/** @typedef {{[filePath: string]: FileRef|FileFsRef}} Files */
/**
* Validate if the entrypoint is allowed to be used
* @param {string} entrypoint
* @throws {Error}
*/
function validateEntrypoint(entrypoint) {
if (
!/package\.json$/.exec(entrypoint)
&& !/next\.config\.js$/.exec(entrypoint)
) {
throw new Error(
'Specified "src" for "@now/next" has to be "package.json" or "next.config.js"',
);
}
}
/**
* This callback type is called `requestCallback` and is displayed as a global symbol.
*
* @callback matcher
* @param {string} filePath
* @returns {boolean}
*/
/**
* Exclude certain files from the files object
* @param {Files} files
* @param {matcher} matcher
* @returns {Files}
*/
function excludeFiles(files, matcher) {
return Object.keys(files).reduce((newFiles, filePath) => {
if (matcher(filePath)) {
return newFiles;
}
return {
...newFiles,
[filePath]: files[filePath],
};
}, {});
}
/**
* Creates a new Files object holding only the entrypoint files
* @param {Files} files
* @param {string} entryDirectory
* @returns {Files}
*/
function includeOnlyEntryDirectory(files, entryDirectory) {
if (entryDirectory === '.') {
return files;
}
function matcher(filePath) {
return !filePath.startsWith(entryDirectory);
}
return excludeFiles(files, matcher);
}
/**
* Moves all files under the entry directory to the root directory
* @param {Files} files
* @param {string} entryDirectory
* @returns {Files}
*/
function moveEntryDirectoryToRoot(files, entryDirectory) {
if (entryDirectory === '.') {
return files;
}
function delegate(filePath) {
return filePath.replace(new RegExp(`^${entryDirectory}/`), '');
}
return rename(files, delegate);
}
/**
* Exclude package manager lockfiles from files
* @param {Files} files
* @returns {Files}
*/
function excludeLockFiles(files) {
const newFiles = files;
if (newFiles['package-lock.json']) {
delete newFiles['package-lock.json'];
}
if (newFiles['yarn.lock']) {
delete newFiles['yarn.lock'];
}
return files;
}
/**
* Exclude the static directory from files
* @param {Files} files
* @returns {Files}
*/
function excludeStaticDirectory(files) {
function matcher(filePath) {
return filePath.startsWith('static');
}
return excludeFiles(files, matcher);
}
/**
* Enforce specific package.json configuration for smallest possible lambda
* @param {Object} defaultPackageJson
*/
function normalizePackageJson(defaultPackageJson = {}) {
return {
...defaultPackageJson,
dependencies: {
// react and react-dom can be overwritten
react: 'latest',
'react-dom': 'latest',
...defaultPackageJson.dependencies,
// next-server is forced to canary
'next-server': 'canary',
next: undefined,
},
devDependencies: {
...defaultPackageJson.devDependencies,
// next is forced to canary
next: 'canary',
'next-server': undefined,
},
scripts: {
...defaultPackageJson.scripts,
'now-build': 'next build',
},
};
}
module.exports = {
excludeFiles,
validateEntrypoint,
includeOnlyEntryDirectory,
moveEntryDirectoryToRoot,
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
};

View File

@@ -4,7 +4,9 @@ function normalizeEvent(event) {
if (event.Action === 'Invoke') {
const invokeEvent = JSON.parse(event.body);
const { method, path, headers, encoding } = invokeEvent;
const {
method, path, headers, encoding,
} = invokeEvent;
let { body } = invokeEvent;
@@ -22,17 +24,19 @@ function normalizeEvent(event) {
method,
path,
headers,
body
body,
};
}
const { httpMethod: method, path, headers, body } = event;
const {
httpMethod: method, path, headers, body,
} = event;
return {
method,
path,
headers,
body
body,
};
}
@@ -53,17 +57,19 @@ class Bridge {
return resolve({ statusCode: 504, body: '' });
}
const { method, path, headers, body } = normalizeEvent(event);
const {
method, path, headers, body,
} = normalizeEvent(event);
const opts = {
hostname: '127.0.0.1',
port: this.port,
path,
method,
headers
headers,
};
const req = http.request(opts, res => {
const req = http.request(opts, (res) => {
const response = res;
const respBodyChunks = [];
response.on('data', chunk => respBodyChunks.push(Buffer.from(chunk)));
@@ -76,7 +82,7 @@ class Bridge {
statusCode: response.statusCode,
headers: response.headers,
body: Buffer.concat(respBodyChunks).toString('base64'),
encoding: 'base64'
encoding: 'base64',
});
});
});
@@ -88,5 +94,5 @@ class Bridge {
}
module.exports = {
Bridge
Bridge,
};

View File

@@ -1,6 +1,6 @@
{
"name": "@now/node-bridge",
"version": "0.1.6",
"version": "0.1.9-canary.0",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}

View File

@@ -2,11 +2,14 @@ const { createLambda } = require('@now/build-utils/lambda.js');
const download = require('@now/build-utils/fs/download.js');
const FileBlob = require('@now/build-utils/file-blob.js');
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
const fs = require('fs');
const fs = require('fs-extra');
const glob = require('@now/build-utils/fs/glob.js');
const path = require('path');
const { promisify } = require('util');
const { runNpmInstall, runPackageJsonScript } = require('@now/build-utils/fs/run-user-scripts.js');
const {
runNpmInstall,
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const fsp = {
readFile: promisify(fs.readFile),
@@ -19,7 +22,7 @@ async function commonForTwo({
const preferOfflineArgument = workPath ? ['--prefer-offline'] : [];
const xUserPath = path.join(xPath, 'user');
const xRollupPath = path.join(xPath, 'rollup');
const xNccPath = path.join(xPath, 'ncc');
console.log('downloading user files...');
const filesOnDisk = await download(files, xUserPath);
@@ -28,75 +31,46 @@ async function commonForTwo({
const entrypointFsDirname = path.join(xUserPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, preferOfflineArgument);
console.log('writing rollup package.json...');
await download({
'package.json': new FileBlob({
data: JSON.stringify({
dependencies: {
builtins: '2.0.0',
rollup: '0.67.0',
'rollup-plugin-commonjs': '9.2.0',
'rollup-plugin-json': '3.1.0',
'rollup-plugin-node-resolve': '3.4.0',
'rollup-plugin-terser': '3.0.0',
},
console.log('writing ncc package.json...');
await download(
{
'package.json': new FileBlob({
data: JSON.stringify({
dependencies: {
'@zeit/ncc': '0.1.4-webpack',
},
}),
}),
}),
}, xRollupPath);
console.log('running npm install for rollup...');
await runNpmInstall(xRollupPath, preferOfflineArgument);
return [filesOnDisk, xRollupPath, entrypointFsDirname];
}
async function compile(workRollupPath, input) {
const rollup = require(path.join(workRollupPath, 'node_modules/rollup'));
const nodeResolve = require(path.join(workRollupPath, 'node_modules/rollup-plugin-node-resolve'));
const commonjs = require(path.join(workRollupPath, 'node_modules/rollup-plugin-commonjs'));
const json = require(path.join(workRollupPath, 'node_modules/rollup-plugin-json'));
const { terser } = require(path.join(workRollupPath, 'node_modules/rollup-plugin-terser'));
const builtins = require(path.join(workRollupPath, 'node_modules/builtins'))();
const bundle = await rollup.rollup({
input,
plugins: [
nodeResolve({
module: false,
jsnext: false,
browser: false,
preferBuiltins: true,
}),
json(),
commonjs(),
terser(),
],
onwarn(error) {
if (/external dependency/.test(error.message)) {
const mod = error.message.split('\'')[1];
// ignore rollup warnings about known node.js modules
if (builtins.indexOf(mod) > -1) return;
}
console.error(error.message);
},
});
xNccPath,
);
return (await bundle.generate({
format: 'cjs',
})).code;
console.log('running npm install for ncc...');
await runNpmInstall(xNccPath, preferOfflineArgument);
return [filesOnDisk, xNccPath, entrypointFsDirname];
}
async function compile(workNccPath, input) {
const ncc = require(path.join(workNccPath, 'node_modules/@zeit/ncc'));
return ncc(input);
}
exports.config = {
maxLambdaSize: '15mb',
};
exports.build = async ({ files, entrypoint, workPath }) => {
const [
filesOnDisk,
workRollupPath,
entrypointFsDirname,
] = await commonForTwo({ files, entrypoint, workPath });
const [filesOnDisk, workNccPath, entrypointFsDirname] = await commonForTwo({
files,
entrypoint,
workPath,
});
console.log('running user script...');
await runPackageJsonScript(entrypointFsDirname, 'now-build');
console.log('compiling entrypoint with rollup...');
const data = await compile(workRollupPath, filesOnDisk[entrypoint].fsPath);
console.log('compiling entrypoint with ncc...');
const data = await compile(workNccPath, filesOnDisk[entrypoint].fsPath);
const blob = new FileBlob({ data });
console.log('preparing lambda files...');
@@ -105,10 +79,13 @@ exports.build = async ({ files, entrypoint, workPath }) => {
const launcherPath = path.join(__dirname, 'launcher.js');
let launcherData = await fsp.readFile(launcherPath, 'utf8');
launcherData = launcherData.replace('// PLACEHOLDER', [
'process.chdir("./user");',
`require("./${path.join('user', entrypoint)}");`,
].join(' '));
launcherData = launcherData.replace(
'// PLACEHOLDER',
[
'process.chdir("./user");',
`require("./${path.join('user', entrypoint)}");`,
].join(' '),
);
const launcherFiles = {
'launcher.js': new FileBlob({ data: launcherData }),
@@ -124,15 +101,18 @@ exports.build = async ({ files, entrypoint, workPath }) => {
return { [entrypoint]: lambda };
};
exports.prepareCache = async ({ files, entrypoint, cachePath }) => {
exports.prepareCache = async ({
files, entrypoint, workPath, cachePath,
}) => {
await fs.remove(workPath);
await commonForTwo({ files, entrypoint, cachePath });
return {
...await glob('user/node_modules/**', cachePath),
...await glob('user/package-lock.json', cachePath),
...await glob('user/yarn.lock', cachePath),
...await glob('rollup/node_modules/**', cachePath),
...await glob('rollup/package-lock.json', cachePath),
...await glob('rollup/yarn.lock', cachePath),
...(await glob('user/node_modules/**', cachePath)),
...(await glob('user/package-lock.json', cachePath)),
...(await glob('user/yarn.lock', cachePath)),
...(await glob('ncc/node_modules/**', cachePath)),
...(await glob('ncc/package-lock.json', cachePath)),
...(await glob('ncc/yarn.lock', cachePath)),
};
};

View File

@@ -1,8 +1,9 @@
{
"name": "@now/node-server",
"version": "0.4.21",
"version": "0.4.24-canary.0",
"dependencies": {
"@now/node-bridge": "^0.1.6"
"@now/node-bridge": "^0.1.9-canary.0",
"fs-extra": "7.0.1"
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"

View File

@@ -2,113 +2,109 @@ const { createLambda } = require('@now/build-utils/lambda.js');
const download = require('@now/build-utils/fs/download.js');
const FileBlob = require('@now/build-utils/file-blob.js');
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
const fsExtra = require('fs-extra');
const fs = require('fs');
const glob = require('@now/build-utils/fs/glob.js');
const path = require('path');
const { promisify } = require('util');
const { runNpmInstall, runPackageJsonScript } = require('@now/build-utils/fs/run-user-scripts.js');
const {
runNpmInstall,
runPackageJsonScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
const fsp = {
readFile: promisify(fs.readFile),
};
const readFile = promisify(fs.readFile);
async function commonForTwo({
files, entrypoint, workPath, cachePath,
}) {
const xPath = workPath || cachePath;
const preferOfflineArgument = workPath ? ['--prefer-offline'] : [];
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
/** @typedef {{[filePath: string]: FileRef}} Files */
const xUserPath = path.join(xPath, 'user');
const xRollupPath = path.join(xPath, 'rollup');
/**
* @typedef {Object} BuildParamsType
* @property {Files} files - Files object
* @property {string} entrypoint - Entrypoint specified for the builder
* @property {string} workPath - Working directory for this build
*/
/**
* @param {BuildParamsType} buildParams
* @param {Object} [options]
* @param {string[]} [options.npmArguments]
*/
async function downloadInstallAndBundle(
{ files, entrypoint, workPath },
{ npmArguments = [] } = {},
) {
const userPath = path.join(workPath, 'user');
const nccPath = path.join(workPath, 'ncc');
console.log('downloading user files...');
const filesOnDisk = await download(files, xUserPath);
const filesOnDisk = await download(files, userPath);
console.log('running npm install for user...');
const entrypointFsDirname = path.join(xUserPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, preferOfflineArgument);
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
await runNpmInstall(entrypointFsDirname, npmArguments);
console.log('writing rollup package.json...');
await download({
'package.json': new FileBlob({
data: JSON.stringify({
dependencies: {
builtins: '2.0.0',
rollup: '0.67.0',
'rollup-plugin-commonjs': '9.2.0',
'rollup-plugin-json': '3.1.0',
'rollup-plugin-node-resolve': '3.4.0',
'rollup-plugin-terser': '3.0.0',
},
console.log('writing ncc package.json...');
await download(
{
'package.json': new FileBlob({
data: JSON.stringify({
dependencies: {
'@zeit/ncc': '0.1.4-webpack',
},
}),
}),
}),
}, xRollupPath);
console.log('running npm install for rollup...');
await runNpmInstall(xRollupPath, preferOfflineArgument);
return [filesOnDisk, xRollupPath, entrypointFsDirname];
}
async function compile(workRollupPath, input) {
const rollup = require(path.join(workRollupPath, 'node_modules/rollup'));
const nodeResolve = require(path.join(workRollupPath, 'node_modules/rollup-plugin-node-resolve'));
const commonjs = require(path.join(workRollupPath, 'node_modules/rollup-plugin-commonjs'));
const json = require(path.join(workRollupPath, 'node_modules/rollup-plugin-json'));
const { terser } = require(path.join(workRollupPath, 'node_modules/rollup-plugin-terser'));
const builtins = require(path.join(workRollupPath, 'node_modules/builtins'))();
const bundle = await rollup.rollup({
input,
plugins: [
nodeResolve({
module: false,
jsnext: false,
browser: false,
preferBuiltins: true,
}),
json(),
commonjs(),
terser(),
],
onwarn(error) {
if (/external dependency/.test(error.message)) {
const mod = error.message.split('\'')[1];
// ignore rollup warnings about known node.js modules
if (builtins.indexOf(mod) > -1) return;
}
console.error(error.message);
},
});
nccPath,
);
return (await bundle.generate({
format: 'cjs',
})).code;
console.log('running npm install for ncc...');
await runNpmInstall(nccPath, npmArguments);
return [filesOnDisk, nccPath, entrypointFsDirname];
}
async function compile(workNccPath, input) {
const ncc = require(path.join(workNccPath, 'node_modules/@zeit/ncc'));
return ncc(input);
}
exports.config = {
maxLambdaSize: '5mb',
};
/**
* @param {BuildParamsType} buildParams
* @returns {Promise<Files>}
*/
exports.build = async ({ files, entrypoint, workPath }) => {
const [
filesOnDisk,
workRollupPath,
workNccPath,
entrypointFsDirname,
] = await commonForTwo({ files, entrypoint, workPath });
] = await downloadInstallAndBundle(
{ files, entrypoint, workPath },
{ npmArguments: ['--prefer-offline'] },
);
console.log('running user script...');
await runPackageJsonScript(entrypointFsDirname, 'now-build');
console.log('compiling entrypoint with rollup...');
const data = await compile(workRollupPath, filesOnDisk[entrypoint].fsPath);
console.log('compiling entrypoint with ncc...');
const data = await compile(workNccPath, filesOnDisk[entrypoint].fsPath);
const blob = new FileBlob({ data });
console.log('preparing lambda files...');
// move all user code to 'user' subdirectory
const compiledFiles = { [path.join('user', entrypoint)]: blob };
const launcherPath = path.join(__dirname, 'launcher.js');
let launcherData = await fsp.readFile(launcherPath, 'utf8');
let launcherData = await readFile(launcherPath, 'utf8');
launcherData = launcherData.replace('// PLACEHOLDER', [
'process.chdir("./user");',
`listener = require("./${path.join('user', entrypoint)}");`,
].join(' '));
launcherData = launcherData.replace(
'// PLACEHOLDER',
[
'process.chdir("./user");',
`listener = require("./${path.join('user', entrypoint)}");`,
].join(' '),
);
const launcherFiles = {
'launcher.js': new FileBlob({ data: launcherData }),
@@ -124,15 +120,18 @@ exports.build = async ({ files, entrypoint, workPath }) => {
return { [entrypoint]: lambda };
};
exports.prepareCache = async ({ files, entrypoint, cachePath }) => {
await commonForTwo({ files, entrypoint, cachePath });
exports.prepareCache = async ({
files, entrypoint, workPath, cachePath,
}) => {
await fsExtra.remove(workPath);
await downloadInstallAndBundle({ files, entrypoint, workPath: cachePath });
return {
...await glob('user/node_modules/**', cachePath),
...await glob('user/package-lock.json', cachePath),
...await glob('user/yarn.lock', cachePath),
...await glob('rollup/node_modules/**', cachePath),
...await glob('rollup/package-lock.json', cachePath),
...await glob('rollup/yarn.lock', cachePath),
...(await glob('user/node_modules/**', cachePath)),
...(await glob('user/package-lock.json', cachePath)),
...(await glob('user/yarn.lock', cachePath)),
...(await glob('ncc/node_modules/**', cachePath)),
...(await glob('ncc/package-lock.json', cachePath)),
...(await glob('ncc/yarn.lock', cachePath)),
};
};

View File

@@ -1,8 +1,9 @@
{
"name": "@now/node",
"version": "0.4.23",
"version": "0.4.26-canary.0",
"dependencies": {
"@now/node-bridge": "^0.1.6"
"@now/node-bridge": "^0.1.9-canary.0",
"fs-extra": "7.0.1"
},
"peerDependencies": {
"@now/build-utils": ">=0.0.1"

View File

@@ -6,7 +6,10 @@ exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({ files, entrypoint }) => {
const optimizer = new OptiPng(['-o9']);
const stream = pipe(files[entrypoint].toStream(), optimizer);
const stream = pipe(
files[entrypoint].toStream(),
optimizer,
);
const result = await FileBlob.fromStream({ stream });
return { [entrypoint]: result };
};

View File

@@ -1,6 +1,6 @@
{
"name": "@now/optipng",
"version": "0.4.4",
"version": "0.4.7-canary.0",
"dependencies": {
"multipipe": "2.0.3",
"optipng": "1.1.0"

View File

@@ -3,6 +3,10 @@ const glob = require('@now/build-utils/fs/glob.js');
const path = require('path');
const rename = require('@now/build-utils/fs/rename.js');
exports.config = {
maxLambdaSize: '10mb',
};
exports.build = async ({ files, entrypoint }) => {
// move all user code to 'user' subdirectory
const userFiles = rename(files, name => path.join('user', name));

View File

@@ -1,6 +1,6 @@
{
"name": "@now/php",
"version": "0.4.8",
"version": "0.4.11-canary.0",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}

View File

@@ -37,7 +37,9 @@ async function downloadAndInstallPip() {
// installed to. `--user` will assume `~` if this
// is not set, and `~` is not writeable on AWS Lambda.
// let's refuse to proceed
throw new Error('Could not install "pip": "PYTHONUSERBASE" env var is not set');
throw new Error(
'Could not install "pip": "PYTHONUSERBASE" env var is not set',
);
}
const getPipFilePath = await downloadGetPipScript();

View File

@@ -10,21 +10,19 @@ const downloadAndInstallPip = require('./download-and-install-pip');
async function pipInstall(pipPath, srcDir, ...args) {
console.log(`running "pip install -t ${srcDir} ${args.join(' ')}"...`);
try {
await execa(
pipPath,
[
'install',
'-t', srcDir,
...args,
],
{ stdio: 'inherit' },
);
await execa(pipPath, ['install', '-t', srcDir, ...args], {
stdio: 'inherit',
});
} catch (err) {
console.log(`failed to run "pip install -t ${srcDir} ${args.join(' ')}"`);
throw err;
}
}
exports.config = {
maxLambdaSize: '5mb',
};
exports.build = async ({ files, entrypoint }) => {
console.log('downloading files...');
@@ -49,11 +47,16 @@ exports.build = async ({ files, entrypoint }) => {
await pipInstall(pipPath, srcDir, '-r', requirementsTxtPath);
}
const originalNowHandlerPyContents = await readFile(path.join(__dirname, 'now_handler.py'), 'utf8');
const originalNowHandlerPyContents = await readFile(
path.join(__dirname, 'now_handler.py'),
'utf8',
);
// will be used on `from $here import handler`
// for example, `from api.users import handler`
console.log('entrypoint is', entrypoint);
const userHandlerFilePath = entrypoint.replace(/\//g, '.').replace(/\.py$/, '');
const userHandlerFilePath = entrypoint
.replace(/\//g, '.')
.replace(/\.py$/, '');
const nowHandlerPyContents = originalNowHandlerPyContents.replace(
'__NOW_HANDLER_FILENAME',
userHandlerFilePath,
@@ -63,7 +66,10 @@ exports.build = async ({ files, entrypoint }) => {
// somethig else
const nowHandlerPyFilename = 'now__handler__python';
await writeFile(path.join(srcDir, `${nowHandlerPyFilename}.py`), nowHandlerPyContents);
await writeFile(
path.join(srcDir, `${nowHandlerPyFilename}.py`),
nowHandlerPyContents,
);
const lambda = await createLambda({
files: await glob('**', srcDir),

View File

@@ -1,6 +1,6 @@
{
"name": "@now/python",
"version": "0.0.37",
"version": "0.0.40-canary.0",
"main": "index.js",
"license": "MIT",
"dependencies": {

View File

@@ -2,7 +2,9 @@ const download = require('@now/build-utils/fs/download.js');
const glob = require('@now/build-utils/fs/glob.js');
const path = require('path');
const {
runNpmInstall, runPackageJsonScript, runShellScript,
runNpmInstall,
runPackageJsonScript,
runShellScript,
} = require('@now/build-utils/fs/run-user-scripts.js');
exports.build = async ({

View File

@@ -1,6 +1,6 @@
{
"name": "@now/static-build",
"version": "0.4.12",
"version": "0.4.15-canary.0",
"peerDependencies": {
"@now/build-utils": ">=0.0.1"
}

View File

@@ -14,7 +14,7 @@ it(
const { buildResult } = await runBuildForFolder('airtable');
expect(buildResult['index.js']).toBeDefined();
},
TWO_MINUTES
TWO_MINUTES,
);
it(
@@ -23,7 +23,7 @@ it(
const { buildResult } = await runBuildForFolder('aws-sdk');
expect(buildResult['index.js']).toBeDefined();
},
TWO_MINUTES
TWO_MINUTES,
);
it(
@@ -32,7 +32,7 @@ it(
const { buildResult } = await runBuildForFolder('axios');
expect(buildResult['index.js']).toBeDefined();
},
TWO_MINUTES
TWO_MINUTES,
);
it(
@@ -41,5 +41,5 @@ it(
const { buildResult } = await runBuildForFolder('mongoose');
expect(buildResult['index.js']).toBeDefined();
},
TWO_MINUTES
TWO_MINUTES,
);

View File

@@ -0,0 +1,292 @@
const {
excludeFiles,
validateEntrypoint,
includeOnlyEntryDirectory,
moveEntryDirectoryToRoot,
excludeLockFiles,
normalizePackageJson,
excludeStaticDirectory,
} = require('@now/next/utils');
const FileRef = require('@now/build-utils/file-ref');
describe('excludeFiles', () => {
it('should exclude files', () => {
const files = {
'pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
};
const result = excludeFiles(
files,
filePath => filePath === 'package-lock.json',
);
expect(result['pages/index.js']).toBeDefined();
expect(result['package.json']).toBeDefined();
expect(result['package-lock.json']).toBeUndefined();
});
});
describe('validateEntrypoint', () => {
it('should allow package.json', () => {
expect(validateEntrypoint('package.json')).toBeUndefined();
});
it('should allow nested package.json', () => {
expect(validateEntrypoint('frontend/package.json')).toBeUndefined();
});
it('should allow next.config.js', () => {
expect(validateEntrypoint('next.config.js')).toBeUndefined();
});
it('should allow nested next.config.js', () => {
expect(validateEntrypoint('frontend/next.config.js')).toBeUndefined();
});
it('should not allow pages/index.js', () => {
expect(() => validateEntrypoint('pages/index.js')).toThrow();
});
});
describe('includeOnlyEntryDirectory', () => {
it('should exclude files outside entry directory', () => {
const entryDirectory = 'frontend';
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
};
const result = includeOnlyEntryDirectory(files, entryDirectory);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['package.json']).toBeUndefined();
expect(result['package-lock.json']).toBeUndefined();
});
it('should handle entry directory being dot', () => {
const entryDirectory = '.';
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
};
const result = includeOnlyEntryDirectory(files, entryDirectory);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['package.json']).toBeDefined();
expect(result['package-lock.json']).toBeDefined();
});
});
describe('moveEntryDirectoryToRoot', () => {
it('should move entrydirectory files to the root', () => {
const entryDirectory = 'frontend';
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
};
const result = moveEntryDirectoryToRoot(files, entryDirectory);
expect(result['pages/index.js']).toBeDefined();
});
it('should work with deep nested subdirectories', () => {
const entryDirectory = 'frontend/my/app';
const files = {
'frontend/my/app/pages/index.js': new FileRef({ digest: 'index' }),
};
const result = moveEntryDirectoryToRoot(files, entryDirectory);
expect(result['pages/index.js']).toBeDefined();
});
it('should do nothing when entry directory is dot', () => {
const entryDirectory = '.';
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
};
const result = moveEntryDirectoryToRoot(files, entryDirectory);
expect(result['frontend/pages/index.js']).toBeDefined();
});
});
describe('excludeLockFiles', () => {
it('should remove package-lock.json', () => {
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
};
const result = excludeLockFiles(files);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['package-lock.json']).toBeUndefined();
});
it('should remove yarn.lock', () => {
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'yarn.lock': new FileRef({ digest: 'yarn-lock' }),
};
const result = excludeLockFiles(files);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['yarn.lock']).toBeUndefined();
});
it('should remove both package-lock.json and yarn.lock', () => {
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'yarn.lock': new FileRef({ digest: 'yarn-lock' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
};
const result = excludeLockFiles(files);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['yarn.lock']).toBeUndefined();
expect(result['package-lock.json']).toBeUndefined();
});
});
describe('excludeStaticDirectory', () => {
it('should remove the /static directory files', () => {
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'yarn.lock': new FileRef({ digest: 'yarn-lock' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
'static/image.png': new FileRef({ digest: 'image' }),
};
const result = excludeStaticDirectory(files);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['yarn.lock']).toBeDefined();
expect(result['package-lock.json']).toBeDefined();
expect(result['static/image.png']).toBeUndefined();
});
it('should remove the nested /static directory files', () => {
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'yarn.lock': new FileRef({ digest: 'yarn-lock' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
'static/images/png/image.png': new FileRef({ digest: 'image' }),
};
const result = excludeStaticDirectory(files);
expect(result['frontend/pages/index.js']).toBeDefined();
expect(result['yarn.lock']).toBeDefined();
expect(result['package-lock.json']).toBeDefined();
expect(result['static/images/png/image.png']).toBeUndefined();
});
});
describe('normalizePackageJson', () => {
it('should work without a package.json being supplied', () => {
const result = normalizePackageJson();
expect(result).toEqual({
dependencies: {
'next-server': 'canary',
react: 'latest',
'react-dom': 'latest',
},
devDependencies: {
next: 'canary',
},
scripts: {
'now-build': 'next build',
},
});
});
it('should work with a package.json being supplied', () => {
const defaultPackage = {
dependencies: {
'next-server': 'canary',
react: 'latest',
'react-dom': 'latest',
},
devDependencies: {
next: 'canary',
},
scripts: {
'now-build': 'next build',
},
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'canary',
react: 'latest',
'react-dom': 'latest',
},
devDependencies: {
next: 'canary',
},
scripts: {
'now-build': 'next build',
},
});
});
it('should force next@canary to be a devDependency', () => {
const defaultPackage = {
dependencies: {
react: 'latest',
'react-dom': 'latest',
next: 'latest',
},
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'canary',
react: 'latest',
'react-dom': 'latest',
},
devDependencies: {
next: 'canary',
},
scripts: {
'now-build': 'next build',
},
});
});
it('should force next-server@canary to be a dependency', () => {
const defaultPackage = {
dependencies: {
react: 'latest',
'react-dom': 'latest',
next: 'latest',
},
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'canary',
react: 'latest',
'react-dom': 'latest',
},
devDependencies: {
next: 'canary',
},
scripts: {
'now-build': 'next build',
},
});
});
it('should force now-build script', () => {
const defaultPackage = {
dependencies: {
react: 'latest',
'react-dom': 'latest',
next: 'latest',
},
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'canary',
react: 'latest',
'react-dom': 'latest',
},
devDependencies: {
next: 'canary',
},
scripts: {
'now-build': 'next build',
},
});
});
});

25
tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"lib": ["es2017"],
"allowJs": true,
"checkJs": true,
"noEmit": true,
"strict": false,
"types": ["node"],
"esModuleInterop": true
},
"include": [
"./packages/now-node/index.js",
"./packages/now-build-utils/file-ref.js",
"./packages/now-build-utils/file-fs-ref.js",
"./packages/now-build-utils/fs/rename.js",
"./packages/now-build-utils/fs/download.js",
"./packages/now-build-utils/fs/glob.js",
"./packages/now-next"
],
"exclude": [
"./packages/now-next/launcher.js"
]
}