mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-25 11:49:15 +00:00
Compare commits
156 Commits
@now/node-
...
@now/node@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49e63de5fe | ||
|
|
4742cd32f2 | ||
|
|
377b73105d | ||
|
|
a5577efb3d | ||
|
|
2ec46dc5c9 | ||
|
|
42708ed93c | ||
|
|
2fabe95f6e | ||
|
|
ac1a3dab22 | ||
|
|
ad4011512d | ||
|
|
9ff1a25c8f | ||
|
|
8039b3d377 | ||
|
|
dd9017475c | ||
|
|
031499014f | ||
|
|
2a68d2a2ad | ||
|
|
31299fae6e | ||
|
|
4bac0db379 | ||
|
|
95e7d459d3 | ||
|
|
dd120b8d20 | ||
|
|
b6975676e5 | ||
|
|
a7951dae81 | ||
|
|
b0c918f7fb | ||
|
|
df54dc7dc9 | ||
|
|
0dd801ff6c | ||
|
|
398743ef95 | ||
|
|
337c74b81b | ||
|
|
680bb82ec3 | ||
|
|
17ed5411e3 | ||
|
|
d9bbcb6939 | ||
|
|
800e4de76f | ||
|
|
864dd468d9 | ||
|
|
ba833871bb | ||
|
|
e732bac78e | ||
|
|
28ea4015b4 | ||
|
|
a93d97cabd | ||
|
|
67f39f7c9b | ||
|
|
acd793b9e9 | ||
|
|
f74d61279d | ||
|
|
fcb8eacec0 | ||
|
|
c8fca2ba72 | ||
|
|
4feffa13eb | ||
|
|
3e330b25f4 | ||
|
|
9b2cae33af | ||
|
|
4b6371530c | ||
|
|
9e1d577fc0 | ||
|
|
cf2f542c71 | ||
|
|
e608861e4e | ||
|
|
a99b999209 | ||
|
|
fd9c6e7847 | ||
|
|
b2ad3a6147 | ||
|
|
997d3c2a30 | ||
|
|
ca575bf0a6 | ||
|
|
4c2e93ccef | ||
|
|
4d6437d235 | ||
|
|
0d8058d062 | ||
|
|
2b5cdfc0a7 | ||
|
|
69a41f78fb | ||
|
|
a013d59d62 | ||
|
|
173a29cfdb | ||
|
|
3f73451311 | ||
|
|
2fc706be43 | ||
|
|
0fb7eb6093 | ||
|
|
aa43c0bc87 | ||
|
|
3c5925a6e3 | ||
|
|
9fc7b047f5 | ||
|
|
ecae29457f | ||
|
|
77d445af71 | ||
|
|
79251ad180 | ||
|
|
a215dc9103 | ||
|
|
ea7d8f0f6c | ||
|
|
2232efc984 | ||
|
|
b64ce0f3c0 | ||
|
|
74233d50ad | ||
|
|
8aebec9fc3 | ||
|
|
54584b7763 | ||
|
|
d163fcbd71 | ||
|
|
04c2996c76 | ||
|
|
2b69b898ed | ||
|
|
846aa11d6a | ||
|
|
a314a74479 | ||
|
|
40f029a72c | ||
|
|
493d8a778f | ||
|
|
cb5dcb658f | ||
|
|
d77287d07b | ||
|
|
61d66bd957 | ||
|
|
ae73df9e3c | ||
|
|
cb09ae5bbf | ||
|
|
a28eeacdaa | ||
|
|
dd9d46d555 | ||
|
|
4472331ee0 | ||
|
|
ac69836b44 | ||
|
|
15949a4ab4 | ||
|
|
697ada9d73 | ||
|
|
cafbe30fa3 | ||
|
|
583ebcc526 | ||
|
|
52d1bd410c | ||
|
|
11d0753bc1 | ||
|
|
538710fe56 | ||
|
|
2828c89e8d | ||
|
|
e40b45a939 | ||
|
|
38ba8a36fc | ||
|
|
0323c505a3 | ||
|
|
17ee07f4f6 | ||
|
|
0a6ada77ac | ||
|
|
4d817dd67d | ||
|
|
9682a7cc0b | ||
|
|
3456f23b3e | ||
|
|
800ca2cb0e | ||
|
|
ba54b4d706 | ||
|
|
e9482d66a9 | ||
|
|
401b669363 | ||
|
|
a2a0ede1f6 | ||
|
|
3c9fcff743 | ||
|
|
e5aa526583 | ||
|
|
822b0ee3de | ||
|
|
d612e46233 | ||
|
|
77ee10cead | ||
|
|
fb2029c464 | ||
|
|
3b15755054 | ||
|
|
4f65cc3aa8 | ||
|
|
9936e35280 | ||
|
|
a04fd242b8 | ||
|
|
17bc6174a9 | ||
|
|
a7c2d9648a | ||
|
|
faa5ea9e21 | ||
|
|
c52f30c898 | ||
|
|
d675edf1dc | ||
|
|
f85c4f496f | ||
|
|
d52d7904c2 | ||
|
|
79232024bd | ||
|
|
660b787bc3 | ||
|
|
2dbf983ddb | ||
|
|
0866ba9391 | ||
|
|
d259a722a0 | ||
|
|
bf77c51f64 | ||
|
|
062b78130c | ||
|
|
fa70bc50cb | ||
|
|
08e22b35d1 | ||
|
|
9d8f3315a1 | ||
|
|
a737a99a9d | ||
|
|
ee92d92c9f | ||
|
|
34d3ebd289 | ||
|
|
785f187e5d | ||
|
|
44449f474e | ||
|
|
f44dae7f39 | ||
|
|
06f973f641 | ||
|
|
47bb47804e | ||
|
|
5df692979a | ||
|
|
cd02d5390f | ||
|
|
c93fd416c4 | ||
|
|
431db7a62d | ||
|
|
6f86c70313 | ||
|
|
0923fc9200 | ||
|
|
787675f462 | ||
|
|
977615720a | ||
|
|
1a4e64cd27 | ||
|
|
c9fc255002 |
@@ -1,3 +1,4 @@
|
||||
/tmp/*
|
||||
/node_modules/*
|
||||
/**/node_modules/*
|
||||
/packages/now-go/go/*
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
node_modules
|
||||
tmp
|
||||
target/
|
||||
.next
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This is the full list of official Builders provided by the ZEIT team.
|
||||
|
||||
More details here: http://zeit.co/docs
|
||||
More details here: https://zeit.co/docs/v2/deployments/builders/overview/
|
||||
|
||||
### Publishing to npm
|
||||
|
||||
|
||||
73
errors/now-next-legacy-mode.md
Normal file
73
errors/now-next-legacy-mode.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# `@now/next` Legacy Mode
|
||||
|
||||
#### Why This Warning Occurred
|
||||
|
||||
`@now/next` has two modes: `legacy` and `serverless`. You will always want to use the `serverless` mode. `legacy` is to provide backwards compatibility with previous `@now/next` versions.
|
||||
|
||||
The differences:
|
||||
|
||||
Legacy:
|
||||
|
||||
- Minimal lambda size of `2.2Mb` (approximately)
|
||||
- Forces `next@v7.0.2-canary.49` and `next-server@v7.0.2-canary.49`
|
||||
- Forces all `dependencies` to be `devDependencies`
|
||||
- Loads `next.config.js` on bootup, breaking sometimes when users didn't use `phases` to load files
|
||||
- Used `next-server` which is the full Next.js server with routing etc.
|
||||
- Runs `npm install`
|
||||
- Runs `npm run now-build`
|
||||
- Runs `npm install --production` after build
|
||||
|
||||
Serverless:
|
||||
|
||||
- Minimal lambda size of `49Kb` (approximately)
|
||||
- Uses Next.js build targets (`target: 'serverless'`) in `next.config.js`. [documentation](https://github.com/zeit/next.js#summary)
|
||||
- Does not make changes to your application dependencies
|
||||
- Does not load `next.config.js` ([as per the serverless target documentation](https://github.com/zeit/next.js#summary))
|
||||
- Runs `npm install`
|
||||
- Runs `npm run now-build`
|
||||
- Does not run `npm install --production` as the output from the build is all that's needed to bundle lambdas.
|
||||
- No runtime dependencies, meaning smaller lambda functions
|
||||
- Optimized for fast [cold start](https://zeit.co/blog/serverless-ssr#cold-start)
|
||||
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
In order to create the smallest possible lambdas Next.js has to be configured to build for the `serverless` target.
|
||||
|
||||
1. Serverless Next.js requires Next.js 8 or later, to upgrade you can install the `latest` version:
|
||||
|
||||
```
|
||||
npm install next --save
|
||||
```
|
||||
|
||||
2. Add the `now-build` script to your `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"now-build": "next build"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
3. Add `target: 'serverless'` to `next.config.js`
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
target: 'serverless'
|
||||
// Other options are still valid
|
||||
}
|
||||
```
|
||||
|
||||
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
|
||||
|
||||
```js
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@now/next" }]
|
||||
}
|
||||
```
|
||||
|
||||
### Useful Links
|
||||
|
||||
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)
|
||||
43
errors/now-next-no-serverless-pages-built.md
Normal file
43
errors/now-next-no-serverless-pages-built.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# `@now/next` No Serverless Pages Built
|
||||
|
||||
#### Why This Error Occurred
|
||||
|
||||
This error occurs when you have your application is not configured for Serverless Next.js build output.
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
In order to create the smallest possible lambdas Next.js has to be configured to build for the `serverless` target.
|
||||
|
||||
1. Serverless Next.js requires Next.js 8 or later, to upgrade you can install the `latest` version:
|
||||
|
||||
```
|
||||
npm install next --save
|
||||
```
|
||||
|
||||
2. Add the `now-build` script to your `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"now-build": "next build"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
3. Add `target: 'serverless'` to `next.config.js`
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
target: 'serverless'
|
||||
// Other options are still valid
|
||||
}
|
||||
```
|
||||
|
||||
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
|
||||
|
||||
```js
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@now/next" }]
|
||||
}
|
||||
```
|
||||
@@ -15,7 +15,7 @@
|
||||
"publish-stable": "lerna version",
|
||||
"publish-canary": "lerna version prerelease --preid canary",
|
||||
"lint": "tsc && eslint .",
|
||||
"test": "jest --runInBand",
|
||||
"test": "jest --runInBand --verbose",
|
||||
"lint-staged": "lint-staged"
|
||||
},
|
||||
"pre-commit": "lint-staged",
|
||||
@@ -31,6 +31,7 @@
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/multistream": "^2.1.1",
|
||||
"@types/node": "^10.12.8",
|
||||
"async-retry": "1.2.3",
|
||||
"buffer-replace": "^1.0.0",
|
||||
"eslint": "^5.9.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
|
||||
32
packages/now-bash/.editorconfig
Normal file
32
packages/now-bash/.editorconfig
Normal 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
|
||||
@@ -33,17 +33,8 @@ if declare -f build > /dev/null; then
|
||||
build "$@"
|
||||
fi
|
||||
|
||||
# Ensure the entrypoint defined a `serve` function
|
||||
if ! declare -f serve > /dev/null; then
|
||||
echo "ERROR: A \`serve\` function must be defined in \"$ENTRYPOINT\"!" >&2
|
||||
# Ensure the entrypoint defined a `handler` function
|
||||
if ! declare -f handler > /dev/null; then
|
||||
echo "ERROR: A \`handler\` function must be defined in \"$ENTRYPOINT\"!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Show a tree of the final lambda build
|
||||
show_tree() {
|
||||
import "static-binaries@0.0.6"
|
||||
static_binaries tree
|
||||
echo "Final lambda file tree:"
|
||||
tree -a .
|
||||
}
|
||||
IMPORT_DEBUG= IMPORT_CACHE="$(mktemp -d)" show_tree
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const execa = require('execa');
|
||||
const { join } = require('path');
|
||||
const snakeCase = require('snake-case');
|
||||
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');
|
||||
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
exports.config = {
|
||||
maxLambdaSize: '10mb',
|
||||
@@ -38,6 +38,7 @@ exports.build = async ({ files, entrypoint, config }) => {
|
||||
await execa(builderPath, [entrypoint], {
|
||||
env,
|
||||
cwd: workDir,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
const lambda = await createLambda({
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
{
|
||||
"name": "@now/bash",
|
||||
"version": "0.0.3",
|
||||
"version": "0.1.2",
|
||||
"description": "Now 2.0 builder for HTTP endpoints written in Bash",
|
||||
"main": "index.js",
|
||||
"author": "Nathan Rajlich <nate@zeit.co>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-bash"
|
||||
},
|
||||
"files": [
|
||||
"builder.sh",
|
||||
"runtime.sh",
|
||||
@@ -15,8 +20,5 @@
|
||||
"dependencies": {
|
||||
"execa": "^1.0.0",
|
||||
"snake-case": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "static-binaries@0.0.6"
|
||||
import "static-binaries@1.0.0"
|
||||
static_binaries jq
|
||||
|
||||
# These get reset upon each request
|
||||
@@ -35,11 +35,10 @@ _lambda_runtime_next() {
|
||||
# Get an event
|
||||
local event
|
||||
event="$(mktemp)"
|
||||
_lambda_runtime_api invocation/next -D "$headers" | jq -r '.body' > "$event"
|
||||
_lambda_runtime_api invocation/next -D "$headers" | jq --raw-output --monochrome-output '.body' > "$event"
|
||||
|
||||
local request_id
|
||||
request_id="$(grep -Fi Lambda-Runtime-Aws-Request-Id "$headers" | tr -d '[:space:]' | cut -d: -f2)"
|
||||
echo "Request-Id: $request_id" >&2
|
||||
rm -f "$headers"
|
||||
|
||||
# Execute the handler function from the script
|
||||
@@ -49,41 +48,38 @@ _lambda_runtime_next() {
|
||||
local exit_code=0
|
||||
REQUEST="$event"
|
||||
|
||||
# Stdin of the `serve` function is the HTTP request body.
|
||||
# Stdin of the `handler` function is the HTTP request body.
|
||||
# Need to use a fifo here instead of bash <() because Lambda
|
||||
# errors with "/dev/fd/63 not found" for some reason :/
|
||||
local stdin
|
||||
stdin="$(mktemp --dry-run)"
|
||||
stdin="$(mktemp -u)"
|
||||
mkfifo "$stdin"
|
||||
_lambda_runtime_body "$event" > "$stdin" &
|
||||
|
||||
serve "$event" < "$stdin" > "$body" || exit_code="$?"
|
||||
handler "$event" < "$stdin" > "$body" || exit_code="$?"
|
||||
rm -f "$event" "$stdin"
|
||||
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
# Send the response
|
||||
local response
|
||||
response="$(jq -cnMr \
|
||||
jq --raw-input --raw-output --compact-output --slurp --monochrome-output \
|
||||
--arg statusCode "$(cat "$_STATUS_CODE")" \
|
||||
--argjson headers "$(cat "$_HEADERS")" \
|
||||
--arg body "$(base64 --wrap=0 < "$body")" \
|
||||
'{statusCode:$statusCode|tonumber, headers:$headers, encoding:"base64", body:$body}')"
|
||||
'{statusCode:$statusCode|tonumber, headers:$headers, encoding:"base64", body:.|@base64}' < "$body" \
|
||||
| _lambda_runtime_api "invocation/$request_id/response" -X POST -d @- > /dev/null
|
||||
rm -f "$body" "$_HEADERS"
|
||||
_lambda_runtime_api "invocation/$request_id/response" -X POST -d "$response"
|
||||
else
|
||||
local error
|
||||
error='{"exitCode":'"$exit_code"'}'
|
||||
_lambda_runtime_api "invocation/$request_id/error" -X POST -d "$error"
|
||||
echo "\`handler\` function return code: $exit_code"
|
||||
_lambda_runtime_api "invocation/$request_id/error" -X POST -d @- > /dev/null <<< '{"exitCode":'"$exit_code"'}'
|
||||
fi
|
||||
}
|
||||
|
||||
_lambda_runtime_body() {
|
||||
if [ "$(jq -r '.body | type' < "$1")" = "string" ]; then
|
||||
if [ "$(jq -r '.encoding' < "$1")" = "base64" ]; then
|
||||
jq -r '.body' < "$1" | base64 -d
|
||||
if [ "$(jq --raw-output '.body | type' < "$1")" = "string" ]; then
|
||||
if [ "$(jq --raw-output '.encoding' < "$1")" = "base64" ]; then
|
||||
jq --raw-output '.body' < "$1" | base64 -d
|
||||
else
|
||||
# assume plain-text body
|
||||
jq -r '.body' < "$1"
|
||||
jq --raw-output '.body' < "$1"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/test
|
||||
tmp
|
||||
@@ -26,6 +26,18 @@ class FileFsRef {
|
||||
this.fsPath = fsPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `FileFsRef` with the correct `mode` from the file system.
|
||||
*
|
||||
* @argument {Object} options
|
||||
* @argument {string} options.fsPath
|
||||
* @returns {Promise<FileFsRef>}
|
||||
*/
|
||||
static async fromFsPath({ fsPath }) {
|
||||
const { mode } = await fs.lstat(fsPath);
|
||||
return new FileFsRef({ mode, fsPath });
|
||||
}
|
||||
|
||||
/**
|
||||
* @argument {Object} options
|
||||
* @argument {number} [options.mode=0o100644]
|
||||
|
||||
@@ -49,14 +49,14 @@ class FileRef {
|
||||
assert(url);
|
||||
|
||||
await semaToDownloadFromS3.acquire();
|
||||
console.time(`downloading ${url}`);
|
||||
// console.time(`downloading ${url}`);
|
||||
try {
|
||||
return await retry(
|
||||
async () => {
|
||||
const resp = await fetch(url);
|
||||
if (!resp.ok) {
|
||||
const error = new BailableError(
|
||||
`${resp.status} ${resp.statusText}`,
|
||||
`download: ${resp.status} ${resp.statusText} for ${url}`,
|
||||
);
|
||||
if (resp.status === 403) error.bail = true;
|
||||
throw error;
|
||||
@@ -66,7 +66,7 @@ class FileRef {
|
||||
{ factor: 1, retries: 3 },
|
||||
);
|
||||
} finally {
|
||||
console.timeEnd(`downloading ${url}`);
|
||||
// console.timeEnd(`downloading ${url}`);
|
||||
semaToDownloadFromS3.release();
|
||||
}
|
||||
}
|
||||
|
||||
83
packages/now-build-utils/fs/bootstrap-yarn.js
vendored
83
packages/now-build-utils/fs/bootstrap-yarn.js
vendored
@@ -1,83 +0,0 @@
|
||||
const MemoryFileSystem = require('memory-fs');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
const yarnPath = spawnSync('which', ['yarn'])
|
||||
.stdout.toString()
|
||||
.trim();
|
||||
|
||||
const cachePath = spawnSync(yarnPath, ['cache', 'dir'])
|
||||
.stdout.toString()
|
||||
.trim();
|
||||
|
||||
spawnSync(yarnPath, ['cache', 'clean']);
|
||||
const vfs = new MemoryFileSystem();
|
||||
|
||||
function isOutsideCachePath(filename) {
|
||||
const relative = path.relative(cachePath, filename);
|
||||
return relative.startsWith('..');
|
||||
}
|
||||
|
||||
const saveCreateWriteStream = fs.createWriteStream;
|
||||
fs.createWriteStream = (...args) => {
|
||||
const filename = args[0];
|
||||
if (isOutsideCachePath(filename)) {
|
||||
return saveCreateWriteStream.call(fs, ...args);
|
||||
}
|
||||
|
||||
vfs.mkdirpSync(path.dirname(filename));
|
||||
fs.writeFileSync(filename, Buffer.alloc(0));
|
||||
const stream = vfs.createWriteStream(...args);
|
||||
|
||||
stream.on('finish', () => {
|
||||
setTimeout(() => {
|
||||
stream.emit('close');
|
||||
});
|
||||
});
|
||||
|
||||
return stream;
|
||||
};
|
||||
|
||||
const saveReadFile = fs.readFile;
|
||||
fs.readFile = (...args) => {
|
||||
const filename = args[0];
|
||||
if (isOutsideCachePath(filename)) {
|
||||
return saveReadFile.call(fs, ...args);
|
||||
}
|
||||
|
||||
const callback = args[args.length - 1];
|
||||
return vfs.readFile(...args.slice(0, -1), (error, result) => {
|
||||
if (error) {
|
||||
saveReadFile.call(fs, ...args);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(error, result);
|
||||
});
|
||||
};
|
||||
|
||||
const saveCopyFile = fs.copyFile;
|
||||
fs.copyFile = (...args) => {
|
||||
const src = args[0];
|
||||
if (isOutsideCachePath(src)) {
|
||||
return saveCopyFile.call(fs, ...args);
|
||||
}
|
||||
|
||||
const dest = args[1];
|
||||
const callback = args[args.length - 1];
|
||||
const buffer = vfs.readFileSync(src);
|
||||
return fs.writeFile(dest, buffer, callback);
|
||||
};
|
||||
|
||||
const saveWriteFile = fs.writeFile;
|
||||
fs.writeFile = (...args) => {
|
||||
const filename = args[0];
|
||||
if (isOutsideCachePath(filename)) {
|
||||
return saveWriteFile.call(fs, ...args);
|
||||
}
|
||||
|
||||
return vfs.writeFile(...args);
|
||||
};
|
||||
|
||||
require(yarnPath);
|
||||
@@ -1,8 +1,8 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const dev = !process.env.AWS_EXECUTION_ENV;
|
||||
const TMP_PATH = dev ? path.join(process.cwd(), 'tmp') : '/tmp';
|
||||
const prod = process.env.AWS_EXECUTION_ENV || process.env.X_GOOGLE_CODE_LOCATION;
|
||||
const TMP_PATH = prod ? '/tmp' : path.join(__dirname, 'tmp');
|
||||
|
||||
module.exports = async function getWritableDirectory() {
|
||||
const name = Math.floor(Math.random() * 0x7fffffff).toString(16);
|
||||
|
||||
@@ -35,7 +35,7 @@ async function scanParentDirs(destPath, scriptName) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const packageJson = JSON.parse(await fs.readFile(packageJsonPath));
|
||||
hasScript = Boolean(
|
||||
packageJson.scripts && packageJson.scripts[scriptName],
|
||||
packageJson.scripts && scriptName && packageJson.scripts[scriptName],
|
||||
);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
hasPackageLockJson = await fs.exists(
|
||||
@@ -52,7 +52,7 @@ async function scanParentDirs(destPath, scriptName) {
|
||||
return { hasScript, hasPackageLockJson };
|
||||
}
|
||||
|
||||
async function runNpmInstall(destPath, args = []) {
|
||||
async function installDependencies(destPath, args = []) {
|
||||
assert(path.isAbsolute(destPath));
|
||||
|
||||
let commandArgs = args;
|
||||
@@ -63,15 +63,6 @@ async function runNpmInstall(destPath, args = []) {
|
||||
commandArgs = args.filter(a => a !== '--prefer-offline');
|
||||
await spawnAsync('npm', ['install'].concat(commandArgs), destPath);
|
||||
await spawnAsync('npm', ['cache', 'clean', '--force'], destPath);
|
||||
} else if (process.env.AWS_EXECUTION_ENV) {
|
||||
console.log('using memory-fs for yarn cache');
|
||||
await spawnAsync(
|
||||
'node',
|
||||
[path.join(__dirname, 'bootstrap-yarn.js'), '--cwd', destPath].concat(
|
||||
commandArgs,
|
||||
),
|
||||
destPath,
|
||||
);
|
||||
} else {
|
||||
await spawnAsync('yarn', ['--cwd', destPath].concat(commandArgs), destPath);
|
||||
await spawnAsync('yarn', ['cache', 'clean'], destPath);
|
||||
@@ -99,6 +90,7 @@ async function runPackageJsonScript(destPath, scriptName) {
|
||||
|
||||
module.exports = {
|
||||
runShellScript,
|
||||
runNpmInstall,
|
||||
installDependencies,
|
||||
runNpmInstall: installDependencies,
|
||||
runPackageJsonScript,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const assert = require('assert');
|
||||
const Sema = require('async-sema');
|
||||
const { ZipFile } = require('yazl');
|
||||
const streamToBuffer = require('./fs/stream-to-buffer.js');
|
||||
|
||||
@@ -14,6 +15,7 @@ class Lambda {
|
||||
}
|
||||
}
|
||||
|
||||
const sema = new Sema(10);
|
||||
const mtime = new Date(1540000000000);
|
||||
|
||||
async function createLambda({
|
||||
@@ -23,24 +25,33 @@ async function createLambda({
|
||||
assert(typeof handler === 'string', '"handler" is not a string');
|
||||
assert(typeof runtime === 'string', '"runtime" is not a string');
|
||||
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 });
|
||||
await sema.acquire();
|
||||
try {
|
||||
const zipFile = new ZipFile();
|
||||
const zipBuffer = await new Promise((resolve, reject) => {
|
||||
Object.keys(files)
|
||||
.sort()
|
||||
.forEach((name) => {
|
||||
const file = files[name];
|
||||
const stream = file.toStream();
|
||||
stream.on('error', reject);
|
||||
zipFile.addReadStream(stream, name, { mode: file.mode, mtime });
|
||||
});
|
||||
|
||||
zipFile.end();
|
||||
streamToBuffer(zipFile.outputStream).then(resolve).catch(reject);
|
||||
});
|
||||
|
||||
zipFile.end();
|
||||
const zipBuffer = await streamToBuffer(zipFile.outputStream);
|
||||
return new Lambda({
|
||||
zipBuffer,
|
||||
handler,
|
||||
runtime,
|
||||
environment,
|
||||
});
|
||||
return new Lambda({
|
||||
zipBuffer,
|
||||
handler,
|
||||
runtime,
|
||||
environment,
|
||||
});
|
||||
} finally {
|
||||
sema.release();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"name": "@now/build-utils",
|
||||
"version": "0.4.31",
|
||||
"version": "0.4.35-canary.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-build-utils"
|
||||
},
|
||||
"dependencies": {
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "2.1.4",
|
||||
|
||||
5
packages/now-build-utils/test/fixtures/07-cross-install/api/index.js
vendored
Normal file
5
packages/now-build-utils/test/fixtures/07-cross-install/api/index.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
const cowsay = require('cowsay').say;
|
||||
|
||||
module.exports = (req, resp) => {
|
||||
resp.end(cowsay({ text: 'cross-cow:RANDOMNESS_PLACEHOLDER' }));
|
||||
};
|
||||
5
packages/now-build-utils/test/fixtures/07-cross-install/api/package.json
vendored
Normal file
5
packages/now-build-utils/test/fixtures/07-cross-install/api/package.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"lib": "../lib"
|
||||
}
|
||||
}
|
||||
7
packages/now-build-utils/test/fixtures/07-cross-install/lib/package.json
vendored
Normal file
7
packages/now-build-utils/test/fixtures/07-cross-install/lib/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "lib",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"cowsay": "*"
|
||||
}
|
||||
}
|
||||
9
packages/now-build-utils/test/fixtures/07-cross-install/now.json
vendored
Normal file
9
packages/now-build-utils/test/fixtures/07-cross-install/now.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "api/index.js", "use": "@now/node" }
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/api/index.js", "mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER" }
|
||||
]
|
||||
}
|
||||
@@ -7,7 +7,7 @@ const {
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
|
||||
jest.setTimeout(2 * 60 * 1000);
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
const builderUrl = '@canary';
|
||||
let buildUtilsUrl;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
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');
|
||||
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"name": "@now/cgi",
|
||||
"version": "0.0.14",
|
||||
"version": "0.0.16-canary.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-cgi"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "best -I test/*.js",
|
||||
"prepublish": "./build.sh"
|
||||
@@ -15,8 +21,5 @@
|
||||
"devDependencies": {
|
||||
"@zeit/best": "0.4.3",
|
||||
"rmfr": "2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
5
packages/now-go/.gitignore
vendored
5
packages/now-go/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
node_modules
|
||||
*.log
|
||||
launcher
|
||||
bin
|
||||
/?.js
|
||||
/go
|
||||
/get-exported-function-name
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
mkdir -p bin
|
||||
cd util
|
||||
GOOS=linux GOARCH=amd64 go build get-exported-function-name.go
|
||||
mv get-exported-function-name ../bin/
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
const path = require('path');
|
||||
|
||||
const fetch = require('node-fetch');
|
||||
const tar = require('tar');
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
||||
|
||||
const url = 'https://dl.google.com/go/go1.11.1.linux-amd64.tar.gz';
|
||||
|
||||
module.exports = async () => {
|
||||
const res = await fetch(url);
|
||||
const dir = await getWritableDirectory();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to download: ${url}`);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
res.body
|
||||
.on('error', reject)
|
||||
.pipe(tar.extract({ cwd: dir, strip: 1 }))
|
||||
.on('finish', () => resolve(path.join(dir, 'bin', 'go')));
|
||||
});
|
||||
};
|
||||
124
packages/now-go/go-helpers.js
Normal file
124
packages/now-go/go-helpers.js
Normal file
@@ -0,0 +1,124 @@
|
||||
const tar = require('tar');
|
||||
const execa = require('execa');
|
||||
const fetch = require('node-fetch');
|
||||
const { mkdirp } = require('fs-extra');
|
||||
const { dirname, join } = require('path');
|
||||
const debug = require('debug')('@now/go:go-helpers');
|
||||
|
||||
const archMap = new Map([['x64', 'amd64'], ['x86', '386']]);
|
||||
const platformMap = new Map([['win32', 'windows']]);
|
||||
|
||||
// Location where the `go` binary will be installed after `postinstall`
|
||||
const GO_DIR = join(__dirname, 'go');
|
||||
const GO_BIN = join(GO_DIR, 'bin/go');
|
||||
|
||||
const getPlatform = p => platformMap.get(p) || p;
|
||||
const getArch = a => archMap.get(a) || a;
|
||||
const getGoUrl = (version, platform, arch) => {
|
||||
const goArch = getArch(arch);
|
||||
const goPlatform = getPlatform(platform);
|
||||
const ext = platform === 'win32' ? 'zip' : 'tar.gz';
|
||||
return `https://dl.google.com/go/go${version}.${goPlatform}-${goArch}.${ext}`;
|
||||
};
|
||||
|
||||
function getExportedFunctionName(filePath) {
|
||||
debug('Detecting handler name for %o', filePath);
|
||||
const bin = join(__dirname, 'get-exported-function-name');
|
||||
const args = [filePath];
|
||||
const name = execa.stdout(bin, args);
|
||||
debug('Detected exported name %o', filePath);
|
||||
return name;
|
||||
}
|
||||
|
||||
// Creates a `$GOPATH` directory tree, as per `go help gopath` instructions.
|
||||
// Without this, `go` won't recognize the `$GOPATH`.
|
||||
function createGoPathTree(goPath, platform, arch) {
|
||||
const tuple = `${getPlatform(platform)}_${getArch(arch)}`;
|
||||
debug('Creating GOPATH directory structure for %o (%s)', goPath, tuple);
|
||||
return Promise.all([
|
||||
mkdirp(join(goPath, 'bin')),
|
||||
mkdirp(join(goPath, 'pkg', tuple)),
|
||||
]);
|
||||
}
|
||||
|
||||
async function get({ src } = {}) {
|
||||
const args = ['get'];
|
||||
if (src) {
|
||||
debug('Fetching `go` dependencies for file %o', src);
|
||||
args.push(src);
|
||||
} else {
|
||||
debug('Fetching `go` dependencies for cwd %o', this.cwd);
|
||||
}
|
||||
await this(...args);
|
||||
}
|
||||
|
||||
async function build({ src, dest }) {
|
||||
debug('Building `go` binary %o -> %o', src, dest);
|
||||
let sources;
|
||||
if (Array.isArray(src)) {
|
||||
sources = src;
|
||||
} else {
|
||||
sources = [src];
|
||||
}
|
||||
await this('build', '-o', dest, ...sources);
|
||||
}
|
||||
|
||||
async function createGo(
|
||||
goPath,
|
||||
platform = process.platform,
|
||||
arch = process.arch,
|
||||
opts = {},
|
||||
) {
|
||||
const env = {
|
||||
...process.env,
|
||||
PATH: `${dirname(GO_BIN)}:${process.env.PATH}`,
|
||||
GOPATH: goPath,
|
||||
...opts.env,
|
||||
};
|
||||
|
||||
function go(...args) {
|
||||
debug('Exec %o', `go ${args.join(' ')}`);
|
||||
return execa('go', args, { stdio: 'inherit', ...opts, env });
|
||||
}
|
||||
go.cwd = opts.cwd || process.cwd();
|
||||
go.get = get;
|
||||
go.build = build;
|
||||
go.goPath = goPath;
|
||||
await createGoPathTree(goPath, platform, arch);
|
||||
return go;
|
||||
}
|
||||
|
||||
async function downloadGo(
|
||||
dir = GO_DIR,
|
||||
version = '1.11.5',
|
||||
platform = process.platform,
|
||||
arch = process.arch,
|
||||
) {
|
||||
debug('Installing `go` v%s to %o for %s %s', version, dir, platform, arch);
|
||||
|
||||
const url = getGoUrl(version, platform, arch);
|
||||
debug('Downloading `go` URL: %o', url);
|
||||
const res = await fetch(url);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to download: ${url} (${res.status})`);
|
||||
}
|
||||
|
||||
// TODO: use a zip extractor when `ext === "zip"`
|
||||
await mkdirp(dir);
|
||||
await new Promise((resolve, reject) => {
|
||||
res.body
|
||||
.on('error', reject)
|
||||
.pipe(tar.extract({ cwd: dir, strip: 1 }))
|
||||
.on('error', reject)
|
||||
.on('finish', resolve);
|
||||
});
|
||||
|
||||
return createGo(dir, platform, arch);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createGo,
|
||||
downloadGo,
|
||||
getExportedFunctionName,
|
||||
};
|
||||
@@ -1,79 +1,52 @@
|
||||
const path = require('path');
|
||||
const { mkdirp, readFile, writeFile } = require('fs-extra');
|
||||
const { join, dirname } = require('path');
|
||||
const { readFile, writeFile } = require('fs-extra');
|
||||
|
||||
const execa = require('execa');
|
||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
||||
const download = require('@now/build-utils/fs/download.js');
|
||||
const downloadGit = require('lambda-git');
|
||||
const glob = require('@now/build-utils/fs/glob.js');
|
||||
const downloadGoBin = require('./download-go-bin');
|
||||
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const { createGo, getExportedFunctionName } = require('./go-helpers');
|
||||
|
||||
// creates a `$GOPATH` directory tree, as per
|
||||
// `go help gopath`'s instructions.
|
||||
// without this, Go won't recognize the `$GOPATH`
|
||||
async function createGoPathTree(goPath) {
|
||||
await mkdirp(path.join(goPath, 'bin'));
|
||||
await mkdirp(path.join(goPath, 'pkg', 'linux_amd64'));
|
||||
}
|
||||
|
||||
exports.config = {
|
||||
const config = {
|
||||
maxLambdaSize: '10mb',
|
||||
};
|
||||
|
||||
exports.build = async ({ files, entrypoint }) => {
|
||||
console.log('downloading files...');
|
||||
async function build({ files, entrypoint }) {
|
||||
console.log('Downloading user files...');
|
||||
|
||||
const gitPath = await getWritableDirectory();
|
||||
const goPath = await getWritableDirectory();
|
||||
const srcPath = path.join(goPath, 'src', 'lambda');
|
||||
const outDir = await getWritableDirectory();
|
||||
|
||||
await createGoPathTree(goPath);
|
||||
const [goPath, outDir] = await Promise.all([
|
||||
getWritableDirectory(),
|
||||
getWritableDirectory(),
|
||||
]);
|
||||
|
||||
const srcPath = join(goPath, 'src', 'lambda');
|
||||
const downloadedFiles = await download(files, srcPath);
|
||||
|
||||
console.log('downloading go binary...');
|
||||
const goBin = await downloadGoBin();
|
||||
|
||||
console.log('downloading git binary...');
|
||||
// downloads a git binary that works on Amazon Linux and sets
|
||||
// `process.env.GIT_EXEC_PATH` so `go(1)` can see it
|
||||
await downloadGit({ targetDirectory: gitPath });
|
||||
|
||||
const goEnv = {
|
||||
...process.env,
|
||||
GOOS: 'linux',
|
||||
GOARCH: 'amd64',
|
||||
GOPATH: goPath,
|
||||
};
|
||||
|
||||
console.log(`parsing AST for "${entrypoint}"`);
|
||||
let handlerFunctionName = '';
|
||||
console.log(`Parsing AST for "${entrypoint}"`);
|
||||
let handlerFunctionName;
|
||||
try {
|
||||
handlerFunctionName = await execa.stdout(
|
||||
path.join(__dirname, 'bin', 'get-exported-function-name'),
|
||||
[downloadedFiles[entrypoint].fsPath],
|
||||
handlerFunctionName = await getExportedFunctionName(
|
||||
downloadedFiles[entrypoint].fsPath,
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(`failed to parse AST for "${entrypoint}"`);
|
||||
console.log(`Failed to parse AST for "${entrypoint}"`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (handlerFunctionName === '') {
|
||||
const e = new Error(
|
||||
`Could not find an exported function on "${entrypoint}"`,
|
||||
if (!handlerFunctionName) {
|
||||
const err = new Error(
|
||||
`Could not find an exported function in "${entrypoint}"`,
|
||||
);
|
||||
console.log(e.message);
|
||||
throw e;
|
||||
console.log(err.message);
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Found exported function "${handlerFunctionName}" on "${entrypoint}"`,
|
||||
`Found exported function "${handlerFunctionName}" in "${entrypoint}"`,
|
||||
);
|
||||
|
||||
const origianlMainGoContents = await readFile(
|
||||
path.join(__dirname, 'main.go'),
|
||||
join(__dirname, 'main.go'),
|
||||
'utf8',
|
||||
);
|
||||
const mainGoContents = origianlMainGoContents.replace(
|
||||
@@ -85,39 +58,33 @@ exports.build = async ({ files, entrypoint }) => {
|
||||
|
||||
// we need `main.go` in the same dir as the entrypoint,
|
||||
// otherwise `go build` will refuse to build
|
||||
const entrypointDirname = path.dirname(downloadedFiles[entrypoint].fsPath);
|
||||
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
|
||||
|
||||
// Go doesn't like to build files in different directories,
|
||||
// so now we place `main.go` together with the user code
|
||||
await writeFile(path.join(entrypointDirname, mainGoFileName), mainGoContents);
|
||||
await writeFile(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
|
||||
const go = await createGo(goPath, process.platform, process.arch, {
|
||||
cwd: entrypointDirname,
|
||||
});
|
||||
|
||||
// `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 go.get();
|
||||
} catch (err) {
|
||||
console.log('failed to `go get`');
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log('running go build...');
|
||||
console.log('Running `go build`...');
|
||||
const destPath = join(outDir, 'handler');
|
||||
try {
|
||||
await execa(
|
||||
goBin,
|
||||
[
|
||||
'build',
|
||||
'-o',
|
||||
path.join(outDir, 'handler'),
|
||||
path.join(entrypointDirname, mainGoFileName),
|
||||
downloadedFiles[entrypoint].fsPath,
|
||||
],
|
||||
{ env: goEnv, cwd: entrypointDirname, stdio: 'inherit' },
|
||||
);
|
||||
const src = [
|
||||
join(entrypointDirname, mainGoFileName),
|
||||
downloadedFiles[entrypoint].fsPath,
|
||||
];
|
||||
await go.build({ src, dest: destPath });
|
||||
} catch (err) {
|
||||
console.log('failed to `go build`');
|
||||
throw err;
|
||||
@@ -133,4 +100,6 @@ exports.build = async ({ files, entrypoint }) => {
|
||||
return {
|
||||
[entrypoint]: lambda,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { config, build };
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
now "../../utils/go/bridge"
|
||||
"net/http"
|
||||
now "github.com/zeit/now-builders/utils/go/bridge"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
{
|
||||
"name": "@now/go",
|
||||
"version": "0.2.11",
|
||||
"version": "0.2.13-canary.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-go"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "best -I test/*.js",
|
||||
"prepublish": "./build.sh"
|
||||
"postinstall": "node ./util/install"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"download-go-bin.js",
|
||||
"index.js",
|
||||
"main.go"
|
||||
"*.js",
|
||||
"main.go",
|
||||
"util"
|
||||
],
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"execa": "^1.0.0",
|
||||
"fs-extra": "^7.0.0",
|
||||
"lambda-git": "^0.1.2",
|
||||
"mkdirp-promise": "5.0.1",
|
||||
"node-fetch": "^2.2.1",
|
||||
"tar": "4.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@zeit/best": "0.4.3",
|
||||
"rmfr": "2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
18
packages/now-go/util/install.js
Normal file
18
packages/now-go/util/install.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { join } = require('path');
|
||||
const { downloadGo } = require('../go-helpers');
|
||||
|
||||
async function main() {
|
||||
// First download the `go` binary for this platform/arch.
|
||||
const go = await downloadGo();
|
||||
|
||||
// Build the `get-exported-function-name` helper program.
|
||||
// `go get` is not necessary because the program has no external deps.
|
||||
const src = join(__dirname, 'get-exported-function-name.go');
|
||||
const dest = join(__dirname, '../get-exported-function-name');
|
||||
await go.build({ src, dest });
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
||||
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const { minify } = require('html-minifier');
|
||||
|
||||
const defaultOptions = {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
{
|
||||
"name": "@now/html-minifier",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.8-canary.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-html-minifier"
|
||||
},
|
||||
"dependencies": {
|
||||
"html-minifier": "3.5.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { Lambda } = require('@now/build-utils/lambda.js');
|
||||
const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js');
|
||||
const { Lambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const streamToBuffer = require('@now/build-utils/fs/stream-to-buffer.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
exports.build = async ({ files, entrypoint, config }) => {
|
||||
if (!files[entrypoint]) throw new Error('Entrypoint not found in files');
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@now/lambda",
|
||||
"version": "0.4.8",
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
"version": "0.4.10-canary.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-lambda"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
||||
@@ -7,7 +7,7 @@ const {
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
|
||||
jest.setTimeout(2 * 60 * 1000);
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
const buildUtilsUrl = '@canary';
|
||||
let builderUrl;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
||||
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const unified = require('unified');
|
||||
const unifiedStream = require('unified-stream');
|
||||
const markdown = require('remark-parse');
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"name": "@now/md",
|
||||
"version": "0.4.8",
|
||||
"version": "0.4.10-canary.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-md"
|
||||
},
|
||||
"dependencies": {
|
||||
"rehype-document": "^2.2.0",
|
||||
"rehype-format": "^2.3.0",
|
||||
@@ -10,9 +16,6 @@
|
||||
"unified": "^7.0.0",
|
||||
"unified-stream": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const {
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
|
||||
jest.setTimeout(2 * 60 * 1000);
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
const buildUtilsUrl = '@canary';
|
||||
let builderUrl;
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
const download = require('@now/build-utils/fs/download.js');
|
||||
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const fs = require('fs');
|
||||
const { promisify } = require('util');
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js');
|
||||
const glob = require('@now/build-utils/fs/glob.js');
|
||||
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const path = require('path');
|
||||
const { runNpmInstall } = require('@now/build-utils/fs/run-user-scripts.js');
|
||||
|
||||
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
|
||||
const { runNpmInstall } = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
|
||||
@@ -17,7 +15,7 @@ exports.build = async ({ files, entrypoint, workPath }) => {
|
||||
const packageJson = { dependencies: { 'mdx-deck': '1.7.15' } };
|
||||
const packageJsonPath = path.join(workPath, 'package.json');
|
||||
await writeFile(packageJsonPath, JSON.stringify(packageJson));
|
||||
console.log('running npm install...');
|
||||
console.log('installing dependencies...');
|
||||
process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = '1'; // TODO opts argument for runNpmInstall
|
||||
await runNpmInstall(path.dirname(packageJsonPath), [
|
||||
'--prod',
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@now/mdx-deck",
|
||||
"version": "0.4.17",
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
"version": "0.4.19-canary.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-mdx-deck"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
||||
@@ -7,7 +7,7 @@ const {
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
|
||||
jest.setTimeout(2 * 60 * 1000);
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
const buildUtilsUrl = '@canary';
|
||||
let builderUrl;
|
||||
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
const { createLambda } = require('@now/build-utils/lambda.js');
|
||||
const download = require('@now/build-utils/fs/download.js');
|
||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js');
|
||||
const FileBlob = require('@now/build-utils/file-blob');
|
||||
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileBlob = require('@now/build-utils/file-blob'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const path = require('path');
|
||||
const { readFile, writeFile, unlink } = require('fs.promised');
|
||||
const {
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
||||
const glob = require('@now/build-utils/fs/glob.js');
|
||||
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const semver = require('semver');
|
||||
const nextLegacyVersions = require('./legacy-versions');
|
||||
const {
|
||||
excludeFiles,
|
||||
validateEntrypoint,
|
||||
includeOnlyEntryDirectory,
|
||||
moveEntryDirectoryToRoot,
|
||||
excludeLockFiles,
|
||||
normalizePackageJson,
|
||||
excludeStaticDirectory,
|
||||
onlyStaticDirectory,
|
||||
} = require('./utils');
|
||||
|
||||
@@ -32,15 +31,17 @@ const {
|
||||
|
||||
/**
|
||||
* Read package.json from files
|
||||
* @param {DownloadedFiles} files
|
||||
* @param {string} entryPath
|
||||
*/
|
||||
async function readPackageJson(files) {
|
||||
if (!files['package.json']) {
|
||||
async function readPackageJson(entryPath) {
|
||||
const packagePath = path.join(entryPath, 'package.json');
|
||||
|
||||
try {
|
||||
return JSON.parse(await readFile(packagePath, 'utf8'));
|
||||
} catch (err) {
|
||||
console.log('package.json not found in entry');
|
||||
return {};
|
||||
}
|
||||
|
||||
const packageJsonPath = files['package.json'].fsPath;
|
||||
return JSON.parse(await readFile(packageJsonPath, 'utf8'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,125 +81,229 @@ exports.build = async ({ files, workPath, entrypoint }) => {
|
||||
|
||||
console.log('downloading user files...');
|
||||
const entryDirectory = path.dirname(entrypoint);
|
||||
const filesOnlyEntryDirectory = includeOnlyEntryDirectory(
|
||||
files,
|
||||
entryDirectory,
|
||||
);
|
||||
const filesWithEntryDirectoryRoot = moveEntryDirectoryToRoot(
|
||||
filesOnlyEntryDirectory,
|
||||
entryDirectory,
|
||||
);
|
||||
const filesWithoutLockfiles = excludeLockFiles(filesWithEntryDirectoryRoot);
|
||||
const filesWithoutStaticDirectory = excludeStaticDirectory(
|
||||
filesWithoutLockfiles,
|
||||
);
|
||||
const downloadedFiles = await download(filesWithoutStaticDirectory, workPath);
|
||||
await download(files, workPath);
|
||||
const entryPath = path.join(workPath, entryDirectory);
|
||||
|
||||
console.log('normalizing package.json');
|
||||
const packageJson = normalizePackageJson(
|
||||
await readPackageJson(downloadedFiles),
|
||||
);
|
||||
console.log('normalized package.json result: ', packageJson);
|
||||
await writePackageJson(workPath, packageJson);
|
||||
const pkg = await readPackageJson(entryPath);
|
||||
|
||||
let nextVersion;
|
||||
if (pkg.dependencies && pkg.dependencies.next) {
|
||||
nextVersion = pkg.dependencies.next;
|
||||
} else if (pkg.devDependencies && pkg.devDependencies.next) {
|
||||
nextVersion = pkg.devDependencies.next;
|
||||
}
|
||||
|
||||
if (!nextVersion) {
|
||||
throw new Error(
|
||||
'No Next.js version could be detected in "package.json". Make sure `"next"` is installed in "dependencies" or "devDependencies"',
|
||||
);
|
||||
}
|
||||
|
||||
const isLegacy = (() => {
|
||||
// If version is using the dist-tag instead of a version range
|
||||
if (nextVersion === 'canary' || nextVersion === 'latest') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the version is an exact match with the legacy versions
|
||||
if (nextLegacyVersions.indexOf(nextVersion) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const maxSatisfying = semver.maxSatisfying(nextLegacyVersions, nextVersion);
|
||||
// When the version can't be matched with legacy versions, so it must be a newer version
|
||||
if (maxSatisfying === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})();
|
||||
|
||||
console.log(`MODE: ${isLegacy ? 'legacy' : 'serverless'}`);
|
||||
|
||||
if (isLegacy) {
|
||||
try {
|
||||
await unlink(path.join(entryPath, 'yarn.lock'));
|
||||
} catch (err) {
|
||||
console.log('no yarn.lock removed');
|
||||
}
|
||||
|
||||
try {
|
||||
await unlink(path.join(entryPath, 'package-lock.json'));
|
||||
} catch (err) {
|
||||
console.log('no package-lock.json removed');
|
||||
}
|
||||
|
||||
console.warn(
|
||||
"WARNING: your application is being deployed in @now/next's legacy mode. http://err.sh/zeit/now-builders/now-next-legacy-mode",
|
||||
);
|
||||
|
||||
console.log('normalizing package.json');
|
||||
const packageJson = normalizePackageJson(pkg);
|
||||
console.log('normalized package.json result: ', packageJson);
|
||||
await writePackageJson(entryPath, packageJson);
|
||||
} else if (!pkg.scripts || !pkg.scripts['now-build']) {
|
||||
console.warn(
|
||||
'WARNING: "now-build" script not found. Adding \'"now-build": "next build"\' to "package.json" automatically',
|
||||
);
|
||||
pkg.scripts = {
|
||||
'now-build': 'next build',
|
||||
...(pkg.scripts || {}),
|
||||
};
|
||||
console.log('normalized package.json result: ', pkg);
|
||||
await writePackageJson(entryPath, pkg);
|
||||
}
|
||||
|
||||
if (process.env.NPM_AUTH_TOKEN) {
|
||||
console.log('found NPM_AUTH_TOKEN in environment, creating .npmrc');
|
||||
await writeNpmRc(workPath, process.env.NPM_AUTH_TOKEN);
|
||||
await writeNpmRc(entryPath, process.env.NPM_AUTH_TOKEN);
|
||||
}
|
||||
|
||||
console.log('running npm install...');
|
||||
await runNpmInstall(workPath, ['--prefer-offline']);
|
||||
console.log('installing dependencies...');
|
||||
await runNpmInstall(entryPath, ['--prefer-offline']);
|
||||
console.log('running user script...');
|
||||
await runPackageJsonScript(workPath, 'now-build');
|
||||
console.log('running npm install --production...');
|
||||
await runNpmInstall(workPath, ['--prefer-offline', '--production']);
|
||||
await runPackageJsonScript(entryPath, 'now-build');
|
||||
|
||||
if (isLegacy) {
|
||||
console.log('running npm install --production...');
|
||||
await runNpmInstall(entryPath, ['--prefer-offline', '--production']);
|
||||
}
|
||||
|
||||
if (process.env.NPM_AUTH_TOKEN) {
|
||||
await unlink(path.join(workPath, '.npmrc'));
|
||||
await unlink(path.join(entryPath, '.npmrc'));
|
||||
}
|
||||
|
||||
const filesAfterBuild = await glob('**', workPath);
|
||||
|
||||
console.log('preparing lambda files...');
|
||||
let buildId;
|
||||
try {
|
||||
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"',
|
||||
);
|
||||
throw new Error('Missing BUILD_ID');
|
||||
}
|
||||
const dotNextRootFiles = await glob('.next/*', workPath);
|
||||
const dotNextServerRootFiles = await glob('.next/server/*', workPath);
|
||||
const nodeModules = excludeFiles(
|
||||
await glob('node_modules/**', workPath),
|
||||
file => file.startsWith('node_modules/.cache'),
|
||||
);
|
||||
const launcherFiles = {
|
||||
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
|
||||
};
|
||||
const nextFiles = {
|
||||
...nodeModules,
|
||||
...dotNextRootFiles,
|
||||
...dotNextServerRootFiles,
|
||||
...launcherFiles,
|
||||
};
|
||||
if (filesAfterBuild['next.config.js']) {
|
||||
nextFiles['next.config.js'] = filesAfterBuild['next.config.js'];
|
||||
}
|
||||
const pages = await glob(
|
||||
'**/*.js',
|
||||
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) => {
|
||||
// These default pages don't have to be handled as they'd always 404
|
||||
if (['_app.js', '_error.js', '_document.js'].includes(page)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pathname = page.replace(/\.js$/, '');
|
||||
const launcher = launcherData.replace(
|
||||
'PATHNAME_PLACEHOLDER',
|
||||
`/${pathname.replace(/(^|\/)index$/, '')}`,
|
||||
if (isLegacy) {
|
||||
const filesAfterBuild = await glob('**', entryPath);
|
||||
|
||||
console.log('preparing lambda files...');
|
||||
let buildId;
|
||||
try {
|
||||
buildId = await readFile(
|
||||
path.join(entryPath, '.next', 'BUILD_ID'),
|
||||
'utf8',
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'BUILD_ID not found in ".next". The "package.json" "build" script did not run "next build"',
|
||||
);
|
||||
throw new Error('Missing BUILD_ID');
|
||||
}
|
||||
const dotNextRootFiles = await glob('.next/*', entryPath);
|
||||
const dotNextServerRootFiles = await glob('.next/server/*', entryPath);
|
||||
const nodeModules = excludeFiles(
|
||||
await glob('node_modules/**', entryPath),
|
||||
file => file.startsWith('node_modules/.cache'),
|
||||
);
|
||||
const launcherFiles = {
|
||||
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
|
||||
};
|
||||
const nextFiles = {
|
||||
...nodeModules,
|
||||
...dotNextRootFiles,
|
||||
...dotNextServerRootFiles,
|
||||
...launcherFiles,
|
||||
};
|
||||
if (filesAfterBuild['next.config.js']) {
|
||||
nextFiles['next.config.js'] = filesAfterBuild['next.config.js'];
|
||||
}
|
||||
const pages = await glob(
|
||||
'**/*.js',
|
||||
path.join(entryPath, '.next', 'server', 'static', buildId, 'pages'),
|
||||
);
|
||||
const launcherPath = path.join(__dirname, 'legacy-launcher.js');
|
||||
const launcherData = await readFile(launcherPath, 'utf8');
|
||||
|
||||
const pageFiles = {
|
||||
[`.next/server/static/${buildId}/pages/_document.js`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/_document.js`
|
||||
],
|
||||
[`.next/server/static/${buildId}/pages/_app.js`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/_app.js`
|
||||
],
|
||||
[`.next/server/static/${buildId}/pages/_error.js`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/_error.js`
|
||||
],
|
||||
[`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/${page}`
|
||||
],
|
||||
};
|
||||
await Promise.all(
|
||||
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;
|
||||
}
|
||||
|
||||
console.log(`Creating lambda for page: "${page}"...`);
|
||||
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
|
||||
files: {
|
||||
...nextFiles,
|
||||
...pageFiles,
|
||||
'now__launcher.js': new FileBlob({ data: launcher }),
|
||||
},
|
||||
handler: 'now__launcher.launcher',
|
||||
runtime: 'nodejs8.10',
|
||||
});
|
||||
console.log(`Created lambda for page: "${page}"`);
|
||||
}),
|
||||
);
|
||||
const pathname = page.replace(/\.js$/, '');
|
||||
const launcher = launcherData.replace(
|
||||
'PATHNAME_PLACEHOLDER',
|
||||
`/${pathname.replace(/(^|\/)index$/, '')}`,
|
||||
);
|
||||
|
||||
const pageFiles = {
|
||||
[`.next/server/static/${buildId}/pages/_document.js`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/_document.js`
|
||||
],
|
||||
[`.next/server/static/${buildId}/pages/_app.js`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/_app.js`
|
||||
],
|
||||
[`.next/server/static/${buildId}/pages/_error.js`]: filesAfterBuild[
|
||||
`.next/server/static/${buildId}/pages/_error.js`
|
||||
],
|
||||
[`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[
|
||||
`.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 }),
|
||||
},
|
||||
handler: 'now__launcher.launcher',
|
||||
runtime: 'nodejs8.10',
|
||||
});
|
||||
console.log(`Created lambda for page: "${page}"`);
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
console.log('preparing lambda files...');
|
||||
const launcherFiles = {
|
||||
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
|
||||
'now__launcher.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'launcher.js'),
|
||||
}),
|
||||
};
|
||||
const pages = await glob(
|
||||
'**/*.js',
|
||||
path.join(entryPath, '.next', 'serverless', 'pages'),
|
||||
);
|
||||
|
||||
const pageKeys = Object.keys(pages);
|
||||
|
||||
if (pageKeys.length === 0) {
|
||||
throw new Error(
|
||||
'No serverless pages were built. https://err.sh/zeit/now-builders/now-next-no-serverless-pages-built',
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
pageKeys.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;
|
||||
}
|
||||
|
||||
const pathname = page.replace(/\.js$/, '');
|
||||
|
||||
console.log(`Creating lambda for page: "${page}"...`);
|
||||
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
|
||||
files: {
|
||||
...launcherFiles,
|
||||
'page.js': pages[page],
|
||||
},
|
||||
handler: 'now__launcher.launcher',
|
||||
runtime: 'nodejs8.10',
|
||||
});
|
||||
console.log(`Created lambda for page: "${page}"`);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const nextStaticFiles = await glob(
|
||||
'**',
|
||||
path.join(workPath, '.next', 'static'),
|
||||
path.join(entryPath, '.next', 'static'),
|
||||
);
|
||||
const staticFiles = Object.keys(nextStaticFiles).reduce(
|
||||
(mappedFiles, file) => ({
|
||||
@@ -208,7 +313,9 @@ exports.build = async ({ files, workPath, entrypoint }) => {
|
||||
{},
|
||||
);
|
||||
|
||||
const nextStaticDirectory = onlyStaticDirectory(filesWithoutLockfiles);
|
||||
const nextStaticDirectory = onlyStaticDirectory(
|
||||
includeOnlyEntryDirectory(files, entryDirectory),
|
||||
);
|
||||
const staticDirectoryFiles = Object.keys(nextStaticDirectory).reduce(
|
||||
(mappedFiles, file) => ({
|
||||
...mappedFiles,
|
||||
@@ -219,41 +326,3 @@ exports.build = async ({ files, workPath, entrypoint }) => {
|
||||
|
||||
return { ...lambdas, ...staticFiles, ...staticDirectoryFiles };
|
||||
};
|
||||
|
||||
exports.prepareCache = async ({
|
||||
files, entrypoint, cachePath, workPath,
|
||||
}) => {
|
||||
console.log('downloading user files...');
|
||||
const entryDirectory = path.dirname(entrypoint);
|
||||
const filesOnlyEntryDirectory = includeOnlyEntryDirectory(
|
||||
files,
|
||||
entryDirectory,
|
||||
);
|
||||
const filesWithEntryDirectoryRoot = moveEntryDirectoryToRoot(
|
||||
filesOnlyEntryDirectory,
|
||||
entryDirectory,
|
||||
);
|
||||
const filesWithoutLockfiles = excludeLockFiles(filesWithEntryDirectoryRoot);
|
||||
const filesWithoutStaticDirectory = excludeStaticDirectory(
|
||||
filesWithoutLockfiles,
|
||||
);
|
||||
await download(filesWithoutStaticDirectory, workPath);
|
||||
await download(await glob('.next/**', workPath), cachePath);
|
||||
await download(await glob('node_modules/**', workPath), cachePath);
|
||||
|
||||
console.log('.next folder contents', await glob('.next/**', cachePath));
|
||||
console.log(
|
||||
'.cache folder contents',
|
||||
await glob('node_modules/.cache/**', cachePath),
|
||||
);
|
||||
|
||||
console.log('running npm install...');
|
||||
await runNpmInstall(cachePath);
|
||||
|
||||
return {
|
||||
...(await glob('.next/records.json', cachePath)),
|
||||
...(await glob('.next/server/records.json', cachePath)),
|
||||
...(await glob('node_modules/**', cachePath)),
|
||||
...(await glob('yarn.lock', cachePath)),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const { Server } = require('http');
|
||||
const next = require('next-server');
|
||||
const url = require('url');
|
||||
const { Bridge } = require('./now__bridge.js');
|
||||
const page = require('./page.js');
|
||||
|
||||
const bridge = new Bridge();
|
||||
bridge.port = 3000;
|
||||
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const app = next({});
|
||||
|
||||
const server = new Server((req, res) => {
|
||||
const parsedUrl = url.parse(req.url, true);
|
||||
app.render(req, res, 'PATHNAME_PLACEHOLDER', parsedUrl.query, parsedUrl);
|
||||
});
|
||||
const server = new Server(page.render);
|
||||
server.listen(bridge.port);
|
||||
|
||||
exports.launcher = bridge.launcher;
|
||||
|
||||
19
packages/now-next/legacy-launcher.js
Normal file
19
packages/now-next/legacy-launcher.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const { Server } = require('http');
|
||||
const next = require('next-server');
|
||||
const url = require('url');
|
||||
const { Bridge } = require('./now__bridge.js');
|
||||
|
||||
const bridge = new Bridge();
|
||||
bridge.port = 3000;
|
||||
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const app = next({});
|
||||
|
||||
const server = new Server((req, res) => {
|
||||
const parsedUrl = url.parse(req.url, true);
|
||||
app.render(req, res, 'PATHNAME_PLACEHOLDER', parsedUrl.query, parsedUrl);
|
||||
});
|
||||
server.listen(bridge.port);
|
||||
|
||||
exports.launcher = bridge.launcher;
|
||||
336
packages/now-next/legacy-versions.js
Normal file
336
packages/now-next/legacy-versions.js
Normal file
@@ -0,0 +1,336 @@
|
||||
module.exports = [
|
||||
'0.1.0',
|
||||
'0.1.1',
|
||||
'0.2.0',
|
||||
'0.2.1',
|
||||
'0.2.2',
|
||||
'0.2.3',
|
||||
'0.2.4',
|
||||
'0.2.5',
|
||||
'0.2.6',
|
||||
'0.2.7',
|
||||
'0.2.8',
|
||||
'0.2.9',
|
||||
'0.2.10',
|
||||
'0.2.11',
|
||||
'0.2.12',
|
||||
'0.2.13',
|
||||
'0.2.14',
|
||||
'0.3.0',
|
||||
'0.3.1',
|
||||
'0.3.2',
|
||||
'0.3.3',
|
||||
'0.4.0',
|
||||
'0.4.1',
|
||||
'0.9.9',
|
||||
'0.9.10',
|
||||
'0.9.11',
|
||||
'1.0.0',
|
||||
'1.0.1',
|
||||
'1.0.2',
|
||||
'1.1.0',
|
||||
'1.1.1',
|
||||
'1.1.2',
|
||||
'1.2.0',
|
||||
'1.2.1',
|
||||
'1.2.2',
|
||||
'1.2.3',
|
||||
'2.0.0-beta.0',
|
||||
'2.0.0-beta.1',
|
||||
'2.0.0-beta.2',
|
||||
'2.0.0-beta.3',
|
||||
'2.0.0-beta.4',
|
||||
'2.0.0-beta.5',
|
||||
'2.0.0-beta.6',
|
||||
'2.0.0-beta.7',
|
||||
'2.0.0-beta.8',
|
||||
'2.0.0-beta.9',
|
||||
'2.0.0-beta.10',
|
||||
'2.0.0-beta.11',
|
||||
'2.0.0-beta.12',
|
||||
'2.0.0-beta.13',
|
||||
'2.0.0-beta.14',
|
||||
'2.0.0-beta.15',
|
||||
'2.0.0-beta.16',
|
||||
'2.0.0-beta.17',
|
||||
'2.0.0-beta.18',
|
||||
'2.0.0-beta.19',
|
||||
'2.0.0-beta.20',
|
||||
'2.0.0-beta.21',
|
||||
'2.0.0-beta.22',
|
||||
'2.0.0-beta.23',
|
||||
'2.0.0-beta.24',
|
||||
'2.0.0-beta.25',
|
||||
'2.0.0-beta.26',
|
||||
'2.0.0-beta.27',
|
||||
'2.0.0-beta.28',
|
||||
'2.0.0-beta.29',
|
||||
'2.0.0-beta.30',
|
||||
'2.0.0-beta.31',
|
||||
'2.0.0-beta.32',
|
||||
'2.0.0-beta.33',
|
||||
'2.0.0-beta.34',
|
||||
'2.0.0-beta.35',
|
||||
'2.0.0-beta.36',
|
||||
'2.0.0-beta.37',
|
||||
'2.0.0-beta.38',
|
||||
'2.0.0-beta.39',
|
||||
'2.0.0-beta.40',
|
||||
'2.0.0-beta.41',
|
||||
'2.0.0-beta.42',
|
||||
'2.0.0',
|
||||
'2.0.1',
|
||||
'2.1.0',
|
||||
'2.1.1',
|
||||
'2.2.0',
|
||||
'2.3.0-alpha1',
|
||||
'2.3.0',
|
||||
'2.3.1',
|
||||
'2.4.0',
|
||||
'2.4.1',
|
||||
'2.4.2',
|
||||
'2.4.3',
|
||||
'2.4.4',
|
||||
'2.4.5',
|
||||
'2.4.6',
|
||||
'2.4.7',
|
||||
'2.4.8',
|
||||
'2.4.9',
|
||||
'3.0.0-beta1',
|
||||
'3.0.0-beta10',
|
||||
'3.0.0-beta11',
|
||||
'3.0.0-beta12',
|
||||
'3.0.0-beta13',
|
||||
'3.0.0-beta14',
|
||||
'3.0.0-beta15',
|
||||
'3.0.0-beta16',
|
||||
'3.0.0-beta2',
|
||||
'3.0.0-beta3',
|
||||
'3.0.0-beta4',
|
||||
'3.0.0-beta5',
|
||||
'3.0.0-beta6',
|
||||
'3.0.0-beta7',
|
||||
'3.0.0-beta8',
|
||||
'3.0.0-beta9',
|
||||
'3.0.1-beta.1',
|
||||
'3.0.1-beta.2',
|
||||
'3.0.1-beta.3',
|
||||
'3.0.1-beta.4',
|
||||
'3.0.1-beta.5',
|
||||
'3.0.1-beta.6',
|
||||
'3.0.1-beta.7',
|
||||
'3.0.1-beta.8',
|
||||
'3.0.1-beta.9',
|
||||
'3.0.1-beta.10',
|
||||
'3.0.1-beta.11',
|
||||
'3.0.1-beta.12',
|
||||
'3.0.1-beta.13',
|
||||
'3.0.1-beta.14',
|
||||
'3.0.1-beta.15',
|
||||
'3.0.1-beta.16',
|
||||
'3.0.1-beta.17',
|
||||
'3.0.1-beta.18',
|
||||
'3.0.1-beta.19',
|
||||
'3.0.1-beta.20',
|
||||
'3.0.1-beta.21',
|
||||
'3.0.1',
|
||||
'3.0.2',
|
||||
'3.0.3',
|
||||
'3.0.4',
|
||||
'3.0.5',
|
||||
'3.0.6',
|
||||
'3.1.0',
|
||||
'3.2.0',
|
||||
'3.2.1',
|
||||
'3.2.2',
|
||||
'3.2.3',
|
||||
'4.0.0-beta.1',
|
||||
'4.0.0-beta.2',
|
||||
'4.0.0-beta.3',
|
||||
'4.0.0-beta.4',
|
||||
'4.0.0-beta.5',
|
||||
'4.0.0-beta.6',
|
||||
'4.0.0',
|
||||
'4.0.1',
|
||||
'4.0.2',
|
||||
'4.0.3',
|
||||
'4.0.4',
|
||||
'4.0.5',
|
||||
'4.1.0',
|
||||
'4.1.1',
|
||||
'4.1.2',
|
||||
'4.1.3',
|
||||
'4.1.4-canary.1',
|
||||
'4.1.4-canary.2',
|
||||
'4.1.4',
|
||||
'4.2.0-canary.1',
|
||||
'4.2.0-zones.2',
|
||||
'4.2.0',
|
||||
'4.2.1',
|
||||
'4.2.2',
|
||||
'4.2.3',
|
||||
'4.3.0-canary.1',
|
||||
'4.3.0-universal-alpha.1',
|
||||
'4.3.0-universal-alpha.2',
|
||||
'4.3.0-universal-alpha.3',
|
||||
'4.3.0-universal-alpha.4',
|
||||
'4.3.0-zones.1',
|
||||
'4.4.0-canary.2',
|
||||
'4.4.0-canary.3',
|
||||
'5.0.0-universal-alpha.1',
|
||||
'5.0.0-universal-alpha.2',
|
||||
'5.0.0-universal-alpha.3',
|
||||
'5.0.0-universal-alpha.4',
|
||||
'5.0.0-universal-alpha.5',
|
||||
'5.0.0-universal-alpha.6',
|
||||
'5.0.0-universal-alpha.7',
|
||||
'5.0.0-universal-alpha.8',
|
||||
'5.0.0-universal-alpha.9',
|
||||
'5.0.0-universal-alpha.10',
|
||||
'5.0.0-universal-alpha.11',
|
||||
'5.0.0-universal-alpha.12',
|
||||
'5.0.0-universal-alpha.13',
|
||||
'5.0.0-universal-alpha.14',
|
||||
'5.0.0-universal-alpha.15',
|
||||
'5.0.0-universal-alpha.16',
|
||||
'5.0.0-universal-alpha.17',
|
||||
'5.0.0-universal-alpha.18',
|
||||
'5.0.0-universal-alpha.19',
|
||||
'5.0.0-universal-alpha.20',
|
||||
'5.0.0-universal-alpha.21',
|
||||
'5.0.0-universal-alpha.22',
|
||||
'5.0.0-universal-alpha.23',
|
||||
'5.0.0-zones.1',
|
||||
'5.0.0',
|
||||
'5.0.1-canary.1',
|
||||
'5.0.1-canary.2',
|
||||
'5.0.1-canary.3',
|
||||
'5.0.1-canary.4',
|
||||
'5.0.1-canary.5',
|
||||
'5.0.1-canary.6',
|
||||
'5.0.1-canary.7',
|
||||
'5.0.1-canary.8',
|
||||
'5.0.1-canary.9',
|
||||
'5.0.1-canary.10',
|
||||
'5.0.1-canary.11',
|
||||
'5.0.1-canary.12',
|
||||
'5.0.1-canary.13',
|
||||
'5.0.1-canary.14',
|
||||
'5.0.1-canary.15',
|
||||
'5.0.1-canary.16',
|
||||
'5.0.1-canary.17',
|
||||
'5.1.0',
|
||||
'6.0.0-canary.1',
|
||||
'6.0.0-canary.2',
|
||||
'6.0.0-canary.3',
|
||||
'6.0.0-canary.4',
|
||||
'6.0.0-canary.5',
|
||||
'6.0.0-canary.6',
|
||||
'6.0.0-canary.7',
|
||||
'6.0.0',
|
||||
'6.0.1-canary.0',
|
||||
'6.0.1-canary.1',
|
||||
'6.0.1-canary.2',
|
||||
'6.0.1',
|
||||
'6.0.2-canary.0',
|
||||
'6.0.2',
|
||||
'6.0.3-canary.0',
|
||||
'6.0.3-canary.1',
|
||||
'6.0.3',
|
||||
'6.0.4-canary.0',
|
||||
'6.0.4-canary.1',
|
||||
'6.0.4-canary.2',
|
||||
'6.0.4-canary.3',
|
||||
'6.0.4-canary.4',
|
||||
'6.0.4-canary.5',
|
||||
'6.0.4-canary.6',
|
||||
'6.0.4-canary.7',
|
||||
'6.0.4-canary.8',
|
||||
'6.0.4-canary.9',
|
||||
'6.1.0-canary.0',
|
||||
'6.1.0',
|
||||
'6.1.1-canary.0',
|
||||
'6.1.1-canary.1',
|
||||
'6.1.1-canary.2',
|
||||
'6.1.1-canary.3',
|
||||
'6.1.1-canary.4',
|
||||
'6.1.1-canary.5',
|
||||
'6.1.1',
|
||||
'6.1.2',
|
||||
'7.0.0-canary.0',
|
||||
'7.0.0-canary.1',
|
||||
'7.0.0-canary.2',
|
||||
'7.0.0-canary.3',
|
||||
'7.0.0-canary.4',
|
||||
'7.0.0-canary.5',
|
||||
'7.0.0-canary.6',
|
||||
'7.0.0-canary.7',
|
||||
'7.0.0-canary.8',
|
||||
'7.0.0-canary.9',
|
||||
'7.0.0-canary.10',
|
||||
'7.0.0-canary.11',
|
||||
'7.0.0-canary.12',
|
||||
'7.0.0-canary.13',
|
||||
'7.0.0-canary.14',
|
||||
'7.0.0-canary.15',
|
||||
'7.0.0-canary.16',
|
||||
'7.0.0-canary.18',
|
||||
'7.0.0-canary.19',
|
||||
'7.0.0-canary.20',
|
||||
'7.0.0',
|
||||
'7.0.1-canary.0',
|
||||
'7.0.1-canary.1',
|
||||
'7.0.1-canary.2',
|
||||
'7.0.1-canary.3',
|
||||
'7.0.1-canary.4',
|
||||
'7.0.1-canary.5',
|
||||
'7.0.1-canary.6',
|
||||
'7.0.1',
|
||||
'7.0.2-alpha.1',
|
||||
'7.0.2-alpha.3',
|
||||
'7.0.2-canary.5',
|
||||
'7.0.2-canary.6',
|
||||
'7.0.2-canary.7',
|
||||
'7.0.2-canary.8',
|
||||
'7.0.2-canary.9',
|
||||
'7.0.2-canary.10',
|
||||
'7.0.2-canary.11',
|
||||
'7.0.2-canary.12',
|
||||
'7.0.2-canary.13',
|
||||
'7.0.2-canary.14',
|
||||
'7.0.2-canary.15',
|
||||
'7.0.2-canary.16',
|
||||
'7.0.2-canary.17',
|
||||
'7.0.2-canary.18',
|
||||
'7.0.2-canary.19',
|
||||
'7.0.2-canary.20',
|
||||
'7.0.2-canary.21',
|
||||
'7.0.2-canary.22',
|
||||
'7.0.2-canary.23',
|
||||
'7.0.2-canary.24',
|
||||
'7.0.2-canary.25',
|
||||
'7.0.2-canary.26',
|
||||
'7.0.2-canary.27',
|
||||
'7.0.2-canary.28',
|
||||
'7.0.2-canary.29',
|
||||
'7.0.2-canary.31',
|
||||
'7.0.2-canary.33',
|
||||
'7.0.2-canary.34',
|
||||
'7.0.2-canary.35',
|
||||
'7.0.2-canary.36',
|
||||
'7.0.2-canary.37',
|
||||
'7.0.2-canary.38',
|
||||
'7.0.2-canary.39',
|
||||
'7.0.2-canary.40',
|
||||
'7.0.2-canary.41',
|
||||
'7.0.2-canary.42',
|
||||
'7.0.2-canary.43',
|
||||
'7.0.2-canary.44',
|
||||
'7.0.2-canary.45',
|
||||
'7.0.2-canary.46',
|
||||
'7.0.2-canary.47',
|
||||
'7.0.2-canary.48',
|
||||
'7.0.2-canary.49',
|
||||
'7.0.2-canary.50',
|
||||
'7.0.2',
|
||||
];
|
||||
@@ -1,12 +1,16 @@
|
||||
{
|
||||
"name": "@now/next",
|
||||
"version": "0.0.81",
|
||||
"version": "0.0.85-canary.5",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-next"
|
||||
},
|
||||
"dependencies": {
|
||||
"@now/node-bridge": "0.1.4",
|
||||
"execa": "^1.0.0",
|
||||
"fs.promised": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
"fs.promised": "^3.0.0",
|
||||
"semver": "^5.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
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 */
|
||||
@@ -64,24 +62,6 @@ function includeOnlyEntryDirectory(files, 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
|
||||
@@ -98,19 +78,6 @@ function excludeLockFiles(files) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude the static directory from files
|
||||
* @param {Files} files
|
||||
@@ -153,18 +120,18 @@ function normalizePackageJson(defaultPackageJson = {}) {
|
||||
'react-dom': 'latest',
|
||||
...dependencies, // override react if user provided it
|
||||
// next-server is forced to canary
|
||||
'next-server': 'canary',
|
||||
'next-server': 'v7.0.2-canary.49',
|
||||
},
|
||||
devDependencies: {
|
||||
...devDependencies,
|
||||
// next is forced to canary
|
||||
next: 'canary',
|
||||
next: 'v7.0.2-canary.49',
|
||||
// next-server is a dependency here
|
||||
'next-server': undefined,
|
||||
},
|
||||
scripts: {
|
||||
...defaultPackageJson.scripts,
|
||||
'now-build': 'next build --lambdas',
|
||||
'now-build': 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -173,9 +140,7 @@ module.exports = {
|
||||
excludeFiles,
|
||||
validateEntrypoint,
|
||||
includeOnlyEntryDirectory,
|
||||
moveEntryDirectoryToRoot,
|
||||
excludeLockFiles,
|
||||
normalizePackageJson,
|
||||
excludeStaticDirectory,
|
||||
onlyStaticDirectory,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
const http = require('http');
|
||||
|
||||
function normalizeEvent(event) {
|
||||
let isApiGateway = true;
|
||||
|
||||
if (event.Action === 'Invoke') {
|
||||
isApiGateway = false;
|
||||
const invokeEvent = JSON.parse(event.body);
|
||||
|
||||
const {
|
||||
@@ -21,10 +24,7 @@ function normalizeEvent(event) {
|
||||
}
|
||||
|
||||
return {
|
||||
method,
|
||||
path,
|
||||
headers,
|
||||
body,
|
||||
isApiGateway, method, path, headers, body,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,10 +33,7 @@ function normalizeEvent(event) {
|
||||
} = event;
|
||||
|
||||
return {
|
||||
method,
|
||||
path,
|
||||
headers,
|
||||
body,
|
||||
isApiGateway, method, path, headers, body,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -58,7 +55,7 @@ class Bridge {
|
||||
}
|
||||
|
||||
const {
|
||||
method, path, headers, body,
|
||||
isApiGateway, method, path, headers, body,
|
||||
} = normalizeEvent(event);
|
||||
|
||||
const opts = {
|
||||
@@ -73,20 +70,35 @@ class Bridge {
|
||||
const response = res;
|
||||
const respBodyChunks = [];
|
||||
response.on('data', chunk => respBodyChunks.push(Buffer.from(chunk)));
|
||||
response.on('error', error => reject(error));
|
||||
response.on('error', reject);
|
||||
response.on('end', () => {
|
||||
const bodyBuffer = Buffer.concat(respBodyChunks);
|
||||
delete response.headers.connection;
|
||||
delete response.headers['content-length'];
|
||||
|
||||
if (isApiGateway) {
|
||||
delete response.headers['content-length'];
|
||||
} else
|
||||
if (response.headers['content-length']) {
|
||||
response.headers['content-length'] = bodyBuffer.length;
|
||||
}
|
||||
|
||||
resolve({
|
||||
statusCode: response.statusCode,
|
||||
headers: response.headers,
|
||||
body: Buffer.concat(respBodyChunks).toString('base64'),
|
||||
body: bodyBuffer.toString('base64'),
|
||||
encoding: 'base64',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
setTimeout(() => {
|
||||
// this lets express print the true error of why the connection was closed.
|
||||
// it is probably 'Cannot set headers after they are sent to the client'
|
||||
reject(error);
|
||||
}, 2);
|
||||
});
|
||||
|
||||
if (body) req.write(body);
|
||||
req.end();
|
||||
});
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"name": "@now/node-bridge",
|
||||
"version": "0.1.9",
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
"version": "0.1.11-canary.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-node-bridge"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
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 { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const fs = require('fs-extra');
|
||||
const glob = require('@now/build-utils/fs/glob.js');
|
||||
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const path = require('path');
|
||||
const rename = require('@now/build-utils/fs/rename.js');
|
||||
const rename = require('@now/build-utils/fs/rename.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const {
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
||||
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
||||
/** @typedef {{[filePath: string]: FileRef}} Files */
|
||||
@@ -37,7 +37,7 @@ async function downloadInstallAndBundle(
|
||||
console.log('downloading user files...');
|
||||
const downloadedFiles = await download(files, userPath);
|
||||
|
||||
console.log('running npm install for user...');
|
||||
console.log("installing dependencies for user's code...");
|
||||
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
|
||||
await runNpmInstall(entrypointFsDirname, npmArguments);
|
||||
|
||||
@@ -46,8 +46,9 @@ async function downloadInstallAndBundle(
|
||||
{
|
||||
'package.json': new FileBlob({
|
||||
data: JSON.stringify({
|
||||
license: 'UNLICENSED',
|
||||
dependencies: {
|
||||
'@zeit/ncc': '0.4.1',
|
||||
'@zeit/ncc': '0.15.2',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -55,7 +56,7 @@ async function downloadInstallAndBundle(
|
||||
nccPath,
|
||||
);
|
||||
|
||||
console.log('running npm install for ncc...');
|
||||
console.log('installing dependencies for ncc...');
|
||||
await runNpmInstall(nccPath, npmArguments);
|
||||
return [downloadedFiles, userPath, nccPath, entrypointFsDirname];
|
||||
}
|
||||
@@ -63,7 +64,7 @@ async function downloadInstallAndBundle(
|
||||
async function compile(workNccPath, downloadedFiles, entrypoint) {
|
||||
const input = downloadedFiles[entrypoint].fsPath;
|
||||
const ncc = require(path.join(workNccPath, 'node_modules/@zeit/ncc'));
|
||||
const { code, assets } = await ncc(input);
|
||||
const { code, assets } = await ncc(input, { sourceMap: true });
|
||||
|
||||
const preparedFiles = {};
|
||||
const blob = new FileBlob({ data: code });
|
||||
@@ -71,7 +72,8 @@ async function compile(workNccPath, downloadedFiles, entrypoint) {
|
||||
preparedFiles[path.join('user', entrypoint)] = blob;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const assetName of Object.keys(assets)) {
|
||||
const blob2 = new FileBlob({ data: assets[assetName] });
|
||||
const { source: data, permissions: mode } = assets[assetName];
|
||||
const blob2 = new FileBlob({ data, mode });
|
||||
preparedFiles[
|
||||
path.join('user', path.dirname(entrypoint), assetName)
|
||||
] = blob2;
|
||||
|
||||
@@ -12,7 +12,10 @@ Server.prototype.listen = function listen(...args) {
|
||||
};
|
||||
|
||||
try {
|
||||
process.env.NODE_ENV = 'production';
|
||||
if (!process.env.NODE_ENV) {
|
||||
process.env.NODE_ENV = 'production';
|
||||
}
|
||||
|
||||
// PLACEHOLDER
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
{
|
||||
"name": "@now/node-server",
|
||||
"version": "0.4.25",
|
||||
"dependencies": {
|
||||
"@now/node-bridge": "^0.1.9",
|
||||
"fs-extra": "7.0.1"
|
||||
"version": "0.4.27-canary.5",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-node-server"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
"dependencies": {
|
||||
"@now/node-bridge": "^0.1.11-canary.0",
|
||||
"fs-extra": "7.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const cowsay = require('cowsay/build/cowsay.umd.js').say;
|
||||
const cowsay = require('cowsay').say;
|
||||
const http = require('http');
|
||||
|
||||
// test that process.env is not replaced by webpack
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cowsay": "^1.3.1"
|
||||
"cowsay": "1.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const yodasay = require('yodasay/build/yodasay.umd.js').say;
|
||||
const yodasay = require('yodasay').say;
|
||||
const http = require('http');
|
||||
|
||||
// test that process.env is not replaced by webpack
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"yodasay": "^1.1.6"
|
||||
"yodasay": "1.1.9"
|
||||
}
|
||||
}
|
||||
|
||||
7
packages/now-node-server/test/fixtures/06-content-type/index.js
vendored
Normal file
7
packages/now-node-server/test/fixtures/06-content-type/index.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const http = require('http');
|
||||
|
||||
const server = http.createServer((req, resp) => {
|
||||
resp.end('RANDOMNESS_PLACEHOLDER');
|
||||
});
|
||||
|
||||
server.listen();
|
||||
6
packages/now-node-server/test/fixtures/06-content-type/now.json
vendored
Normal file
6
packages/now-node-server/test/fixtures/06-content-type/now.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "index.js", "use": "@now/node-server" }
|
||||
]
|
||||
}
|
||||
7
packages/now-node-server/test/fixtures/06-content-type/probe.js
vendored
Normal file
7
packages/now-node-server/test/fixtures/06-content-type/probe.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const assert = require('assert');
|
||||
|
||||
module.exports = async ({ deploymentUrl, fetch, randomness }) => {
|
||||
const resp = await fetch(`https://${deploymentUrl}/`);
|
||||
assert.equal(resp.headers.get('content-type'), null);
|
||||
assert.equal(await resp.text(), randomness);
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
{ "src": "without-bundle/index.js", "use": "@now/node-server", "config": { "bundle": false } }
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/with-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER" },
|
||||
{ "path": "/without-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER" }
|
||||
{ "path": "/with-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER:with-bundle" },
|
||||
{ "path": "/without-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER:without-bundle" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ const http = require('http');
|
||||
const isBundled = require('./is-bundled.js');
|
||||
|
||||
const server = http.createServer((req, resp) => {
|
||||
resp.end(isBundled() ? 'RANDOMNESS_PLACEHOLDER' : '');
|
||||
resp.end(isBundled() ? 'RANDOMNESS_PLACEHOLDER:with-bundle' : 'WITHOUT-BUNDLE-THAT-IS-WRONG');
|
||||
});
|
||||
|
||||
server.listen();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = () => path.basename(__filename) === 'index.js';
|
||||
// eslint-disable-next-line no-eval
|
||||
module.exports = () => path.basename(eval('__filename')) === 'index.js';
|
||||
|
||||
@@ -2,7 +2,7 @@ const http = require('http');
|
||||
const isBundled = require('./is-bundled.js');
|
||||
|
||||
const server = http.createServer((req, resp) => {
|
||||
resp.end(isBundled() ? '' : 'RANDOMNESS_PLACEHOLDER');
|
||||
resp.end(isBundled() ? 'WITH-BUNDLE-THAT-IS-WRONG' : 'RANDOMNESS_PLACEHOLDER:without-bundle');
|
||||
});
|
||||
|
||||
server.listen();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = () => path.basename(__filename) === 'index.js';
|
||||
// eslint-disable-next-line no-eval
|
||||
module.exports = () => path.basename(eval('__filename')) === 'index.js';
|
||||
|
||||
@@ -7,7 +7,7 @@ const {
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
|
||||
jest.setTimeout(2 * 60 * 1000);
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
const buildUtilsUrl = '@canary';
|
||||
let builderUrl;
|
||||
|
||||
|
||||
@@ -1,14 +1,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 { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const fs = require('fs-extra');
|
||||
const glob = require('@now/build-utils/fs/glob.js');
|
||||
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const path = require('path');
|
||||
const {
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
} = require('@now/build-utils/fs/run-user-scripts.js');
|
||||
} = require('@now/build-utils/fs/run-user-scripts.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
/** @typedef { import('@now/build-utils/file-ref') } FileRef */
|
||||
/** @typedef {{[filePath: string]: FileRef}} Files */
|
||||
@@ -35,7 +35,7 @@ async function downloadInstallAndBundle(
|
||||
console.log('downloading user files...');
|
||||
const downloadedFiles = await download(files, userPath);
|
||||
|
||||
console.log('running npm install for user...');
|
||||
console.log("installing dependencies for user's code...");
|
||||
const entrypointFsDirname = path.join(userPath, path.dirname(entrypoint));
|
||||
await runNpmInstall(entrypointFsDirname, npmArguments);
|
||||
|
||||
@@ -44,8 +44,9 @@ async function downloadInstallAndBundle(
|
||||
{
|
||||
'package.json': new FileBlob({
|
||||
data: JSON.stringify({
|
||||
license: 'UNLICENSED',
|
||||
dependencies: {
|
||||
'@zeit/ncc': '0.4.1',
|
||||
'@zeit/ncc': '0.15.2',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
@@ -53,7 +54,7 @@ async function downloadInstallAndBundle(
|
||||
nccPath,
|
||||
);
|
||||
|
||||
console.log('running npm install for ncc...');
|
||||
console.log('installing dependencies for ncc...');
|
||||
await runNpmInstall(nccPath, npmArguments);
|
||||
return [downloadedFiles, nccPath, entrypointFsDirname];
|
||||
}
|
||||
@@ -61,7 +62,7 @@ async function downloadInstallAndBundle(
|
||||
async function compile(workNccPath, downloadedFiles, entrypoint) {
|
||||
const input = downloadedFiles[entrypoint].fsPath;
|
||||
const ncc = require(path.join(workNccPath, 'node_modules/@zeit/ncc'));
|
||||
const { code, assets } = await ncc(input);
|
||||
const { code, assets } = await ncc(input, { sourceMap: true });
|
||||
|
||||
const preparedFiles = {};
|
||||
const blob = new FileBlob({ data: code });
|
||||
@@ -69,7 +70,8 @@ async function compile(workNccPath, downloadedFiles, entrypoint) {
|
||||
preparedFiles[path.join('user', entrypoint)] = blob;
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const assetName of Object.keys(assets)) {
|
||||
const blob2 = new FileBlob({ data: assets[assetName] });
|
||||
const { source: data, permissions: mode } = assets[assetName];
|
||||
const blob2 = new FileBlob({ data, mode });
|
||||
preparedFiles[
|
||||
path.join('user', path.dirname(entrypoint), assetName)
|
||||
] = blob2;
|
||||
|
||||
@@ -6,7 +6,10 @@ bridge.port = 3000;
|
||||
let listener;
|
||||
|
||||
try {
|
||||
process.env.NODE_ENV = 'production';
|
||||
if (!process.env.NODE_ENV) {
|
||||
process.env.NODE_ENV = 'production';
|
||||
}
|
||||
|
||||
// PLACEHOLDER
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
{
|
||||
"name": "@now/node",
|
||||
"version": "0.4.27",
|
||||
"dependencies": {
|
||||
"@now/node-bridge": "^0.1.9",
|
||||
"fs-extra": "7.0.1"
|
||||
"version": "0.4.29-canary.5",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-node"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
"dependencies": {
|
||||
"@now/node-bridge": "^0.1.11-canary.0",
|
||||
"fs-extra": "7.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const cowsay = require('cowsay/build/cowsay.umd.js').say;
|
||||
const cowsay = require('cowsay').say;
|
||||
|
||||
// test that process.env is not replaced by webpack
|
||||
process.env.NODE_ENV = 'development';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cowsay": "^1.3.1"
|
||||
"cowsay": "1.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const yodasay = require('yodasay/build/yodasay.umd.js').say;
|
||||
const yodasay = require('yodasay').say;
|
||||
|
||||
// test that process.env is not replaced by webpack
|
||||
process.env.NODE_ENV = 'development';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"yodasay": "^1.1.6"
|
||||
"yodasay": "1.1.9"
|
||||
}
|
||||
}
|
||||
|
||||
8
packages/now-node/test/fixtures/07-content-length/now.json
vendored
Normal file
8
packages/now-node/test/fixtures/07-content-length/now.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "test1.js", "use": "@now/node" },
|
||||
{ "src": "test2.js", "use": "@now/node" },
|
||||
{ "src": "test3.js", "use": "@now/node" }
|
||||
]
|
||||
}
|
||||
31
packages/now-node/test/fixtures/07-content-length/probe.js
vendored
Normal file
31
packages/now-node/test/fixtures/07-content-length/probe.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
const assert = require('assert');
|
||||
|
||||
async function test1({ deploymentUrl, fetch, randomness }) {
|
||||
const bodyMustBe = `${randomness}:content-length`;
|
||||
const resp = await fetch(`https://${deploymentUrl}/test1.js`);
|
||||
assert.equal(resp.status, 401);
|
||||
assert.equal(await resp.text(), bodyMustBe);
|
||||
assert.equal(resp.headers.get('content-length'), bodyMustBe.length);
|
||||
}
|
||||
|
||||
async function test2({ deploymentUrl, fetch }) {
|
||||
const bodyMustBe = '';
|
||||
const resp = await fetch(`https://${deploymentUrl}/test2.js`);
|
||||
assert.equal(resp.status, 401);
|
||||
assert.equal(await resp.text(), bodyMustBe);
|
||||
assert.equal(resp.headers.get('content-length'), bodyMustBe.length);
|
||||
}
|
||||
|
||||
async function test3({ deploymentUrl, fetch, randomness }) {
|
||||
const bodyMustBe = `${randomness}:content-length`;
|
||||
const resp = await fetch(`https://${deploymentUrl}/test3.js`);
|
||||
assert.equal(resp.status, 401);
|
||||
assert.equal(await resp.text(), bodyMustBe);
|
||||
assert.equal(resp.headers.get('content-length'), null);
|
||||
}
|
||||
|
||||
module.exports = async ({ deploymentUrl, fetch, randomness }) => {
|
||||
await test1({ deploymentUrl, fetch, randomness });
|
||||
await test2({ deploymentUrl, fetch, randomness });
|
||||
await test3({ deploymentUrl, fetch, randomness });
|
||||
};
|
||||
4
packages/now-node/test/fixtures/07-content-length/test1.js
vendored
Normal file
4
packages/now-node/test/fixtures/07-content-length/test1.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = (_, resp) => {
|
||||
resp.writeHead(401, { 'content-length': 4242 });
|
||||
resp.end(`${process.env.RANDOMNESS_ENV_VAR}:content-length`);
|
||||
};
|
||||
4
packages/now-node/test/fixtures/07-content-length/test2.js
vendored
Normal file
4
packages/now-node/test/fixtures/07-content-length/test2.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = (_, resp) => {
|
||||
resp.writeHead(401, { 'content-length': 2 });
|
||||
resp.end();
|
||||
};
|
||||
4
packages/now-node/test/fixtures/07-content-length/test3.js
vendored
Normal file
4
packages/now-node/test/fixtures/07-content-length/test3.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = (_, resp) => {
|
||||
resp.writeHead(401);
|
||||
resp.end(`${process.env.RANDOMNESS_ENV_VAR}:content-length`);
|
||||
};
|
||||
@@ -7,7 +7,7 @@ const {
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
|
||||
jest.setTimeout(2 * 60 * 1000);
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
const buildUtilsUrl = '@canary';
|
||||
let builderUrl;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const FileBlob = require('@now/build-utils/file-blob.js');
|
||||
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const OptiPng = require('optipng');
|
||||
const pipe = require('multipipe');
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
{
|
||||
"name": "@now/optipng",
|
||||
"version": "0.4.7",
|
||||
"version": "0.4.9-canary.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zeit/now-builders.git",
|
||||
"directory": "packages/now-optipng"
|
||||
},
|
||||
"dependencies": {
|
||||
"multipipe": "2.0.3",
|
||||
"optipng": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@now/build-utils": ">=0.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
1
packages/now-php-bridge/.npmignore
Normal file
1
packages/now-php-bridge/.npmignore
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
20
packages/now-php-bridge/build/Dockerfile
Normal file
20
packages/now-php-bridge/build/Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM library/centos:6.8
|
||||
RUN yum -y install wget git
|
||||
RUN rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm
|
||||
RUN yum -y install php71w-cli php71w-fpm php71w-mbstring php71w-mysql php71w-opcache
|
||||
RUN yum -y install epel-release
|
||||
RUN yum -y install patchelf
|
||||
|
||||
RUN mkdir -p /root/app/public
|
||||
|
||||
WORKDIR /root/app
|
||||
COPY ./php.ini /root/app/php.ini
|
||||
COPY ./php-fpm.ini /root/app/php-fpm.ini
|
||||
COPY ./test.php /root/app/test.php
|
||||
COPY ./test.sh /root/app/test.sh
|
||||
|
||||
RUN patchelf --set-rpath '$ORIGIN' /usr/bin/php
|
||||
RUN patchelf --set-rpath '$ORIGIN' /usr/sbin/php-fpm
|
||||
RUN patchelf --set-rpath '$ORIGIN' /usr/lib64/php/modules/mysqli.so
|
||||
|
||||
CMD ["/bin/bash", "test.sh"]
|
||||
15
packages/now-php-bridge/build/build.sh
Executable file
15
packages/now-php-bridge/build/build.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
rm -rf ../native
|
||||
mkdir -p ../native/modules
|
||||
docker rmi now-php-docker-image --force
|
||||
docker build . -t now-php-docker-image
|
||||
docker run now-php-docker-image
|
||||
docker run now-php-docker-image /bin/cat /usr/sbin/php-fpm > ../native/php-fpm
|
||||
docker run now-php-docker-image /bin/cat /root/app/php.ini > ../native/php.ini
|
||||
docker run now-php-docker-image /bin/cat /root/app/php-fpm.ini > ../native/php-fpm.ini
|
||||
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/curl.so > ../native/modules/curl.so
|
||||
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/json.so > ../native/modules/json.so
|
||||
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/mbstring.so > ../native/modules/mbstring.so
|
||||
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/mysqli.so > ../native/modules/mysqli.so
|
||||
docker run now-php-docker-image /bin/cat /usr/lib64/mysql/libmysqlclient.so.16 > ../native/modules/libmysqlclient.so.16
|
||||
docker run now-php-docker-image /bin/cat /usr/lib64/php/modules/opcache.so > ../native/modules/opcache.so
|
||||
chmod +x ../native/php-fpm
|
||||
9
packages/now-php-bridge/build/php-fpm.ini
Normal file
9
packages/now-php-bridge/build/php-fpm.ini
Normal file
@@ -0,0 +1,9 @@
|
||||
[global]
|
||||
error_log=/tmp/fpm-error.log
|
||||
|
||||
[www]
|
||||
listen=0.0.0.0:9000
|
||||
pm=static
|
||||
pm.max_children=1
|
||||
catch_workers_output=yes
|
||||
clear_env=no
|
||||
8
packages/now-php-bridge/build/php.ini
Normal file
8
packages/now-php-bridge/build/php.ini
Normal file
@@ -0,0 +1,8 @@
|
||||
extension=/root/app/modules/curl.so
|
||||
extension=/root/app/modules/json.so
|
||||
extension=/root/app/modules/mbstring.so
|
||||
extension=/root/app/modules/mysqli.so
|
||||
zend_extension=/root/app/modules/opcache.so
|
||||
opcache.enable_cli=1
|
||||
mysqli.max_links=10
|
||||
mysqli.max_persistent=10
|
||||
4
packages/now-php-bridge/build/test.php
Normal file
4
packages/now-php-bridge/build/test.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
mysqli_connect();
|
||||
print('php_sapi_name=' . php_sapi_name() . PHP_EOL);
|
||||
print('opcache_enabled=' . opcache_get_status()['opcache_enabled'] . PHP_EOL);
|
||||
18
packages/now-php-bridge/build/test.sh
Normal file
18
packages/now-php-bridge/build/test.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
mkdir -p /root/app/modules
|
||||
cp /usr/bin/php /root/app/php
|
||||
cp /usr/sbin/php-fpm /root/app/php-fpm
|
||||
cp /usr/lib64/php/modules/curl.so /root/app/modules/curl.so
|
||||
cp /usr/lib64/php/modules/json.so /root/app/modules/json.so
|
||||
cp /usr/lib64/php/modules/mbstring.so /root/app/modules/mbstring.so
|
||||
cp /usr/lib64/php/modules/mysqli.so /root/app/modules/mysqli.so
|
||||
cp /usr/lib64/mysql/libmysqlclient.so.16 /root/app/modules/libmysqlclient.so.16
|
||||
cp /usr/lib64/php/modules/opcache.so /root/app/modules/opcache.so
|
||||
rm -rf $(which php)
|
||||
rm -rf $(which php-fpm)
|
||||
rm -rf /usr/lib64/php
|
||||
rm -rf /usr/lib64/mysql
|
||||
rm -rf /etc/php.d
|
||||
./php-fpm --help
|
||||
./php -c php.ini test.php
|
||||
echo "if you see 'can't connect to local mysql' - it is good - mysql library is found and used"
|
||||
echo "if you see 'call to undefined function mysqli_connect' - it is bad - something went wrong"
|
||||
149
packages/now-php-bridge/fastcgi/index.js
Normal file
149
packages/now-php-bridge/fastcgi/index.js
Normal file
@@ -0,0 +1,149 @@
|
||||
/* eslint-disable no-bitwise,no-use-before-define */
|
||||
|
||||
const assert = require('assert');
|
||||
const { freeParser } = require('_http_common');
|
||||
const { spawn } = require('child_process');
|
||||
const createConnection = require('./connection.js');
|
||||
const { MSG_TYPE, PROTOCOL_STATUS } = require('./consts.js');
|
||||
const { whenPortOpens } = require('./port.js');
|
||||
|
||||
const { HTTPParser } = process.binding('http_parser');
|
||||
const BEGIN_REQUEST_DATA_KEEP_CONN = Buffer.from('\0\x01\x01\0\0\0\0\0'); // FCGI_ROLE_RESPONDER && FCGI_KEEP_CONN
|
||||
const MESSAGE_FCGI_STDOUT = `message-${MSG_TYPE.FCGI_STDOUT}`;
|
||||
const MESSAGE_FCGI_STDERR = `message-${MSG_TYPE.FCGI_STDERR}`;
|
||||
const MESSAGE_FCGI_END_REQUEST = `message-${MSG_TYPE.FCGI_END_REQUEST}`;
|
||||
|
||||
let curReqId = 0;
|
||||
let connection;
|
||||
|
||||
async function startPhp() {
|
||||
assert(!connection);
|
||||
|
||||
const child = spawn(
|
||||
'./php-fpm',
|
||||
['-c', 'php.ini',
|
||||
'--fpm-config', 'php-fpm.ini',
|
||||
'--nodaemonize'],
|
||||
{
|
||||
stdio: 'inherit',
|
||||
cwd: '/var/task/native',
|
||||
},
|
||||
);
|
||||
|
||||
child.on('exit', () => {
|
||||
console.error('php exited');
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
child.on('error', (error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
await whenPortOpens(9000, 400);
|
||||
|
||||
const newConnection = createConnection({
|
||||
_host: '127.0.0.1',
|
||||
_port: 9000,
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
function onError() {
|
||||
cleanup();
|
||||
reject();
|
||||
}
|
||||
function onConnect() {
|
||||
connection = newConnection;
|
||||
cleanup();
|
||||
resolve();
|
||||
}
|
||||
|
||||
newConnection.on('error', onError);
|
||||
newConnection.on('connect', onConnect);
|
||||
function cleanup() {
|
||||
newConnection.removeListener('error', onError);
|
||||
newConnection.removeListener('connect', onConnect);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function query({ params, stdin }) {
|
||||
if (!connection) {
|
||||
await startPhp();
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
assert(connection);
|
||||
|
||||
const chunks = [
|
||||
Buffer.from('HTTP/1.1 200 MAKES-PARSER-WORK\n'),
|
||||
];
|
||||
|
||||
function onError(error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
function onStdout(reqId, data) {
|
||||
chunks.push(data);
|
||||
}
|
||||
function onStderr(reqId, data) {
|
||||
console.error(data.toString().trim());
|
||||
}
|
||||
function onEndRequest(reqId, data) {
|
||||
const protocolStatus = data.readUInt8(4, true);
|
||||
if (protocolStatus !== PROTOCOL_STATUS.FCGI_REQUEST_COMPLETE) {
|
||||
console.error('protocolStatus', protocolStatus);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const response = Buffer.concat(chunks);
|
||||
const parser = new HTTPParser(HTTPParser.RESPONSE);
|
||||
|
||||
let tuples = [];
|
||||
parser[HTTPParser.kOnHeadersComplete | 0] = (major, minor, t) => {
|
||||
tuples = t;
|
||||
};
|
||||
|
||||
let body;
|
||||
parser[HTTPParser.kOnBody | 0] = (b, start, len) => {
|
||||
body = b.slice(start, start + len);
|
||||
};
|
||||
|
||||
parser.execute(response);
|
||||
freeParser(parser);
|
||||
cleanup();
|
||||
resolve({ tuples, body });
|
||||
}
|
||||
|
||||
connection.on('error', onError);
|
||||
connection.on(MESSAGE_FCGI_STDOUT, onStdout);
|
||||
connection.on(MESSAGE_FCGI_STDERR, onStderr);
|
||||
connection.on(MESSAGE_FCGI_END_REQUEST, onEndRequest);
|
||||
function cleanup() {
|
||||
connection.removeListener('error', onError);
|
||||
connection.removeListener(MESSAGE_FCGI_STDOUT, onStdout);
|
||||
connection.removeListener(MESSAGE_FCGI_STDERR, onStderr);
|
||||
connection.removeListener(MESSAGE_FCGI_END_REQUEST, onEndRequest);
|
||||
}
|
||||
|
||||
curReqId += 1;
|
||||
// TODO these things have callbacks. what to do with them?
|
||||
connection.send(MSG_TYPE.FCGI_BEGIN_REQUEST, curReqId, BEGIN_REQUEST_DATA_KEEP_CONN);
|
||||
connection.send(MSG_TYPE.FCGI_PARAMS, curReqId, params);
|
||||
connection.send(MSG_TYPE.FCGI_PARAMS, curReqId, null);
|
||||
if (stdin) connection.send(MSG_TYPE.FCGI_STDIN, curReqId, stdin);
|
||||
connection.send(MSG_TYPE.FCGI_STDIN, curReqId, null);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
query,
|
||||
};
|
||||
|
||||
/*
|
||||
(async function() {
|
||||
console.log(await query({ params: {
|
||||
REQUEST_METHOD: 'GET', SCRIPT_FILENAME: '/phpinfo.php'
|
||||
} }));
|
||||
})();
|
||||
*/
|
||||
41
packages/now-php-bridge/fastcgi/port.js
Normal file
41
packages/now-php-bridge/fastcgi/port.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/* eslint-disable consistent-return */
|
||||
|
||||
const net = require('net');
|
||||
|
||||
function whenPortOpensCallback(port, attempts, cb) {
|
||||
const client = net.connect(port, '127.0.0.1');
|
||||
client.on('error', (error) => {
|
||||
if (!attempts) return cb(error);
|
||||
setTimeout(() => {
|
||||
whenPortOpensCallback(port, attempts - 1, cb);
|
||||
}, 50);
|
||||
});
|
||||
client.on('connect', () => {
|
||||
client.destroy();
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
function isPortOpen(port) {
|
||||
return new Promise((resolve) => {
|
||||
whenPortOpensCallback(port, 0, (error) => {
|
||||
if (error) return resolve(false);
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function whenPortOpens(port, attempts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
whenPortOpensCallback(port, attempts, (error) => {
|
||||
if (error) return reject(error);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isPortOpen,
|
||||
whenPortOpensCallback,
|
||||
whenPortOpens,
|
||||
};
|
||||
43
packages/now-php-bridge/index.js
Normal file
43
packages/now-php-bridge/index.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const FileBlob = require('@now/build-utils/file-blob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const FileFsRef = require('@now/build-utils/file-fs-ref.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
const path = require('path');
|
||||
|
||||
async function getFiles() {
|
||||
const files = await glob('native/**', __dirname);
|
||||
|
||||
const phpConfig = await FileBlob.fromStream({
|
||||
stream: files['native/php.ini'].toStream(),
|
||||
});
|
||||
phpConfig.data = phpConfig.data
|
||||
.toString()
|
||||
.replace(/\/root\/app\/modules/g, '/var/task/native/modules');
|
||||
files['native/php.ini'] = phpConfig;
|
||||
|
||||
Object.assign(files, {
|
||||
'fastcgi/connection.js': new FileFsRef({
|
||||
fsPath: require.resolve('fastcgi-client/lib/connection.js'),
|
||||
}),
|
||||
'fastcgi/consts.js': new FileFsRef({
|
||||
fsPath: require.resolve('fastcgi-client/lib/consts.js'),
|
||||
}),
|
||||
'fastcgi/stringifykv.js': new FileFsRef({
|
||||
fsPath: require.resolve('fastcgi-client/lib/stringifykv.js'),
|
||||
}),
|
||||
'fastcgi/index.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'fastcgi/index.js'),
|
||||
}),
|
||||
'fastcgi/port.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'fastcgi/port.js'),
|
||||
}),
|
||||
'launcher.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'launcher.js'),
|
||||
}),
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFiles,
|
||||
};
|
||||
142
packages/now-php-bridge/launcher.js
Normal file
142
packages/now-php-bridge/launcher.js
Normal file
@@ -0,0 +1,142 @@
|
||||
/* eslint-disable prefer-template */
|
||||
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const { join: pathJoin } = require('path');
|
||||
const { parse: parseUrl } = require('url');
|
||||
const { query } = require('./fastcgi/index.js');
|
||||
|
||||
function normalizeEvent(event) {
|
||||
if (event.Action === 'Invoke') {
|
||||
const invokeEvent = JSON.parse(event.body);
|
||||
|
||||
const {
|
||||
method, path, headers, encoding,
|
||||
} = invokeEvent;
|
||||
|
||||
let { body } = invokeEvent;
|
||||
|
||||
if (body) {
|
||||
if (encoding === 'base64') {
|
||||
body = Buffer.from(body, encoding);
|
||||
} else if (encoding === undefined) {
|
||||
body = Buffer.from(body);
|
||||
} else {
|
||||
throw new Error(`Unsupported encoding: ${encoding}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
method, path, headers, body,
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
httpMethod: method, path, headers, body,
|
||||
} = event;
|
||||
|
||||
return {
|
||||
method, path, headers, body,
|
||||
};
|
||||
}
|
||||
|
||||
function isDirectory(p) {
|
||||
return new Promise((resolve) => {
|
||||
fs.stat(p, (error, s) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.isDirectory()) {
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function transformFromAwsRequest({
|
||||
method, path, headers, body,
|
||||
}) {
|
||||
const { pathname, search, query: queryString } = parseUrl(path);
|
||||
let requestUri = pathname + (search || '');
|
||||
|
||||
let filename = pathJoin('/var/task/user', pathname);
|
||||
if (await isDirectory(filename)) {
|
||||
if (!filename.endsWith('/')) {
|
||||
filename += '/';
|
||||
requestUri = pathname + '/' + (search || '');
|
||||
}
|
||||
filename += 'index.php';
|
||||
}
|
||||
|
||||
const params = {};
|
||||
params.REQUEST_METHOD = method;
|
||||
params.REQUEST_URI = requestUri;
|
||||
params.QUERY_STRING = queryString || ''; // can be null
|
||||
params.SCRIPT_FILENAME = filename;
|
||||
params.SERVER_PROTOCOL = 'HTTP/1.1';
|
||||
params.SERVER_PORT = 443;
|
||||
params.HTTPS = 'on';
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [k, v] of Object.entries(headers)) {
|
||||
const camel = k.toUpperCase().replace(/-/g, '_');
|
||||
params[`HTTP_${camel}`] = v;
|
||||
if (camel === 'HOST') {
|
||||
params.SERVER_NAME = v;
|
||||
} else
|
||||
if (['CONTENT_TYPE', 'CONTENT_LENGTH'].includes(camel)) {
|
||||
params[camel] = v; // without HOST_ prepended
|
||||
}
|
||||
}
|
||||
|
||||
return { params, stdin: body };
|
||||
}
|
||||
|
||||
function transformToAwsResponse({ tuples, body }) {
|
||||
let statusCode = 200;
|
||||
const headers = {};
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
if (!body) body = Buffer.alloc(0);
|
||||
assert(Buffer.isBuffer(body));
|
||||
|
||||
for (let i = 0; i < tuples.length; i += 2) {
|
||||
const k = tuples[i].toLowerCase();
|
||||
const v = tuples[i + 1];
|
||||
if (k === 'status') {
|
||||
statusCode = Number(v.split(' ')[0]); // '408 Request Timeout'
|
||||
} else {
|
||||
if (!headers[k]) headers[k] = [];
|
||||
headers[k].push(v);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode,
|
||||
headers,
|
||||
body: body.toString('base64'),
|
||||
encoding: 'base64',
|
||||
};
|
||||
}
|
||||
|
||||
async function launcher(event) {
|
||||
const awsRequest = normalizeEvent(event);
|
||||
const input = await transformFromAwsRequest(awsRequest);
|
||||
const output = await query(input);
|
||||
return transformToAwsResponse(output);
|
||||
}
|
||||
|
||||
exports.launcher = launcher;
|
||||
|
||||
/*
|
||||
(async function() {
|
||||
console.log(await launcher({
|
||||
httpMethod: 'GET',
|
||||
path: '/phpinfo.php'
|
||||
}));
|
||||
})();
|
||||
*/
|
||||
Binary file not shown.
Binary file not shown.
BIN
packages/now-php-bridge/native/modules/libmysqlclient.so.16
Normal file
BIN
packages/now-php-bridge/native/modules/libmysqlclient.so.16
Normal file
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user