Skip to content

Commit

Permalink
fix: annotate ISC errors and split into to separate errors (#1146)
Browse files Browse the repository at this point in the history
* fix: annotate ISC errors and split into to separate errors

* chore: refactor all other places

* chore: remove unused function and fix types

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
danez and kodiakhq[bot] committed Jul 18, 2022
1 parent b0048a4 commit ca005ba
Show file tree
Hide file tree
Showing 23 changed files with 185 additions and 141 deletions.
2 changes: 1 addition & 1 deletion src/config.ts
@@ -1,7 +1,7 @@
import mergeOptions from 'merge-options'

import { FunctionSource } from './function.js'
import type { NodeBundlerName } from './runtimes/node/bundlers/index.js'
import type { NodeBundlerName } from './runtimes/node/bundlers/types.js'
import type { NodeVersionString } from './runtimes/node/index.js'
import { minimatch } from './utils/matching.js'

Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Expand Up @@ -39,7 +39,7 @@ const augmentWithISC = async (func: FunctionSource): Promise<AugmentedFunctionSo
return func
}

const inSourceConfig = await findISCDeclarationsInPath(func.mainFile)
const inSourceConfig = await findISCDeclarationsInPath(func.mainFile, func.name)

return { ...func, inSourceConfig }
}
Expand Down
8 changes: 2 additions & 6 deletions src/runtimes/go/builder.ts
@@ -1,8 +1,8 @@
import { promises as fs } from 'fs'
import { basename } from 'path'

import { FunctionBundlingUserError } from '../../utils/error.js'
import { shellUtils } from '../../utils/shell.js'
import type { RuntimeName } from '../runtime.js'

export const build = async ({ destPath, mainFile, srcDir }: { destPath: string; mainFile: string; srcDir: string }) => {
const functionName = basename(srcDir)
Expand All @@ -17,13 +17,9 @@ export const build = async ({ destPath, mainFile, srcDir }: { destPath: string;
},
})
} catch (error) {
const runtime: RuntimeName = 'go'

error.customErrorInfo = { type: 'functionsBundling', location: { functionName, runtime } }

console.error(`Could not compile Go function ${functionName}:\n`)

throw error
throw new FunctionBundlingUserError(error, { functionName, runtime: 'go' })
}

const stat = await fs.lstat(destPath)
Expand Down
13 changes: 2 additions & 11 deletions src/runtimes/node/bundlers/esbuild/bundler.ts
Expand Up @@ -5,9 +5,8 @@ import { tmpName } from 'tmp-promise'

import type { FunctionConfig } from '../../../../config.js'
import { FeatureFlags } from '../../../../feature_flags.js'
import { FunctionBundlingUserError } from '../../../../utils/error.js'
import { getPathWithExtension, safeUnlink } from '../../../../utils/fs.js'
import type { RuntimeName } from '../../../runtime.js'
import type { NodeBundlerName } from '../index.js'

import { getBundlerTarget, getModuleFormat } from './bundler_target.js'
import { getDynamicImportsPlugin } from './plugin_dynamic_imports.js'
Expand Down Expand Up @@ -134,15 +133,7 @@ export const bundleJsFile = async function ({
warnings,
}
} catch (error) {
const bundler: NodeBundlerName = 'esbuild'
const runtime: RuntimeName = 'js'

error.customErrorInfo = {
type: 'functionsBundling',
location: { bundler, functionName: name, runtime },
}

throw error
throw new FunctionBundlingUserError(error, { functionName: name, runtime: 'js', bundler: 'esbuild' })
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/runtimes/node/bundlers/esbuild/index.ts
Expand Up @@ -4,7 +4,7 @@ import type { FunctionConfig } from '../../../../config.js'
import { getPathWithExtension } from '../../../../utils/fs.js'
import { nonNullable } from '../../../../utils/non_nullable.js'
import { getBasePath } from '../../utils/base_path.js'
import type { BundleFunction } from '../index.js'
import type { BundleFunction } from '../types.js'

import { bundleJsFile } from './bundler.js'
import { getExternalAndIgnoredModulesFromSpecialCases } from './special_cases.js'
Expand Down
Expand Up @@ -5,7 +5,7 @@ import readPackageJson from 'read-package-json-fast'

import { isNativeModule } from '../../utils/detect_native_module.js'
import { PackageJson } from '../../utils/package_json.js'
import type { NativeNodeModules } from '../index.js'
import type { NativeNodeModules } from '../types.js'

type NativeModuleCacheEntry = [boolean | undefined, PackageJson]
type NativeModuleCache = Record<string, Promise<NativeModuleCacheEntry>>
Expand Down
2 changes: 1 addition & 1 deletion src/runtimes/node/bundlers/esbuild/src_files.ts
@@ -1,7 +1,7 @@
import { filterExcludedPaths, getPathsOfIncludedFiles } from '../../utils/included_files.js'
import { getPackageJson, PackageJson } from '../../utils/package_json.js'
import { getNewCache, TraversalCache } from '../../utils/traversal_cache.js'
import type { GetSrcFilesFunction } from '../index.js'
import type { GetSrcFilesFunction } from '../types.js'
import { getDependencyPathsForDependency } from '../zisi/traverse.js'

export const getSrcFiles: GetSrcFilesFunction = async ({ config, mainFile, pluginsModulesPath, srcDir }) => {
Expand Down
72 changes: 2 additions & 70 deletions src/runtimes/node/bundlers/index.ts
@@ -1,79 +1,11 @@
import type { Message } from '@netlify/esbuild'

import { FunctionConfig } from '../../../config.js'
import { FeatureFlag, FeatureFlags } from '../../../feature_flags.js'
import { FunctionSource } from '../../../function.js'
import { FeatureFlags } from '../../../feature_flags.js'
import { detectEsModule } from '../utils/detect_es_module.js'
import { ModuleFormat } from '../utils/module_format.js'

import esbuildBundler from './esbuild/index.js'
import nftBundler from './nft/index.js'
import type { NodeBundler, NodeBundlerName } from './types.js'
import zisiBundler from './zisi/index.js'

export type NodeBundlerName = 'esbuild' | 'esbuild_zisi' | 'nft' | 'zisi'

// TODO: Create a generic warning type
type BundlerWarning = Message

type CleanupFunction = () => Promise<void>

export type NativeNodeModules = Record<string, Record<string, string | undefined>>

export type BundleFunction = (
args: {
basePath?: string
config: FunctionConfig
featureFlags: Record<FeatureFlag, boolean>
pluginsModulesPath?: string
repositoryRoot?: string
} & FunctionSource,
) => Promise<{
// Aliases are used to change the path that a file should take inside the
// generated archive. For example:
//
// "/my-transpiled-function.js" => "/my-function.js"
//
// When "/my-transpiled-function.js" is found in the list of files, it will
// be added to the archive with the "/my-function.js" path.
aliases?: Map<string, string>

// Rewrites are used to change the source file associated with a given path.
// For example:
//
// "/my-function.js" => "console.log(`Hello!`)"
//
// When "/my-function.js" is found in the list of files, it will be added to
// the archive with "console.log(`Hello!`)" as its source, replacing whatever
// the file at "/my-function.js" contains.
rewrites?: Map<string, string>

basePath: string
bundlerWarnings?: BundlerWarning[]
cleanupFunction?: CleanupFunction
includedFiles: string[]
inputs: string[]
mainFile: string
moduleFormat: ModuleFormat
nativeNodeModules?: NativeNodeModules
nodeModulesWithDynamicImports?: string[]
srcFiles: string[]
}>

export type GetSrcFilesFunction = (
args: {
basePath?: string
config: FunctionConfig
featureFlags: FeatureFlags
pluginsModulesPath?: string
repositoryRoot?: string
} & FunctionSource,
) => Promise<{ srcFiles: string[]; includedFiles: string[] }>

interface NodeBundler {
bundle: BundleFunction
getSrcFiles: GetSrcFilesFunction
}

export const getBundler = (name: NodeBundlerName): NodeBundler => {
switch (name) {
case 'esbuild':
Expand Down
2 changes: 1 addition & 1 deletion src/runtimes/node/bundlers/nft/index.ts
Expand Up @@ -9,7 +9,7 @@ import { cachedReadFile, FsCache } from '../../../../utils/fs.js'
import { minimatch } from '../../../../utils/matching.js'
import { getBasePath } from '../../utils/base_path.js'
import { filterExcludedPaths, getPathsOfIncludedFiles } from '../../utils/included_files.js'
import type { GetSrcFilesFunction, BundleFunction } from '../index.js'
import type { GetSrcFilesFunction, BundleFunction } from '../types.js'

import { processESM } from './es_modules.js'

Expand Down
13 changes: 2 additions & 11 deletions src/runtimes/node/bundlers/nft/transpile.ts
@@ -1,9 +1,8 @@
import { build } from '@netlify/esbuild'

import type { FunctionConfig } from '../../../../config.js'
import type { RuntimeName } from '../../../runtime.js'
import { FunctionBundlingUserError } from '../../../../utils/error.js'
import { getBundlerTarget } from '../esbuild/bundler_target.js'
import type { NodeBundlerName } from '../index.js'

export const transpile = async (path: string, config: FunctionConfig, functionName: string) => {
// The version of ECMAScript to use as the build target. This will determine
Expand All @@ -24,14 +23,6 @@ export const transpile = async (path: string, config: FunctionConfig, functionNa

return transpiled.outputFiles[0].text
} catch (error) {
const bundler: NodeBundlerName = 'nft'
const runtime: RuntimeName = 'js'

error.customErrorInfo = {
type: 'functionsBundling',
location: { bundler, functionName, runtime },
}

throw error
throw new FunctionBundlingUserError(error, { functionName, runtime: 'js', bundler: 'nft' })
}
}
70 changes: 70 additions & 0 deletions src/runtimes/node/bundlers/types.ts
@@ -0,0 +1,70 @@
import type { Message } from '@netlify/esbuild'

import type { FunctionConfig } from '../../../config.js'
import type { FeatureFlag, FeatureFlags } from '../../../feature_flags.js'
import type { FunctionSource } from '../../../function.js'
import type { ModuleFormat } from '../utils/module_format.js'

export type NodeBundlerName = 'esbuild' | 'esbuild_zisi' | 'nft' | 'zisi'

// TODO: Create a generic warning type
type BundlerWarning = Message

type CleanupFunction = () => Promise<void>

export type NativeNodeModules = Record<string, Record<string, string | undefined>>

export type BundleFunction = (
args: {
basePath?: string
config: FunctionConfig
featureFlags: Record<FeatureFlag, boolean>
pluginsModulesPath?: string
repositoryRoot?: string
} & FunctionSource,
) => Promise<{
// Aliases are used to change the path that a file should take inside the
// generated archive. For example:
//
// "/my-transpiled-function.js" => "/my-function.js"
//
// When "/my-transpiled-function.js" is found in the list of files, it will
// be added to the archive with the "/my-function.js" path.
aliases?: Map<string, string>

// Rewrites are used to change the source file associated with a given path.
// For example:
//
// "/my-function.js" => "console.log(`Hello!`)"
//
// When "/my-function.js" is found in the list of files, it will be added to
// the archive with "console.log(`Hello!`)" as its source, replacing whatever
// the file at "/my-function.js" contains.
rewrites?: Map<string, string>

basePath: string
bundlerWarnings?: BundlerWarning[]
cleanupFunction?: CleanupFunction
includedFiles: string[]
inputs: string[]
mainFile: string
moduleFormat: ModuleFormat
nativeNodeModules?: NativeNodeModules
nodeModulesWithDynamicImports?: string[]
srcFiles: string[]
}>

export type GetSrcFilesFunction = (
args: {
basePath?: string
config: FunctionConfig
featureFlags: FeatureFlags
pluginsModulesPath?: string
repositoryRoot?: string
} & FunctionSource,
) => Promise<{ srcFiles: string[]; includedFiles: string[] }>

export interface NodeBundler {
bundle: BundleFunction
getSrcFiles: GetSrcFilesFunction
}
2 changes: 1 addition & 1 deletion src/runtimes/node/bundlers/zisi/index.ts
@@ -1,7 +1,7 @@
import { dirname, normalize } from 'path'

import { getBasePath } from '../../utils/base_path.js'
import type { BundleFunction } from '../index.js'
import type { BundleFunction } from '../types.js'

import { getSrcFiles } from './src_files.js'

Expand Down
13 changes: 2 additions & 11 deletions src/runtimes/node/bundlers/zisi/list_imports.ts
Expand Up @@ -2,9 +2,8 @@ import * as esbuild from '@netlify/esbuild'
import isBuiltinModule from 'is-builtin-module'
import { tmpName } from 'tmp-promise'

import { FunctionBundlingUserError } from '../../../../utils/error.js'
import { safeUnlink } from '../../../../utils/fs.js'
import type { RuntimeName } from '../../../runtime.js'
import type { NodeBundlerName } from '../index.js'

// Maximum number of log messages that an esbuild instance will produce. This
// limit is important to avoid out-of-memory errors due to too much data being
Expand Down Expand Up @@ -58,15 +57,7 @@ export const listImports = async ({
target: 'esnext',
})
} catch (error) {
const bundler: NodeBundlerName = 'zisi'
const runtime: RuntimeName = 'js'

error.customErrorInfo = {
type: 'functionsBundling',
location: { bundler, functionName, runtime },
}

throw error
throw new FunctionBundlingUserError(error, { functionName, runtime: 'js', bundler: 'zisi' })
} finally {
await safeUnlink(targetPath)
}
Expand Down
2 changes: 1 addition & 1 deletion src/runtimes/node/bundlers/zisi/src_files.ts
Expand Up @@ -9,7 +9,7 @@ import { nonNullable } from '../../../../utils/non_nullable.js'
import { filterExcludedPaths, getPathsOfIncludedFiles } from '../../utils/included_files.js'
import { getPackageJson, PackageJson } from '../../utils/package_json.js'
import { getNewCache, TraversalCache } from '../../utils/traversal_cache.js'
import type { GetSrcFilesFunction } from '../index.js'
import type { GetSrcFilesFunction } from '../types.js'

import { listImports } from './list_imports.js'
import { resolvePathPreserveSymlinks } from './resolve.js'
Expand Down

1 comment on commit ca005ba

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⏱ Benchmark results

largeDepsEsbuild: 6s

largeDepsNft: 29.8s

largeDepsZisi: 44.2s

Please sign in to comment.