Skip to content
This repository was archived by the owner on May 22, 2024. It is now read-only.

Commit b5286b3

Browse files
authoredApr 11, 2023
feat: add new runtimeVersion to manifest (#1367)
* feat: add new runtimeName to manifest * chore: increase test timeout * chore: fix docs * chore: rename field
1 parent f9e621b commit b5286b3

14 files changed

+128
-99
lines changed
 

‎README.md

+7-8
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,15 @@ The following properties are accepted:
128128
- `nodeVersion`
129129

130130
- _Type_: `string`\
131-
- _Default value_: `16.x`
131+
- _Default value_: `16`
132132

133-
The version of Node.js to use as the compilation target. Possible values:
133+
The version of Node.js to use as the compilation target for bundlers. This is also used to determine the runtime
134+
reported in the manifest. Any valid and supported Node.js version is accepted. Examples:
134135

135-
- `8.x` (or `nodejs8.x`)
136-
- `10.x` (or `nodejs10.x`)
137-
- `12.x` (or `nodejs12.x`)
138-
- `14.x` (or `nodejs14.x`)
139-
- `16.x` (or `nodejs16.x`)
140-
- `18.x` (or `nodejs18.x`)
136+
- `14.x`
137+
- `16.1.0`
138+
- `v18`
139+
- `nodejs18.x` (for backwards compatibility)
141140

142141
- `rustTargetDirectory`
143142

‎src/config.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import mergeOptions from 'merge-options'
77

88
import { FunctionSource } from './function.js'
99
import type { NodeBundlerType } from './runtimes/node/bundlers/types.js'
10-
import type { NodeVersionString } from './runtimes/node/index.js'
1110
import type { ModuleFormat } from './runtimes/node/utils/module_format.js'
1211
import { minimatch } from './utils/matching.js'
1312

@@ -18,7 +17,7 @@ interface FunctionConfig {
1817
ignoredNodeModules?: string[]
1918
nodeBundler?: NodeBundlerType
2019
nodeSourcemap?: boolean
21-
nodeVersion?: NodeVersionString
20+
nodeVersion?: string
2221
processDynamicNodeImports?: boolean
2322
rustTargetDirectory?: string
2423
schedule?: string

‎src/manifest.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface ManifestFunction {
99
name: string
1010
path: string
1111
runtime: string
12+
runtimeVersion?: string
1213
schedule?: string
1314
displayName?: string
1415
bundler?: string
@@ -40,21 +41,23 @@ export const createManifest = async ({ functions, path }: { functions: FunctionR
4041
}
4142

4243
const formatFunctionForManifest = ({
44+
bundler,
45+
displayName,
46+
generator,
4347
mainFile,
4448
name,
4549
path,
4650
runtime,
51+
runtimeVersion,
4752
schedule,
48-
displayName,
53+
}: FunctionResult): ManifestFunction => ({
4954
bundler,
55+
displayName,
5056
generator,
51-
}: FunctionResult): ManifestFunction => ({
5257
mainFile,
5358
name,
59+
runtimeVersion,
5460
path: resolve(path),
5561
runtime,
5662
schedule,
57-
displayName,
58-
bundler,
59-
generator,
6063
})
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,24 @@
11
import { FeatureFlags } from '../../../../feature_flags.js'
22
import { ModuleFileExtension, ModuleFormat } from '../../utils/module_format.js'
3-
import {
4-
DEFAULT_NODE_VERSION,
5-
getNodeSupportMatrix,
6-
NodeVersionString,
7-
ShortNodeVersionString,
8-
} from '../../utils/node_version.js'
3+
import { DEFAULT_NODE_VERSION, getNodeSupportMatrix, parseVersion } from '../../utils/node_version.js'
94
import { getClosestPackageJson } from '../../utils/package_json.js'
105

116
const versionMap = {
12-
'8.x': 'node8',
13-
'10.x': 'node10',
14-
'12.x': 'node12',
15-
'14.x': 'node14',
16-
'16.x': 'node16',
17-
'18.x': 'node18',
7+
14: 'node14',
8+
16: 'node16',
9+
18: 'node18',
1810
} as const
1911

2012
type VersionValues = (typeof versionMap)[keyof typeof versionMap]
2113

22-
const getBundlerTarget = (suppliedVersion?: NodeVersionString): VersionValues => {
23-
const version = normalizeVersion(suppliedVersion)
14+
const getBundlerTarget = (suppliedVersion?: string): VersionValues => {
15+
const version = parseVersion(suppliedVersion)
2416

2517
if (version && version in versionMap) {
26-
return versionMap[version]
18+
return versionMap[version as keyof typeof versionMap]
2719
}
2820

29-
return versionMap[`${DEFAULT_NODE_VERSION}.x`]
21+
return versionMap[DEFAULT_NODE_VERSION]
3022
}
3123

3224
const getModuleFormat = async (
@@ -35,20 +27,22 @@ const getModuleFormat = async (
3527
extension: string,
3628
configVersion?: string,
3729
): Promise<{ includedFiles: string[]; moduleFormat: ModuleFormat }> => {
38-
if (extension === ModuleFileExtension.MJS && featureFlags.zisi_pure_esm_mjs) {
30+
if (featureFlags.zisi_pure_esm_mjs && extension === ModuleFileExtension.MJS) {
3931
return {
4032
includedFiles: [],
4133
moduleFormat: ModuleFormat.ESM,
4234
}
4335
}
4436

45-
const packageJsonFile = await getClosestPackageJson(srcDir)
46-
const nodeSupport = getNodeSupportMatrix(configVersion)
37+
if (featureFlags.zisi_pure_esm) {
38+
const packageJsonFile = await getClosestPackageJson(srcDir)
39+
const nodeSupport = getNodeSupportMatrix(configVersion)
4740

48-
if (featureFlags.zisi_pure_esm && packageJsonFile?.contents.type === 'module' && nodeSupport.esm) {
49-
return {
50-
includedFiles: [packageJsonFile.path],
51-
moduleFormat: ModuleFormat.ESM,
41+
if (packageJsonFile?.contents.type === 'module' && nodeSupport.esm) {
42+
return {
43+
includedFiles: [packageJsonFile.path],
44+
moduleFormat: ModuleFormat.ESM,
45+
}
5246
}
5347
}
5448

@@ -58,10 +52,4 @@ const getModuleFormat = async (
5852
}
5953
}
6054

61-
const normalizeVersion = (version?: NodeVersionString): ShortNodeVersionString | undefined => {
62-
const match = version && (version.match(/^nodejs(.*)$/) as [string, ShortNodeVersionString])
63-
64-
return match ? match[1] : (version as ShortNodeVersionString)
65-
}
66-
6755
export { getBundlerTarget, getModuleFormat }

‎src/runtimes/node/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import { getBundler, getBundlerName } from './bundlers/index.js'
99
import { NodeBundlerType } from './bundlers/types.js'
1010
import { findFunctionsInPaths, findFunctionInPath } from './finder.js'
1111
import { findISCDeclarationsInPath } from './in_source_config/index.js'
12+
import { getNodeRuntime } from './utils/node_runtime.js'
1213
import { createAliases as createPluginsModulesPathAliases, getPluginsModulesPath } from './utils/plugin_modules_path.js'
1314
import { zipNodeJs } from './utils/zip.js'
1415

15-
export { NodeVersionString } from './utils/node_version.js'
16-
1716
// A proxy for the `getSrcFiles` that calls `getSrcFiles` on the bundler
1817
const getSrcFilesWithBundler: GetSrcFilesFunction = async (parameters) => {
1918
const { config, extension, featureFlags, mainFile, srcDir } = parameters
@@ -128,6 +127,7 @@ const zipFunction: ZipFunction = async function ({
128127
nativeNodeModules,
129128
nodeModulesWithDynamicImports,
130129
path: zipPath,
130+
runtimeVersion: getNodeRuntime(config.nodeVersion),
131131
displayName: config?.name,
132132
generator: config?.generator || getInternalValue(isInternal),
133133
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { parseVersion } from './node_version.js'
2+
3+
const validRuntimeMap = {
4+
14: 'nodejs14.x',
5+
16: 'nodejs16.x',
6+
18: 'nodejs18.x',
7+
} as const
8+
9+
export const getNodeRuntime = (input: string | undefined): string | undefined => {
10+
const version = parseVersion(input)
11+
12+
if (!version || !(version in validRuntimeMap)) {
13+
return
14+
}
15+
16+
return validRuntimeMap[version as keyof typeof validRuntimeMap]
17+
}
+3-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
type SupportedVersionNumbers = 8 | 10 | 12 | 14 | 16 | 18
2-
export type ShortNodeVersionString = `${SupportedVersionNumbers}.x`
3-
export type NodeVersionString = ShortNodeVersionString | `nodejs${SupportedVersionNumbers}.x`
1+
import semver from 'semver'
42

53
export interface NodeVersionSupport {
64
esm: boolean
75
}
86

97
// Must match the default version used in Bitballoon.
108
export const DEFAULT_NODE_VERSION = 16
11-
const VERSION_REGEX = /(nodejs)?(\d+)\.x/
129

1310
export const getNodeVersion = (configVersion?: string) => parseVersion(configVersion) ?? DEFAULT_NODE_VERSION
1411

@@ -22,22 +19,10 @@ export const getNodeSupportMatrix = (configVersion?: string): NodeVersionSupport
2219

2320
// Takes a string in the format defined by the `NodeVersion` type and returns
2421
// the numeric major version (e.g. "nodejs14.x" => 14).
25-
export const parseVersion = (input: string | undefined) => {
22+
export const parseVersion = (input: string | undefined): number | undefined => {
2623
if (input === undefined) {
2724
return
2825
}
2926

30-
const match = input.match(VERSION_REGEX)
31-
32-
if (match === null) {
33-
return
34-
}
35-
36-
const version = Number.parseInt(match[2])
37-
38-
if (Number.isNaN(version)) {
39-
return
40-
}
41-
42-
return version
27+
return semver.coerce(input)?.major
4328
}

‎src/runtimes/runtime.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ export interface ZipFunctionResult {
3939
bundlerErrors?: object[]
4040
bundlerWarnings?: object[]
4141
config: FunctionConfig
42+
displayName?: string
43+
generator?: string
4244
inputs?: string[]
4345
includedFiles?: string[]
4446
inSourceConfig?: ISCValues
4547
nativeNodeModules?: object
4648
nodeModulesWithDynamicImports?: string[]
4749
path: string
48-
displayName?: string
49-
generator?: string
50+
runtimeVersion?: string
5051
}
5152

5253
export type ZipFunction = (

‎tests/__snapshots__/main.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
// Vitest Snapshot v1
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`zip-it-and-ship-it > None bundler throws when using ESM on node < 14 > bundler_none 1`] = `"Function file is an ES module, which the Node.js version specified in the config (12.x) does not support. ES modules are supported as of version 14 of Node.js."`;

‎tests/esbuild.test.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { build } from '@netlify/esbuild'
2+
import { afterEach, describe, expect, test, vi } from 'vitest'
3+
4+
import { NodeBundlerType } from '../src/runtimes/node/bundlers/types.js'
5+
6+
import { zipFixture } from './helpers/main.js'
7+
8+
// eslint-disable-next-line import/no-unassigned-import
9+
import 'source-map-support/register'
10+
11+
vi.mock('../src/utils/shell.js', () => ({ shellUtils: { runCommand: vi.fn() } }))
12+
13+
vi.mock('@netlify/esbuild', async () => {
14+
const esbuild = await vi.importActual<any>('@netlify/esbuild')
15+
16+
return {
17+
...esbuild,
18+
build: vi.fn(esbuild.build),
19+
}
20+
})
21+
22+
describe('esbuild', () => {
23+
afterEach(() => {
24+
vi.mocked(build).mockReset()
25+
})
26+
27+
test('Generates a bundle for the Node runtime version specified in the `nodeVersion` config property', async () => {
28+
// Using the optional catch binding feature to assert that the bundle is
29+
// respecting the Node version supplied.
30+
// - in Node <10 we should see `try {} catch (e) {}`
31+
// - in Node >= 10 we should see `try {} catch {}`
32+
await zipFixture('node-module-optional-catch-binding', {
33+
opts: { archiveFormat: 'none', config: { '*': { nodeBundler: NodeBundlerType.ESBUILD, nodeVersion: '18.x' } } },
34+
})
35+
36+
expect(build).toHaveBeenCalledWith(expect.objectContaining({ target: ['node18'] }))
37+
})
38+
})

‎tests/main.test.ts

+1-23
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ describe('zip-it-and-ship-it', () => {
276276
['bundler_default', 'bundler_esbuild', 'bundler_esbuild_zisi'],
277277
async (options) => {
278278
await expect(zipNode('invalid-package-json', { opts: options })).rejects.toThrowError(
279-
/(invalid JSON|package.json:1:1: error: Expected string but found "{")/,
279+
/(invalid json|package.json:1:1: error: expected string but found "{")/i,
280280
)
281281
},
282282
)
@@ -1267,28 +1267,6 @@ describe('zip-it-and-ship-it', () => {
12671267
},
12681268
)
12691269

1270-
test('Generates a bundle for the Node runtime version specified in the `nodeVersion` config property', async () => {
1271-
// Using the optional catch binding feature to assert that the bundle is
1272-
// respecting the Node version supplied.
1273-
// - in Node <10 we should see `try {} catch (e) {}`
1274-
// - in Node >= 10 we should see `try {} catch {}`
1275-
const { files: node8Files } = await zipNode('node-module-optional-catch-binding', {
1276-
opts: { archiveFormat: 'none', config: { '*': { nodeBundler: NodeBundlerType.ESBUILD, nodeVersion: '8.x' } } },
1277-
})
1278-
1279-
const node8Function = await readFile(`${node8Files[0].path}/src/function.js`, 'utf8')
1280-
1281-
expect(node8Function).toMatch(/catch \(\w+\) {/)
1282-
1283-
const { files: node12Files } = await zipNode('node-module-optional-catch-binding', {
1284-
opts: { archiveFormat: 'none', config: { '*': { nodeBundler: NodeBundlerType.ESBUILD, nodeVersion: '12.x' } } },
1285-
})
1286-
1287-
const node12Function = await readFile(`${node12Files[0].path}/src/function.js`, 'utf8')
1288-
1289-
expect(node12Function).toMatch(/catch {/)
1290-
})
1291-
12921270
testMany('Returns an `inputs` property with all the imported paths', [...allBundleConfigs], async (options) => {
12931271
const fixtureName = 'node-module-and-local-imports'
12941272
const { files, tmpDir } = await zipNode(fixtureName, {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { describe, expect, test } from 'vitest'
2+
3+
import { getNodeRuntime } from '../../../../../src/runtimes/node/utils/node_runtime.js'
4+
5+
describe('getNodeRuntime', () => {
6+
test.each([
7+
['nodejs14.x', 'nodejs14.x'],
8+
['nodejs16.x', 'nodejs16.x'],
9+
['nodejs18.x', 'nodejs18.x'],
10+
['14.x', 'nodejs14.x'],
11+
['v16.x', 'nodejs16.x'],
12+
['18.0.0', 'nodejs18.x'],
13+
['v14.2.0', 'nodejs14.x'],
14+
['14.1', 'nodejs14.x'],
15+
[':shrug:', undefined],
16+
])('handles `%s`', (input, expected) => {
17+
expect(getNodeRuntime(input)).toBe(expected)
18+
})
19+
})

‎tests/unit/runtimes/node/utils/node_version.test.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ describe('getNodeVersion', () => {
1010
test.each([
1111
['nodejs14.x', 14],
1212
['nodejs12.x', 12],
13-
['nodejs8.x', 8],
14-
['12.x', 12],
15-
['8.x', 8],
16-
['node16', DEFAULT_NODE_VERSION],
13+
['nodejs16.x', 16],
14+
['18.x', 18],
15+
['node16', 16],
16+
['14.1.1', 14],
17+
['v14.1', 14],
1718
[':shrug:', DEFAULT_NODE_VERSION],
1819
])('handles `%s`', (input, expected) => {
1920
expect(getNodeVersion(input)).toBe(expected)
@@ -24,10 +25,11 @@ describe('parseVersion', () => {
2425
test.each([
2526
['nodejs14.x', 14],
2627
['nodejs12.x', 12],
27-
['nodejs8.x', 8],
28-
['12.x', 12],
29-
['8.x', 8],
30-
['node16', undefined],
28+
['nodejs18.x', 18],
29+
['18.x', 18],
30+
['node14', 14],
31+
['14.1.1', 14],
32+
['v14.1', 14],
3133
[':shrug:', undefined],
3234
])('handles `%s`', (input, expected) => {
3335
expect(parseVersion(input)).toBe(expected)

‎vitest.config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default defineConfig({
55
test: {
66
setupFiles: ['./tests/helpers/vitest_setup.ts'],
77
include: ['tests/**/*.test.ts'],
8-
testTimeout: 30_000,
8+
testTimeout: 60_000,
99
deps: {
1010
external: ['**/fixtures/**', '**/node_modules/**', '**/dist/**'],
1111
interopDefault: false,

1 commit comments

Comments
 (1)

github-actions[bot] commented on Apr 11, 2023

@github-actions[bot]
Contributor

⏱ Benchmark results

  • largeDepsEsbuild: 2.1s
  • largeDepsNft: 8s
  • largeDepsZisi: 15.4s
This repository has been archived.