@netlify/zip-it-and-ship-it 8.2.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,12 +14,8 @@ export const defaultFlags = {
14
14
  zisi_pure_esm_mjs: false,
15
15
  // Load configuration from per-function JSON files.
16
16
  project_deploy_configuration_api_use_per_function_configuration_files: false,
17
- // Enable runtime cache for NFT
18
- zisi_nft_use_cache: false,
19
- // Raise file IO limit for NFT
20
- zisi_nft_higher_fileio_limit: false,
21
- // Provide banner to esbuild which allows requires in ESM output
22
- zisi_esbuild_require_banner: false,
17
+ // Output CJS file extension
18
+ zisi_output_cjs_extension: false,
23
19
  };
24
20
  // List of supported flags and their default value.
25
21
  export const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
@@ -1,6 +1,6 @@
1
1
  import type { FunctionConfig } from '../../../../config.js';
2
2
  import { FeatureFlags } from '../../../../feature_flags.js';
3
- import { ModuleFileExtension, ModuleFormat } from '../../utils/module_format.js';
3
+ import { ModuleFormat } from '../../utils/module_format.js';
4
4
  export declare const ESBUILD_LOG_LIMIT = 10;
5
5
  export declare const bundleJsFile: ({ additionalModulePaths, basePath, config, externalModules, featureFlags, ignoredModules, mainFile, name, srcDir, srcFile, }: {
6
6
  additionalModulePaths?: string[] | undefined;
@@ -17,10 +17,10 @@ export declare const bundleJsFile: ({ additionalModulePaths, basePath, config, e
17
17
  additionalPaths: string[];
18
18
  bundlePaths: Map<string, string>;
19
19
  cleanTempFiles: () => Promise<void>;
20
- extension: ModuleFileExtension;
21
20
  inputs: string[];
22
21
  moduleFormat: ModuleFormat;
23
22
  nativeNodeModules: {};
24
23
  nodeModulesWithDynamicImports: string[];
24
+ outputExtension: import("../../utils/module_format.js").ModuleFileExtension;
25
25
  warnings: import("@netlify/esbuild").Message[];
26
26
  }>;
@@ -56,9 +56,7 @@ export const bundleJsFile = async function ({ additionalModulePaths, basePath, c
56
56
  // to a `package.json` with {"type": "module"} in case of an ESM function.
57
57
  const { includedFiles: includedFilesFromModuleDetection, moduleFormat } = await getModuleFormat(srcDir, featureFlags, extname(mainFile), config.nodeVersion);
58
58
  // The extension of the output file.
59
- const extension = getFileExtensionForFormat(moduleFormat, featureFlags);
60
- // When outputting an ESM file, configure esbuild to produce a `.mjs` file.
61
- const outExtension = moduleFormat === "esm" /* ModuleFormat.ESM */ ? { [".js" /* ModuleFileExtension.JS */]: ".mjs" /* ModuleFileExtension.MJS */ } : undefined;
59
+ const outputExtension = getFileExtensionForFormat(moduleFormat, featureFlags);
62
60
  // We add this banner so that calls to require() still work in ESM modules, especially when importing node built-ins
63
61
  // We have to do this until this is fixed in esbuild: https://github.com/evanw/esbuild/pull/2067
64
62
  const esmJSBanner = `
@@ -71,7 +69,7 @@ export const bundleJsFile = async function ({ additionalModulePaths, basePath, c
71
69
  `;
72
70
  try {
73
71
  const { metafile = { inputs: {}, outputs: {} }, warnings } = await build({
74
- banner: moduleFormat === "esm" /* ModuleFormat.ESM */ && featureFlags.zisi_esbuild_require_banner ? { js: esmJSBanner } : undefined,
72
+ banner: moduleFormat === "esm" /* ModuleFormat.ESM */ ? { js: esmJSBanner } : undefined,
75
73
  bundle: true,
76
74
  entryPoints: [srcFile],
77
75
  external,
@@ -80,8 +78,8 @@ export const bundleJsFile = async function ({ additionalModulePaths, basePath, c
80
78
  logLimit: ESBUILD_LOG_LIMIT,
81
79
  metafile: true,
82
80
  nodePaths: additionalModulePaths,
83
- outExtension,
84
81
  outdir: targetDirectory,
82
+ outExtension: { '.js': outputExtension },
85
83
  platform: 'node',
86
84
  plugins,
87
85
  resolveExtensions: RESOLVE_EXTENSIONS,
@@ -91,9 +89,9 @@ export const bundleJsFile = async function ({ additionalModulePaths, basePath, c
91
89
  });
92
90
  const bundlePaths = getBundlePaths({
93
91
  destFolder: targetDirectory,
94
- extension,
95
92
  outputs: metafile.outputs,
96
93
  srcFile,
94
+ outputExtension,
97
95
  });
98
96
  const inputs = Object.keys(metafile.inputs).map((path) => resolve(path));
99
97
  const cleanTempFiles = getCleanupFunction([...bundlePaths.keys()]);
@@ -102,11 +100,11 @@ export const bundleJsFile = async function ({ additionalModulePaths, basePath, c
102
100
  additionalPaths,
103
101
  bundlePaths,
104
102
  cleanTempFiles,
105
- extension,
106
103
  inputs,
107
104
  moduleFormat,
108
105
  nativeNodeModules,
109
106
  nodeModulesWithDynamicImports: [...nodeModulesWithDynamicImports],
107
+ outputExtension,
110
108
  warnings,
111
109
  };
112
110
  }
@@ -122,7 +120,7 @@ export const bundleJsFile = async function ({ additionalModulePaths, basePath, c
122
120
  // absolute paths of the generated files as keys, and the paths that those
123
121
  // files should take in the generated bundle as values. This is compatible
124
122
  // with the `aliases` format used upstream.
125
- const getBundlePaths = ({ destFolder, extension: outputExtension, outputs, srcFile, }) => {
123
+ const getBundlePaths = ({ destFolder, outputExtension, outputs, srcFile, }) => {
126
124
  const bundleFilename = basename(srcFile, extname(srcFile)) + outputExtension;
127
125
  const mainFileDirectory = dirname(srcFile);
128
126
  const bundlePaths = new Map();
@@ -9,7 +9,7 @@ declare const versionMap: {
9
9
  readonly '16.x': "node16";
10
10
  readonly '18.x': "node18";
11
11
  };
12
- type VersionValues = typeof versionMap[keyof typeof versionMap];
12
+ type VersionValues = (typeof versionMap)[keyof typeof versionMap];
13
13
  declare const getBundlerTarget: (suppliedVersion?: NodeVersionString) => VersionValues;
14
14
  declare const getModuleFormat: (srcDir: string, featureFlags: FeatureFlags, extension: string, configVersion?: string) => Promise<{
15
15
  includedFiles: string[];
@@ -28,7 +28,7 @@ const getExternalAndIgnoredModules = async ({ config, srcDir }) => {
28
28
  };
29
29
  const bundle = async ({ basePath, config = {}, extension, featureFlags, filename, mainFile, name, pluginsModulesPath, repositoryRoot, runtime, srcDir, srcPath, stat, }) => {
30
30
  const { externalModules, ignoredModules } = await getExternalAndIgnoredModules({ config, srcDir });
31
- const { additionalPaths, bundlePaths, cleanTempFiles, extension: outputExtension, inputs, moduleFormat, nativeNodeModules = {}, nodeModulesWithDynamicImports, warnings, } = await bundleJsFile({
31
+ const { additionalPaths, bundlePaths, cleanTempFiles, inputs, moduleFormat, nativeNodeModules = {}, nodeModulesWithDynamicImports, outputExtension, warnings, } = await bundleJsFile({
32
32
  additionalModulePaths: pluginsModulesPath ? [pluginsModulesPath] : [],
33
33
  basePath,
34
34
  config,
@@ -43,9 +43,9 @@ const ignoreFunction = (path) => {
43
43
  const traceFilesAndTranspile = async function ({ basePath, cache, config, featureFlags, mainFile, pluginsModulesPath, name, }) {
44
44
  const { fileList: dependencyPaths, esmFileList, reasons, } = await nodeFileTrace([mainFile], {
45
45
  // Default is 1024. Allowing double the fileIO in parallel makes nft faster, but uses a little more memory.
46
- fileIOConcurrency: featureFlags.zisi_nft_higher_fileio_limit ? 2048 : 1024,
46
+ fileIOConcurrency: 2048,
47
47
  base: basePath,
48
- cache: featureFlags.zisi_nft_use_cache ? cache.nftCache : undefined,
48
+ cache: cache.nftCache,
49
49
  ignore: ignoreFunction,
50
50
  readFile: async (path) => {
51
51
  try {
@@ -1,7 +1,23 @@
1
+ import type { FeatureFlags } from '../../../feature_flags.js';
1
2
  import { ModuleFormat } from './module_format.js';
2
- export declare const getEntryFile: ({ commonPrefix, mainFile, moduleFormat, userNamespace, }: {
3
+ export interface EntryFile {
4
+ contents: string;
5
+ filename: string;
6
+ }
7
+ export declare const isNamedLikeEntryFile: (file: string, { basePath, filename, }: {
8
+ basePath: string;
9
+ filename: string;
10
+ }) => boolean;
11
+ export declare const conflictsWithEntryFile: (srcFiles: string[], { basePath, mainFile, filename, }: {
12
+ basePath: string;
13
+ filename: string;
14
+ mainFile: string;
15
+ }) => boolean;
16
+ export declare const getEntryFile: ({ commonPrefix, featureFlags, filename, mainFile, moduleFormat, userNamespace, }: {
3
17
  commonPrefix: string;
18
+ featureFlags: FeatureFlags;
19
+ filename: string;
4
20
  mainFile: string;
5
21
  moduleFormat: ModuleFormat;
6
22
  userNamespace: string;
7
- }) => string;
23
+ }) => EntryFile;
@@ -1,10 +1,35 @@
1
+ import { basename, extname, resolve } from 'path';
2
+ import { getFileExtensionForFormat } from './module_format.js';
1
3
  import { normalizeFilePath } from './normalize_path.js';
2
- export const getEntryFile = ({ commonPrefix, mainFile, moduleFormat, userNamespace, }) => {
3
- const mainPath = normalizeFilePath({ commonPrefix, path: mainFile, userNamespace });
4
+ const getEntryFileContents = (mainPath, moduleFormat) => {
4
5
  const importPath = `.${mainPath.startsWith('/') ? mainPath : `/${mainPath}`}`;
5
6
  if (moduleFormat === "cjs" /* ModuleFormat.COMMONJS */) {
6
7
  return `module.exports = require('${importPath}')`;
7
8
  }
8
9
  return `export { handler } from '${importPath}'`;
9
10
  };
11
+ // They are in the order that AWS Lambda will try to find the entry point
12
+ const POSSIBLE_LAMBDA_ENTRY_EXTENSIONS = [".js" /* ModuleFileExtension.JS */, ".mjs" /* ModuleFileExtension.MJS */, ".cjs" /* ModuleFileExtension.CJS */];
13
+ // checks if the file is considered a entry-file in AWS Lambda
14
+ export const isNamedLikeEntryFile = (file, { basePath, filename, }) => POSSIBLE_LAMBDA_ENTRY_EXTENSIONS.some((extension) => {
15
+ const entryFilename = getEntryFileName({ extension, filename });
16
+ const entryFilePath = resolve(basePath, entryFilename);
17
+ return entryFilePath === file;
18
+ });
19
+ // Check if any src file (except the mainFile) is considered an entry file for AWS Lambda
20
+ export const conflictsWithEntryFile = (srcFiles, { basePath, mainFile, filename, }) => srcFiles.some((srcFile) => isNamedLikeEntryFile(srcFile, { basePath, filename }) && srcFile !== mainFile);
21
+ // Returns the name for the AWS Lambda entry file
22
+ // We do set the handler in AWS Lambda to `<func-name>.handler` and because of
23
+ // this it considers `<func-name>.(c|m)?js` as possible entry-points
24
+ const getEntryFileName = ({ extension, filename }) => `${basename(filename, extname(filename))}${extension}`;
25
+ export const getEntryFile = ({ commonPrefix, featureFlags, filename, mainFile, moduleFormat, userNamespace, }) => {
26
+ const mainPath = normalizeFilePath({ commonPrefix, path: mainFile, userNamespace });
27
+ const extension = getFileExtensionForFormat(moduleFormat, featureFlags);
28
+ const entryFilename = getEntryFileName({ extension, filename });
29
+ const contents = getEntryFileContents(mainPath, moduleFormat);
30
+ return {
31
+ contents,
32
+ filename: entryFilename,
33
+ };
34
+ };
10
35
  //# sourceMappingURL=entry_file.js.map
@@ -2,6 +2,9 @@ export const getFileExtensionForFormat = (moduleFormat, featureFlags) => {
2
2
  if (moduleFormat === "esm" /* ModuleFormat.ESM */ && featureFlags.zisi_pure_esm_mjs) {
3
3
  return ".mjs" /* ModuleFileExtension.MJS */;
4
4
  }
5
+ if (featureFlags.zisi_output_cjs_extension && moduleFormat === "cjs" /* ModuleFormat.COMMONJS */) {
6
+ return ".cjs" /* ModuleFileExtension.CJS */;
7
+ }
5
8
  return ".js" /* ModuleFileExtension.JS */;
6
9
  };
7
10
  //# sourceMappingURL=module_format.js.map
@@ -1,14 +1,13 @@
1
1
  import { Buffer } from 'buffer';
2
2
  import { promises as fs } from 'fs';
3
3
  import os from 'os';
4
- import { basename, join, resolve } from 'path';
4
+ import { basename, join } from 'path';
5
5
  import { copyFile } from 'cp-file';
6
6
  import { deleteAsync as deleteFiles } from 'del';
7
7
  import pMap from 'p-map';
8
8
  import { startZip, addZipFile, addZipContent, endZip } from '../../../archive.js';
9
9
  import { cachedLstat, mkdirAndWriteFile } from '../../../utils/fs.js';
10
- import { getEntryFile } from './entry_file.js';
11
- import { getFileExtensionForFormat } from './module_format.js';
10
+ import { conflictsWithEntryFile, getEntryFile, isNamedLikeEntryFile } from './entry_file.js';
12
11
  import { normalizeFilePath } from './normalize_path.js';
13
12
  // Taken from https://www.npmjs.com/package/cpy.
14
13
  const COPY_FILE_CONCURRENCY = os.cpus().length === 0 ? 2 : os.cpus().length * 2;
@@ -16,21 +15,20 @@ const COPY_FILE_CONCURRENCY = os.cpus().length === 0 ? 2 : os.cpus().length * 2;
16
15
  // the entry file generated by zip-it-and-ship-it).
17
16
  const DEFAULT_USER_SUBDIRECTORY = 'src';
18
17
  const createDirectory = async function ({ aliases = new Map(), basePath, destFolder, extension, featureFlags, filename, mainFile, moduleFormat, rewrites = new Map(), srcFiles, }) {
19
- const entryFile = getEntryFile({
18
+ const { contents: entryContents, filename: entryFilename } = getEntryFile({
20
19
  commonPrefix: basePath,
20
+ featureFlags,
21
+ filename,
21
22
  mainFile,
22
23
  moduleFormat,
23
24
  userNamespace: DEFAULT_USER_SUBDIRECTORY,
24
25
  });
25
- const entryFileExtension = getFileExtensionForFormat(moduleFormat, featureFlags);
26
- const entryFilename = basename(filename, extension) + entryFileExtension;
27
26
  const functionFolder = join(destFolder, basename(filename, extension));
28
- const entryFilePath = resolve(functionFolder, entryFilename);
29
27
  // Deleting the functions directory in case it exists before creating it.
30
28
  await deleteFiles(functionFolder, { force: true });
31
29
  await fs.mkdir(functionFolder, { recursive: true });
32
30
  // Writing entry file.
33
- await fs.writeFile(entryFilePath, entryFile);
31
+ await fs.writeFile(join(functionFolder, entryFilename), entryContents);
34
32
  // Copying source files.
35
33
  await pMap(srcFiles, (srcFile) => {
36
34
  const destPath = aliases.get(srcFile) || srcFile;
@@ -50,22 +48,30 @@ const createDirectory = async function ({ aliases = new Map(), basePath, destFol
50
48
  const createZipArchive = async function ({ aliases, basePath, cache, destFolder, extension, featureFlags, filename, mainFile, moduleFormat, rewrites, srcFiles, }) {
51
49
  const destPath = join(destFolder, `${basename(filename, extension)}.zip`);
52
50
  const { archive, output } = startZip(destPath);
53
- const entryFileExtension = getFileExtensionForFormat(moduleFormat, featureFlags);
54
- const entryFilename = basename(filename, extension) + entryFileExtension;
55
- const entryFilePath = resolve(basePath, entryFilename);
56
51
  // We don't need an entry file if it would end up with the same path as the
57
52
  // function's main file.
58
- const needsEntryFile = entryFilePath !== mainFile;
53
+ const needsEntryFile = !isNamedLikeEntryFile(mainFile, { basePath, filename });
59
54
  // There is a naming conflict with the entry file if one of the supporting
60
55
  // files (i.e. not the main file) has the path that the entry file needs to
61
56
  // take.
62
- const hasEntryFileConflict = srcFiles.some((srcFile) => srcFile === entryFilePath && srcFile !== mainFile);
57
+ const hasEntryFileConflict = conflictsWithEntryFile(srcFiles, {
58
+ basePath,
59
+ filename,
60
+ mainFile,
61
+ });
63
62
  // If there is a naming conflict, we move all user files (everything other
64
63
  // than the entry file) to its own sub-directory.
65
64
  const userNamespace = hasEntryFileConflict ? DEFAULT_USER_SUBDIRECTORY : '';
66
65
  if (needsEntryFile) {
67
- const entryFile = getEntryFile({ commonPrefix: basePath, mainFile, moduleFormat, userNamespace });
68
- addEntryFileToZip(archive, entryFile, basename(entryFilePath));
66
+ const entryFile = getEntryFile({
67
+ commonPrefix: basePath,
68
+ filename,
69
+ mainFile,
70
+ moduleFormat,
71
+ userNamespace,
72
+ featureFlags,
73
+ });
74
+ addEntryFileToZip(archive, entryFile);
69
75
  }
70
76
  const srcFilesInfos = await Promise.all(srcFiles.map((file) => addStat(cache, file)));
71
77
  // We ensure this is not async, so that the archive's checksum is
@@ -90,7 +96,7 @@ export const zipNodeJs = function ({ archiveFormat, ...options }) {
90
96
  }
91
97
  return createDirectory(options);
92
98
  };
93
- const addEntryFileToZip = function (archive, contents, filename) {
99
+ const addEntryFileToZip = function (archive, { contents, filename }) {
94
100
  const contentBuffer = Buffer.from(contents);
95
101
  addZipContent(archive, contentBuffer, filename);
96
102
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/zip-it-and-ship-it",
3
- "version": "8.2.0",
3
+ "version": "8.3.0",
4
4
  "description": "Zip it and ship it",
5
5
  "main": "./dist/main.js",
6
6
  "type": "module",
@@ -97,7 +97,7 @@
97
97
  "@types/tmp": "^0.2.3",
98
98
  "@types/unixify": "^1.0.0",
99
99
  "@types/yargs": "^17.0.4",
100
- "@vitest/coverage-c8": "^0.25.0",
100
+ "@vitest/coverage-c8": "^0.27.0",
101
101
  "cpy": "^9.0.0",
102
102
  "deepmerge": "^4.2.2",
103
103
  "get-stream": "^6.0.0",
@@ -108,7 +108,7 @@
108
108
  "throat": "^6.0.1",
109
109
  "typescript": "^4.8.4",
110
110
  "vite": "^4.0.0",
111
- "vitest": "^0.25.0"
111
+ "vitest": "^0.27.0"
112
112
  },
113
113
  "engines": {
114
114
  "node": "^14.16.0 || >=16.0.0"