@netlify/zip-it-and-ship-it 4.22.0 → 4.23.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/zip-it-and-ship-it",
3
- "version": "4.22.0",
3
+ "version": "4.23.0",
4
4
  "description": "Zip it and ship it",
5
5
  "main": "./src/main.js",
6
6
  "bin": {
@@ -54,8 +54,8 @@
54
54
  "url": "https://github.com/netlify/zip-it-and-ship-it/issues"
55
55
  },
56
56
  "dependencies": {
57
+ "@babel/parser": "^7.15.7",
57
58
  "@netlify/esbuild": "^0.13.6",
58
- "acorn": "^8.4.0",
59
59
  "archiver": "^5.3.0",
60
60
  "array-flat-polyfill": "^1.0.1",
61
61
  "common-path-prefix": "^3.0.0",
@@ -68,6 +68,7 @@
68
68
  "filter-obj": "^2.0.1",
69
69
  "find-up": "^5.0.0",
70
70
  "glob": "^7.1.6",
71
+ "is-builtin-module": "^3.1.0",
71
72
  "junk": "^3.1.0",
72
73
  "locate-path": "^6.0.0",
73
74
  "make-dir": "^3.1.0",
@@ -5,6 +5,7 @@ const FLAGS = {
5
5
  buildGoSource: Boolean(env.NETLIFY_EXPERIMENTAL_BUILD_GO_SOURCE),
6
6
  buildRustSource: Boolean(env.NETLIFY_EXPERIMENTAL_BUILD_RUST_SOURCE),
7
7
  defaultEsModulesToEsbuild: Boolean(env.NETLIFY_EXPERIMENTAL_DEFAULT_ES_MODULES_TO_ESBUILD),
8
+ parseWithEsbuild: false,
8
9
  }
9
10
 
10
11
  const getFlags = (input = {}, flags = FLAGS) =>
package/src/main.js CHANGED
@@ -27,7 +27,7 @@ const listFunctionsFiles = async function (relativeSrcFolders, { config, feature
27
27
  getPluginsModulesPath(srcFolders[0]),
28
28
  ])
29
29
  const listedFunctionsFiles = await Promise.all(
30
- [...functions.values()].map((func) => getListedFunctionFiles(func, { pluginsModulesPath })),
30
+ [...functions.values()].map((func) => getListedFunctionFiles(func, { featureFlags, pluginsModulesPath })),
31
31
  )
32
32
 
33
33
  // TODO: switch to Array.flat() once we drop support for Node.js < 11.0.0
@@ -41,9 +41,10 @@ const getListedFunction = function ({ runtime, name, mainFile, extension }) {
41
41
 
42
42
  const getListedFunctionFiles = async function (
43
43
  { config, runtime, name, stat, mainFile, extension, srcPath, srcDir },
44
- { pluginsModulesPath },
44
+ { featureFlags, pluginsModulesPath },
45
45
  ) {
46
46
  const srcFiles = await getSrcFiles({
47
+ featureFlags,
47
48
  runtime,
48
49
  stat,
49
50
  mainFile,
@@ -59,6 +60,7 @@ const getListedFunctionFiles = async function (
59
60
  const getSrcFiles = function ({
60
61
  bundler,
61
62
  config,
63
+ featureFlags,
62
64
  runtime,
63
65
  stat,
64
66
  mainFile,
@@ -77,6 +79,7 @@ const getSrcFiles = function ({
77
79
  bundler,
78
80
  config,
79
81
  extension,
82
+ featureFlags,
80
83
  srcPath,
81
84
  mainFile,
82
85
  srcDir,
@@ -4,6 +4,8 @@ const findUp = require('find-up')
4
4
  const { not: notJunk } = require('junk')
5
5
  const precinct = require('precinct')
6
6
 
7
+ const { listImports } = require('../runtimes/node/list_imports')
8
+
7
9
  const { getPackageJson } = require('./package_json')
8
10
  const { resolvePathPreserveSymlinks } = require('./resolve')
9
11
  const { getExternalAndIgnoredModulesFromSpecialCases } = require('./special_cases')
@@ -23,10 +25,17 @@ const getPluginsModulesPath = (srcDir) => findUp(`${AUTO_PLUGINS_DIR}node_module
23
25
  // Retrieve the paths to the Node.js files to zip.
24
26
  // We only include the files actually needed by the function because AWS Lambda
25
27
  // has a size limit for the zipped file. It also makes cold starts faster.
26
- const listFilesUsingLegacyBundler = async function ({ srcPath, mainFile, srcDir, stat, pluginsModulesPath }) {
28
+ const listFilesUsingLegacyBundler = async function ({
29
+ featureFlags,
30
+ srcPath,
31
+ mainFile,
32
+ srcDir,
33
+ stat,
34
+ pluginsModulesPath,
35
+ }) {
27
36
  const [treeFiles, depFiles] = await Promise.all([
28
37
  getTreeFiles(srcPath, stat),
29
- getDependencies(mainFile, srcDir, pluginsModulesPath),
38
+ getDependencies(mainFile, srcDir, pluginsModulesPath, featureFlags),
30
39
  ])
31
40
  const files = [...treeFiles, ...depFiles].map(normalize)
32
41
  const uniqueFiles = [...new Set(files)]
@@ -43,19 +52,26 @@ const isNotJunk = function (file) {
43
52
  }
44
53
 
45
54
  // Retrieve all the files recursively required by a Node.js file
46
- const getDependencies = async function (mainFile, srcDir, pluginsModulesPath) {
55
+ const getDependencies = async function (mainFile, srcDir, pluginsModulesPath, featureFlags) {
47
56
  const packageJson = await getPackageJson(srcDir)
48
57
  const state = getNewCache()
49
58
 
50
59
  try {
51
- return await getFileDependencies({ path: mainFile, packageJson, state, pluginsModulesPath })
60
+ return await getFileDependencies({ featureFlags, path: mainFile, packageJson, pluginsModulesPath, state })
52
61
  } catch (error) {
53
62
  error.message = `In file "${mainFile}"\n${error.message}`
54
63
  throw error
55
64
  }
56
65
  }
57
66
 
58
- const getFileDependencies = async function ({ path, packageJson, pluginsModulesPath, state, treeShakeNext }) {
67
+ const getFileDependencies = async function ({
68
+ featureFlags,
69
+ path,
70
+ packageJson,
71
+ pluginsModulesPath,
72
+ state,
73
+ treeShakeNext,
74
+ }) {
59
75
  if (state.localFiles.has(path)) {
60
76
  return []
61
77
  }
@@ -63,16 +79,21 @@ const getFileDependencies = async function ({ path, packageJson, pluginsModulesP
63
79
  state.localFiles.add(path)
64
80
 
65
81
  const basedir = dirname(path)
66
- // This parses JavaScript in `path` to retrieve all the `require()` statements
67
- // TODO: `precinct.paperwork()` uses `fs.readFileSync()` under the hood,
68
- // but should use `fs.readFile()` instead
69
- const dependencies = precinct.paperwork(path, { includeCore: false })
82
+ const dependencies = featureFlags.parseWithEsbuild
83
+ ? await listImports({ path })
84
+ : precinct.paperwork(path, { includeCore: false })
70
85
  const depsPaths = await Promise.all(
71
- dependencies
72
- .filter(Boolean)
73
- .map((dependency) =>
74
- getImportDependencies({ dependency, basedir, packageJson, state, treeShakeNext, pluginsModulesPath }),
75
- ),
86
+ dependencies.filter(Boolean).map((dependency) =>
87
+ getImportDependencies({
88
+ dependency,
89
+ basedir,
90
+ featureFlags,
91
+ packageJson,
92
+ pluginsModulesPath,
93
+ state,
94
+ treeShakeNext,
95
+ }),
96
+ ),
76
97
  )
77
98
  // TODO: switch to Array.flat() once we drop support for Node.js < 11.0.0
78
99
  // eslint-disable-next-line unicorn/prefer-spread
@@ -82,20 +103,22 @@ const getFileDependencies = async function ({ path, packageJson, pluginsModulesP
82
103
  const getImportDependencies = function ({
83
104
  dependency,
84
105
  basedir,
106
+ featureFlags,
85
107
  packageJson,
108
+ pluginsModulesPath,
86
109
  state,
87
110
  treeShakeNext,
88
- pluginsModulesPath,
89
111
  }) {
90
112
  const shouldTreeShakeNext = treeShakeNext || isNextOnNetlify(dependency)
91
113
  if (shouldTreeShake(dependency, shouldTreeShakeNext)) {
92
114
  return getTreeShakedDependencies({
93
115
  dependency,
94
116
  basedir,
117
+ featureFlags,
95
118
  packageJson,
119
+ pluginsModulesPath,
96
120
  state,
97
121
  treeShakeNext: shouldTreeShakeNext,
98
- pluginsModulesPath,
99
122
  })
100
123
  }
101
124
 
@@ -110,13 +133,21 @@ const isNextOnNetlify = function (dependency) {
110
133
  const getTreeShakedDependencies = async function ({
111
134
  dependency,
112
135
  basedir,
136
+ featureFlags,
113
137
  packageJson,
138
+ pluginsModulesPath,
114
139
  state,
115
140
  treeShakeNext,
116
- pluginsModulesPath,
117
141
  }) {
118
142
  const path = await resolvePathPreserveSymlinks(dependency, [basedir, pluginsModulesPath].filter(Boolean))
119
- const depsPath = await getFileDependencies({ path, packageJson, state, treeShakeNext, pluginsModulesPath })
143
+ const depsPath = await getFileDependencies({
144
+ featureFlags,
145
+ path,
146
+ packageJson,
147
+ pluginsModulesPath,
148
+ state,
149
+ treeShakeNext,
150
+ })
120
151
  return [path, ...depsPath]
121
152
  }
122
153
 
@@ -1,8 +1,7 @@
1
1
  const { join, relative, resolve } = require('path')
2
2
 
3
- const acorn = require('acorn')
3
+ const babel = require('@babel/parser')
4
4
 
5
- const ECMA_VERSION = 2021
6
5
  const GLOB_WILDCARD = '**'
7
6
 
8
7
  // Transforms an array of glob nodes into a glob string including an absolute
@@ -56,8 +55,10 @@ const getWildcardFromASTNode = (node) => {
56
55
  // - `includedPathsGlob`: A glob with the files to be included in the bundle
57
56
  // - `type`: The expression type (e.g. "require", "import")
58
57
  const parseExpression = ({ basePath, expression: rawExpression, resolveDir }) => {
59
- const { body } = acorn.parse(rawExpression, { ecmaVersion: ECMA_VERSION })
60
- const [topLevelExpression] = body
58
+ const { program } = babel.parse(rawExpression, {
59
+ sourceType: 'module',
60
+ })
61
+ const [topLevelExpression] = program.body
61
62
  const { expression } = topLevelExpression
62
63
 
63
64
  if (expression.type === 'CallExpression' && expression.callee.name === 'require') {
@@ -113,7 +114,7 @@ const parseBinaryExpression = (expression) => {
113
114
  case 'BinaryExpression':
114
115
  return parseBinaryExpression(operand)
115
116
 
116
- case 'Literal':
117
+ case 'StringLiteral':
117
118
  return operand.value
118
119
 
119
120
  default:
@@ -42,6 +42,7 @@ const zipFunction = async function ({
42
42
  config = {},
43
43
  destFolder,
44
44
  extension,
45
+ featureFlags,
45
46
  filename,
46
47
  mainFile,
47
48
  name,
@@ -49,7 +50,6 @@ const zipFunction = async function ({
49
50
  srcDir,
50
51
  srcPath,
51
52
  stat,
52
- featureFlags,
53
53
  }) {
54
54
  const bundler = config.nodeBundler || (await getDefaultBundler({ extension, mainFile, featureFlags }))
55
55
  // If the file is a zip, we assume the function is bundled and ready to go.
@@ -67,6 +67,7 @@ const zipFunction = async function ({
67
67
  config,
68
68
  destFolder,
69
69
  extension,
70
+ featureFlags,
70
71
  filename,
71
72
  mainFile,
72
73
  pluginsModulesPath,
@@ -0,0 +1,51 @@
1
+ const esbuild = require('@netlify/esbuild')
2
+ const isBuiltinModule = require('is-builtin-module')
3
+ const { tmpName } = require('tmp-promise')
4
+
5
+ const { safeUnlink } = require('../../utils/fs')
6
+
7
+ const getListImportsPlugin = ({ imports, path }) => ({
8
+ name: 'list-imports',
9
+ setup(build) {
10
+ build.onResolve({ filter: /.*/ }, (args) => {
11
+ const isEntryPoint = args.path === path
12
+ const isImport = !isEntryPoint && !isBuiltinModule(args.path)
13
+
14
+ if (isImport) {
15
+ imports.add(args.path)
16
+ }
17
+
18
+ return {
19
+ namespace: 'list-imports',
20
+ external: isImport,
21
+ }
22
+ })
23
+ },
24
+ })
25
+
26
+ const listImports = async ({ path }) => {
27
+ // We're not interested in the output that esbuild generates, we're just
28
+ // using it for its parsing capabilities in order to find import/require
29
+ // statements. However, if we don't give esbuild a path in `outfile`, it
30
+ // will pipe the output to stdout, which we also don't want. So we create
31
+ // a temporary file to serve as the esbuild output and then get rid of it
32
+ // when we're done.
33
+ const targetPath = await tmpName()
34
+ const imports = new Set()
35
+
36
+ try {
37
+ await esbuild.build({
38
+ entryPoints: [path],
39
+ bundle: true,
40
+ outfile: targetPath,
41
+ platform: 'node',
42
+ plugins: [getListImportsPlugin({ imports, path })],
43
+ })
44
+ } finally {
45
+ await safeUnlink(targetPath)
46
+ }
47
+
48
+ return [...imports]
49
+ }
50
+
51
+ module.exports = { listImports }
@@ -53,6 +53,7 @@ const getSrcFiles = async function ({ config, ...parameters }) {
53
53
  const getSrcFilesAndExternalModules = async function ({
54
54
  bundler,
55
55
  externalNodeModules = [],
56
+ featureFlags,
56
57
  includedFiles = [],
57
58
  includedFilesBasePath,
58
59
  mainFile,
@@ -64,7 +65,14 @@ const getSrcFilesAndExternalModules = async function ({
64
65
  const includedFilePaths = await getPathsOfIncludedFiles(includedFiles, includedFilesBasePath)
65
66
 
66
67
  if (bundler === JS_BUNDLER_ZISI) {
67
- const paths = await listFilesUsingLegacyBundler({ srcPath, mainFile, srcDir, stat, pluginsModulesPath })
68
+ const paths = await listFilesUsingLegacyBundler({
69
+ featureFlags,
70
+ srcPath,
71
+ mainFile,
72
+ srcDir,
73
+ stat,
74
+ pluginsModulesPath,
75
+ })
68
76
 
69
77
  return {
70
78
  moduleNames: [],
@@ -12,6 +12,7 @@ const zipZisi = async ({
12
12
  config,
13
13
  destFolder,
14
14
  extension,
15
+ featureFlags,
15
16
  filename,
16
17
  mainFile,
17
18
  pluginsModulesPath,
@@ -22,6 +23,7 @@ const zipZisi = async ({
22
23
  const { paths: srcFiles } = await getSrcFilesAndExternalModules({
23
24
  bundler: JS_BUNDLER_ZISI,
24
25
  extension,
26
+ featureFlags,
25
27
  includedFiles: config.includedFiles,
26
28
  includedFilesBasePath: config.includedFilesBasePath || basePath,
27
29
  mainFile,