[tests] Unify linting and autoformatting (#2914)

* add prettier and eslint on root

* remove eslint from now-cli

* adjust root package.json

* adjust eslintignore

* adjust now-cli rules

* remove @zeit/git-hooks in packages

* adjust now-client eslint config

* add lint-staged and hook on pre-commit

* add pre-commit script

* replace @zeit/git-hooks with husky

* remove unnecessary script

* fix eslint errors

* trigger tests

* fix fixable errors

* fix fixable errors (bis)

* revert two changes
This commit is contained in:
Luc
2019-08-29 21:17:40 +02:00
committed by Andy Bitz
parent 84af278e86
commit 59e7367e03
43 changed files with 1033 additions and 1019 deletions

29
.eslintignore Normal file
View File

@@ -0,0 +1,29 @@
node_modules
dist
# now-cli
packages/now-cli/@types
packages/now-cli/download
packages/now-cli/dist
packages/now-cli/test/fixtures
packages/now-cli/test/dev/fixtures
packages/now-cli/bin
packages/now-cli/link
packages/now-cli/src/util/dev/templates/*.ts
# now-client
packages/now-client/tests/fixtures
packages/now-client/lib
# now-next
packages/now-next/test/fixtures
# now-node
packages/now-node/src/bridge.ts
packages/now-node/test/fixtures
# now-node-bridge
packages/now-node-bridge/bridge.*
# now-static-build
packages/now-static-build/test/fixtures

64
.eslintrc.json Normal file
View File

@@ -0,0 +1,64 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"modules": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"env": {
"node": true,
"jest": true,
"es6": true
},
"rules": {
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-use-before-define": 0
},
"overrides": [
{
"files": ["**/*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
},
{
"files": ["packages/now-cli/**/*"],
"rules": {
"lines-between-class-members": 0,
"no-async-promise-executor": 0,
"no-control-regex": 0,
"no-empty": 0,
"prefer-const": 0,
"prefer-destructuring": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-var-requires": 0
}
},
{
"files": ["packages/now-client/**/*"],
"rules": {
"prefer-const": 0,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
]
}

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

View File

@@ -15,10 +15,17 @@
"lerna": "3.16.4" "lerna": "3.16.4"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "2.0.0",
"@typescript-eslint/parser": "2.0.0",
"@zeit/ncc": "0.20.4", "@zeit/ncc": "0.20.4",
"async-retry": "1.2.3", "async-retry": "1.2.3",
"buffer-replace": "1.0.0", "buffer-replace": "1.0.0",
"node-fetch": "2.6.0" "eslint": "6.2.2",
"eslint-config-prettier": "6.1.0",
"husky": "3.0.4",
"lint-staged": "9.2.5",
"node-fetch": "2.6.0",
"prettier": "1.18.2"
}, },
"scripts": { "scripts": {
"lerna": "lerna", "lerna": "lerna",
@@ -31,6 +38,23 @@
"test-unit": "node run.js test-unit", "test-unit": "node run.js test-unit",
"test-integration": "node run.js test-integration", "test-integration": "node run.js test-integration",
"test-integration-once": "node run.js test-integration-once", "test-integration-once": "node run.js test-integration-once",
"test-integration-now-dev": "node run.js test-integration-now-dev" "test-integration-now-dev": "node run.js test-integration-now-dev",
"lint": "eslint . --ext .ts,.js"
},
"lint-staged": {
"*.{js,ts}": [
"prettier --write",
"eslint",
"git add"
],
"*.{json,md}": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
} }
} }

View File

@@ -10,20 +10,20 @@ interface Options {
tag?: 'canary' | 'latest' | string; tag?: 'canary' | 'latest' | string;
} }
const src: string = 'package.json'; const src = 'package.json';
const config: Config = { zeroConfig: true }; const config: Config = { zeroConfig: true };
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = { const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
code: 'missing_build_script', code: 'missing_build_script',
message: message:
'Your `package.json` file is missing a `build` property inside the `script` property.' + 'Your `package.json` file is missing a `build` property inside the `script` property.' +
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script', '\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script'
}; };
// Static builders are special cased in `@now/static-build` // Static builders are special cased in `@now/static-build`
function getBuilders(): Map<string, Builder> { function getBuilders(): Map<string, Builder> {
return new Map<string, Builder>([ return new Map<string, Builder>([
['next', { src, use: '@now/next', config }], ['next', { src, use: '@now/next', config }]
]); ]);
} }
@@ -35,7 +35,7 @@ function getApiBuilders(): Builder[] {
{ src: 'api/**/*.ts', use: '@now/node', config }, { src: 'api/**/*.ts', use: '@now/node', config },
{ src: 'api/**/*.go', use: '@now/go', config }, { src: 'api/**/*.go', use: '@now/go', config },
{ src: 'api/**/*.py', use: '@now/python', config }, { src: 'api/**/*.py', use: '@now/python', config },
{ src: 'api/**/*.rb', use: '@now/ruby', config }, { src: 'api/**/*.rb', use: '@now/ruby', config }
]; ];
} }
@@ -96,8 +96,8 @@ async function detectApiBuilders(files: string[]): Promise<Builder[]> {
.sort(sortFiles) .sort(sortFiles)
.filter(ignoreApiFilter) .filter(ignoreApiFilter)
.map(file => { .map(file => {
const result = getApiBuilders().find( const result = getApiBuilders().find(({ src }): boolean =>
({ src }): boolean => minimatch(file, src) minimatch(file, src)
); );
return result ? { ...result, src: file } : null; return result ? { ...result, src: file } : null;
@@ -138,7 +138,7 @@ export async function detectBuilders(
builders.push({ builders.push({
use: '@now/static', use: '@now/static',
src: 'public/**/*', src: 'public/**/*',
config, config
}); });
} else if (builders.length > 0) { } else if (builders.length > 0) {
// We can't use pattern matching, since `!(api)` and `!(api)/**/*` // We can't use pattern matching, since `!(api)` and `!(api)/**/*`
@@ -150,7 +150,7 @@ export async function detectBuilders(
.map(name => ({ .map(name => ({
use: '@now/static', use: '@now/static',
src: name, src: name,
config, config
})) }))
); );
} }
@@ -177,6 +177,6 @@ export async function detectBuilders(
return { return {
builders: builders.length ? builders : null, builders: builders.length ? builders : null,
errors: errors.length ? errors : null, errors: errors.length ? errors : null
}; };
} }

View File

@@ -43,37 +43,35 @@ function getSegmentName(segment: string): string | null {
function createRouteFromPath(filePath: string): Route { function createRouteFromPath(filePath: string): Route {
const parts = filePath.split('/'); const parts = filePath.split('/');
let counter: number = 1; let counter = 1;
const query: string[] = []; const query: string[] = [];
const srcParts = parts.map( const srcParts = parts.map((segment, index): string => {
(segment, index): string => { const name = getSegmentName(segment);
const name = getSegmentName(segment); const isLast = index === parts.length - 1;
const isLast = index === parts.length - 1;
if (name !== null) { if (name !== null) {
// We can't use `URLSearchParams` because `$` would get escaped // We can't use `URLSearchParams` because `$` would get escaped
query.push(`${name}=$${counter++}`); query.push(`${name}=$${counter++}`);
return `([^\\/]+)`; return `([^\\/]+)`;
} else if (isLast) { } else if (isLast) {
const { name: fileName, ext } = parsePath(segment); const { name: fileName, ext } = parsePath(segment);
const isIndex = fileName === 'index'; const isIndex = fileName === 'index';
const prefix = isIndex ? '\\/' : ''; const prefix = isIndex ? '\\/' : '';
const names = [ const names = [
prefix, prefix,
prefix + escapeName(fileName), prefix + escapeName(fileName),
prefix + escapeName(fileName) + escapeName(ext), prefix + escapeName(fileName) + escapeName(ext)
].filter(Boolean); ].filter(Boolean);
// Either filename with extension, filename without extension // Either filename with extension, filename without extension
// or nothing when the filename is `index` // or nothing when the filename is `index`
return `(${names.join('|')})${isIndex ? '?' : ''}`; return `(${names.join('|')})${isIndex ? '?' : ''}`;
}
return segment;
} }
);
return segment;
});
const { name: fileName } = parsePath(filePath); const { name: fileName } = parsePath(filePath);
const isIndex = fileName === 'index'; const isIndex = fileName === 'index';
@@ -230,8 +228,8 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
message: message:
`The segment "${conflictingSegment}" occurres more than ` + `The segment "${conflictingSegment}" occurres more than ` +
`one time in your path "${file}". Please make sure that ` + `one time in your path "${file}". Please make sure that ` +
`every segment in a path is unique`, `every segment in a path is unique`
}, }
}; };
} }
@@ -251,8 +249,8 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
message: message:
`Two or more files have conflicting paths or names. ` + `Two or more files have conflicting paths or names. ` +
`Please make sure path segments and filenames, without their extension, are unique. ` + `Please make sure path segments and filenames, without their extension, are unique. ` +
`The path "${file}" has conflicts with ${messagePaths}`, `The path "${file}" has conflicts with ${messagePaths}`
}, }
}; };
} }
@@ -263,7 +261,7 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
if (defaultRoutes.length) { if (defaultRoutes.length) {
defaultRoutes.push({ defaultRoutes.push({
status: 404, status: 404,
src: '/api(\\/.*)?$', src: '/api(\\/.*)?$'
}); });
} }
@@ -289,7 +287,7 @@ export async function detectRoutes(
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) { if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
routesResult.defaultRoutes.push({ routesResult.defaultRoutes.push({
src: '/(.*)', src: '/(.*)',
dest: '/public/$1', dest: '/public/$1'
}); });
} }

View File

@@ -1,20 +1,16 @@
/* global beforeAll, expect, it, jest */
const path = require('path'); const path = require('path');
const fs = require('fs-extra'); const fs = require('fs-extra');
// eslint-disable-next-line import/no-extraneous-dependencies
const execa = require('execa'); const execa = require('execa');
const assert = require('assert'); const assert = require('assert');
const { createZip } = require('../dist/lambda'); const { createZip } = require('../dist/lambda');
const { const { glob, download, detectBuilders, detectRoutes } = require('../');
glob, download, detectBuilders, detectRoutes,
} = require('../');
const { const {
getSupportedNodeVersion, getSupportedNodeVersion,
defaultSelection, defaultSelection
} = require('../dist/fs/node-version'); } = require('../dist/fs/node-version');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment'); } = require('../../../test/lib/deployment/test-deployment');
jest.setTimeout(4 * 60 * 1000); jest.setTimeout(4 * 60 * 1000);
@@ -42,7 +38,7 @@ it('should re-create symlinks properly', async () => {
const [linkStat, aStat] = await Promise.all([ const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')), fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')), fs.lstat(path.join(outDir, 'a.txt'))
]); ]);
assert(linkStat.isSymbolicLink()); assert(linkStat.isSymbolicLink());
assert(aStat.isFile()); assert(aStat.isFile());
@@ -64,7 +60,7 @@ it('should create zip files with symlinks properly', async () => {
const [linkStat, aStat] = await Promise.all([ const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')), fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')), fs.lstat(path.join(outDir, 'a.txt'))
]); ]);
assert(linkStat.isSymbolicLink()); assert(linkStat.isSymbolicLink());
assert(aStat.isFile()); assert(aStat.isFile());
@@ -86,33 +82,33 @@ it('should match all semver ranges', () => {
// See https://docs.npmjs.com/files/package.json#engines // See https://docs.npmjs.com/files/package.json#engines
expect(getSupportedNodeVersion('10.0.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('10.0.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
expect(getSupportedNodeVersion('10.x')).resolves.toHaveProperty('major', 10); expect(getSupportedNodeVersion('10.x')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10')).resolves.toHaveProperty('major', 10); expect(getSupportedNodeVersion('>=10')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10.3.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('>=10.3.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
expect(getSupportedNodeVersion('8.5.0 - 10.5.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('8.5.0 - 10.5.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
expect(getSupportedNodeVersion('>=9.0.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('>=9.0.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
expect(getSupportedNodeVersion('>=9.5.0 <=10.5.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('>=9.5.0 <=10.5.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
expect(getSupportedNodeVersion('~10.5.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('~10.5.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
expect(getSupportedNodeVersion('^10.5.0')).resolves.toHaveProperty( expect(getSupportedNodeVersion('^10.5.0')).resolves.toHaveProperty(
'major', 'major',
10, 10
); );
}); });
@@ -124,7 +120,7 @@ it('should support require by path for legacy builders', () => {
const glob2 = require('@now/build-utils/fs/glob.js'); const glob2 = require('@now/build-utils/fs/glob.js');
const rename2 = require('@now/build-utils/fs/rename.js'); const rename2 = require('@now/build-utils/fs/rename.js');
const { const {
runNpmInstall: runNpmInstall2, runNpmInstall: runNpmInstall2
} = require('@now/build-utils/fs/run-user-scripts.js'); } = require('@now/build-utils/fs/run-user-scripts.js');
const streamToBuffer2 = require('@now/build-utils/fs/stream-to-buffer.js'); const streamToBuffer2 = require('@now/build-utils/fs/stream-to-buffer.js');
@@ -162,8 +158,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }
@@ -176,7 +172,7 @@ const buildersToTestWith = ['now-next', 'now-node', 'now-static-build'];
for (const builder of buildersToTestWith) { for (const builder of buildersToTestWith) {
const fixturesPath2 = path.resolve( const fixturesPath2 = path.resolve(
__dirname, __dirname,
`../../${builder}/test/fixtures`, `../../${builder}/test/fixtures`
); );
// eslint-disable-next-line no-restricted-syntax // eslint-disable-next-line no-restricted-syntax
@@ -188,8 +184,8 @@ for (const builder of buildersToTestWith) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath2, fixture), path.join(fixturesPath2, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }
@@ -210,7 +206,7 @@ it('Test `detectBuilders`', async () => {
// package.json + no build + next // package.json + no build + next
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
dependencies: { next: '9.0.0' }, dependencies: { next: '9.0.0' }
}; };
const files = ['package.json', 'pages/index.js']; const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg); const { builders, errors } = await detectBuilders(files, pkg);
@@ -222,7 +218,7 @@ it('Test `detectBuilders`', async () => {
// package.json + no build + next // package.json + no build + next
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' }, devDependencies: { next: '9.0.0' }
}; };
const files = ['package.json', 'pages/index.js']; const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg); const { builders, errors } = await detectBuilders(files, pkg);
@@ -286,7 +282,7 @@ it('Test `detectBuilders`', async () => {
const files = [ const files = [
'api/_utils/handler.js', 'api/_utils/handler.js',
'api/[endpoint]/.helper.js', 'api/[endpoint]/.helper.js',
'api/[endpoint]/[id].js', 'api/[endpoint]/[id].js'
]; ];
const { builders } = await detectBuilders(files); const { builders } = await detectBuilders(files);
@@ -299,7 +295,7 @@ it('Test `detectBuilders`', async () => {
// api + next + public // api + next + public
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' }, devDependencies: { next: '9.0.0' }
}; };
const files = ['package.json', 'api/endpoint.js', 'public/index.html']; const files = ['package.json', 'api/endpoint.js', 'public/index.html'];
@@ -315,7 +311,7 @@ it('Test `detectBuilders`', async () => {
// api + next + raw static // api + next + raw static
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' }, devDependencies: { next: '9.0.0' }
}; };
const files = ['package.json', 'api/endpoint.js', 'index.html']; const files = ['package.json', 'api/endpoint.js', 'index.html'];
@@ -347,7 +343,7 @@ it('Test `detectBuilders`', async () => {
'api/endpoint.js', 'api/endpoint.js',
'public/index.html', 'public/index.html',
'public/favicon.ico', 'public/favicon.ico',
'README.md', 'README.md'
]; ];
const { builders } = await detectBuilders(files); const { builders } = await detectBuilders(files);
@@ -371,7 +367,7 @@ it('Test `detectBuilders`', async () => {
// next + public // next + public
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' }, devDependencies: { next: '9.0.0' }
}; };
const files = ['package.json', 'public/index.html', 'README.md']; const files = ['package.json', 'public/index.html', 'README.md'];
@@ -385,7 +381,7 @@ it('Test `detectBuilders`', async () => {
// nuxt // nuxt
const pkg = { const pkg = {
scripts: { build: 'nuxt build' }, scripts: { build: 'nuxt build' },
dependencies: { nuxt: '2.8.1' }, dependencies: { nuxt: '2.8.1' }
}; };
const files = ['package.json', 'pages/index.js']; const files = ['package.json', 'pages/index.js'];
@@ -437,12 +433,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + canary // package.json + api + canary
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
dependencies: { next: '9.0.0' }, dependencies: { next: '9.0.0' }
}; };
const files = [ const files = [
'pages/index.js', 'pages/index.js',
'api/[endpoint].js', 'api/[endpoint].js',
'api/[endpoint]/[id].js', 'api/[endpoint]/[id].js'
]; ];
const { builders } = await detectBuilders(files, pkg, { tag: 'canary' }); const { builders } = await detectBuilders(files, pkg, { tag: 'canary' });
@@ -456,12 +452,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + latest // package.json + api + latest
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
dependencies: { next: '9.0.0' }, dependencies: { next: '9.0.0' }
}; };
const files = [ const files = [
'pages/index.js', 'pages/index.js',
'api/[endpoint].js', 'api/[endpoint].js',
'api/[endpoint]/[id].js', 'api/[endpoint]/[id].js'
]; ];
const { builders } = await detectBuilders(files, pkg, { tag: 'latest' }); const { builders } = await detectBuilders(files, pkg, { tag: 'latest' });
@@ -475,12 +471,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + random tag // package.json + api + random tag
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
dependencies: { next: '9.0.0' }, dependencies: { next: '9.0.0' }
}; };
const files = [ const files = [
'pages/index.js', 'pages/index.js',
'api/[endpoint].js', 'api/[endpoint].js',
'api/[endpoint]/[id].js', 'api/[endpoint]/[id].js'
]; ];
const { builders } = await detectBuilders(files, pkg, { tag: 'haha' }); const { builders } = await detectBuilders(files, pkg, { tag: 'haha' });
@@ -549,7 +545,7 @@ it('Test `detectRoutes`', async () => {
const files = [ const files = [
'public/index.html', 'public/index.html',
'api/[endpoint].js', 'api/[endpoint].js',
'api/[endpoint]/[id].js', 'api/[endpoint]/[id].js'
]; ];
const { builders } = await detectBuilders(files); const { builders } = await detectBuilders(files);
@@ -564,7 +560,7 @@ it('Test `detectRoutes`', async () => {
{ {
const pkg = { const pkg = {
scripts: { build: 'next build' }, scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' }, devDependencies: { next: '9.0.0' }
}; };
const files = ['public/index.html', 'api/[endpoint].js']; const files = ['public/index.html', 'api/[endpoint].js'];
@@ -592,7 +588,7 @@ it('Test `detectRoutes`', async () => {
expect(defaultRoutes.length).toBe(3); expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe( expect(defaultRoutes[0].src).toBe(
'^/api/date(\\/|\\/index|\\/index\\.js)?$', '^/api/date(\\/|\\/index|\\/index\\.js)?$'
); );
expect(defaultRoutes[0].dest).toBe('/api/date/index.js'); expect(defaultRoutes[0].dest).toBe('/api/date/index.js');
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$'); expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
@@ -607,7 +603,7 @@ it('Test `detectRoutes`', async () => {
expect(defaultRoutes.length).toBe(3); expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe( expect(defaultRoutes[0].src).toBe(
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$', '^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$'
); );
expect(defaultRoutes[0].dest).toBe('/api/[date]/index.js?date=$1'); expect(defaultRoutes[0].dest).toBe('/api/[date]/index.js?date=$1');
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$'); expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
@@ -621,7 +617,7 @@ it('Test `detectRoutes`', async () => {
'api/users/index.ts', 'api/users/index.ts',
'api/users/index.d.ts', 'api/users/index.d.ts',
'api/food.ts', 'api/food.ts',
'api/ts/gold.ts', 'api/ts/gold.ts'
]; ];
const { builders } = await detectBuilders(files); const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders); const { defaultRoutes } = await detectRoutes(files, builders);
@@ -645,39 +641,39 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
{ {
path: '/api/my-endpoint', path: '/api/my-endpoint',
mustContain: 'my-endpoint', mustContain: 'my-endpoint',
status: 200, status: 200
}, },
{ {
path: '/api/other-endpoint', path: '/api/other-endpoint',
mustContain: 'other-endpoint', mustContain: 'other-endpoint',
status: 200, status: 200
}, },
{ {
path: '/api/team/zeit', path: '/api/team/zeit',
mustContain: 'team/zeit', mustContain: 'team/zeit',
status: 200, status: 200
}, },
{ {
path: '/api/user/myself', path: '/api/user/myself',
mustContain: 'user/myself', mustContain: 'user/myself',
status: 200, status: 200
}, },
{ {
path: '/api/not-okay/', path: '/api/not-okay/',
status: 404, status: 404
}, },
{ {
path: '/api', path: '/api',
status: 404, status: 404
}, },
{ {
path: '/api/', path: '/api/',
status: 404, status: 404
}, },
{ {
path: '/', path: '/',
mustContain: 'hello from index.txt', mustContain: 'hello from index.txt'
}, }
]; ];
const { builders } = await detectBuilders(files, pkg); const { builders } = await detectBuilders(files, pkg);
@@ -686,12 +682,12 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
const nowConfig = { builds: builders, routes: defaultRoutes, probes }; const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile( await fs.writeFile(
path.join(fixture, 'now.json'), path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2), JSON.stringify(nowConfig, null, 2)
); );
const deployment = await testDeployment( const deployment = await testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
fixture, fixture
); );
expect(deployment).toBeDefined(); expect(deployment).toBeDefined();
}); });
@@ -705,32 +701,32 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
const probes = [ const probes = [
{ {
path: '/api/not-okay', path: '/api/not-okay',
status: 404, status: 404
}, },
{ {
path: '/api', path: '/api',
mustContain: 'hello from api/index.js', mustContain: 'hello from api/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/', path: '/api/',
mustContain: 'hello from api/index.js', mustContain: 'hello from api/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/index', path: '/api/index',
mustContain: 'hello from api/index.js', mustContain: 'hello from api/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/index.js', path: '/api/index.js',
mustContain: 'hello from api/index.js', mustContain: 'hello from api/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/date.js', path: '/api/date.js',
mustContain: 'hello from api/date.js', mustContain: 'hello from api/date.js',
status: 200, status: 200
}, },
{ {
// Someone might expect this to be `date.js`, // Someone might expect this to be `date.js`,
@@ -739,27 +735,27 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
// so it is not special cased // so it is not special cased
path: '/api/date', path: '/api/date',
mustContain: 'hello from api/date/index.js', mustContain: 'hello from api/date/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/date/', path: '/api/date/',
mustContain: 'hello from api/date/index.js', mustContain: 'hello from api/date/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/date/index', path: '/api/date/index',
mustContain: 'hello from api/date/index.js', mustContain: 'hello from api/date/index.js',
status: 200, status: 200
}, },
{ {
path: '/api/date/index.js', path: '/api/date/index.js',
mustContain: 'hello from api/date/index.js', mustContain: 'hello from api/date/index.js',
status: 200, status: 200
}, },
{ {
path: '/', path: '/',
mustContain: 'hello from index.txt', mustContain: 'hello from index.txt'
}, }
]; ];
const { builders } = await detectBuilders(files, pkg); const { builders } = await detectBuilders(files, pkg);
@@ -768,12 +764,12 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
const nowConfig = { builds: builders, routes: defaultRoutes, probes }; const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile( await fs.writeFile(
path.join(fixture, 'now.json'), path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2), JSON.stringify(nowConfig, null, 2)
); );
const deployment = await testDeployment( const deployment = await testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
fixture, fixture
); );
expect(deployment).toBeDefined(); expect(deployment).toBeDefined();
}); });

View File

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

View File

@@ -1,8 +0,0 @@
@types
download
dist
test/fixtures
test/dev/fixtures
bin
link
src/util/dev/templates/*.ts

View File

@@ -1,86 +0,0 @@
module.exports = {
'extends': [
'airbnb',
'prettier'
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 2018,
'sourceType': 'module',
'modules': true
},
'plugins': [
'@typescript-eslint'
],
'settings': {
'import/resolver': {
'typescript': {
}
}
},
'rules': {
'quotes': [
2,
'single',
{
'allowTemplateLiterals': true
}
],
'class-methods-use-this': 0,
'consistent-return': 0,
'func-names': 0,
'global-require': 0,
'guard-for-in': 0,
'import/no-duplicates': 0,
'import/no-dynamic-require': 0,
'import/no-extraneous-dependencies': 0,
'import/prefer-default-export': 0,
'lines-between-class-members': 0,
'no-await-in-loop': 0,
'no-bitwise': 0,
'no-console': 0,
'no-continue': 0,
'no-control-regex': 0,
'no-empty': 0,
'no-loop-func': 0,
'no-nested-ternary': 0,
'no-param-reassign': 0,
'no-plusplus': 0,
'no-restricted-globals': 0,
'no-restricted-syntax': 0,
'no-shadow': 0,
'no-underscore-dangle': 0,
'no-use-before-define': 0,
'prefer-const': 0,
'prefer-destructuring': 0,
'camelcase': 0,
'no-unused-vars': 0, // in favor of '@typescript-eslint/no-unused-vars'
// 'indent': 0 // in favor of '@typescript-eslint/indent'
'@typescript-eslint/no-unused-vars': 'warn',
// '@typescript-eslint/indent': ['error', 2] // this might conflict with a lot ongoing changes
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/class-name-casing': 'error',
'@typescript-eslint/interface-name-prefix': 'error',
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-assertion': 'error',
'@typescript-eslint/no-parameter-properties': 'error',
'@typescript-eslint/no-triple-slash-reference': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/type-annotation-spacing': 'error',
// '@typescript-eslint/array-type': 'error',
// '@typescript-eslint/ban-types': 'error',
// '@typescript-eslint/explicit-function-return-type': 'warn',
// '@typescript-eslint/explicit-member-accessibility': 'error',
// '@typescript-eslint/member-delimiter-style': 'error',
// '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
// '@typescript-eslint/no-explicit-any': 'warn',
// '@typescript-eslint/no-object-literal-type-assertion': 'error',
// '@typescript-eslint/no-use-before-define': 'error',
// '@typescript-eslint/no-var-requires': 'error',
// '@typescript-eslint/prefer-interface': 'error'
}
}

View File

@@ -11,17 +11,15 @@
"directory": "packages/now-cli" "directory": "packages/now-cli"
}, },
"scripts": { "scripts": {
"test": "yarn test-lint",
"preinstall": "node ./scripts/preinstall.js", "preinstall": "node ./scripts/preinstall.js",
"test-unit": "nyc ava test/*unit.js --serial --fail-fast --verbose", "test-unit": "nyc ava test/*unit.js --serial --fail-fast --verbose",
"test-integration": "ava test/integration.js --serial --fail-fast", "test-integration": "ava test/integration.js --serial --fail-fast",
"test-integration-now-dev": "ava test/dev/integration.js --serial --fail-fast --verbose", "test-integration-now-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
"test-lint": "eslint . --ext .js,.ts",
"prepublishOnly": "yarn build", "prepublishOnly": "yarn build",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov", "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"build": "ts-node ./scripts/build.ts", "build": "ts-node ./scripts/build.ts",
"build-dev": "ts-node ./scripts/build.ts --dev", "build-dev": "ts-node ./scripts/build.ts --dev",
"format-modified": "prettier --parser typescript --write --single-quote `git diff --name-only HEAD * | grep -e \".*\\.ts$\" -e \".*\\.js$\" | xargs echo`" "test-lint": "eslint . --ext .ts,.js --ignore-path ../../.eslintignore"
}, },
"nyc": { "nyc": {
"include": [ "include": [
@@ -42,12 +40,6 @@
"instrument": true, "instrument": true,
"all": true "all": true
}, },
"git": {
"pre-commit": [
"test-lint",
"format-modified"
]
},
"bin": { "bin": {
"now": "./dist/index.js" "now": "./dist/index.js"
}, },
@@ -106,11 +98,8 @@
"@types/universal-analytics": "0.4.2", "@types/universal-analytics": "0.4.2",
"@types/which": "1.3.1", "@types/which": "1.3.1",
"@types/write-json-file": "2.2.1", "@types/write-json-file": "2.2.1",
"@typescript-eslint/eslint-plugin": "1.6.0",
"@typescript-eslint/parser": "1.1.0",
"@zeit/dockerignore": "0.0.5", "@zeit/dockerignore": "0.0.5",
"@zeit/fun": "0.9.1", "@zeit/fun": "0.9.1",
"@zeit/git-hooks": "0.1.4",
"@zeit/ncc": "0.18.5", "@zeit/ncc": "0.18.5",
"@zeit/source-map-support": "0.6.2", "@zeit/source-map-support": "0.6.2",
"ajv": "6.10.2", "ajv": "6.10.2",
@@ -142,13 +131,6 @@
"email-validator": "1.1.1", "email-validator": "1.1.1",
"epipebomb": "1.0.0", "epipebomb": "1.0.0",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"eslint": "5.16.0",
"eslint-config-airbnb": "17.1.0",
"eslint-config-prettier": "4.1.0",
"eslint-import-resolver-typescript": "1.1.1",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.12.4",
"esm": "3.1.4", "esm": "3.1.4",
"execa": "1.0.0", "execa": "1.0.0",
"fetch-h2": "2.0.3", "fetch-h2": "2.0.3",
@@ -173,7 +155,6 @@
"pcre-to-regexp": "0.0.5", "pcre-to-regexp": "0.0.5",
"pluralize": "7.0.0", "pluralize": "7.0.0",
"pre-commit": "1.2.2", "pre-commit": "1.2.2",
"prettier": "1.16.2",
"printf": "0.2.5", "printf": "0.2.5",
"progress": "2.0.3", "progress": "2.0.3",
"promisepipe": "3.0.0", "promisepipe": "3.0.0",

View File

@@ -202,7 +202,6 @@ const promptForEnvFields = async (list: string[]) => {
}); });
} }
// eslint-disable-next-line import/no-unassigned-import
require('../../util/input/patch-inquirer'); require('../../util/input/patch-inquirer');
log('Please enter values for the following environment variables:'); log('Please enter values for the following environment variables:');

View File

@@ -2,7 +2,6 @@ import inquirer from 'inquirer';
import stripAnsi from 'strip-ansi'; import stripAnsi from 'strip-ansi';
import eraseLines from '../output/erase-lines'; import eraseLines from '../output/erase-lines';
// eslint-disable-next-line import/no-unassigned-import
import './patch-inquirer'; import './patch-inquirer';
function getLength(string) { function getLength(string) {

View File

@@ -1,4 +1,3 @@
/* eslint-disable import/no-unresolved */
import path from 'path'; import path from 'path';
import pkg from '../../package.json'; import pkg from '../../package.json';

View File

@@ -7,9 +7,7 @@
"build": "ncc build ./src/index.ts -o ./lib --source-map", "build": "ncc build ./src/index.ts -o ./lib --source-map",
"prepare": "npm run build", "prepare": "npm run build",
"test-integration-once": "jest --verbose --forceExit", "test-integration-once": "jest --verbose --forceExit",
"test-lint": "eslint --ext .ts ./src", "test-lint": "eslint . --ext .js,.ts --ignore-path ../../.eslintignore"
"lint": "eslint --fix --ext .ts ./src",
"lint-staged": "git diff --diff-filter=ACMRT --cached --name-only '*.ts' | xargs eslint --fix"
}, },
"devDependencies": { "devDependencies": {
"@types/async-retry": "1.4.1", "@types/async-retry": "1.4.1",
@@ -19,56 +17,11 @@
"@types/node": "12.0.4", "@types/node": "12.0.4",
"@types/node-fetch": "2.3.4", "@types/node-fetch": "2.3.4",
"@types/recursive-readdir": "2.2.0", "@types/recursive-readdir": "2.2.0",
"@typescript-eslint/eslint-plugin": "1.9.0",
"@typescript-eslint/parser": "1.9.0",
"@zeit/git-hooks": "0.1.4",
"@zeit/ncc": "0.18.5", "@zeit/ncc": "0.18.5",
"eslint": "5.16.0",
"jest": "24.8.0", "jest": "24.8.0",
"ts-jest": "24.0.2", "ts-jest": "24.0.2",
"typescript": "3.5.1" "typescript": "3.5.1"
}, },
"eslintConfig": {
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"env": {
"es6": true,
"node": true,
"jest": true
},
"rules": {
"func-names": [
"error",
"as-needed"
],
"no-shadow": "error",
"no-extra-semi": 0,
"react/prop-types": 0,
"react/react-in-jsx-scope": 0,
"react/no-unescaped-entities": 0,
"react/jsx-no-target-blank": 0,
"react/no-string-refs": 0,
"semi": [
"error",
"never"
],
"@typescript-eslint/indent": [
"error",
2
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-member-accessibility": "off"
}
},
"git": {
"pre-commit": "lint-staged"
},
"jest": { "jest": {
"preset": "ts-jest", "preset": "ts-jest",
"testEnvironment": "node", "testEnvironment": "node",

View File

@@ -11,7 +11,7 @@ import {
BuildOptions, BuildOptions,
shouldServe, shouldServe,
Files, Files,
debug, debug
} from '@now/build-utils'; } from '@now/build-utils';
import { createGo, getAnalyzedEntrypoint } from './go-helpers'; import { createGo, getAnalyzedEntrypoint } from './go-helpers';
@@ -38,7 +38,7 @@ async function initPrivateGit(credentials: string) {
'config', 'config',
'--global', '--global',
'credential.helper', 'credential.helper',
`store --file ${join(homedir(), '.git-credentials')}`, `store --file ${join(homedir(), '.git-credentials')}`
]); ]);
await writeFile(join(homedir(), '.git-credentials'), credentials); await writeFile(join(homedir(), '.git-credentials'), credentials);
@@ -51,7 +51,7 @@ export async function build({
entrypoint, entrypoint,
config, config,
workPath, workPath,
meta = {} as BuildParamsMeta, meta = {} as BuildParamsMeta
}: BuildParamsType) { }: BuildParamsType) {
if (process.env.GIT_CREDENTIALS && !meta.isDev) { if (process.env.GIT_CREDENTIALS && !meta.isDev) {
debug('Initialize Git credentials...'); debug('Initialize Git credentials...');
@@ -73,9 +73,10 @@ Learn more: https://github.com/golang/go/wiki/Modules
debug('Downloading user files...'); debug('Downloading user files...');
const entrypointArr = entrypoint.split(sep); const entrypointArr = entrypoint.split(sep);
// eslint-disable-next-line prefer-const
let [goPath, outDir] = await Promise.all([ let [goPath, outDir] = await Promise.all([
getWriteableDirectory(), getWriteableDirectory(),
getWriteableDirectory(), getWriteableDirectory()
]); ]);
const srcPath = join(goPath, 'src', 'lambda'); const srcPath = join(goPath, 'src', 'lambda');
@@ -161,7 +162,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
} }
const input = entrypointDirname; const input = entrypointDirname;
var includedFiles: Files = {}; const includedFiles: Files = {};
if (config && config.includeFiles) { if (config && config.includeFiles) {
for (const pattern of config.includeFiles) { for (const pattern of config.includeFiles) {
@@ -193,7 +194,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
process.platform, process.platform,
process.arch, process.arch,
{ {
cwd: entrypointDirname, cwd: entrypointDirname
}, },
true true
); );
@@ -222,7 +223,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
const usrModName = goModContents.split('\n')[0].split(' ')[1]; const usrModName = goModContents.split('\n')[0].split(' ')[1];
if (entrypointArr.length > 1 && isGoModInRootDir) { if (entrypointArr.length > 1 && isGoModInRootDir) {
let cleanPackagePath = [...entrypointArr]; const cleanPackagePath = [...entrypointArr];
cleanPackagePath.pop(); cleanPackagePath.pop();
goPackageName = `${usrModName}/${cleanPackagePath.join('/')}`; goPackageName = `${usrModName}/${cleanPackagePath.join('/')}`;
} else { } else {
@@ -276,7 +277,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
!isGoModExist !isGoModExist
) { ) {
await move(downloadedFiles[entrypoint].fsPath, finalDestination, { await move(downloadedFiles[entrypoint].fsPath, finalDestination, {
overwrite: forceMove, overwrite: forceMove
}); });
} }
} catch (err) { } catch (err) {
@@ -324,7 +325,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
const destPath = join(outDir, 'handler'); const destPath = join(outDir, 'handler');
try { try {
let src = [join(baseGoModPath, mainModGoFileName)]; const src = [join(baseGoModPath, mainModGoFileName)];
await go.build(src, destPath, config.ldsflags); await go.build(src, destPath, config.ldsflags);
} catch (err) { } catch (err) {
@@ -353,7 +354,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
process.platform, process.platform,
process.arch, process.arch,
{ {
cwd: entrypointDirname, cwd: entrypointDirname
}, },
false false
); );
@@ -389,7 +390,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
try { try {
const src = [ const src = [
join(entrypointDirname, mainGoFileName), join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath, downloadedFiles[entrypoint].fsPath
]; ];
await go.build(src, destPath); await go.build(src, destPath);
} catch (err) { } catch (err) {
@@ -402,13 +403,13 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
files: { ...(await glob('**', outDir)), ...includedFiles }, files: { ...(await glob('**', outDir)), ...includedFiles },
handler: 'handler', handler: 'handler',
runtime: 'go1.x', runtime: 'go1.x',
environment: {}, environment: {}
}); });
const output = { const output = {
[entrypoint]: lambda, [entrypoint]: lambda
}; };
let watch = parsedAnalyzed.watch; const watch = parsedAnalyzed.watch;
let watchSub: string[] = []; let watchSub: string[] = [];
// if `entrypoint` located in subdirectory // if `entrypoint` located in subdirectory
// we will need to concat it with return watch array // we will need to concat it with return watch array
@@ -419,7 +420,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
return { return {
output, output,
watch: watch.concat(watchSub), watch: watch.concat(watchSub)
}; };
} }

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment.js'); } = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000); jest.setTimeout(4 * 60 * 1000);

View File

@@ -1,2 +1,4 @@
// needed for @types/JSZip since we aren't building in browser mode // needed for @types/JSZip since we aren't building in browser mode
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Blob {} interface Blob {}

View File

@@ -3,10 +3,9 @@ import {
pathExists, pathExists,
readFile, readFile,
unlink as unlinkFile, unlink as unlinkFile,
writeFile, writeFile
} from 'fs-extra'; } from 'fs-extra';
import os from 'os'; import os from 'os';
import zlib from 'zlib';
import path from 'path'; import path from 'path';
import semver from 'semver'; import semver from 'semver';
import resolveFrom from 'resolve-from'; import resolveFrom from 'resolve-from';
@@ -27,8 +26,7 @@ import {
Route, Route,
runNpmInstall, runNpmInstall,
runPackageJsonScript, runPackageJsonScript,
debug, debug
streamToBuffer,
} from '@now/build-utils'; } from '@now/build-utils';
import nodeFileTrace from '@zeit/node-file-trace'; import nodeFileTrace from '@zeit/node-file-trace';
@@ -52,7 +50,7 @@ import {
validateEntrypoint, validateEntrypoint,
createLambdaFromPseudoLayers, createLambdaFromPseudoLayers,
PseudoLayer, PseudoLayer,
createPseudoLayer, createPseudoLayer
} from './utils'; } from './utils';
interface BuildParamsMeta { interface BuildParamsMeta {
@@ -87,7 +85,10 @@ async function readPackageJson(entryPath: string) {
/** /**
* Write package.json * Write package.json
*/ */
async function writePackageJson(workPath: string, packageJson: Object) { async function writePackageJson(
workPath: string,
packageJson: Record<string, any>
) {
await writeFile( await writeFile(
path.join(workPath, 'package.json'), path.join(workPath, 'package.json'),
JSON.stringify(packageJson, null, 2) JSON.stringify(packageJson, null, 2)
@@ -150,7 +151,7 @@ function startDevServer(entryPath: string, runtimeEnv: EnvConfig) {
// makes it default to `process.env` // makes it default to `process.env`
const forked = fork(path.join(__dirname, 'dev-server.js'), [encodedEnv], { const forked = fork(path.join(__dirname, 'dev-server.js'), [encodedEnv], {
cwd: entryPath, cwd: entryPath,
execArgv: [], execArgv: []
}); });
const getUrl = () => const getUrl = () =>
@@ -167,7 +168,7 @@ export const build = async ({
workPath, workPath,
entrypoint, entrypoint,
config = {} as Config, config = {} as Config,
meta = {} as BuildParamsMeta, meta = {} as BuildParamsMeta
}: BuildParamsType): Promise<{ }: BuildParamsType): Promise<{
routes: Route[]; routes: Route[];
output: Files; output: Files;
@@ -232,7 +233,7 @@ export const build = async ({
urls[entrypoint] urls[entrypoint]
), ),
watch: pathsInside, watch: pathsInside,
childProcesses: childProcess ? [childProcess] : [], childProcesses: childProcess ? [childProcess] : []
}; };
} }
@@ -275,7 +276,7 @@ export const build = async ({
); );
pkg.scripts = { pkg.scripts = {
'now-build': 'next build', 'now-build': 'next build',
...(pkg.scripts || {}), ...(pkg.scripts || {})
}; };
await writePackageJson(entryPath, pkg); await writePackageJson(entryPath, pkg);
} }
@@ -350,14 +351,14 @@ export const build = async ({
); );
const launcherFiles = { const launcherFiles = {
'now__bridge.js': new FileFsRef({ 'now__bridge.js': new FileFsRef({
fsPath: path.join(__dirname, 'now__bridge.js'), fsPath: path.join(__dirname, 'now__bridge.js')
}), })
}; };
const nextFiles: { [key: string]: FileFsRef } = { const nextFiles: { [key: string]: FileFsRef } = {
...nodeModules, ...nodeModules,
...dotNextRootFiles, ...dotNextRootFiles,
...dotNextServerRootFiles, ...dotNextServerRootFiles,
...launcherFiles, ...launcherFiles
}; };
if (filesAfterBuild['next.config.js']) { if (filesAfterBuild['next.config.js']) {
nextFiles['next.config.js'] = filesAfterBuild['next.config.js']; nextFiles['next.config.js'] = filesAfterBuild['next.config.js'];
@@ -394,7 +395,7 @@ export const build = async ({
], ],
[`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[ [`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/${page}` `.next/server/static/${buildId}/pages/${page}`
], ]
}; };
debug(`Creating lambda for page: "${page}"...`); debug(`Creating lambda for page: "${page}"...`);
@@ -402,10 +403,10 @@ export const build = async ({
files: { files: {
...nextFiles, ...nextFiles,
...pageFiles, ...pageFiles,
'now__launcher.js': new FileBlob({ data: launcher }), 'now__launcher.js': new FileBlob({ data: launcher })
}, },
handler: 'now__launcher.launcher', handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime, runtime: nodeVersion.runtime
}); });
debug(`Created lambda for page: "${page}"`); debug(`Created lambda for page: "${page}"`);
}) })
@@ -430,7 +431,7 @@ export const build = async ({
exportedPageRoutes.push({ exportedPageRoutes.push({
src: `^${path.join('/', entryDirectory, pathname)}$`, src: `^${path.join('/', entryDirectory, pathname)}$`,
dest: path.join('/', staticRoute), dest: path.join('/', staticRoute)
}); });
}); });
@@ -469,11 +470,13 @@ export const build = async ({
); );
} }
let assets: undefined | { let assets:
[filePath: string]: FileFsRef; | undefined
}; | {
[filePath: string]: FileFsRef;
};
const pseudoLayers: PseudoLayer[] = [] const pseudoLayers: PseudoLayer[] = [];
const tracedFiles: { const tracedFiles: {
[filePath: string]: FileFsRef; [filePath: string]: FileFsRef;
@@ -504,7 +507,7 @@ export const build = async ({
} }
tracedFiles[file] = new FileFsRef({ tracedFiles[file] = new FileFsRef({
fsPath: path.join(workPath, file), fsPath: path.join(workPath, file)
}); });
}); });
console.timeEnd(tracingLabel); console.timeEnd(tracingLabel);
@@ -512,8 +515,8 @@ export const build = async ({
const zippingLabel = 'Compressing shared lambda files'; const zippingLabel = 'Compressing shared lambda files';
console.time(zippingLabel); console.time(zippingLabel);
pseudoLayers.push(await createPseudoLayer(tracedFiles)) pseudoLayers.push(await createPseudoLayer(tracedFiles));
console.timeEnd(zippingLabel) console.timeEnd(zippingLabel);
} else { } else {
// An optional assets folder that is placed alongside every page // An optional assets folder that is placed alongside every page
// entrypoint. // entrypoint.
@@ -536,8 +539,8 @@ export const build = async ({
const launcherPath = path.join(__dirname, 'templated-launcher.js'); const launcherPath = path.join(__dirname, 'templated-launcher.js');
const launcherData = await readFile(launcherPath, 'utf8'); const launcherData = await readFile(launcherPath, 'utf8');
const allLambdasLabel = `All lambdas created` const allLambdasLabel = `All lambdas created`;
console.time(allLambdasLabel) console.time(allLambdasLabel);
await Promise.all( await Promise.all(
pageKeys.map(async page => { pageKeys.map(async page => {
@@ -564,20 +567,22 @@ export const build = async ({
); );
const launcherFiles: { [name: string]: FileFsRef | FileBlob } = { const launcherFiles: { [name: string]: FileFsRef | FileBlob } = {
'now__bridge.js': new FileFsRef({ 'now__bridge.js': new FileFsRef({
fsPath: path.join(__dirname, 'now__bridge.js'), fsPath: path.join(__dirname, 'now__bridge.js')
}), }),
'now__launcher.js': new FileBlob({ data: launcher }), 'now__launcher.js': new FileBlob({ data: launcher })
}; };
if (requiresTracing) { if (requiresTracing) {
lambdas[path.join(entryDirectory, pathname)] = await createLambdaFromPseudoLayers({ lambdas[
path.join(entryDirectory, pathname)
] = await createLambdaFromPseudoLayers({
files: { files: {
...launcherFiles, ...launcherFiles,
[requiresTracing ? pageFileName : 'page.js']: pages[page], [requiresTracing ? pageFileName : 'page.js']: pages[page]
}, },
layers: pseudoLayers, layers: pseudoLayers,
handler: 'now__launcher.launcher', handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime, runtime: nodeVersion.runtime
}); });
} else { } else {
lambdas[path.join(entryDirectory, pathname)] = await createLambda({ lambdas[path.join(entryDirectory, pathname)] = await createLambda({
@@ -585,16 +590,16 @@ export const build = async ({
...launcherFiles, ...launcherFiles,
...assets, ...assets,
...tracedFiles, ...tracedFiles,
[requiresTracing ? pageFileName : 'page.js']: pages[page], [requiresTracing ? pageFileName : 'page.js']: pages[page]
}, },
handler: 'now__launcher.launcher', handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime, runtime: nodeVersion.runtime
}); });
} }
console.timeEnd(label); console.timeEnd(label);
}) })
); );
console.timeEnd(allLambdasLabel) console.timeEnd(allLambdasLabel);
} }
const nextStaticFiles = await glob( const nextStaticFiles = await glob(
@@ -604,9 +609,7 @@ export const build = async ({
const staticFiles = Object.keys(nextStaticFiles).reduce( const staticFiles = Object.keys(nextStaticFiles).reduce(
(mappedFiles, file) => ({ (mappedFiles, file) => ({
...mappedFiles, ...mappedFiles,
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[ [path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[file]
file
],
}), }),
{} {}
); );
@@ -623,14 +626,14 @@ export const build = async ({
const publicFiles = Object.keys(publicDirectoryFiles).reduce( const publicFiles = Object.keys(publicDirectoryFiles).reduce(
(mappedFiles, file) => ({ (mappedFiles, file) => ({
...mappedFiles, ...mappedFiles,
[file.replace(/public[/\\]+/, '')]: publicDirectoryFiles[file], [file.replace(/public[/\\]+/, '')]: publicDirectoryFiles[file]
}), }),
{} {}
); );
let dynamicPrefix = path.join('/', entryDirectory); let dynamicPrefix = path.join('/', entryDirectory);
dynamicPrefix = dynamicPrefix === '/' ? '' : dynamicPrefix; dynamicPrefix = dynamicPrefix === '/' ? '' : dynamicPrefix;
let dynamicRoutes = getDynamicRoutes( const dynamicRoutes = getDynamicRoutes(
entryPath, entryPath,
entryDirectory, entryDirectory,
dynamicPages dynamicPages
@@ -650,7 +653,7 @@ export const build = async ({
...lambdas, ...lambdas,
...staticPages, ...staticPages,
...staticFiles, ...staticFiles,
...staticDirectoryFiles, ...staticDirectoryFiles
}, },
routes: [ routes: [
// Static exported pages (.html rewrites) // Static exported pages (.html rewrites)
@@ -663,7 +666,7 @@ export const build = async ({
// Next.js assets contain a hash or entropy in their filenames, so they // Next.js assets contain a hash or entropy in their filenames, so they
// are guaranteed to be unique and cacheable indefinitely. // are guaranteed to be unique and cacheable indefinitely.
headers: { 'cache-control': 'public,max-age=31536000,immutable' }, headers: { 'cache-control': 'public,max-age=31536000,immutable' },
continue: true, continue: true
}, },
// Next.js page lambdas, `static/` folder, reserved assets, and `public/` // Next.js page lambdas, `static/` folder, reserved assets, and `public/`
// folder // folder
@@ -676,18 +679,18 @@ export const build = async ({
{ {
src: path.join('/', entryDirectory, '.*'), src: path.join('/', entryDirectory, '.*'),
dest: path.join('/', entryDirectory, '_error'), dest: path.join('/', entryDirectory, '_error'),
status: 404, status: 404
}, }
]), ])
], ],
watch: [], watch: [],
childProcesses: [], childProcesses: []
}; };
}; };
export const prepareCache = async ({ export const prepareCache = async ({
workPath, workPath,
entrypoint, entrypoint
}: PrepareCacheOptions) => { }: PrepareCacheOptions) => {
debug('preparing cache ...'); debug('preparing cache ...');
const entryDirectory = path.dirname(entrypoint); const entryDirectory = path.dirname(entrypoint);
@@ -709,7 +712,7 @@ export const prepareCache = async ({
...(await glob(path.join(cacheEntrypoint, 'node_modules/**'), workPath)), ...(await glob(path.join(cacheEntrypoint, 'node_modules/**'), workPath)),
...(await glob(path.join(cacheEntrypoint, '.next/cache/**'), workPath)), ...(await glob(path.join(cacheEntrypoint, '.next/cache/**'), workPath)),
...(await glob(path.join(cacheEntrypoint, 'package-lock.json'), workPath)), ...(await glob(path.join(cacheEntrypoint, 'package-lock.json'), workPath)),
...(await glob(path.join(cacheEntrypoint, 'yarn.lock'), workPath)), ...(await glob(path.join(cacheEntrypoint, 'yarn.lock'), workPath))
}; };
debug('cache file manifest produced'); debug('cache file manifest produced');
return cache; return cache;

View File

@@ -1,4 +1,3 @@
/* global it, expect */
const path = require('path'); const path = require('path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const runBuildLambda = require('../../../../test/lib/run-build-lambda'); const runBuildLambda = require('../../../../test/lib/run-build-lambda');
@@ -9,70 +8,84 @@ it(
'Should build the standard example', 'Should build the standard example',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'standard')); } = await runBuildLambda(path.join(__dirname, 'standard'));
expect(output['index.html']).toBeDefined(); expect(output['index.html']).toBeDefined();
expect(output.goodbye).toBeDefined(); expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output); const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/)); const serverlessError = filePaths.some(filePath =>
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/)); filePath.match(/_error/)
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/)); );
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(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy(); expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy(); expect(serverlessError).toBeTruthy();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
'Should build the monorepo example', 'Should build the monorepo example',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'monorepo')); } = await runBuildLambda(path.join(__dirname, 'monorepo'));
expect(output['www/index']).toBeDefined(); expect(output['www/index']).toBeDefined();
expect(output['www/static/test.txt']).toBeDefined(); expect(output['www/static/test.txt']).toBeDefined();
expect(output['www/data.txt']).toBeDefined(); expect(output['www/data.txt']).toBeDefined();
const filePaths = Object.keys(output); const filePaths = Object.keys(output);
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/)); const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/)); filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy(); expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy(); expect(hasUnderScoreErrorStaticFile).toBeTruthy();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
'Should build the legacy standard example', 'Should build the legacy standard example',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'legacy-standard')); } = await runBuildLambda(path.join(__dirname, 'legacy-standard'));
expect(output.index).toBeDefined(); expect(output.index).toBeDefined();
const filePaths = Object.keys(output); const filePaths = Object.keys(output);
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/)); const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/)); filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy(); expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy(); expect(hasUnderScoreErrorStaticFile).toBeTruthy();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
'Should build the legacy custom dependency test', 'Should build the legacy custom dependency test',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'legacy-custom-dependency')); } = await runBuildLambda(path.join(__dirname, 'legacy-custom-dependency'));
expect(output.index).toBeDefined(); expect(output.index).toBeDefined();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it('Should throw when package.json or next.config.js is not the "src"', async () => { it('Should throw when package.json or next.config.js is not the "src"', async () => {
try { try {
await runBuildLambda( await runBuildLambda(
path.join(__dirname, 'no-package-json-and-next-config'), path.join(__dirname, 'no-package-json-and-next-config')
); );
throw new Error('did not throw'); throw new Error('did not throw');
} catch (err) { } catch (err) {
@@ -84,33 +97,33 @@ it(
'Should build the static-files test on legacy', 'Should build the static-files test on legacy',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'legacy-static-files')); } = await runBuildLambda(path.join(__dirname, 'legacy-static-files'));
expect(output['static/test.txt']).toBeDefined(); expect(output['static/test.txt']).toBeDefined();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
'Should build the static-files test', 'Should build the static-files test',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'static-files')); } = await runBuildLambda(path.join(__dirname, 'static-files'));
expect(output['static/test.txt']).toBeDefined(); expect(output['static/test.txt']).toBeDefined();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
'Should build the public-files test', 'Should build the public-files test',
async () => { async () => {
const { const {
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'public-files')); } = await runBuildLambda(path.join(__dirname, 'public-files'));
expect(output['robots.txt']).toBeDefined(); expect(output['robots.txt']).toBeDefined();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
@@ -118,15 +131,21 @@ it(
async () => { async () => {
const { const {
workPath, workPath,
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'serverless-config')); } = await runBuildLambda(path.join(__dirname, 'serverless-config'));
expect(output.index).toBeDefined(); expect(output.index).toBeDefined();
expect(output.goodbye).toBeDefined(); expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output); const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/)); const serverlessError = filePaths.some(filePath =>
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/)); filePath.match(/_error/)
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/)); );
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(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy(); expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy(); expect(serverlessError).toBeTruthy();
@@ -135,10 +154,10 @@ it(
expect(contents.some(name => name === 'next.config.js')).toBeTruthy(); expect(contents.some(name => name === 'next.config.js')).toBeTruthy();
expect( expect(
contents.some(name => name.includes('next.config.original.')), contents.some(name => name.includes('next.config.original.'))
).toBeTruthy(); ).toBeTruthy();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
@@ -154,7 +173,7 @@ it(
expect(error).not.toBe(null); expect(error).not.toBe(null);
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
@@ -170,7 +189,7 @@ it(
expect(error).not.toBe(null); expect(error).not.toBe(null);
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
@@ -178,15 +197,21 @@ it(
async () => { async () => {
const { const {
workPath, workPath,
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object')); } = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
expect(output['index.html']).toBeDefined(); expect(output['index.html']).toBeDefined();
expect(output.goodbye).toBeDefined(); expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output); const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/)); const serverlessError = filePaths.some(filePath =>
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/)); filePath.match(/_error/)
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/)); );
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(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy(); expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy(); expect(serverlessError).toBeTruthy();
@@ -195,10 +220,10 @@ it(
expect(contents.some(name => name === 'next.config.js')).toBeTruthy(); expect(contents.some(name => name === 'next.config.js')).toBeTruthy();
expect( expect(
contents.some(name => name.includes('next.config.original.')), contents.some(name => name.includes('next.config.original.'))
).toBeTruthy(); ).toBeTruthy();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );
it( it(
@@ -206,15 +231,21 @@ it(
async () => { async () => {
const { const {
workPath, workPath,
buildResult: { output }, buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config')); } = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
expect(output['index.html']).toBeDefined(); expect(output['index.html']).toBeDefined();
expect(output.goodbye).toBeDefined(); expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output); const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/)); const serverlessError = filePaths.some(filePath =>
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/)); filePath.match(/_error/)
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/)); );
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(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy(); expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy(); expect(serverlessError).toBeTruthy();
@@ -223,8 +254,8 @@ it(
expect(contents.some(name => name === 'next.config.js')).toBeTruthy(); expect(contents.some(name => name === 'next.config.js')).toBeTruthy();
expect( expect(
contents.some(name => name.includes('next.config.original.')), contents.some(name => name.includes('next.config.original.'))
).toBeFalsy(); ).toBeFalsy();
}, },
FOUR_MINUTES, FOUR_MINUTES
); );

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment.js'); } = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000); jest.setTimeout(4 * 60 * 1000);
@@ -26,8 +25,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }

View File

@@ -1,4 +1,3 @@
/* global expect, it, jest */
const path = require('path'); const path = require('path');
const os = require('os'); const os = require('os');
const { build } = require('@now/next'); const { build } = require('@now/next');
@@ -14,40 +13,40 @@ describe('build meta dev', () => {
module.exports = { module.exports = {
target: 'serverless' target: 'serverless'
} }
`, `
}), }),
'pages/index.js': new FileBlob({ 'pages/index.js': new FileBlob({
mode: 0o777, mode: 0o777,
data: ` data: `
export default () => 'Index page' export default () => 'Index page'
`, `
}), }),
'pages/nested/[param].js': new FileBlob({ 'pages/nested/[param].js': new FileBlob({
mode: 0o777, mode: 0o777,
data: ` data: `
export default () => 'Dynamic page' export default () => 'Dynamic page'
`, `
}), }),
'pages/nested/page.tsx': new FileBlob({ 'pages/nested/page.tsx': new FileBlob({
mode: 0o777, mode: 0o777,
data: ` data: `
export default () => 'Nested page' export default () => 'Nested page'
`, `
}), }),
'pages/api/test.js': new FileBlob({ 'pages/api/test.js': new FileBlob({
mode: 0o777, mode: 0o777,
data: ` data: `
export default (req, res) => res.status(200).end('API Route') export default (req, res) => res.status(200).end('API Route')
`, `
}), }),
// This file should be omitted because `pages/index.js` will use the same route // This file should be omitted because `pages/index.js` will use the same route
'public/index': new FileBlob({ 'public/index': new FileBlob({
mode: 0o777, mode: 0o777,
data: 'text', data: 'text'
}), }),
'public/data.txt': new FileBlob({ 'public/data.txt': new FileBlob({
mode: 0o777, mode: 0o777,
data: 'data', data: 'data'
}), }),
'package.json': new FileBlob({ 'package.json': new FileBlob({
mode: 0o777, mode: 0o777,
@@ -67,15 +66,15 @@ describe('build meta dev', () => {
"typescript": "3" "typescript": "3"
} }
} }
`, `
}), })
}; };
const entrypoint = 'next.config.js'; const entrypoint = 'next.config.js';
const workPath = path.join( const workPath = path.join(
os.tmpdir(), os.tmpdir(),
Math.random() Math.random()
.toString() .toString()
.slice(3), .slice(3)
); );
console.log('workPath directory: ', workPath); console.log('workPath directory: ', workPath);
@@ -85,15 +84,13 @@ describe('build meta dev', () => {
await download(files, workPath); await download(files, workPath);
const meta = { isDev: true, requestPath: null }; const meta = { isDev: true, requestPath: null };
const { const { output, routes, watch, childProcesses } = await build({
output, routes, watch, childProcesses,
} = await build({
files, files,
workPath, workPath,
entrypoint, entrypoint,
meta, meta
}); });
routes.forEach((route) => { routes.forEach(route => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
route.dest = route.dest.replace(':4000', ':5000'); route.dest = route.dest.replace(':4000', ':5000');
}); });
@@ -107,9 +104,9 @@ describe('build meta dev', () => {
{ src: '/api/test', dest: 'http://localhost:5000/api/test' }, { src: '/api/test', dest: 'http://localhost:5000/api/test' },
{ {
src: '^/(nested\\/([^\\/]+?)(?:\\/)?)$', src: '^/(nested\\/([^\\/]+?)(?:\\/)?)$',
dest: 'http://localhost:5000/$1', dest: 'http://localhost:5000/$1'
}, },
{ src: '/data.txt', dest: 'http://localhost:5000/data.txt' }, { src: '/data.txt', dest: 'http://localhost:5000/data.txt' }
]); ]);
expect(watch).toEqual([ expect(watch).toEqual([
'next.config.js', 'next.config.js',
@@ -119,7 +116,7 @@ describe('build meta dev', () => {
'pages/api/test.js', 'pages/api/test.js',
'public/index', 'public/index',
'public/data.txt', 'public/data.txt',
'package.json', 'package.json'
]); ]);
childProcesses.forEach(cp => cp.kill()); childProcesses.forEach(cp => cp.kill());
}); });

View File

@@ -4,9 +4,9 @@ const {
validateEntrypoint, validateEntrypoint,
includeOnlyEntryDirectory, includeOnlyEntryDirectory,
normalizePackageJson, normalizePackageJson,
getNextConfig, getNextConfig
} = require('@now/next/dist/utils'); } = require('@now/next/dist/utils');
const { FileRef } = require('@now/build-utils'); // eslint-disable-line import/no-extraneous-dependencies const { FileRef } = require('@now/build-utils');
describe('getNextConfig', () => { describe('getNextConfig', () => {
const workPath = path.join(__dirname, 'fixtures'); const workPath = path.join(__dirname, 'fixtures');
@@ -33,11 +33,11 @@ describe('excludeFiles', () => {
const files = { const files = {
'pages/index.js': new FileRef({ digest: 'index' }), 'pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }), 'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }), 'package-lock.json': new FileRef({ digest: 'package-lock' })
}; };
const result = excludeFiles( const result = excludeFiles(
files, files,
filePath => filePath === 'package-lock.json', filePath => filePath === 'package-lock.json'
); );
expect(result['pages/index.js']).toBeDefined(); expect(result['pages/index.js']).toBeDefined();
expect(result['package.json']).toBeDefined(); expect(result['package.json']).toBeDefined();
@@ -69,7 +69,7 @@ describe('includeOnlyEntryDirectory', () => {
const files = { const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }), 'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }), 'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }), 'package-lock.json': new FileRef({ digest: 'package-lock' })
}; };
const result = includeOnlyEntryDirectory(files, entryDirectory); const result = includeOnlyEntryDirectory(files, entryDirectory);
expect(result['frontend/pages/index.js']).toBeDefined(); expect(result['frontend/pages/index.js']).toBeDefined();
@@ -85,15 +85,15 @@ describe('normalizePackageJson', () => {
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest'
}, },
devDependencies: { devDependencies: {
next: 'v7.0.2-canary.49', next: 'v7.0.2-canary.49'
}, },
scripts: { scripts: {
'now-build': 'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas', 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}, }
}); });
}); });
@@ -102,29 +102,29 @@ describe('normalizePackageJson', () => {
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest'
}, },
devDependencies: { devDependencies: {
next: 'v7.0.2-canary.49', next: 'v7.0.2-canary.49'
}, },
scripts: { scripts: {
'now-build': 'next build', 'now-build': 'next build'
}, }
}; };
const result = normalizePackageJson(defaultPackage); const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({ expect(result).toEqual({
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest'
}, },
devDependencies: { devDependencies: {
next: 'v7.0.2-canary.49', next: 'v7.0.2-canary.49'
}, },
scripts: { scripts: {
'now-build': 'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas', 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}, }
}); });
}); });
@@ -133,23 +133,23 @@ describe('normalizePackageJson', () => {
dependencies: { dependencies: {
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest',
next: 'latest', next: 'latest'
}, }
}; };
const result = normalizePackageJson(defaultPackage); const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({ expect(result).toEqual({
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest'
}, },
devDependencies: { devDependencies: {
next: 'v7.0.2-canary.49', next: 'v7.0.2-canary.49'
}, },
scripts: { scripts: {
'now-build': 'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas', 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}, }
}); });
}); });
@@ -158,23 +158,23 @@ describe('normalizePackageJson', () => {
dependencies: { dependencies: {
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest',
next: 'latest', next: 'latest'
}, }
}; };
const result = normalizePackageJson(defaultPackage); const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({ expect(result).toEqual({
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest'
}, },
devDependencies: { devDependencies: {
next: 'v7.0.2-canary.49', next: 'v7.0.2-canary.49'
}, },
scripts: { scripts: {
'now-build': 'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas', 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}, }
}); });
}); });
@@ -183,23 +183,23 @@ describe('normalizePackageJson', () => {
dependencies: { dependencies: {
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest',
next: 'latest', next: 'latest'
}, }
}; };
const result = normalizePackageJson(defaultPackage); const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({ expect(result).toEqual({
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: 'latest', react: 'latest',
'react-dom': 'latest', 'react-dom': 'latest'
}, },
devDependencies: { devDependencies: {
next: 'v7.0.2-canary.49', next: 'v7.0.2-canary.49'
}, },
scripts: { scripts: {
'now-build': 'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas', 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}, }
}); });
}); });
@@ -211,7 +211,7 @@ describe('normalizePackageJson', () => {
dev: 'next', dev: 'next',
build: 'next build', build: 'next build',
start: 'next start', start: 'next start',
test: "xo && stylelint './pages/**/*.js' && jest", test: "xo && stylelint './pages/**/*.js' && jest"
}, },
main: 'pages/index.js', main: 'pages/index.js',
license: 'MIT', license: 'MIT',
@@ -226,7 +226,7 @@ describe('normalizePackageJson', () => {
'stylelint-config-recommended': '^2.1.0', 'stylelint-config-recommended': '^2.1.0',
'stylelint-config-styled-components': '^0.1.1', 'stylelint-config-styled-components': '^0.1.1',
'stylelint-processor-styled-components': '^1.5.1', 'stylelint-processor-styled-components': '^1.5.1',
xo: '^0.23.0', xo: '^0.23.0'
}, },
dependencies: { dependencies: {
consola: '^2.2.6', consola: '^2.2.6',
@@ -234,7 +234,7 @@ describe('normalizePackageJson', () => {
next: '^7.0.2', next: '^7.0.2',
react: '^16.6.3', react: '^16.6.3',
'react-dom': '^16.6.3', 'react-dom': '^16.6.3',
'styled-components': '^4.1.1', 'styled-components': '^4.1.1'
}, },
xo: { xo: {
extends: 'xo-react', extends: 'xo-react',
@@ -244,15 +244,15 @@ describe('normalizePackageJson', () => {
'test', 'test',
'pages/_document.js', 'pages/_document.js',
'pages/index.js', 'pages/index.js',
'pages/home.js', 'pages/home.js'
], ],
rules: { rules: {
'react/no-unescaped-entities': null, 'react/no-unescaped-entities': null
}, }
}, },
jest: { jest: {
testEnvironment: 'node', testEnvironment: 'node'
}, }
}; };
const result = normalizePackageJson(defaultPackage); const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({ expect(result).toEqual({
@@ -263,7 +263,7 @@ describe('normalizePackageJson', () => {
'now-build': 'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas', 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
start: 'next start', start: 'next start',
test: "xo && stylelint './pages/**/*.js' && jest", test: "xo && stylelint './pages/**/*.js' && jest"
}, },
main: 'pages/index.js', main: 'pages/index.js',
license: 'MIT', license: 'MIT',
@@ -283,12 +283,12 @@ describe('normalizePackageJson', () => {
xo: '^0.23.0', xo: '^0.23.0',
consola: '^2.2.6', consola: '^2.2.6',
fontfaceobserver: '^2.0.13', fontfaceobserver: '^2.0.13',
'styled-components': '^4.1.1', 'styled-components': '^4.1.1'
}, },
dependencies: { dependencies: {
'next-server': 'v7.0.2-canary.49', 'next-server': 'v7.0.2-canary.49',
react: '^16.6.3', react: '^16.6.3',
'react-dom': '^16.6.3', 'react-dom': '^16.6.3'
}, },
xo: { xo: {
extends: 'xo-react', extends: 'xo-react',
@@ -298,15 +298,15 @@ describe('normalizePackageJson', () => {
'test', 'test',
'pages/_document.js', 'pages/_document.js',
'pages/index.js', 'pages/index.js',
'pages/home.js', 'pages/home.js'
], ],
rules: { rules: {
'react/no-unescaped-entities': null, 'react/no-unescaped-entities': null
}, }
}, },
jest: { jest: {
testEnvironment: 'node', testEnvironment: 'node'
}, }
}); });
}); });
}); });

View File

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

View File

@@ -5,7 +5,7 @@ import {
Server, Server,
IncomingHttpHeaders, IncomingHttpHeaders,
OutgoingHttpHeaders, OutgoingHttpHeaders,
request, request
} from 'http'; } from 'http';
interface NowProxyEvent { interface NowProxyEvent {
@@ -107,10 +107,10 @@ export class Bridge {
private listening: Promise<AddressInfo>; private listening: Promise<AddressInfo>;
private resolveListening: (info: AddressInfo) => void; private resolveListening: (info: AddressInfo) => void;
private events: { [key: string]: NowProxyRequest } = {}; private events: { [key: string]: NowProxyRequest } = {};
private reqIdSeed: number = 1; private reqIdSeed = 1;
private shouldStoreEvents: boolean = false; private shouldStoreEvents = false;
constructor(server?: ServerLike, shouldStoreEvents: boolean = false) { constructor(server?: ServerLike, shouldStoreEvents = false) {
this.server = null; this.server = null;
this.shouldStoreEvents = shouldStoreEvents; this.shouldStoreEvents = shouldStoreEvents;
if (server) { if (server) {
@@ -141,7 +141,7 @@ export class Bridge {
return this.server.listen( return this.server.listen(
{ {
host: '127.0.0.1', host: '127.0.0.1',
port: 0, port: 0
}, },
function listeningCallback() { function listeningCallback() {
if (!this || typeof this.address !== 'function') { if (!this || typeof this.address !== 'function') {
@@ -206,7 +206,7 @@ export class Bridge {
statusCode: response.statusCode || 200, statusCode: response.statusCode || 200,
headers: response.headers, headers: response.headers,
body: bodyBuffer.toString('base64'), body: bodyBuffer.toString('base64'),
encoding: 'base64', encoding: 'base64'
}); });
}); });
}); });

View File

@@ -1,4 +1,6 @@
// We intentionally import these types here // We intentionally import these types here
// which will fail at compile time if exports // which will fail at compile time if exports
// are not found in the index file // are not found in the index file
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { NowRequest, NowResponse } from './index'; import { NowRequest, NowResponse } from './index';

View File

@@ -17,7 +17,7 @@ import {
BuildOptions, BuildOptions,
shouldServe, shouldServe,
Config, Config,
debug, debug
} from '@now/build-utils'; } from '@now/build-utils';
export { NowRequest, NowResponse } from './types'; export { NowRequest, NowResponse } from './types';
import { makeLauncher } from './launcher'; import { makeLauncher } from './launcher';
@@ -57,7 +57,7 @@ async function downloadInstallAndBundle({
entrypoint, entrypoint,
workPath, workPath,
config, config,
meta, meta
}: DownloadOptions) { }: DownloadOptions) {
debug('downloading user files...'); debug('downloading user files...');
const downloadTime = Date.now(); const downloadTime = Date.now();
@@ -94,7 +94,7 @@ async function compile(
const sourceCache = new Map<string, string | Buffer | null>(); const sourceCache = new Map<string, string | Buffer | null>();
const fsCache = new Map<string, File>(); const fsCache = new Map<string, File>();
const tsCompiled = new Set<String>(); const tsCompiled = new Set<string>();
let shouldAddSourcemapSupport = false; let shouldAddSourcemapSupport = false;
@@ -141,7 +141,7 @@ async function compile(
tsCompile = register({ tsCompile = register({
basePath: workPath, // The base is the same as root now.json dir basePath: workPath, // The base is the same as root now.json dir
project: path, // Resolve tsconfig.json from entrypoint dir project: path, // Resolve tsconfig.json from entrypoint dir
files: true, // Include all files such as global `.d.ts` files: true // Include all files such as global `.d.ts`
}); });
} }
const { code, map } = tsCompile(source, path); const { code, map } = tsCompile(source, path);
@@ -149,7 +149,7 @@ async function compile(
preparedFiles[ preparedFiles[
relPath.slice(0, -3 - Number(path.endsWith('x'))) + '.js.map' relPath.slice(0, -3 - Number(path.endsWith('x'))) + '.js.map'
] = new FileBlob({ ] = new FileBlob({
data: JSON.stringify(map), data: JSON.stringify(map)
}); });
source = code; source = code;
shouldAddSourcemapSupport = true; shouldAddSourcemapSupport = true;
@@ -189,7 +189,7 @@ async function compile(
} }
throw e; throw e;
} }
}, }
}); });
debug('traced files:'); debug('traced files:');
@@ -252,17 +252,17 @@ async function compile(
const filename = basename(path); const filename = basename(path);
const { data: source } = await FileBlob.fromStream({ const { data: source } = await FileBlob.fromStream({
stream: preparedFiles[path].toStream(), stream: preparedFiles[path].toStream()
}); });
const { code, map } = babelCompile(filename, source); const { code, map } = babelCompile(filename, source);
shouldAddSourcemapSupport = true; shouldAddSourcemapSupport = true;
preparedFiles[path] = new FileBlob({ preparedFiles[path] = new FileBlob({
data: `${code}\n//# sourceMappingURL=${filename}.map`, data: `${code}\n//# sourceMappingURL=${filename}.map`
}); });
delete map.sourcesContent; delete map.sourcesContent;
preparedFiles[path + '.map'] = new FileBlob({ preparedFiles[path + '.map'] = new FileBlob({
data: JSON.stringify(map), data: JSON.stringify(map)
}); });
} }
} }
@@ -270,7 +270,7 @@ async function compile(
return { return {
preparedFiles, preparedFiles,
shouldAddSourcemapSupport, shouldAddSourcemapSupport,
watch: fileList, watch: fileList
}; };
} }
@@ -281,7 +281,7 @@ export async function build({
entrypoint, entrypoint,
workPath, workPath,
config = {}, config = {},
meta = {}, meta = {}
}: BuildOptions) { }: BuildOptions) {
const shouldAddHelpers = config.helpers !== false; const shouldAddHelpers = config.helpers !== false;
@@ -289,13 +289,13 @@ export async function build({
entrypointPath, entrypointPath,
entrypointFsDirname, entrypointFsDirname,
nodeVersion, nodeVersion,
spawnOpts, spawnOpts
} = await downloadInstallAndBundle({ } = await downloadInstallAndBundle({
files, files,
entrypoint, entrypoint,
workPath, workPath,
config, config,
meta, meta
}); });
debug('running user script...'); debug('running user script...');
@@ -321,23 +321,23 @@ export async function build({
helpersPath: `./${HELPERS_FILENAME}`, helpersPath: `./${HELPERS_FILENAME}`,
sourcemapSupportPath: `./${SOURCEMAP_SUPPORT_FILENAME}`, sourcemapSupportPath: `./${SOURCEMAP_SUPPORT_FILENAME}`,
shouldAddHelpers, shouldAddHelpers,
shouldAddSourcemapSupport, shouldAddSourcemapSupport
}), })
}), }),
[`${BRIDGE_FILENAME}.js`]: new FileFsRef({ [`${BRIDGE_FILENAME}.js`]: new FileFsRef({
fsPath: join(__dirname, 'bridge.js'), fsPath: join(__dirname, 'bridge.js')
}), })
}; };
if (shouldAddSourcemapSupport) { if (shouldAddSourcemapSupport) {
launcherFiles[`${SOURCEMAP_SUPPORT_FILENAME}.js`] = new FileFsRef({ launcherFiles[`${SOURCEMAP_SUPPORT_FILENAME}.js`] = new FileFsRef({
fsPath: join(__dirname, 'source-map-support.js'), fsPath: join(__dirname, 'source-map-support.js')
}); });
} }
if (shouldAddHelpers) { if (shouldAddHelpers) {
launcherFiles[`${HELPERS_FILENAME}.js`] = new FileFsRef({ launcherFiles[`${HELPERS_FILENAME}.js`] = new FileFsRef({
fsPath: join(__dirname, 'helpers.js'), fsPath: join(__dirname, 'helpers.js')
}); });
} }
@@ -350,10 +350,10 @@ export async function build({
const lambda = await createLambda({ const lambda = await createLambda({
files: { files: {
...preparedFiles, ...preparedFiles,
...(awsLambdaHandler ? {} : launcherFiles), ...(awsLambdaHandler ? {} : launcherFiles)
}, },
handler: awsLambdaHandler || `${LAUNCHER_FILENAME}.launcher`, handler: awsLambdaHandler || `${LAUNCHER_FILENAME}.launcher`,
runtime, runtime
}); });
const output = { [entrypoint]: lambda }; const output = { [entrypoint]: lambda };
@@ -365,7 +365,7 @@ export async function prepareCache({ workPath }: PrepareCacheOptions) {
return { return {
...(await glob('node_modules/**', workPath)), ...(await glob('node_modules/**', workPath)),
...(await glob('package-lock.json', workPath)), ...(await glob('package-lock.json', workPath)),
...(await glob('yarn.lock', workPath)), ...(await glob('yarn.lock', workPath))
}; };
} }

View File

@@ -87,7 +87,7 @@ const DEFAULTS: Options = {
ignore: undefined, ignore: undefined,
project: undefined, project: undefined,
ignoreDiagnostics: undefined, ignoreDiagnostics: undefined,
logError: null, logError: null
}; };
/** /**
@@ -99,7 +99,7 @@ const TS_NODE_COMPILER_OPTIONS = {
inlineSources: true, inlineSources: true,
declaration: false, declaration: false,
noEmit: false, noEmit: false,
outDir: '$$ts-node$$', outDir: '$$ts-node$$'
}; };
/** /**
@@ -143,15 +143,16 @@ export function register(opts: Options = {}): Register {
6059, // "'rootDir' is expected to contain all source files." 6059, // "'rootDir' is expected to contain all source files."
18002, // "The 'files' list in config file is empty." 18002, // "The 'files' list in config file is empty."
18003, // "No inputs were found in config file." 18003, // "No inputs were found in config file."
...(options.ignoreDiagnostics || []), ...(options.ignoreDiagnostics || [])
].map(Number); ].map(Number);
// Require the TypeScript compiler and configuration. // Require the TypeScript compiler and configuration.
const cwd = options.basePath || process.cwd(); const cwd = options.basePath || process.cwd();
const nowNodeBase = resolve(__dirname, '..', '..', '..'); const nowNodeBase = resolve(__dirname, '..', '..', '..');
try { try {
var compiler = require.resolve(options.compiler || 'typescript', { var compiler = require.resolve(options.compiler || 'typescript', {
paths: [cwd, nowNodeBase], paths: [cwd, nowNodeBase]
}); });
} catch (e) { } catch (e) {
compiler = require.resolve(eval('"./typescript"')); compiler = require.resolve(eval('"./typescript"'));
@@ -174,7 +175,7 @@ export function register(opts: Options = {}): Register {
const diagnosticHost: _ts.FormatDiagnosticsHost = { const diagnosticHost: _ts.FormatDiagnosticsHost = {
getNewLine: () => ts.sys.newLine, getNewLine: () => ts.sys.newLine,
getCurrentDirectory: () => cwd, getCurrentDirectory: () => cwd,
getCanonicalFileName: path => path, getCanonicalFileName: path => path
}; };
function createTSError(diagnostics: ReadonlyArray<_ts.Diagnostic>) { function createTSError(diagnostics: ReadonlyArray<_ts.Diagnostic>) {
@@ -199,7 +200,7 @@ export function register(opts: Options = {}): Register {
// we create a custom build per tsconfig.json instance // we create a custom build per tsconfig.json instance
const builds = new Map<string, Build>(); const builds = new Map<string, Build>();
function getBuild(configFileName: string = ''): Build { function getBuild(configFileName = ''): Build {
let build = builds.get(configFileName); let build = builds.get(configFileName);
if (build) return build; if (build) return build;
@@ -208,12 +209,12 @@ export function register(opts: Options = {}): Register {
/** /**
* Create the basic required function using transpile mode. * Create the basic required function using transpile mode.
*/ */
let getOutput = function(code: string, fileName: string): SourceOutput { const getOutput = function(code: string, fileName: string): SourceOutput {
const result = ts.transpileModule(code, { const result = ts.transpileModule(code, {
fileName, fileName,
transformers, transformers,
compilerOptions: config.options, compilerOptions: config.options,
reportDiagnostics: true, reportDiagnostics: true
}); });
const diagnosticList = result.diagnostics const diagnosticList = result.diagnostics
@@ -268,7 +269,7 @@ export function register(opts: Options = {}): Register {
getCurrentDirectory: () => cwd, getCurrentDirectory: () => cwd,
getCompilationSettings: () => config.options, getCompilationSettings: () => config.options,
getDefaultLibFileName: () => ts.getDefaultLibFilePath(config.options), getDefaultLibFileName: () => ts.getDefaultLibFilePath(config.options),
getCustomTransformers: () => transformers, getCustomTransformers: () => transformers
}; };
const registry = ts.createDocumentRegistry( const registry = ts.createDocumentRegistry(
@@ -322,7 +323,7 @@ export function register(opts: Options = {}): Register {
return { return {
code: output.outputFiles[1].text, code: output.outputFiles[1].text,
map: output.outputFiles[0].text, map: output.outputFiles[0].text
}; };
}; };
} }
@@ -331,15 +332,14 @@ export function register(opts: Options = {}): Register {
configFileName, configFileName,
(build = { (build = {
getOutput, getOutput,
getOutputTypeCheck, getOutputTypeCheck
}) })
); );
return build; return build;
} }
// determine the tsconfig.json path for a given folder // determine the tsconfig.json path for a given folder
function detectConfig(basePath: string): string | undefined { function detectConfig(): string | undefined {
basePath = normalizeSlashes(basePath);
let configFileName: string | undefined = undefined; let configFileName: string | undefined = undefined;
// Read project configuration when available. // Read project configuration when available.
@@ -355,7 +355,7 @@ export function register(opts: Options = {}): Register {
*/ */
function readConfig(configFileName: string): _ts.ParsedCommandLine { function readConfig(configFileName: string): _ts.ParsedCommandLine {
let config: any = { compilerOptions: {} }; let config: any = { compilerOptions: {} };
let basePath = normalizeSlashes(dirname(configFileName)); const basePath = normalizeSlashes(dirname(configFileName));
// Read project configuration when available. // Read project configuration when available.
if (configFileName) { if (configFileName) {
@@ -366,7 +366,7 @@ export function register(opts: Options = {}): Register {
const errorResult = { const errorResult = {
errors: [result.error], errors: [result.error],
fileNames: [], fileNames: [],
options: {}, options: {}
}; };
const configDiagnosticList = filterDiagnostics( const configDiagnosticList = filterDiagnostics(
errorResult.errors, errorResult.errors,
@@ -423,7 +423,7 @@ export function register(opts: Options = {}): Register {
fileName: string, fileName: string,
skipTypeCheck?: boolean skipTypeCheck?: boolean
): SourceOutput { ): SourceOutput {
const configFileName = detectConfig(fileName); const configFileName = detectConfig();
const build = getBuild(configFileName); const build = getBuild(configFileName);
const { code: value, map: sourceMap } = (skipTypeCheck const { code: value, map: sourceMap } = (skipTypeCheck
? build.getOutput ? build.getOutput
@@ -432,8 +432,8 @@ export function register(opts: Options = {}): Register {
code: value, code: value,
map: Object.assign(JSON.parse(sourceMap), { map: Object.assign(JSON.parse(sourceMap), {
file: basename(fileName), file: basename(fileName),
sources: [fileName], sources: [fileName]
}), })
}; };
delete output.map.sourceRoot; delete output.map.sourceRoot;
return output; return output;

View File

@@ -1,4 +1,3 @@
/* global beforeEach, afterEach, expect, it, jest */
const fetch = require('node-fetch'); const fetch = require('node-fetch');
const listen = require('test-listen'); const listen = require('test-listen');
const qs = require('querystring'); const qs = require('querystring');
@@ -22,7 +21,7 @@ async function fetchWithProxyReq(_url, opts = {}) {
return fetch(_url, { return fetch(_url, {
...opts, ...opts,
headers: { ...opts.headers, 'x-now-bridge-request-id': '2' }, headers: { ...opts.headers, 'x-now-bridge-request-id': '2' }
}); });
} }
@@ -67,7 +66,7 @@ describe('all helpers', () => {
['body', 0], ['body', 0],
['status', 1], ['status', 1],
['send', 1], ['send', 1],
['json', 1], ['json', 1]
]; ];
test('should not recalculate req properties twice', async () => { test('should not recalculate req properties twice', async () => {
@@ -84,7 +83,7 @@ describe('all helpers', () => {
await fetchWithProxyReq(`${url}/?who=bill`, { await fetchWithProxyReq(`${url}/?who=bill`, {
method: 'POST', method: 'POST',
body: JSON.stringify({ who: 'mike' }), body: JSON.stringify({ who: 'mike' }),
headers: { 'content-type': 'application/json', cookie: 'who=jim' }, headers: { 'content-type': 'application/json', cookie: 'who=jim' }
}); });
// here we test that bodySpy is called twice with exactly the same arguments // here we test that bodySpy is called twice with exactly the same arguments
@@ -138,7 +137,7 @@ describe('req.query', () => {
expect(mockListener.mock.calls[0][0].query).toMatchObject({ expect(mockListener.mock.calls[0][0].query).toMatchObject({
who: 'bill', who: 'bill',
where: 'us', where: 'us'
}); });
}); });
@@ -153,13 +152,13 @@ describe('req.cookies', () => {
test('req.cookies should reflect req.cookie header', async () => { test('req.cookies should reflect req.cookie header', async () => {
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
headers: { headers: {
cookie: 'who=bill; where=us', cookie: 'who=bill; where=us'
}, }
}); });
expect(mockListener.mock.calls[0][0].cookies).toMatchObject({ expect(mockListener.mock.calls[0][0].cookies).toMatchObject({
who: 'bill', who: 'bill',
where: 'us', where: 'us'
}); });
}); });
}); });
@@ -173,7 +172,7 @@ describe('req.body', () => {
test('req.body should be undefined if content-type is not defined', async () => { test('req.body should be undefined if content-type is not defined', async () => {
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: 'hello', body: 'hello'
}); });
expect(mockListener.mock.calls[0][0].body).toBe(undefined); expect(mockListener.mock.calls[0][0].body).toBe(undefined);
}); });
@@ -182,7 +181,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: 'hello', body: 'hello',
headers: { 'content-type': 'text/plain' }, headers: { 'content-type': 'text/plain' }
}); });
expect(mockListener.mock.calls[0][0].body).toBe('hello'); expect(mockListener.mock.calls[0][0].body).toBe('hello');
@@ -192,7 +191,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: 'hello', body: 'hello',
headers: { 'content-type': 'application/octet-stream' }, headers: { 'content-type': 'application/octet-stream' }
}); });
const [{ body }] = mockListener.mock.calls[0]; const [{ body }] = mockListener.mock.calls[0];
@@ -209,7 +208,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: qs.encode(obj), body: qs.encode(obj),
headers: { 'content-type': 'application/x-www-form-urlencoded' }, headers: { 'content-type': 'application/x-www-form-urlencoded' }
}); });
expect(mockListener.mock.calls[0][0].body).toMatchObject(obj); expect(mockListener.mock.calls[0][0].body).toMatchObject(obj);
@@ -218,13 +217,13 @@ describe('req.body', () => {
test('req.body should be an object when content-type is `application/json`', async () => { test('req.body should be an object when content-type is `application/json`', async () => {
const json = { const json = {
who: 'bill', who: 'bill',
where: 'us', where: 'us'
}; };
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: JSON.stringify(json), body: JSON.stringify(json),
headers: { 'content-type': 'application/json' }, headers: { 'content-type': 'application/json' }
}); });
expect(mockListener.mock.calls[0][0].body).toMatchObject(json); expect(mockListener.mock.calls[0][0].body).toMatchObject(json);
@@ -239,7 +238,7 @@ describe('req.body', () => {
const res = await fetchWithProxyReq(url, { const res = await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: '', body: '',
headers: { 'content-type': 'application/json' }, headers: { 'content-type': 'application/json' }
}); });
expect(res.status).toBe(400); expect(res.status).toBe(400);
@@ -261,7 +260,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, { await fetchWithProxyReq(url, {
method: 'POST', method: 'POST',
body: '{"wrong":"json"', body: '{"wrong":"json"',
headers: { 'content-type': 'application/json' }, headers: { 'content-type': 'application/json' }
}); });
expect(bodySpy).toHaveBeenCalled(); expect(bodySpy).toHaveBeenCalled();

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment.js'); } = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000); jest.setTimeout(4 * 60 * 1000);
@@ -29,7 +28,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
try { try {
await testDeployment( await testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
); );
} catch (err) { } catch (err) {
expect(err.message).toMatch(/is ERROR/); expect(err.message).toMatch(/is ERROR/);
@@ -43,8 +42,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment.js'); } = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000); jest.setTimeout(4 * 60 * 1000);
@@ -26,8 +25,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }

View File

@@ -25,7 +25,7 @@ export type Handler = {
export type Route = Source | Handler; export type Route = Source | Handler;
export function isHandler(route: Route): route is Handler { export function isHandler(route: Route): route is Handler {
return typeof (<Handler>route).handle !== 'undefined'; return typeof (route as Handler).handle !== 'undefined';
} }
export function normalizeRoutes( export function normalizeRoutes(
@@ -47,24 +47,20 @@ export function normalizeRoutes(
// typeof { handle: string } // typeof { handle: string }
if (Object.keys(route).length !== 1) { if (Object.keys(route).length !== 1) {
errors.push({ errors.push({
message: `Cannot have any other keys when handle is used (handle: ${ message: `Cannot have any other keys when handle is used (handle: ${route.handle})`,
route.handle handle: route.handle
})`,
handle: route.handle,
}); });
} }
if (!['filesystem'].includes(route.handle)) { if (!['filesystem'].includes(route.handle)) {
errors.push({ errors.push({
message: `This is not a valid handler (handle: ${route.handle})`, message: `This is not a valid handler (handle: ${route.handle})`,
handle: route.handle, handle: route.handle
}); });
} }
if (handling.includes(route.handle)) { if (handling.includes(route.handle)) {
errors.push({ errors.push({
message: `You can only handle something once (handle: ${ message: `You can only handle something once (handle: ${route.handle})`,
route.handle handle: route.handle
})`,
handle: route.handle,
}); });
} else { } else {
handling.push(route.handle); handling.push(route.handle);
@@ -86,12 +82,12 @@ export function normalizeRoutes(
} catch (err) { } catch (err) {
errors.push({ errors.push({
message: `Invalid regular expression: "${route.src}"`, message: `Invalid regular expression: "${route.src}"`,
src: route.src, src: route.src
}); });
} }
} else { } else {
errors.push({ errors.push({
message: 'A route must set either handle or src', message: 'A route must set either handle or src'
}); });
} }
} }
@@ -105,7 +101,7 @@ export function normalizeRoutes(
null, null,
2 2
)}`, )}`,
errors, errors
} }
: null; : null;
@@ -124,19 +120,19 @@ export const schema = {
properties: { properties: {
src: { src: {
type: 'string', type: 'string',
maxLength: 4096, maxLength: 4096
}, },
dest: { dest: {
type: 'string', type: 'string',
maxLength: 4096, maxLength: 4096
}, },
methods: { methods: {
type: 'array', type: 'array',
maxItems: 10, maxItems: 10,
items: { items: {
type: 'string', type: 'string',
maxLength: 32, maxLength: 32
}, }
}, },
headers: { headers: {
type: 'object', type: 'object',
@@ -146,22 +142,22 @@ export const schema = {
patternProperties: { patternProperties: {
'^.{1,256}$': { '^.{1,256}$': {
type: 'string', type: 'string',
maxLength: 4096, maxLength: 4096
}, }
}, }
}, },
handle: { handle: {
type: 'string', type: 'string',
maxLength: 32, maxLength: 32
}, },
continue: { continue: {
type: 'boolean', type: 'boolean'
}, },
status: { status: {
type: 'integer', type: 'integer',
minimum: 100, minimum: 100,
maximum: 999, maximum: 999
}, }
}, }
}, }
}; };

View File

@@ -6,7 +6,7 @@ import {
remove, remove,
pathExists, pathExists,
readFile, readFile,
writeFile, writeFile
} from 'fs-extra'; } from 'fs-extra';
import { import {
download, download,
@@ -14,7 +14,7 @@ import {
glob, glob,
createLambda, createLambda,
BuildOptions, BuildOptions,
debug, debug
} from '@now/build-utils'; } from '@now/build-utils';
import { installBundler } from './install-ruby'; import { installBundler } from './install-ruby';
@@ -58,15 +58,15 @@ async function bundleInstall(
'--gemfile', '--gemfile',
gemfilePath, gemfilePath,
'--path', '--path',
bundleDir, bundleDir
], ],
{ {
stdio: 'pipe', stdio: 'pipe',
env: { env: {
BUNDLE_SILENCE_ROOT_WARNING: '1', BUNDLE_SILENCE_ROOT_WARNING: '1',
BUNDLE_APP_CONFIG: bundleAppConfig, BUNDLE_APP_CONFIG: bundleAppConfig,
BUNDLE_JOBS: '4', BUNDLE_JOBS: '4'
}, }
} }
); );
} catch (err) { } catch (err) {
@@ -79,12 +79,11 @@ export const build = async ({
workPath, workPath,
files, files,
entrypoint, entrypoint,
config, config
}: BuildOptions) => { }: BuildOptions) => {
debug('downloading files...'); debug('downloading files...');
// eslint-disable-next-line no-param-reassign await download(files, workPath);
files = await download(files, workPath);
const { gemHome, bundlerPath } = await installBundler(); const { gemHome, bundlerPath } = await installBundler();
process.env.GEM_HOME = gemHome; process.env.GEM_HOME = gemHome;
@@ -102,9 +101,9 @@ export const build = async ({
const bundleDir = join(workPath, 'vendor/bundle'); const bundleDir = join(workPath, 'vendor/bundle');
const relativeVendorDir = join(fsEntryDirectory, REQUIRED_VENDOR_DIR); const relativeVendorDir = join(fsEntryDirectory, REQUIRED_VENDOR_DIR);
let hasRootVendorDir = await pathExists(vendorDir); const hasRootVendorDir = await pathExists(vendorDir);
let hasRelativeVendorDir = await pathExists(relativeVendorDir); const hasRelativeVendorDir = await pathExists(relativeVendorDir);
let hasVendorDir = hasRootVendorDir || hasRelativeVendorDir; const hasVendorDir = hasRootVendorDir || hasRelativeVendorDir;
if (hasRelativeVendorDir) { if (hasRelativeVendorDir) {
if (hasRootVendorDir) { if (hasRootVendorDir) {
@@ -151,7 +150,9 @@ export const build = async ({
// try to remove gem cache to slim bundle size // try to remove gem cache to slim bundle size
try { try {
await remove(join(vendorDir, 'cache')); await remove(join(vendorDir, 'cache'));
} catch (e) {} } catch (e) {
// don't do anything here
}
const originalRbPath = join(__dirname, '..', 'now_init.rb'); const originalRbPath = join(__dirname, '..', 'now_init.rb');
const originalNowHandlerRbContents = await readFile(originalRbPath, 'utf8'); const originalNowHandlerRbContents = await readFile(originalRbPath, 'utf8');
@@ -209,10 +210,10 @@ export const build = async ({
files: outputFiles, files: outputFiles,
handler: `${nowHandlerRbFilename}.now__handler`, handler: `${nowHandlerRbFilename}.now__handler`,
runtime: 'ruby2.5', runtime: 'ruby2.5',
environment: {}, environment: {}
}); });
return { return {
[entrypoint]: lambda, [entrypoint]: lambda
}; };
}; };

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment.js'); } = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(5 * 60 * 1000); jest.setTimeout(5 * 60 * 1000);
@@ -26,8 +25,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { const {
packAndDeploy, packAndDeploy,
testDeployment, testDeployment
} = require('../../../test/lib/deployment/test-deployment.js'); } = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(12 * 60 * 1000); jest.setTimeout(12 * 60 * 1000);
@@ -22,7 +21,7 @@ const testsThatFailToBuild = new Set([
'04-wrong-dist-dir', '04-wrong-dist-dir',
'05-empty-dist-dir', '05-empty-dist-dir',
'06-missing-script', '06-missing-script',
'07-nonzero-sh', '07-nonzero-sh'
]); ]);
// eslint-disable-next-line no-restricted-syntax // eslint-disable-next-line no-restricted-syntax
@@ -33,7 +32,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
try { try {
await testDeployment( await testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
); );
} catch (err) { } catch (err) {
expect(err.message).toMatch(/is ERROR/); expect(err.message).toMatch(/is ERROR/);
@@ -47,8 +46,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect( await expect(
testDeployment( testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture), path.join(fixturesPath, fixture)
), )
).resolves.toBeDefined(); ).resolves.toBeDefined();
}); });
} }

2
run.js
View File

@@ -55,7 +55,7 @@ async function main() {
console.log(matches.join('\n') + '\n'); console.log(matches.join('\n') + '\n');
for (let pkgName of matches) { for (const pkgName of matches) {
await runScript(pkgName, script); await runScript(pkgName, script);
} }
} }

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const airtable = require('airtable'); const airtable = require('airtable');
module.exports = (req, res) => { module.exports = (req, res) => {

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const aws = require('aws-sdk'); const aws = require('aws-sdk');
module.exports = (req, res) => { module.exports = (req, res) => {

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const axios = require('axios'); const axios = require('axios');
module.exports = (req, res) => { module.exports = (req, res) => {

View File

@@ -1,4 +1,3 @@
/* global it, expect */
const path = require('path'); const path = require('path');
const runBuildLambda = require('../../lib/run-build-lambda'); const runBuildLambda = require('../../lib/run-build-lambda');
@@ -14,7 +13,7 @@ it(
const { buildResult } = await runBuildForFolder('airtable'); const { buildResult } = await runBuildForFolder('airtable');
expect(buildResult.output['index.js']).toBeDefined(); expect(buildResult.output['index.js']).toBeDefined();
}, },
TWO_MINUTES, TWO_MINUTES
); );
it( it(
@@ -23,7 +22,7 @@ it(
const { buildResult } = await runBuildForFolder('aws-sdk'); const { buildResult } = await runBuildForFolder('aws-sdk');
expect(buildResult.output['index.js']).toBeDefined(); expect(buildResult.output['index.js']).toBeDefined();
}, },
TWO_MINUTES, TWO_MINUTES
); );
it( it(
@@ -32,7 +31,7 @@ it(
const { buildResult } = await runBuildForFolder('axios'); const { buildResult } = await runBuildForFolder('axios');
expect(buildResult.output['index.js']).toBeDefined(); expect(buildResult.output['index.js']).toBeDefined();
}, },
TWO_MINUTES, TWO_MINUTES
); );
it( it(
@@ -41,5 +40,5 @@ it(
const { buildResult } = await runBuildForFolder('mongoose'); const { buildResult } = await runBuildForFolder('mongoose');
expect(buildResult.output['index.js']).toBeDefined(); expect(buildResult.output['index.js']).toBeDefined();
}, },
TWO_MINUTES, TWO_MINUTES
); );

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const mongoose = require('mongoose'); const mongoose = require('mongoose');
module.exports = (req, res) => { module.exports = (req, res) => {

View File

@@ -1,4 +1,3 @@
/* global expect */
const getWritableDirectory = require('../../packages/now-build-utils/fs/get-writable-directory.js'); const getWritableDirectory = require('../../packages/now-build-utils/fs/get-writable-directory.js');
const glob = require('../../packages/now-build-utils/fs/glob.js'); const glob = require('../../packages/now-build-utils/fs/glob.js');
@@ -20,13 +19,14 @@ async function runBuildLambda(inputPath) {
expect(build.src.includes('*')).toBeFalsy(); expect(build.src.includes('*')).toBeFalsy();
const entrypoint = build.src.replace(/^\//, ''); // strip leftmost slash const entrypoint = build.src.replace(/^\//, ''); // strip leftmost slash
expect(inputFiles[entrypoint]).toBeDefined(); expect(inputFiles[entrypoint]).toBeDefined();
inputFiles[entrypoint].digest = 'this-is-a-fake-digest-for-non-default-analyze'; inputFiles[entrypoint].digest =
'this-is-a-fake-digest-for-non-default-analyze';
const wrapper = require(build.use); const wrapper = require(build.use);
const analyzeResult = runAnalyze(wrapper, { const analyzeResult = runAnalyze(wrapper, {
files: inputFiles, files: inputFiles,
entrypoint, entrypoint,
config: build.config, config: build.config
}); });
const workPath = await getWritableDirectory(); const workPath = await getWritableDirectory();
@@ -34,7 +34,7 @@ async function runBuildLambda(inputPath) {
files: inputFiles, files: inputFiles,
entrypoint, entrypoint,
config: build.config, config: build.config,
workPath, workPath
}); });
const { output } = buildResult; const { output } = buildResult;
@@ -43,16 +43,16 @@ async function runBuildLambda(inputPath) {
buildResult.output = Object.keys(output).reduce( buildResult.output = Object.keys(output).reduce(
(result, path) => ({ (result, path) => ({
...result, ...result,
[path.replace(/\\/g, '/')]: output[path], [path.replace(/\\/g, '/')]: output[path]
}), }),
{}, {}
); );
} }
return { return {
analyzeResult, analyzeResult,
buildResult, buildResult,
workPath, workPath
}; };
} }

808
yarn.lock

File diff suppressed because it is too large Load Diff