Compare commits

...

35 Commits

Author SHA1 Message Date
Steven
e186f89cfd Publish
- @now/build-utils@0.5.6
 - @now/go@0.5.1
 - @now/lambda@0.5.4
 - @now/layer-node@0.0.2
 - @now/layer-npm@0.0.2
 - @now/layer-yarn@0.0.2
 - @now/next@0.4.1
 - @now/node-bridge@1.1.4
 - @now/node-server@0.7.4
 - @now/node@0.7.4
 - @now/optipng@0.6.2
 - @now/php-bridge@0.5.3
 - @now/php@0.5.5
 - @now/python@0.2.5
 - @now/rust@0.2.5
 - @now/static-build@0.5.8
 - @now/wordpress@0.5.3
2019-06-06 15:15:47 -04:00
Steven
50cade8bba [now-layer] Add entrypoint to BuildLayerResult (#578)
* [now-layer] Add meta to BuildLayerResult

* Fix tests

* Fix test for expect entrypoint

* Return entrypoint

* Remove meta

* Remove meta

* Remove npmVerison meta check from layer-node
2019-06-06 15:13:06 -04:00
dependabot[bot]
13866e61f6 Bump js-yaml from 3.12.0 to 3.13.1 (#576)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 17:49:33 +00:00
Joe Haddad
b72f902271 [now-next] Route 404 to custom Next.js error page (#569) 2019-06-06 17:49:28 +00:00
JJ Kasper
159cfe99dd Revert "Fix missing slash from prepending entryDirectory (#573)" (#575)
This reverts commit 36ac7605762639968a52d66a1bcb6d3cab68da3f.
2019-06-06 17:49:24 +00:00
JJ Kasper
1d9a96d104 Fix missing slash from prepending entryDirectory (#573)
* Fix missing slash for staticRoute

* Add util for prepending entryDirectory correctly

* Apply suggestions from code review

Co-Authored-By: Connor Davis <mail@connordav.is>

* Don't add export route for dynamic pages

* Fix type error from review commit

* Don't use scopeToEntry on lambdas
2019-06-06 17:49:20 +00:00
JJ Kasper
245f846d3e [now-next] Make sure .html is appended to dynamic auto exported routes (#572) 2019-06-06 17:49:14 +00:00
JJ Kasper
c5ef7f3f35 [now-next] Add generating of dynamic routes for auto exported pages (#570) 2019-06-06 17:49:10 +00:00
Steven
ccba15a5aa [now-next] Add timer to codeowners (#571) 2019-06-06 17:49:06 +00:00
dependabot[bot]
f49aefa8e4 Bump handlebars from 4.0.12 to 4.1.2 (#568)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.12 to 4.1.2.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 17:48:57 +00:00
Sophearak Tha
d6b36df4ce [now-go] Fix subdirectory parse fail (#565) 2019-06-06 17:48:52 +00:00
JJ Kasper
3e4dd10a79 [now-next] Re-add generating of dynamic routes (#559)
* Re-add generating of dynamic routes

* Run prettier

* Update to use startsWith
2019-06-06 17:48:47 +00:00
Connor Davis
73956706bd Prettier everything (#563)
* Prettier everything

* md files should use spaces too

* Move prettier config to package.json

* Retry tests
2019-06-06 17:48:40 +00:00
Steven
bd8da5360d Add layers for npm and yarn (#558)
* Add `now-layer-npm`

* Change version to 0.0.1-canary.0

* Add now-layer-yarn

* Update version

* Add now-metadata.json

* Read package.json to detect npm version

* Fix tests for windows zip
2019-06-06 17:48:27 +00:00
Steven
6d5a2a4438 [now-layer-node] Add node runtime layer (#552)
* [now-node-runtime] Add node runtime layer

* Add now-node-runtime to eslintignore

* Add test

* Rename variables, add comment

* Remove createGunzip()

* Add .yarnrc

* Rename to `now-layer-node`

* Pin dependencies

* Remove npm and npx from the layer

* Ignore uncessary files for node installer

* Use single glob string
2019-06-06 17:48:18 +00:00
Timothy
c88dc78e33 Fix static-build local development docs link (#556) 2019-06-06 17:48:10 +00:00
Steven
63ac11e9f7 [now-python] Publish from dist directory (#550)
* [now-python] Publish from dist directory

* Fix path to `now_init.py`

* Add now-init.py to npm publish

* Fix typo
2019-06-06 17:48:02 +00:00
Steven
1840632729 [tests] Fix duplicate GH Actions (#551)
* [tests] Fix duplicate GH Actions

* Fix typo

* Use linear to avoid cancelled checks
2019-06-06 17:46:48 +00:00
Steven
00d8eb0f65 [now-python] Improve error message (#548)
* [now-python] Improve error message

* Check if BaseHTTPRequestHandler

* Add a test for uppercase Handler
2019-06-06 17:46:43 +00:00
Steven
3db58ac373 [now-python] Disable pip upgrade notice (#547) 2019-06-06 17:46:39 +00:00
Steven
92a1720eea [tests] Only publish to npm from master/canary branch (#546)
* Change circleci workflow to build-and-test

* Add branch filter

* Separate into two workflows

* Move both workflows into single file

* Rename to main.workflow
2019-06-06 17:46:34 +00:00
Sophearak Tha
9abbfbe3f3 [now-go] Add support for go.mod in different entrypoint directory (#540)
* Add support for `go.mod` in different `entrypoint` directory

* Add tests cover Go Modules

* Workaround solution to make `now dev` support `go.mod` in different folder than `entrypoint`

* Ensure to backup `go.mod` and `go.sum` only in isDev

* Update packages/now-go/index.ts

* Update packages/now-go/index.ts

* Update watcher to work for different local packages under the same `go.mod`

* Improve code readability
2019-06-06 17:46:30 +00:00
Joe Haddad
11ef8aa816 [now-next] Define Next.js generated routes (#536)
* Match static files before checking dynamic routes

* Add Next.js lambda matching

* Apply suggestions from code review

Co-Authored-By: Connor Davis <mail@connordav.is>

* Correct index logic

* Add builder support for handle filesystem

* Check html rewrites first
2019-06-06 17:46:24 +00:00
Mike Engel
3a122ea950 [now-rust] Install rust with rustup & convert now-rust to typescript (#533)
* fix: Don't try and install rust and openssl during development

* feat: Convert now-rust to typescript

* Fix some typescript errors

* feat: Fix types for now-rust

* fix: Fix typo in type name

* fix: Small cleanups and tweaks from the PR review

* fix: Increase test timeout duration

- Add built JS files from now-build-utils to the eslintignore file

* fix: Compile to dist directory and don't lint now-rust

* fix: Only ignore linting for now-rust's dist dir
2019-06-06 17:46:20 +00:00
Steven
737e50630a Enable tests for all (#544)
* Enable circleci tests for all

* Update readme to mention GH Actions

* Move variable to the top
2019-06-06 17:46:11 +00:00
Lukáš Huvar
fb27b7b9be Fix servless error page fixes#234 (#541) 2019-06-06 17:46:00 +00:00
Steven
d1a4aecd2f Use GitHub Actions for publishing to npm (#539)
* Use GitHub Actions for publishing to npm

* Move publish from CircleCI to GH Actions

* Add npm install

* Fix names

* Use yarn instead of npm

* Fix typo

* Remove publish from circleci

* Fix typo

* Add check for NPM_TOKEN

* Add tag filter

* Remove tag filter
2019-06-06 17:45:55 +00:00
Steven
5ef7014ed8 Update codeowners for python & rust (#538) 2019-06-06 17:45:43 +00:00
Sophearak Tha
0ff2c9950e Show error when using package main with go.mod #528 (#537) 2019-06-06 17:45:31 +00:00
Steven
ddcdcdf3e2 Merge branch 'canary' into master 2019-05-27 17:21:55 -04:00
Mike Engel
bfc99f19d2 [now-rust] Don't try and install rust and openssl during development (#532) 2019-05-27 16:32:09 -04:00
Steven
de2c08cfe8 Publish
- @now/build-utils@0.5.6-canary.0
2019-05-25 14:24:52 -04:00
Steven
9679f07124 [build-utils] add --unsafe-perm to npm install, so that postinstall runs (#530) 2019-05-25 14:24:01 -04:00
Steven
6ce24d6a4e Switch branch during publish (#529) 2019-05-24 17:28:29 -04:00
Steven
e3e029f5f6 Update README.md 2019-05-24 13:37:35 -04:00
165 changed files with 1892 additions and 702 deletions

View File

@@ -29,14 +29,8 @@ jobs:
- run:
name: Tests and Coverage
command: yarn test-coverage
- run:
name: Potentially save npm token
command: "([[ ! -z $NPM_TOKEN ]] && echo \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> ~/.npmrc) || echo \"Did not write npm token\""
- run:
name: Potentially publish releases to npm
command: ./.circleci/publish.sh
workflows:
version: 2
build-and-deploy:
build-and-test:
jobs:
- build

View File

@@ -1,6 +1,13 @@
#!/bin/bash
set -euo pipefail
if [ -z "$NPM_TOKEN" ]; then
echo "NPM_TOKEN not found. Did you forget to assign the GitHub Action secret?"
exit 1
fi
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
if [ ! -e ~/.npmrc ]; then
echo "~/.npmrc file does not exist, skipping publish"
exit 0

43
.editorconfig Normal file
View File

@@ -0,0 +1,43 @@
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.json,*.json.example,*.gyp,*.yml,*.yaml,*.workflow}]
indent_style = space
indent_size = 2
[{*.py,*.asm}]
indent_style = space
[*.py]
indent_size = 4
[*.asm]
indent_size = 8
[*.md]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2
# Ideal settings - some plugins might support these
[*.js,*.jsx,*.ts,*.tsx]
quote_type = single
indent_style = space
indent_size = 2
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.java,*.go,*.rs,*.php,*.ng,*.d,*.cs,*.swift}]
indent_style = tab
indent_size = 4
tab_width = 4
[{*.c,*.cc,*.h,*.hh,*.cpp,*.hpp,*.m,*.mm,*.mpp,*.js,*.java,*.go,*.rs,*.php,*.ng,*.jsx,*.ts,*.tsx,*.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

View File

@@ -3,9 +3,15 @@
/**/node_modules/*
/packages/now-go/go/*
/packages/now-build-utils/dist/*
/packages/now-build-utils/src/*.js
/packages/now-build-utils/src/fs/*.js
/packages/now-node/dist/*
/packages/now-layer-node/dist/*
/packages/now-layer-npm/dist/*
/packages/now-layer-yarn/dist/*
/packages/now-next/dist/*
/packages/now-node-bridge/*
/packages/now-python/*
/packages/now-python/dist/*
/packages/now-optipng/dist/*
/packages/now-go/*
/packages/now-rust/dist/*

4
.github/CODEOWNERS vendored
View File

@@ -3,5 +3,7 @@
* @styfle
/packages/now-node @styfle @tootallnate
/packages/now-next @styfle @dav-is
/packages/now-next @timer @dav-is
/packages/now-go @styfle @sophearak
/packages/now-python @styfle @sophearak
/packages/now-rust @styfle @mike-engel @anmonteiro

76
.github/main.workflow vendored Normal file
View File

@@ -0,0 +1,76 @@
workflow "Canary publish" {
on = "push"
resolves = ["3. Canary yarn run publish"]
}
action "0. Canary filter" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
args = "branch canary"
}
action "0. Canary PR not deleted" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
needs = ["0. Canary filter"]
args = "not deleted"
}
action "1. Canary yarn install" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["0. Canary PR not deleted"]
runs = "yarn"
args = "install"
}
action "2. Canary yarn run build" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["1. Canary yarn install"]
runs = "yarn"
args = "run build"
}
action "3. Canary yarn run publish" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["2. Canary yarn run build"]
runs = "yarn"
args = "run publish-from-github"
secrets = ["NPM_TOKEN"]
}
workflow "Master publish" {
on = "push"
resolves = ["3. Master yarn run publish"]
}
action "0. Master filter" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
args = "branch master"
}
action "0. Master PR not deleted" {
uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da"
needs = ["0. Master filter"]
args = "not deleted"
}
action "1. Master yarn install" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["0. Master PR not deleted"]
runs = "yarn"
args = "install"
}
action "2. Master yarn run build" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["1. Master yarn install"]
runs = "yarn"
args = "run build"
}
action "3. Master yarn run publish" {
uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680"
needs = ["2. Master yarn run build"]
runs = "yarn"
args = "run publish-from-github"
secrets = ["NPM_TOKEN"]
}

View File

@@ -1,4 +0,0 @@
{
"singleQuote": true,
"trailingComma": "es5"
}

1
.yarnrc Normal file
View File

@@ -0,0 +1 @@
save-prefix ""

View File

@@ -1,8 +1,11 @@
# now-builders
This is the full list of official Builders provided by the ZEIT team.
This is a monorepo containing the [Official Builders](https://zeit.co/docs/v2/deployments/builders/overview) provided by the ZEIT team.
More details here: https://zeit.co/docs/v2/deployments/builders/overview/
There are two branches:
- canary - published to npm as `canary` dist-tag, eg `@now/node@canary`
- master - published to npm as `latest` dist-tag, eg `@now/node@latest`
### Publishing to npm
@@ -20,8 +23,8 @@ For the canary channel use:
yarn publish-canary
```
CircleCI will take care of publishing the updated packages to npm from there.
GitHub Actions will take care of publishing the updated packages to npm from there.
If for some reason CircleCI fails to publish the npm package, you may do so
If for some reason GitHub Actions fails to publish the npm package, you may do so
manually by running `npm publish` from the package directory. Make sure to
include the `--tag canary` parameter if you are publishing a canary release!
use `npm publish --tag canary` if you are publishing a canary release!

View File

@@ -29,12 +29,11 @@ Serverless:
- 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:
1. Serverless Next.js requires Next.js 8 or later, to upgrade you can install the `latest` version:
```
npm install next --save
@@ -46,7 +45,7 @@ npm install next --save
{
"scripts": {
"now-build": "next build"
},
}
}
```
@@ -54,9 +53,9 @@ npm install next --save
```js
module.exports = {
target: 'serverless'
target: 'serverless',
// Other options are still valid
}
};
```
4. Optionally make sure the `"src"` in `"builds"` points to your application `package.json`
@@ -70,4 +69,4 @@ module.exports = {
### Useful Links
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)
- [Serverless target implementation](https://github.com/zeit/now-builders/pull/150)

View File

@@ -20,7 +20,7 @@ npm install next --save
{
"scripts": {
"now-build": "next build"
},
}
}
```
@@ -28,9 +28,9 @@ npm install next --save
```js
module.exports = {
target: 'serverless'
target: 'serverless',
// Other options
}
};
```
4. Remove `distDir` from `next.config.js` as `@now/next` can't parse this file and expects your build output at `/.next`

View File

@@ -7,7 +7,7 @@ requests to the server that is created by the `now-dev` script in the
`package.json` file.
In order for `now dev` to know which port the server is running on, the builder
is provided a `$PORT` environment variable that the server *must* bind to. The
is provided a `$PORT` environment variable that the server _must_ bind to. The
error "Failed to detect a server running on port" is printed if the builder fails
to detect a server listening on that specific port within five minutes.

View File

@@ -1,9 +1,7 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/*"
],
"packages": ["packages/*"],
"command": {
"publish": {
"npmClient": "npm",

View File

@@ -12,8 +12,9 @@
"scripts": {
"lerna": "lerna",
"bootstrap": "lerna bootstrap",
"publish-stable": "lerna version",
"publish-canary": "lerna version prerelease --preid canary",
"publish-stable": "git checkout master && git pull && lerna version",
"publish-canary": "git checkout canary && git pull && lerna version prerelease --preid canary",
"publish-from-github": "./.circleci/publish.sh",
"build": "./.circleci/build.sh",
"lint": "eslint .",
"codecov": "codecov",
@@ -51,6 +52,10 @@
"lint-staged": "^8.0.4",
"node-fetch": "^2.3.0",
"pre-commit": "^1.2.2",
"prettier": "^1.15.2"
"prettier": "1.17.1"
},
"prettier": {
"singleQuote": true,
"trailingComma": "es5"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "0.5.5",
"version": "0.5.6",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -31,7 +31,10 @@ class FileFsRef implements File {
this.fsPath = fsPath;
}
static async fromFsPath({ mode, fsPath }: FileFsRefOptions): Promise<FileFsRef> {
static async fromFsPath({
mode,
fsPath,
}: FileFsRefOptions): Promise<FileFsRef> {
let m = mode;
if (!m) {
const stat = await fs.lstat(fsPath);
@@ -40,7 +43,11 @@ class FileFsRef implements File {
return new FileFsRef({ mode: m, fsPath });
}
static async fromStream({ mode = 0o100644, stream, fsPath }: FromStreamOptions): Promise<FileFsRef> {
static async fromStream({
mode = 0o100644,
stream,
fsPath,
}: FromStreamOptions): Promise<FileFsRef> {
assert(typeof mode === 'number');
assert(typeof stream.pipe === 'function'); // is-stream
assert(typeof fsPath === 'string');
@@ -48,7 +55,7 @@ class FileFsRef implements File {
await new Promise<void>((resolve, reject) => {
const dest = fs.createWriteStream(fsPath, {
mode: mode & 0o777
mode: mode & 0o777,
});
stream.pipe(dest);
stream.on('error', reject);
@@ -72,15 +79,15 @@ class FileFsRef implements File {
let flag = false;
// eslint-disable-next-line consistent-return
return multiStream((cb) => {
return multiStream(cb => {
if (flag) return cb(null, null);
flag = true;
this.toStreamAsync()
.then((stream) => {
.then(stream => {
cb(null, stream);
})
.catch((error) => {
.catch(error => {
cb(error, null);
});
});

View File

@@ -7,6 +7,6 @@ export default function rename(files: Files, delegate: Delegate): Files {
...newFiles,
[delegate(name)]: files[name],
}),
{},
{}
);
}

View File

@@ -109,7 +109,7 @@ export async function installDependencies(
commandArgs = args.filter(a => a !== '--prefer-offline');
await spawnAsync(
'npm',
['install'].concat(commandArgs),
['install', '--unsafe-perm'].concat(commandArgs),
destPath,
opts as SpawnOptions
);

View File

@@ -1,26 +1,28 @@
import eos from 'end-of-stream';
export default function streamToBuffer(stream: NodeJS.ReadableStream): Promise<Buffer> {
export default function streamToBuffer(
stream: NodeJS.ReadableStream
): Promise<Buffer> {
return new Promise<Buffer>((resolve, reject) => {
const buffers: Buffer[] = [];
stream.on('data', buffers.push.bind(buffers))
stream.on('data', buffers.push.bind(buffers));
eos(stream, (err) => {
if (err) {
reject(err);
return;
}
switch (buffers.length) {
case 0:
resolve(Buffer.allocUnsafe(0));
break;
case 1:
resolve(buffers[0]);
break;
default:
resolve(Buffer.concat(buffers));
}
eos(stream, err => {
if (err) {
reject(err);
return;
}
switch (buffers.length) {
case 0:
resolve(Buffer.allocUnsafe(0));
break;
case 1:
resolve(buffers[0]);
break;
default:
resolve(Buffer.concat(buffers));
}
});
});
}
}

View File

@@ -1,34 +1,51 @@
import FileBlob from './file-blob';
import FileFsRef from './file-fs-ref';
import FileRef from './file-ref';
import { File, Files, AnalyzeOptions, BuildOptions, PrepareCacheOptions, ShouldServeOptions, Meta } from './types';
import {
File,
Files,
AnalyzeOptions,
BuildOptions,
PrepareCacheOptions,
ShouldServeOptions,
Meta,
} from './types';
import { Lambda, createLambda } from './lambda';
import download from './fs/download';
import getWriteableDirectory from './fs/get-writable-directory'
import download, { DownloadedFiles } from './fs/download';
import getWriteableDirectory from './fs/get-writable-directory';
import glob from './fs/glob';
import rename from './fs/rename';
import { installDependencies, runPackageJsonScript, runNpmInstall, runShellScript } from './fs/run-user-scripts';
import {
installDependencies,
runPackageJsonScript,
runNpmInstall,
runShellScript,
} from './fs/run-user-scripts';
import streamToBuffer from './fs/stream-to-buffer';
import shouldServe from './should-serve';
export {
FileBlob,
FileFsRef,
FileRef,
Files,
File,
Meta,
Lambda,
createLambda,
download,
getWriteableDirectory,
glob,
rename,
installDependencies, runPackageJsonScript, runNpmInstall, runShellScript,
streamToBuffer,
AnalyzeOptions,
BuildOptions,
PrepareCacheOptions,
ShouldServeOptions,
shouldServe,
FileBlob,
FileFsRef,
FileRef,
Files,
File,
Meta,
Lambda,
createLambda,
download,
DownloadedFiles,
getWriteableDirectory,
glob,
rename,
installDependencies,
runPackageJsonScript,
runNpmInstall,
runShellScript,
streamToBuffer,
AnalyzeOptions,
BuildOptions,
PrepareCacheOptions,
ShouldServeOptions,
shouldServe,
};

View File

@@ -32,9 +32,7 @@ export class Lambda {
public runtime: string;
public environment: Environment;
constructor({
zipBuffer, handler, runtime, environment,
}: LambdaOptions) {
constructor({ zipBuffer, handler, runtime, environment }: LambdaOptions) {
this.type = 'Lambda';
this.zipBuffer = zipBuffer;
this.handler = handler;
@@ -47,7 +45,10 @@ const sema = new Sema(10);
const mtime = new Date(1540000000000);
export async function createLambda({
files, handler, runtime, environment = {},
files,
handler,
runtime,
environment = {},
}: CreateLambdaOptions): Promise<Lambda> {
assert(typeof files === 'object', '"files" must be an object');
assert(typeof handler === 'string', '"handler" is not a string');
@@ -97,7 +98,9 @@ export async function createZip(files: Files): Promise<Buffer> {
}
zipFile.end();
streamToBuffer(zipFile.outputStream).then(resolve).catch(reject);
streamToBuffer(zipFile.outputStream)
.then(resolve)
.catch(reject);
});
return zipBuffer;

View File

@@ -5,7 +5,7 @@ import FileFsRef from './file-fs-ref';
export default function shouldServe({
entrypoint,
files,
requestPath
requestPath,
}: ShouldServeOptions): boolean {
requestPath = requestPath.replace(/\/$/, ''); // sanitize trailing '/'
entrypoint = entrypoint.replace(/\\/, '/'); // windows compatibility
@@ -23,5 +23,5 @@ export default function shouldServe({
}
function hasProp(obj: { [path: string]: FileFsRef }, key: string): boolean {
return Object.hasOwnProperty.call(obj, key)
return Object.hasOwnProperty.call(obj, key);
}

View File

@@ -1,9 +1,10 @@
{
"version": 2,
"builds": [
{ "src": "api/index.js", "use": "@now/node" }
],
"builds": [{ "src": "api/index.js", "use": "@now/node" }],
"probes": [
{ "path": "/api/index.js", "mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER" }
{
"path": "/api/index.js",
"mustContain": "cross-cow:RANDOMNESS_PLACEHOLDER"
}
]
}

View File

@@ -1,10 +1,11 @@
{
"version": 2,
"builds": [
{ "src": "index.js", "use": "@now/node", "config": { "maxLambdaSize": "15mb" } }
],
"probes": [
{ "path": "/", "mustContain": "found:RANDOMNESS_PLACEHOLDER" }
]
}
"version": 2,
"builds": [
{
"src": "index.js",
"use": "@now/node",
"config": { "maxLambdaSize": "15mb" }
}
],
"probes": [{ "path": "/", "mustContain": "found:RANDOMNESS_PLACEHOLDER" }]
}

View File

@@ -15,10 +15,6 @@
"strict": true,
"target": "esnext"
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@@ -23,7 +23,7 @@ const getGoUrl = (version: string, platform: string, arch: string) => {
return `https://dl.google.com/go/go${version}.${goPlatform}-${goArch}.${ext}`;
};
export async function getAnalyzedEntrypoint(filePath: string) {
export async function getAnalyzedEntrypoint(filePath: string, modulePath = '') {
debug('Analyzing entrypoint %o', filePath);
const bin = join(__dirname, 'analyze');
@@ -35,7 +35,8 @@ export async function getAnalyzedEntrypoint(filePath: string) {
await go.build(src, dest);
}
const args = [filePath];
const args = [`-modpath=${modulePath}`, filePath];
const analyzed = await execa.stdout(bin, args);
debug('Analyzed entrypoint %o', analyzed);
return analyzed;

View File

@@ -1,5 +1,5 @@
import { join, sep, dirname, basename } from 'path';
import { readFile, writeFile, pathExists, move, copy } from 'fs-extra';
import { readFile, writeFile, pathExists, move } from 'fs-extra';
import { homedir } from 'os';
import execa from 'execa';
@@ -80,7 +80,16 @@ export async function build({
console.log(`Parsing AST for "${entrypoint}"`);
let analyzed: string;
try {
analyzed = await getAnalyzedEntrypoint(downloadedFiles[entrypoint].fsPath);
let goModAbsPathDir = '';
for (const file of Object.keys(downloadedFiles)) {
if (file === 'go.mod') {
goModAbsPathDir = dirname(downloadedFiles[file].fsPath);
}
}
analyzed = await getAnalyzedEntrypoint(
downloadedFiles[entrypoint].fsPath,
goModAbsPathDir
);
} catch (err) {
console.log(`Failed to parse AST for "${entrypoint}"`);
throw err;
@@ -96,7 +105,6 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
throw err;
}
const entrypointDirnameDev = dirname(downloadedFiles[entrypoint].fsPath);
const parsedAnalyzed = JSON.parse(analyzed) as Analyzed;
if (meta.isDev) {
@@ -109,39 +117,33 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
'src',
'lambda'
);
const goMod = await pathExists(join(entrypointDirnameDev, 'go.mod'));
// this will ensure Go rebuilt fast
goPath = join(base, '.now', 'cache', basename(entrypoint, '.go'));
await download(downloadedFiles, destNow);
for (const file of parsedAnalyzed.watch) {
if (entrypointArr.length > 0) {
await copy(
join(base, dirname(entrypoint), file),
join(destNow, dirname(entrypoint), file)
);
if (goMod) {
await copy(
join(entrypointDirnameDev, 'go.mod'),
join(destNow, dirname(entrypoint), 'go.mod')
);
}
} else {
await copy(join(base, file), join(destNow, file));
if (goMod) {
await copy(
join(entrypointDirnameDev, 'go.mod'),
join(destNow, 'go.mod')
);
}
}
}
downloadedFiles = await glob('**', destNow);
}
// find `go.mod` in downloadedFiles
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
let isGoModExist = false;
let goModPath = '';
let goModPathArr: string[] = [];
for (const file of Object.keys(downloadedFiles)) {
const fileDirname = dirname(downloadedFiles[file].fsPath);
if (file === 'go.mod') {
isGoModExist = true;
goModPath = fileDirname;
goModPathArr = goModPath.split(sep);
} else if (file.includes('go.mod')) {
isGoModExist = true;
if (entrypointDirname === fileDirname) {
goModPath = fileDirname;
goModPathArr = goModPath.split(sep);
}
}
}
const input = entrypointDirname;
var includedFiles: Files = {};
@@ -162,7 +164,11 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
// check if package name other than main
// using `go.mod` way building the handler
const packageName = parsedAnalyzed.packageName;
const isGoModExist = await pathExists(join(entrypointDirname, 'go.mod'));
if (isGoModExist && packageName === 'main') {
throw new Error('Please change `package main` to `package handler`');
}
if (packageName !== 'main') {
const go = await createGo(
goPath,
@@ -194,10 +200,7 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
const goFuncName = `${packageName}.${handlerFunctionName}`;
if (isGoModExist) {
const goModContents = await readFile(
join(entrypointDirname, 'go.mod'),
'utf8'
);
const goModContents = await readFile(join(goModPath, 'go.mod'), 'utf8');
const usrModName = goModContents.split('\n')[0].split(' ')[1];
goPackageName = `${usrModName}/${packageName}`;
}
@@ -206,11 +209,16 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
.replace('__NOW_HANDLER_PACKAGE_NAME', goPackageName)
.replace('__NOW_HANDLER_FUNC_NAME', goFuncName);
// write main__mod__.go
await writeFile(
join(entrypointDirname, mainModGoFileName),
mainModGoContents
);
if (goModPathArr.length > 1) {
// using `go.mod` path to write main__mod__.go
await writeFile(join(goModPath, mainModGoFileName), mainModGoContents);
} else {
// using `entrypointDirname` to write main__mod__.go
await writeFile(
join(entrypointDirname, mainModGoFileName),
mainModGoContents
);
}
// move user go file to folder
try {
@@ -231,25 +239,34 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
);
}
await move(downloadedFiles[entrypoint].fsPath, finalDestination, {
overwrite: forceMove,
});
if (
dirname(downloadedFiles[entrypoint].fsPath) === goModPath ||
!isGoModExist
) {
await move(downloadedFiles[entrypoint].fsPath, finalDestination, {
overwrite: forceMove,
});
}
} catch (err) {
console.log('failed to move entry to package folder');
throw err;
}
if (meta.isDev) {
const isGoModBk = await pathExists(join(entrypointDirname, 'go.mod.bk'));
let entrypointDir = entrypointDirname;
if (goModPathArr.length > 1) {
entrypointDir = goModPath;
}
const isGoModBk = await pathExists(join(entrypointDir, 'go.mod.bk'));
if (isGoModBk) {
await move(
join(entrypointDirname, 'go.mod.bk'),
join(entrypointDirname, 'go.mod'),
join(entrypointDir, 'go.mod.bk'),
join(entrypointDir, 'go.mod'),
{ overwrite: true }
);
await move(
join(entrypointDirname, 'go.sum.bk'),
join(entrypointDirname, 'go.sum'),
join(entrypointDir, 'go.sum.bk'),
join(entrypointDir, 'go.sum'),
{ overwrite: true }
);
}
@@ -266,8 +283,11 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
console.log('Running `go build`...');
const destPath = join(outDir, 'handler');
const isGoModInRootDir = goModPathArr.length === 1;
const baseGoModPath = isGoModInRootDir ? entrypointDirname : goModPath;
try {
const src = [join(entrypointDirname, mainModGoFileName)];
let src = [join(baseGoModPath, mainModGoFileName)];
await go.build(src, destPath, config.ldsflags);
} catch (err) {
console.log('failed to `go build`');
@@ -276,13 +296,13 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
if (meta.isDev) {
// caching for `now dev`
await move(
join(entrypointDirname, 'go.mod'),
join(entrypointDirname, 'go.mod.bk'),
join(baseGoModPath, 'go.mod'),
join(baseGoModPath, 'go.mod.bk'),
{ overwrite: true }
);
await move(
join(entrypointDirname, 'go.sum'),
join(entrypointDirname, 'go.sum.bk'),
join(baseGoModPath, 'go.sum'),
join(baseGoModPath, 'go.sum.bk'),
{ overwrite: true }
);
}
@@ -351,16 +371,17 @@ Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#ent
};
let watch = parsedAnalyzed.watch;
let watchSub: string[] = [];
// if `entrypoint` located in subdirectory
// we will need to concat it with return watch array
if (entrypointArr.length > 1) {
entrypointArr.pop();
watch = parsedAnalyzed.watch.map(file => join(...entrypointArr, file));
watchSub = parsedAnalyzed.watch.map(file => join(...entrypointArr, file));
}
return {
output,
watch,
watch: watch.concat(watchSub),
};
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/go",
"version": "0.5.0",
"version": "0.5.1",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -8,4 +8,4 @@
{ "path": "/", "mustContain": "cow:RANDOMNESS_PLACEHOLDER" },
{ "path": "/subdirectory", "mustContain": "subcow:RANDOMNESS_PLACEHOLDER" }
]
}
}

View File

@@ -15,4 +15,4 @@
"mustContain": "RANDOMNESS_PLACEHOLDER"
}
]
}
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{ "src": "index.go", "use": "@now/go" }
]
}
"builds": [{ "src": "index.go", "use": "@now/go" }]
}

View File

@@ -1,9 +1,7 @@
{
"version": 2,
"builds": [
{ "src": "*.go", "use": "@now/go" }
],
"builds": [{ "src": "*.go", "use": "@now/go" }],
"env": {
"RANDOMNESS_ENV_VAR": "RANDOMNESS_PLACEHOLDER"
}
}
}

View File

@@ -5,9 +5,7 @@
"src": "index.go",
"use": "@now/go",
"config": {
"includeFiles": [
"templates/**"
]
"includeFiles": ["templates/**"]
}
}
],

View File

@@ -1,9 +1,5 @@
{
"version": 2,
"builds": [
{ "src": "index.go", "use": "@now/go" }
],
"probes": [
{ "path": "/", "mustContain": "RANDOMNESS_PLACEHOLDER" }
]
"builds": [{ "src": "index.go", "use": "@now/go" }],
"probes": [{ "path": "/", "mustContain": "RANDOMNESS_PLACEHOLDER" }]
}

View File

@@ -0,0 +1,3 @@
module go-mod
go 1.12

View File

@@ -0,0 +1,11 @@
package handler
import (
"fmt"
"net/http"
)
// Handler func
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -0,0 +1,5 @@
{
"version": 2,
"builds": [{ "src": "index.go", "use": "@now/go" }],
"probes": [{ "path": "/", "mustContain": "RANDOMNESS_PLACEHOLDER" }]
}

View File

@@ -0,0 +1,12 @@
package api
import (
"fmt"
"net/http"
"with-shared/shared"
)
// Handler func
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, shared.Say("RANDOMNESS_PLACEHOLDER"))
}

View File

@@ -0,0 +1,3 @@
module with-shared
go 1.12

View File

@@ -0,0 +1,5 @@
{
"version": 2,
"builds": [{ "src": "api/*.go", "use": "@now/go" }],
"probes": [{ "path": "/api", "mustContain": "RANDOMNESS_PLACEHOLDER" }]
}

View File

@@ -0,0 +1,6 @@
package shared
// Say func
func Say(text string) string {
return text
}

View File

@@ -0,0 +1,8 @@
{
"version": 2,
"builds": [{ "src": "**/*.go", "use": "@now/go" }],
"probes": [
{ "path": "/sub-1", "mustContain": "RANDOMNESS_PLACEHOLDER" },
{ "path": "/sub-2", "mustContain": "RANDOMNESS_PLACEHOLDER" }
]
}

View File

@@ -0,0 +1,3 @@
module sub-1
go 1.12

View File

@@ -0,0 +1,11 @@
package sub1
import (
"fmt"
"net/http"
)
// Handler func
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -0,0 +1,3 @@
module sub-2
go 1.12

View File

@@ -0,0 +1,11 @@
package sub2
import (
"fmt"
"net/http"
)
// Handler func
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -26,8 +26,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}

View File

@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
"flag"
"fmt"
"go/ast"
"go/parser"
@@ -92,13 +93,13 @@ func unique(files []string) []string {
}
func main() {
if len(os.Args) != 2 {
if len(os.Args) != 3 {
// Args should have the program name on `0`
// and the file name on `1`
fmt.Println("Wrong number of args; Usage is:\n ./go-analyze file_name.go")
fmt.Println("Wrong number of args; Usage is:\n ./go-analyze -modpath=module-path file_name.go")
os.Exit(1)
}
fileName := os.Args[1]
fileName := os.Args[2]
rf, err := ioutil.ReadFile(fileName)
if err != nil {
log.Fatal(err)
@@ -122,6 +123,17 @@ func main() {
log.Fatal(err)
}
// looking related packages
var modPath string
flag.StringVar(&modPath, "modpath", "", "module path")
flag.Parse()
if len(modPath) > 1 {
err = filepath.Walk(modPath, visit(&files))
if err != nil {
log.Fatal(err)
}
}
for _, file := range files {
absFileName, _ := filepath.Abs(fileName)
absFile, _ := filepath.Abs(file)
@@ -154,7 +166,14 @@ func main() {
for _, ed := range exportedDecl {
if strings.Contains(se, ed) {
// find relative path of related file
rel, err := filepath.Rel(filepath.Dir(fileName), file)
var basePath string
if modPath == "" {
basePath = filepath.Dir(fileName)
} else {
basePath = modPath
}
rel, err := filepath.Rel(basePath, file)
if err != nil {
log.Fatal(err)
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/lambda",
"version": "0.5.3",
"version": "0.5.4",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -1,11 +1,22 @@
{
"version": 2,
"builds": [
{ "src": "index.zip", "use": "@now/lambda", "config": { "handler": "index.handler", "runtime": "nodejs8.10" } },
{ "src": "subdirectory/index.zip", "use": "@now/lambda", "config": { "handler": "index.handler", "runtime": "nodejs8.10" } }
{
"src": "index.zip",
"use": "@now/lambda",
"config": { "handler": "index.handler", "runtime": "nodejs8.10" }
},
{
"src": "subdirectory/index.zip",
"use": "@now/lambda",
"config": { "handler": "index.handler", "runtime": "nodejs8.10" }
}
],
"probes": [
{ "path": "/", "mustContain": "cow:NO_REPLACE_TO_AVOID_CRC_MISMATCH" },
{ "path": "/subdirectory/", "mustContain": "yoda:NO_REPLACE_TO_AVOID_CRC_MISMATCH" }
{
"path": "/subdirectory/",
"mustContain": "yoda:NO_REPLACE_TO_AVOID_CRC_MISMATCH"
}
]
}

1
packages/now-layer-node/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/dist

View File

@@ -0,0 +1,32 @@
{
"name": "@now/layer-node",
"version": "0.0.2",
"main": "./dist/src/index",
"license": "MIT",
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "https://github.com/zeit/now-builders.git",
"directory": "packages/now-layer-node"
},
"scripts": {
"build": "tsc",
"test": "tsc && jest",
"prepublishOnly": "tsc"
},
"dependencies": {
"fs-extra": "7.0.1",
"node-fetch": "2.6.0",
"promisepipe": "3.0.0",
"stream-to-promise": "2.2.0",
"tar": "4.4.6",
"yauzl-promise": "2.1.3"
},
"devDependencies": {
"@types/tar": "4.0.0",
"@types/yauzl-promise": "2.1.0",
"typescript": "3.3.3"
}
}

View File

@@ -0,0 +1,37 @@
import { tmpdir } from 'os';
import { join } from 'path';
import { glob, Files } from '@now/build-utils';
import { mkdir, remove, pathExists } from 'fs-extra';
import { install } from './install';
interface BuildLayerConfig {
runtimeVersion: string;
platform: string;
arch: string;
}
interface BuildLayerResult {
files: Files;
entrypoint: string;
}
export async function buildLayer({
runtimeVersion,
platform,
arch,
}: BuildLayerConfig): Promise<BuildLayerResult> {
const dir = join(
tmpdir(),
`now-layer-node-${runtimeVersion}-${platform}-${arch}`
);
const exists = await pathExists(dir);
if (exists) {
await remove(dir);
}
await mkdir(dir);
const { entrypoint } = await install(dir, runtimeVersion, platform, arch);
const files = await glob('{bin/node,bin/node.exe,include/**}', {
cwd: dir,
});
return { files, entrypoint };
}

View File

@@ -0,0 +1,68 @@
import { basename, join } from 'path';
import fetch from 'node-fetch';
import { extract } from 'tar';
import pipe from 'promisepipe';
import { createWriteStream } from 'fs-extra';
import { unzip, zipFromFile } from './unzip';
export async function install(
dest: string,
version: string,
platform: string,
arch: string
) {
const tarballUrl = getUrl(version, platform, arch);
console.log('Downloading from ' + tarballUrl);
console.log('Downloading to ' + dest);
const res = await fetch(tarballUrl);
if (!res.ok) {
throw new Error(`HTTP request failed: ${res.status}`);
}
let entrypoint: string;
if (platform === 'win32') {
// Put it in the `bin` dir for consistency with the tarballs
const finalDest = join(dest, 'bin');
const zipName = basename(tarballUrl);
const zipPath = join(dest, zipName);
await pipe(
res.body,
createWriteStream(zipPath)
);
const zipFile = await zipFromFile(zipPath);
await unzip(zipFile, finalDest, { strip: 1 });
entrypoint = join('bin', 'node.exe');
} else {
const extractStream = extract({ strip: 1, C: dest });
if (!extractStream.destroy) {
// If there is an error in promisepipe,
// it expects a destroy method
extractStream.destroy = () => {};
}
await pipe(
res.body,
extractStream
);
entrypoint = join('bin', 'node');
}
return { entrypoint };
}
export function getUrl(
version: string,
platform: string = process.platform,
arch: string = process.arch
): string {
let ext: string;
let plat: string;
if (platform === 'win32') {
ext = 'zip';
plat = 'win';
} else {
ext = 'tar.gz';
plat = platform;
}
return `https://nodejs.org/dist/v${version}/node-v${version}-${plat}-${arch}.${ext}`;
}

View File

@@ -0,0 +1,96 @@
import { tmpdir } from 'os';
import pipe from 'promisepipe';
import { dirname, join } from 'path';
import { createWriteStream, mkdirp, symlink, unlink } from 'fs-extra';
import streamToPromise from 'stream-to-promise';
import {
Entry,
ZipFile,
open as zipFromFile,
fromBuffer as zipFromBuffer,
} from 'yauzl-promise';
export { zipFromFile, zipFromBuffer, ZipFile };
export async function unzipToTemp(
data: Buffer | string,
tmpDir: string = tmpdir()
): Promise<string> {
const dir = join(
tmpDir,
`zeit-fun-${Math.random()
.toString(16)
.substring(2)}`
);
let zip: ZipFile;
if (Buffer.isBuffer(data)) {
zip = await zipFromBuffer(data);
} else {
zip = await zipFromFile(data);
}
await unzip(zip, dir);
await zip.close();
return dir;
}
interface UnzipOptions {
strip?: number;
}
export async function unzip(
zipFile: ZipFile,
dir: string,
opts: UnzipOptions = {}
): Promise<void> {
let entry: Entry;
const strip = opts.strip || 0;
while ((entry = await zipFile.readEntry()) !== null) {
const fileName =
strip === 0
? entry.fileName
: entry.fileName
.split('/')
.slice(strip)
.join('/');
const destPath = join(dir, fileName);
if (/\/$/.test(entry.fileName)) {
await mkdirp(destPath);
} else {
const [entryStream] = await Promise.all([
entry.openReadStream(),
// ensure parent directory exists
mkdirp(dirname(destPath)),
]);
const mode = entry.externalFileAttributes >>> 16;
if (isSymbolicLink(mode)) {
const linkDest = String(await streamToPromise(entryStream));
await symlink(linkDest, destPath);
} else {
const octal = mode & 4095 /* 07777 */;
const modeOctal = ('0000' + octal.toString(8)).slice(-4);
const modeVal = parseInt(modeOctal, 8);
try {
await unlink(destPath);
} catch (err) {
if (err.code !== 'ENOENT') {
throw err;
}
}
const destStream = createWriteStream(destPath, {
mode: modeVal,
});
await pipe(
entryStream,
destStream
);
}
}
}
}
const S_IFMT = 61440; /* 0170000 type of file */
const S_IFLNK = 40960; /* 0120000 symbolic link */
export function isSymbolicLink(mode: number): boolean {
return (mode & S_IFMT) === S_IFLNK;
}

View File

@@ -0,0 +1,54 @@
/* global jest, expect, it */
jest.setTimeout(30 * 1000);
const { buildLayer } = require('../');
describe('buildLayer', () => {
it('should get node 10 and metadata for windows', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '10.16.0',
platform: 'win32',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(names.size).toBeGreaterThan(0);
expect(entrypoint).toBe('bin/node.exe');
expect(names.has('bin/node.exe')).toBeTruthy();
expect(names.has('bin/npm.cmd')).toBeFalsy();
expect(names.has('bin/npx.cmd')).toBeFalsy();
expect(names.has('bin/node_modules')).toBeFalsy();
});
it('should get node 10 and metadata for macos', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '10.16.0',
platform: 'darwin',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(names.size).toBeGreaterThan(0);
expect(entrypoint).toBe('bin/node');
expect(names.has('bin/node')).toBeTruthy();
expect(names.has('bin/npm')).toBeFalsy();
expect(names.has('bin/npx')).toBeFalsy();
expect(names.has('lib/node_modules')).toBeFalsy();
});
it('should get node 10 and metadata for linux', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '10.16.0',
platform: 'linux',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(names.size).toBeGreaterThan(0);
expect(entrypoint).toBe('bin/node');
expect(names.has('bin/node')).toBeTruthy();
expect(names.has('include/node/node.h')).toBeTruthy();
expect(names.has('bin/npm')).toBeFalsy();
expect(names.has('bin/npx')).toBeFalsy();
expect(names.has('lib/node_modules')).toBeFalsy();
});
});

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"declaration": false,
"esModuleInterop": true,
"lib": ["esnext"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "dist",
"types": ["node"],
"strict": true,
"target": "esnext"
}
}

View File

@@ -0,0 +1,4 @@
declare module 'promisepipe' {
import { Stream } from 'stream';
export default function pipe(...args: Stream[]): Promise<void>;
}

View File

@@ -0,0 +1,6 @@
declare module 'stream-to-promise' {
import { Stream } from 'stream';
export default function streamToPromise(
stream: NodeJS.ReadableStream
): Promise<string>;
}

1
packages/now-layer-npm/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/dist

View File

@@ -0,0 +1,29 @@
{
"name": "@now/layer-npm",
"version": "0.0.2",
"main": "./dist/src/index",
"license": "MIT",
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "https://github.com/zeit/now-builders.git",
"directory": "packages/now-layer-npm"
},
"scripts": {
"build": "tsc",
"test": "tsc && jest",
"prepublishOnly": "tsc"
},
"dependencies": {
"fs-extra": "7.0.1",
"node-fetch": "2.6.0",
"promisepipe": "3.0.0",
"tar": "4.4.6"
},
"devDependencies": {
"@types/tar": "4.0.0",
"typescript": "3.3.3"
}
}

View File

@@ -0,0 +1,37 @@
import { tmpdir } from 'os';
import { join } from 'path';
import { glob, Files } from '@now/build-utils';
import { mkdir, remove, pathExists } from 'fs-extra';
import { install } from './install';
interface BuildLayerConfig {
runtimeVersion: string;
platform: string;
arch: string;
}
interface BuildLayerResult {
files: Files;
entrypoint: string;
}
export async function buildLayer({
runtimeVersion,
platform,
arch,
}: BuildLayerConfig): Promise<BuildLayerResult> {
const dir = join(
tmpdir(),
`now-layer-npm-${runtimeVersion}-${platform}-${arch}`
);
const exists = await pathExists(dir);
if (exists) {
await remove(dir);
}
await mkdir(dir);
const { entrypoint } = await install(dir, runtimeVersion);
const files = await glob('{bin/**,lib/**,node_modules/**}', {
cwd: dir,
});
return { files, entrypoint };
}

View File

@@ -0,0 +1,29 @@
import { join } from 'path';
import fetch from 'node-fetch';
import { extract } from 'tar';
import pipe from 'promisepipe';
export async function install(dest: string, version: string) {
const tarballUrl = `https://registry.npmjs.org/npm/-/npm-${version}.tgz`;
console.log('Downloading from ' + tarballUrl);
console.log('Downloading to ' + dest);
const res = await fetch(tarballUrl);
if (!res.ok) {
throw new Error(`HTTP request failed: ${res.status}`);
}
const extractStream = extract({ strip: 1, C: dest });
if (!extractStream.destroy) {
// If there is an error in promisepipe,
// it expects a destroy method
extractStream.destroy = () => {};
}
await pipe(
res.body,
extractStream
);
const pathToManifest = join(dest, 'package.json');
const manifest = require(pathToManifest);
const entrypoint = manifest.bin.npm;
return { entrypoint };
}

View File

@@ -0,0 +1,50 @@
/* global jest, expect, it */
jest.setTimeout(30 * 1000);
const { buildLayer } = require('../');
describe('buildLayer', () => {
it('should get npm 6 but not npm for windows', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '6.9.0',
platform: 'win32',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(entrypoint).toBe('./bin/npm-cli.js');
expect(names.size).toBeGreaterThan(0);
expect(names.has('bin/npm.cmd')).toBeTruthy();
expect(names.has('bin/npx.cmd')).toBeTruthy();
expect(names.has('README.md')).toBeFalsy();
});
it('should get npm 6 but not npm for macos', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '6.9.0',
platform: 'darwin',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(entrypoint).toBe('./bin/npm-cli.js');
expect(names.size).toBeGreaterThan(0);
expect(names.has('bin/npm')).toBeTruthy();
expect(names.has('bin/npx')).toBeTruthy();
expect(names.has('README.md')).toBeFalsy();
});
it('should get npm 6 but not npm for linux', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '6.9.0',
platform: 'linux',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(entrypoint).toBe('./bin/npm-cli.js');
expect(names.size).toBeGreaterThan(0);
expect(names.has('bin/npm')).toBeTruthy();
expect(names.has('bin/npx')).toBeTruthy();
expect(names.has('README.md')).toBeFalsy();
});
});

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"declaration": false,
"esModuleInterop": true,
"lib": ["esnext"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "dist",
"types": ["node"],
"strict": true,
"target": "esnext"
}
}

View File

@@ -0,0 +1,4 @@
declare module 'promisepipe' {
import { Stream } from 'stream';
export default function pipe(...args: Stream[]): Promise<void>;
}

1
packages/now-layer-yarn/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/dist

View File

@@ -0,0 +1,29 @@
{
"name": "@now/layer-yarn",
"version": "0.0.2",
"main": "./dist/src/index",
"license": "MIT",
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "https://github.com/zeit/now-builders.git",
"directory": "packages/now-layer-yarn"
},
"scripts": {
"build": "tsc",
"test": "tsc && jest",
"prepublishOnly": "tsc"
},
"dependencies": {
"fs-extra": "7.0.1",
"node-fetch": "2.6.0",
"promisepipe": "3.0.0",
"tar": "4.4.6"
},
"devDependencies": {
"@types/tar": "4.0.0",
"typescript": "3.3.3"
}
}

View File

@@ -0,0 +1,37 @@
import { tmpdir } from 'os';
import { join } from 'path';
import { glob, Files } from '@now/build-utils';
import { mkdir, remove, pathExists } from 'fs-extra';
import { install } from './install';
interface BuildLayerConfig {
runtimeVersion: string;
platform: string;
arch: string;
}
interface BuildLayerResult {
files: Files;
entrypoint: string;
}
export async function buildLayer({
runtimeVersion,
platform,
arch,
}: BuildLayerConfig): Promise<BuildLayerResult> {
const dir = join(
tmpdir(),
`now-layer-yarn-${runtimeVersion}-${platform}-${arch}`
);
const exists = await pathExists(dir);
if (exists) {
await remove(dir);
}
await mkdir(dir);
const { entrypoint } = await install(dir, runtimeVersion);
const files = await glob('{bin/**,lib/**}', {
cwd: dir,
});
return { files, entrypoint };
}

View File

@@ -0,0 +1,29 @@
import { join } from 'path';
import fetch from 'node-fetch';
import { extract } from 'tar';
import pipe from 'promisepipe';
export async function install(dest: string, version: string) {
const tarballUrl = `https://registry.npmjs.org/yarn/-/yarn-${version}.tgz`;
console.log('Downloading from ' + tarballUrl);
console.log('Downloading to ' + dest);
const res = await fetch(tarballUrl);
if (!res.ok) {
throw new Error(`HTTP request failed: ${res.status}`);
}
const extractStream = extract({ strip: 1, C: dest });
if (!extractStream.destroy) {
// If there is an error in promisepipe,
// it expects a destroy method
extractStream.destroy = () => {};
}
await pipe(
res.body,
extractStream
);
const pathToManifest = join(dest, 'package.json');
const manifest = require(pathToManifest);
const entrypoint = manifest.bin.yarn;
return { entrypoint };
}

View File

@@ -0,0 +1,49 @@
/* global jest, expect, it */
jest.setTimeout(30 * 1000);
const { buildLayer } = require('../');
describe('buildLayer', () => {
it('should get yarn for windows', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '1.16.0',
platform: 'win32',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(entrypoint).toBe('./bin/yarn.js');
expect(names.size).toBeGreaterThan(0);
expect(names.has('bin/yarn.cmd')).toBeTruthy();
expect(names.has('lib/cli.js')).toBeTruthy();
});
it('should get yarn for macos', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '1.16.0',
platform: 'darwin',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(entrypoint).toBe('./bin/yarn.js');
expect(names.size).toBeGreaterThan(0);
expect(names.has('bin/yarn')).toBeTruthy();
expect(names.has('lib/cli.js')).toBeTruthy();
expect(names.has('README.md')).toBeFalsy();
});
it('should get yarn for linux', async () => {
const { files, entrypoint } = await buildLayer({
runtimeVersion: '1.16.0',
platform: 'linux',
arch: 'x64',
});
const names = new Set(Object.keys(files));
expect(names).toBeTruthy();
expect(entrypoint).toBe('./bin/yarn.js');
expect(names.size).toBeGreaterThan(0);
expect(names.has('bin/yarn')).toBeTruthy();
expect(names.has('lib/cli.js')).toBeTruthy();
expect(names.has('README.md')).toBeFalsy();
});
});

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"declaration": false,
"esModuleInterop": true,
"lib": ["esnext"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "dist",
"types": ["node"],
"strict": true,
"target": "esnext"
}
}

View File

@@ -0,0 +1,4 @@
declare module 'promisepipe' {
import { Stream } from 'stream';
export default function pipe(...args: Stream[]): Promise<void>;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/next",
"version": "0.4.0",
"version": "0.4.1",
"license": "MIT",
"main": "./dist/index",
"scripts": {
@@ -14,7 +14,7 @@
"directory": "packages/now-next"
},
"dependencies": {
"@now/node-bridge": "^1.1.3",
"@now/node-bridge": "^1.1.4",
"fs-extra": "^7.0.0",
"get-port": "^5.0.0",
"resolve-from": "^5.0.0",

View File

@@ -36,6 +36,8 @@ import {
stringMap,
syncEnvVars,
validateEntrypoint,
normalizePage,
getDynamicRoutes,
} from './utils';
interface BuildParamsMeta {
@@ -155,7 +157,7 @@ export const build = async ({
entrypoint,
meta = {} as BuildParamsMeta,
}: BuildParamsType): Promise<{
routes?: { src: string; dest: string }[];
routes?: ({ src?: string; dest?: string } | { handle: string })[];
output: Files;
watch?: string[];
childProcesses: ChildProcess[];
@@ -213,7 +215,13 @@ export const build = async ({
return {
output: {},
routes: getRoutes(entryDirectory, pathsInside, files, urls[entrypoint]),
routes: getRoutes(
entryPath,
entryDirectory,
pathsInside,
files,
urls[entrypoint]
),
watch: pathsInside,
childProcesses: childProcess ? [childProcess] : [],
};
@@ -288,9 +296,10 @@ export const build = async ({
await unlinkFile(path.join(entryPath, '.npmrc'));
}
const routes: { src: string; dest: string }[] = [];
const exportedPageRoutes: { src: string; dest: string }[] = [];
const lambdas: { [key: string]: Lambda } = {};
const staticPages: { [key: string]: FileFsRef } = {};
const dynamicPages: string[] = [];
if (isLegacy) {
const filesAfterBuild = await glob('**', entryPath);
@@ -315,7 +324,9 @@ export const build = async ({
file => file.startsWith('node_modules/.cache')
);
const launcherFiles = {
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
'now__bridge.js': new FileFsRef({
fsPath: require('@now/node-bridge'),
}),
};
const nextFiles: { [key: string]: FileFsRef } = {
...nodeModules,
@@ -377,7 +388,9 @@ export const build = async ({
} else {
console.log('preparing lambda files...');
const launcherFiles = {
'now__bridge.js': new FileFsRef({ fsPath: require('@now/node-bridge') }),
'now__bridge.js': new FileFsRef({
fsPath: require('@now/node-bridge'),
}),
'now__launcher.js': new FileFsRef({
fsPath: path.join(__dirname, 'launcher.js'),
}),
@@ -392,7 +405,12 @@ export const build = async ({
staticPages[staticRoute] = staticPageFiles[page];
const pathname = page.replace(/\.html$/, '');
routes.push({
if (pathname.startsWith('$') || pathname.includes('/$')) {
dynamicPages.push(pathname);
}
exportedPageRoutes.push({
src: `^${path.join('/', entryDirectory, pathname)}$`,
dest: path.join('/', staticRoute),
});
@@ -429,12 +447,16 @@ export const build = async ({
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)) {
if (['_app.js', '_document.js'].includes(page)) {
return;
}
const pathname = page.replace(/\.js$/, '');
if (pathname.startsWith('$') || pathname.includes('/$')) {
dynamicPages.push(normalizePage(pathname));
}
console.log(`Creating lambda for page: "${page}"...`);
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
files: {
@@ -481,6 +503,19 @@ export const build = async ({
{}
);
let dynamicRoutes = getDynamicRoutes(
entryPath,
entryDirectory,
dynamicPages
).map(route => {
// make sure .html is added to dest for now until
// outputting static files to clean routes is available
if (staticPages[`${route.dest}.html`]) {
route.dest = `${route.dest}.html`;
}
return route;
});
return {
output: {
...publicFiles,
@@ -489,7 +524,23 @@ export const build = async ({
...staticFiles,
...staticDirectoryFiles,
},
routes,
routes: [
// Static exported pages (.html rewrites)
...exportedPageRoutes,
// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
// folder
{ handle: 'filesystem' },
// Dynamic routes
...dynamicRoutes,
...(isLegacy
? []
: [
{
src: path.join('/', entryDirectory, '.*'),
dest: path.join('/', entryDirectory, '_error'),
},
]),
],
watch: [],
childProcesses: [],
};

View File

@@ -4,7 +4,8 @@ import url from 'url';
import { Bridge } from './now__bridge';
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = process.env.NOW_REGION === 'dev1' ? 'development' : 'production';
process.env.NODE_ENV =
process.env.NOW_REGION === 'dev1' ? 'development' : 'production';
}
const app = next({});

View File

@@ -1,5 +1,6 @@
import fs from 'fs-extra';
import path from 'path';
import resolveFrom from 'resolve-from';
import { Files } from '@now/build-utils';
type stringMap = { [key: string]: string };
@@ -168,7 +169,18 @@ function getPathsInside(entryDirectory: string, files: Files) {
return watch;
}
function normalizePage(page: string): string {
// remove '/index' from the end
page = page.replace(/\/index$/, '/');
// Resolve on anything that doesn't start with `/`
if (!page.startsWith('/')) {
page = `/${page}`;
}
return page;
}
function getRoutes(
entryPath: string,
entryDirectory: string,
pathsInside: string[],
files: Files,
@@ -196,6 +208,7 @@ function getRoutes(
},
];
const filePaths = Object.keys(filesInside);
const dynamicPages = [];
for (const file of filePaths) {
const relativePath = path.relative(entryDirectory, file);
@@ -213,6 +226,10 @@ function getRoutes(
continue;
}
if (pageName.startsWith('$') || pageName.includes('/$')) {
dynamicPages.push(normalizePage(pageName));
}
routes.push({
src: `${prefix}${pageName}`,
dest: `${url}/${pageName}`,
@@ -228,6 +245,17 @@ function getRoutes(
}
}
routes.push(
...getDynamicRoutes(entryPath, entryDirectory, dynamicPages).map(
(route: { src: string; dest: string }) => {
// convert to make entire RegExp match as one group
route.src = route.src.replace('^', '^(').replace('$', ')$');
route.dest = `${url}/$1`;
return route;
}
)
);
// Add public folder routes
for (const file of filePaths) {
const relativePath = path.relative(entryDirectory, file);
@@ -250,6 +278,52 @@ function getRoutes(
return routes;
}
export function getDynamicRoutes(
entryPath: string,
entryDirectory: string,
dynamicPages: string[]
): { src: string; dest: string }[] {
if (!dynamicPages.length) {
return [];
}
let getRouteRegex:
| ((pageName: string) => { re: RegExp })
| undefined = undefined;
let getSortedRoutes: ((normalizedPages: string[]) => string[]) | undefined;
try {
({ getRouteRegex, getSortedRoutes } = require(resolveFrom(
entryPath,
'next-server/dist/lib/router/utils'
)));
if (typeof getRouteRegex !== 'function') {
getRouteRegex = undefined;
}
} catch (_) {}
if (!getRouteRegex || !getSortedRoutes) {
throw new Error(
'Found usage of dynamic routes but not on a new enough version of Next.js.'
);
}
const pageMatchers = getSortedRoutes(dynamicPages).map(pageName => ({
pageName,
matcher: getRouteRegex!(pageName).re,
}));
const routes: { src: string; dest: string }[] = [];
pageMatchers.forEach(pageMatcher => {
routes.push({
src: pageMatcher.matcher.source,
dest: path.join('/', entryDirectory, pageMatcher.pageName),
});
});
return routes;
}
function syncEnvVars(base: EnvConfig, removeEnv: EnvConfig, addEnv: EnvConfig) {
// Remove any env vars from `removeEnv`
// that are not present in the `addEnv`
@@ -276,4 +350,5 @@ export {
getRoutes,
stringMap,
syncEnvVars,
normalizePage,
};

View File

@@ -12,10 +12,12 @@ it(
} = await runBuildLambda(path.join(__dirname, 'standard'));
expect(output.index).toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy();
},
FOUR_MINUTES,
);

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "package.json", "use": "@now/next"}
]
"builds": [{ "src": "package.json", "use": "@now/next" }]
}

View File

@@ -3,4 +3,4 @@
"isomorphic-unfetch": "latest",
"next": "7.0.0"
}
}
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "next.config.js", "use": "@now/next"}
]
"builds": [{ "src": "next.config.js", "use": "@now/next" }]
}

View File

@@ -2,4 +2,4 @@
"dependencies": {
"next": "^7.0.2"
}
}
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "next.config.js", "use": "@now/next"}
]
"builds": [{ "src": "next.config.js", "use": "@now/next" }]
}

View File

@@ -2,4 +2,4 @@
"dependencies": {
"next": "7.0.2"
}
}
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{ "src": "www/package.json", "use": "@now/next" }
]
"version": 2,
"builds": [{ "src": "www/package.json", "use": "@now/next" }]
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "pages/index.js", "use": "@now/next"}
]
"builds": [{ "src": "pages/index.js", "use": "@now/next" }]
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "next.config.js", "use": "@now/next"}
]
"builds": [{ "src": "next.config.js", "use": "@now/next" }]
}

View File

@@ -7,4 +7,4 @@
"react": "16",
"react-dom": "16"
}
}
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "next.config.js", "use": "@now/next"}
]
"builds": [{ "src": "next.config.js", "use": "@now/next" }]
}

View File

@@ -4,4 +4,4 @@
"react": "latest",
"react-dom": "latest"
}
}
}

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{"src": "next.config.js", "use": "@now/next"}
]
"builds": [{ "src": "next.config.js", "use": "@now/next" }]
}

View File

@@ -7,4 +7,4 @@
"react": "16",
"react-dom": "16"
}
}
}

View File

@@ -9,10 +9,6 @@
"sourceMap": false,
"declaration": false
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/node-bridge",
"version": "1.1.3",
"version": "1.1.4",
"license": "MIT",
"main": "./index.js",
"repository": {

View File

@@ -9,10 +9,6 @@
"sourceMap": true,
"declaration": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@@ -105,7 +105,10 @@ exports.build = async ({
}) => {
const [downloadedFiles, entrypointFsDirname] = await downloadInstallAndBundle(
{
files, entrypoint, workPath, meta,
files,
entrypoint,
workPath,
meta,
},
{ npmArguments: ['--prefer-offline'] },
);

View File

@@ -1,6 +1,6 @@
{
"name": "@now/node-server",
"version": "0.7.3",
"version": "0.7.4",
"license": "MIT",
"repository": {
"type": "git",
@@ -8,7 +8,7 @@
"directory": "packages/now-node-server"
},
"dependencies": {
"@now/node-bridge": "^1.1.3",
"@now/node-bridge": "^1.1.4",
"@zeit/ncc": "0.18.5",
"fs-extra": "7.0.1"
},

View File

@@ -1,6 +1,4 @@
{
"version": 2,
"builds": [
{ "src": "index.js", "use": "@now/node-server" }
]
"builds": [{ "src": "index.js", "use": "@now/node-server" }]
}

View File

@@ -1,9 +1,10 @@
{
"version": 2,
"builds": [
{ "src": "index.js", "use": "@now/node-server" }
],
"builds": [{ "src": "index.js", "use": "@now/node-server" }],
"probes": [
{ "path": "/", "mustContain": "asset1:RANDOMNESS_PLACEHOLDER,asset2:RANDOMNESS_PLACEHOLDER" }
{
"path": "/",
"mustContain": "asset1:RANDOMNESS_PLACEHOLDER,asset2:RANDOMNESS_PLACEHOLDER"
}
]
}

View File

@@ -2,10 +2,20 @@
"version": 2,
"builds": [
{ "src": "with-bundle/index.js", "use": "@now/node-server" },
{ "src": "without-bundle/index.js", "use": "@now/node-server", "config": { "bundle": false } }
{
"src": "without-bundle/index.js",
"use": "@now/node-server",
"config": { "bundle": false }
}
],
"probes": [
{ "path": "/with-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER:with-bundle" },
{ "path": "/without-bundle", "mustContain": "RANDOMNESS_PLACEHOLDER:without-bundle" }
{
"path": "/with-bundle",
"mustContain": "RANDOMNESS_PLACEHOLDER:with-bundle"
},
{
"path": "/without-bundle",
"mustContain": "RANDOMNESS_PLACEHOLDER:without-bundle"
}
]
}

Some files were not shown because too many files have changed in this diff Show More