Skip to content

Commit b4cb75b

Browse files
biruwonpieh
andauthored
fix: make large lambda warning message more informative (#2057)
* fix: make large lambda warning message more informative * chore: added unit tests for size warning * test: fix verification unit tests --------- Co-authored-by: Michal Piechowiak <[email protected]>
1 parent 940cbbc commit b4cb75b

File tree

3 files changed

+78
-16
lines changed

3 files changed

+78
-16
lines changed

packages/runtime/src/constants.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ export const CATCH_ALL_REGEX = /\/\[\.{3}(.*)](.json)?$/
2727
export const OPTIONAL_CATCH_ALL_REGEX = /\/\[{2}\.{3}(.*)]{2}(.json)?$/
2828
export const DYNAMIC_PARAMETER_REGEX = /\/\[(.*?)]/g
2929
export const MINIMUM_REVALIDATE_SECONDS = 60
30-
// 50MB, which is the documented max, though the hard max seems to be higher
31-
export const LAMBDA_MAX_SIZE = 1024 * 1024 * 50
30+
// 50MB, which is the warning max
31+
export const LAMBDA_WARNING_SIZE = 1024 * 1024 * 50
32+
// 250MB, which is the hard max
33+
export const LAMBDA_MAX_SIZE = 1024 * 1024 * 250
3234

3335
export const DIVIDER = `
3436
────────────────────────────────────────────────────────────────

packages/runtime/src/helpers/verification.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { existsSync, promises } from 'fs'
22
import path, { relative, join } from 'path'
33

44
import type { NetlifyConfig, NetlifyPluginUtils } from '@netlify/build'
5-
import { yellowBright, greenBright, blueBright, redBright, reset } from 'chalk'
5+
import { yellowBright, greenBright, blueBright, reset } from 'chalk'
66
import { async as StreamZip } from 'node-stream-zip'
77
import { outdent } from 'outdent'
88
import prettyBytes from 'pretty-bytes'
99
import { satisfies } from 'semver'
1010

11-
import { LAMBDA_MAX_SIZE } from '../constants'
11+
import { LAMBDA_MAX_SIZE, LAMBDA_WARNING_SIZE } from '../constants'
1212

1313
import { isBundleSizeCheckDisabled } from './utils'
1414

@@ -105,7 +105,11 @@ export const checkForRootPublish = ({
105105
}
106106
}
107107

108-
export const checkZipSize = async (file: string, maxSize: number = LAMBDA_MAX_SIZE): Promise<void> => {
108+
export const checkZipSize = async (
109+
file: string,
110+
maxSize: number = LAMBDA_MAX_SIZE,
111+
warningSize: number = LAMBDA_WARNING_SIZE,
112+
): Promise<void> => {
109113
// Requires contacting the Netlify Support team to fully enable.
110114
// Enabling this without contacting them can result in failed deploys.
111115
if (isBundleSizeCheckDisabled()) {
@@ -120,15 +124,16 @@ export const checkZipSize = async (file: string, maxSize: number = LAMBDA_MAX_SI
120124
return
121125
}
122126
const fileSize = await promises.stat(file).then(({ size }) => size)
123-
if (fileSize < maxSize) {
127+
if (fileSize < warningSize) {
124128
return
125129
}
126130
// We don't fail the build, because the actual hard max size is larger so it might still succeed
127131
console.log(
128-
redBright(outdent`
129-
The function zip ${yellowBright(relative(process.cwd(), file))} size is ${prettyBytes(
132+
yellowBright(outdent`
133+
The function zip ${blueBright(relative(process.cwd(), file))} size is ${prettyBytes(
130134
fileSize,
131-
)}, which is larger than the maximum supported size of ${prettyBytes(maxSize)}.
135+
)}, which is larger than the recommended maximum size of ${prettyBytes(warningSize)}.
136+
This will fail the build if the unzipped size is bigger than the maximum size of ${prettyBytes(maxSize)}.
132137
There are a few reasons this could happen. You may have accidentally bundled a large dependency, or you might have a
133138
large number of pre-rendered pages included.
134139
`),

test/helpers/verification.spec.ts

+62-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import Chance from 'chance'
2-
import { checkNextSiteHasBuilt, checkZipSize, getProblematicUserRewrites } from '../../packages/runtime/src/helpers/verification'
2+
import {
3+
checkNextSiteHasBuilt,
4+
checkZipSize,
5+
getProblematicUserRewrites,
6+
} from '../../packages/runtime/src/helpers/verification'
37
import { outdent } from 'outdent'
48
import type { NetlifyPluginOptions } from '@netlify/build'
5-
import { describeCwdTmpDir, moveNextDist } from "../test-utils"
9+
import { describeCwdTmpDir, moveNextDist } from '../test-utils'
610

7-
const netlifyConfig = { build: { command: 'npm run build' }, functions: {}, redirects: [], headers: [] } as NetlifyPluginOptions["netlifyConfig"]
11+
const netlifyConfig = {
12+
build: { command: 'npm run build' },
13+
functions: {},
14+
redirects: [],
15+
headers: [],
16+
} as NetlifyPluginOptions['netlifyConfig']
817

918
import type { NetlifyPluginUtils } from '@netlify/build'
1019
type FailBuild = NetlifyPluginUtils['build']['failBuild']
@@ -18,6 +27,12 @@ jest.mock('fs', () => {
1827
}
1928
})
2029

30+
// disable chalk colors to easier validate console text output
31+
jest.mock(`chalk`, () => {
32+
process.env.FORCE_COLOR = '0'
33+
return jest.requireActual('chalk')
34+
})
35+
2136
describe('checkNextSiteHasBuilt', () => {
2237
let failBuildMock
2338
const { existsSync } = require('fs')
@@ -88,24 +103,64 @@ describe('checkNextSiteHasBuilt', () => {
88103
})
89104

90105
describe('checkZipSize', () => {
91-
let consoleSpy
106+
let consoleWarnSpy, consoleLogSpy
107+
const { existsSync, promises } = require('fs')
92108

93109
beforeEach(() => {
94-
consoleSpy = jest.spyOn(global.console, 'warn')
110+
consoleWarnSpy = jest.spyOn(global.console, 'warn')
111+
consoleWarnSpy.mockClear()
112+
consoleLogSpy = jest.spyOn(global.console, 'log')
113+
consoleLogSpy.mockClear()
114+
process.env.DISABLE_BUNDLE_ZIP_SIZE_CHECK = 'false'
95115
})
96116

97117
afterEach(() => {
98118
delete process.env.DISABLE_BUNDLE_ZIP_SIZE_CHECK
99119
})
100120

121+
afterAll(() => {
122+
consoleWarnSpy.mockReset()
123+
consoleLogSpy.mockReset()
124+
existsSync.mockReset()
125+
})
126+
101127
it('emits a warning that DISABLE_BUNDLE_ZIP_SIZE_CHECK was enabled', async () => {
102128
process.env.DISABLE_BUNDLE_ZIP_SIZE_CHECK = 'true'
103129
await checkZipSize(chance.string())
104-
expect(consoleSpy).toHaveBeenCalledWith('Function bundle size check was DISABLED with the DISABLE_BUNDLE_ZIP_SIZE_CHECK environment variable. Your deployment will break if it exceeds the maximum supported size of function zip files in your account.')
130+
expect(consoleWarnSpy).toHaveBeenCalledWith(
131+
'Function bundle size check was DISABLED with the DISABLE_BUNDLE_ZIP_SIZE_CHECK environment variable. Your deployment will break if it exceeds the maximum supported size of function zip files in your account.',
132+
)
133+
})
134+
135+
it('does not emit a warning if the file size is below the warning size', async () => {
136+
existsSync.mockReturnValue(true)
137+
jest.spyOn(promises, 'stat').mockResolvedValue({ size: 1024 * 1024 * 20 })
138+
139+
await checkZipSize('some-file.zip')
140+
141+
expect(consoleWarnSpy).not.toHaveBeenCalled()
142+
})
143+
144+
it('emits a warning if the file size is above the warning size', async () => {
145+
existsSync.mockReturnValue(true)
146+
jest.spyOn(promises, 'stat').mockResolvedValue({ size: 1024 * 1024 * 200 })
147+
148+
try {
149+
await checkZipSize('some-file.zip')
150+
} catch (e) {
151+
// StreamZip is not mocked, so ultimately the call will throw an error,
152+
// but we are logging message before that so we can assert it
153+
}
154+
155+
expect(consoleLogSpy).toHaveBeenCalledWith(
156+
expect.stringContaining(
157+
'The function zip some-file.zip size is 210 MB, which is larger than the recommended maximum size of 52.4 MB.',
158+
),
159+
)
105160
})
106161
})
107162

108-
describeCwdTmpDir("getProblematicUserRewrites", () => {
163+
describeCwdTmpDir('getProblematicUserRewrites', () => {
109164
it('finds problematic user rewrites', async () => {
110165
await moveNextDist()
111166
const rewrites = getProblematicUserRewrites({

0 commit comments

Comments
 (0)