-
Notifications
You must be signed in to change notification settings - Fork 35
feat: add pure ESM support to esbuild and default bundlers #1018
Changes from 5 commits
a468380
8e0c725
12df5fb
419c6c0
0e95b0f
2245a95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,11 +4,12 @@ import { build, Metafile } from '@netlify/esbuild' | |
import { tmpName } from 'tmp-promise' | ||
|
||
import type { FunctionConfig } from '../../../../config.js' | ||
import { FeatureFlags } from '../../../../feature_flags.js' | ||
import { getPathWithExtension, safeUnlink } from '../../../../utils/fs.js' | ||
import type { RuntimeName } from '../../../runtime.js' | ||
import type { NodeBundlerName } from '../index.js' | ||
|
||
import { getBundlerTarget } from './bundler_target.js' | ||
import { getBundlerTarget, getModuleFormat } from './bundler_target.js' | ||
import { getDynamicImportsPlugin } from './plugin_dynamic_imports.js' | ||
import { getNativeModulesPlugin } from './plugin_native_modules.js' | ||
import { getNodeBuiltinPlugin } from './plugin_node_builtin.js' | ||
|
@@ -28,6 +29,7 @@ export const bundleJsFile = async function ({ | |
basePath, | ||
config, | ||
externalModules = [], | ||
featureFlags, | ||
ignoredModules = [], | ||
name, | ||
srcDir, | ||
|
@@ -37,6 +39,7 @@ export const bundleJsFile = async function ({ | |
basePath?: string | ||
config: FunctionConfig | ||
externalModules: string[] | ||
featureFlags: FeatureFlags | ||
ignoredModules: string[] | ||
name: string | ||
srcDir: string | ||
|
@@ -84,11 +87,21 @@ export const bundleJsFile = async function ({ | |
// URLs, not paths, so even on Windows they should use forward slashes. | ||
const sourceRoot = targetDirectory.replace(/\\/g, '/') | ||
|
||
// Configuring the output format of esbuild. The `includedFiles` array we get | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We were not including a |
||
// here contains additional paths to include with the bundle, like the path | ||
// to a `package.json` with {"type": "module"} in case of an ESM function. | ||
const { includedFiles: includedFilesFromModuleDetection, moduleFormat } = await getModuleFormat( | ||
srcDir, | ||
featureFlags, | ||
config.nodeVersion, | ||
) | ||
|
||
try { | ||
const { metafile = { inputs: {}, outputs: {} }, warnings } = await build({ | ||
bundle: true, | ||
entryPoints: [srcFile], | ||
external, | ||
format: moduleFormat, | ||
logLevel: 'warning', | ||
logLimit: ESBUILD_LOG_LIMIT, | ||
metafile: true, | ||
|
@@ -108,12 +121,14 @@ export const bundleJsFile = async function ({ | |
}) | ||
const inputs = Object.keys(metafile.inputs).map((path) => resolve(path)) | ||
const cleanTempFiles = getCleanupFunction([...bundlePaths.keys()]) | ||
const additionalPaths = [...dynamicImportsIncludedPaths, ...includedFilesFromModuleDetection] | ||
|
||
return { | ||
additionalPaths: [...dynamicImportsIncludedPaths], | ||
additionalPaths, | ||
bundlePaths, | ||
cleanTempFiles, | ||
inputs, | ||
moduleFormat, | ||
nativeNodeModules, | ||
nodeModulesWithDynamicImports: [...nodeModulesWithDynamicImports], | ||
warnings, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
const DEFAULT_VERSION = 'node12' | ||
import { FeatureFlags } from '../../../../feature_flags' | ||
import { ModuleFormat } from '../../utils/module_format' | ||
import { DEFAULT_NODE_VERSION, getNodeSupportMatrix } from '../../utils/node_version' | ||
import { getClosestPackageJson } from '../../utils/package_json' | ||
|
||
const versionMap = { | ||
'8.x': 'node8', | ||
|
@@ -10,18 +13,41 @@ const versionMap = { | |
type VersionKeys = keyof typeof versionMap | ||
type VersionValues = typeof versionMap[VersionKeys] | ||
|
||
export const getBundlerTarget = (suppliedVersion?: string): VersionValues => { | ||
const getBundlerTarget = (suppliedVersion?: string): VersionValues => { | ||
const version = normalizeVersion(suppliedVersion) | ||
|
||
if (version && version in versionMap) { | ||
return versionMap[version as VersionKeys] | ||
} | ||
|
||
return DEFAULT_VERSION | ||
return versionMap[`${DEFAULT_NODE_VERSION}.x`] | ||
} | ||
|
||
const getModuleFormat = async ( | ||
srcDir: string, | ||
featureFlags: FeatureFlags, | ||
configVersion?: string, | ||
): Promise<{ includedFiles: string[]; moduleFormat: ModuleFormat }> => { | ||
const packageJsonFile = await getClosestPackageJson(srcDir) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why we introduce + use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, somehow missed this reply. agree! I'll work on that. |
||
const nodeSupport = getNodeSupportMatrix(configVersion) | ||
|
||
if (featureFlags.zisi_pure_esm && packageJsonFile?.contents.type === 'module' && nodeSupport.esm) { | ||
return { | ||
includedFiles: [packageJsonFile.path], | ||
moduleFormat: 'esm', | ||
} | ||
} | ||
|
||
return { | ||
includedFiles: [], | ||
moduleFormat: 'cjs', | ||
} | ||
} | ||
|
||
const normalizeVersion = (version?: string) => { | ||
const match = version && version.match(/^nodejs(.*)$/) | ||
|
||
return match ? match[1] : version | ||
} | ||
|
||
export { getBundlerTarget, getModuleFormat } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This determines whether we'll look at a
.js
file and figure out whether it's CJS or ESM.