netlify-cli 15.9.1-rc.0 → 15.10.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/npm-shrinkwrap.json +236 -738
- package/package.json +6 -5
- package/src/commands/base-command.mjs +59 -195
- package/src/commands/deploy/deploy.mjs +9 -21
- package/src/commands/dev/dev.mjs +15 -21
- package/src/commands/functions/functions-create.mjs +3 -0
- package/src/commands/functions/functions-invoke.mjs +5 -8
- package/src/commands/init/init.mjs +1 -1
- package/src/commands/link/link.mjs +5 -5
- package/src/commands/serve/serve.mjs +5 -11
- package/src/commands/sites/sites-create-template.mjs +1 -1
- package/src/commands/sites/sites-create.mjs +1 -1
- package/src/functions-templates/typescript/hello-world/package-lock.json +6 -6
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/headers.mjs +1 -0
- package/src/lib/edge-functions/internal.mjs +3 -5
- package/src/lib/edge-functions/proxy.mjs +4 -27
- package/src/lib/functions/runtimes/js/index.mjs +1 -1
- package/src/lib/functions/runtimes/js/worker.mjs +1 -1
- package/src/lib/spinner.mjs +1 -1
- package/src/utils/command-helpers.mjs +7 -16
- package/src/utils/detect-server-settings.mjs +198 -147
- package/src/utils/framework-server.mjs +2 -2
- package/src/utils/functions/functions.mjs +0 -7
- package/src/utils/get-repo-data.mjs +6 -5
- package/src/utils/init/config-github.mjs +2 -2
- package/src/utils/init/config-manual.mjs +7 -24
- package/src/utils/init/frameworks.mjs +23 -0
- package/src/utils/init/utils.mjs +63 -62
- package/src/utils/proxy-server.mjs +4 -7
- package/src/utils/proxy.mjs +0 -4
- package/src/utils/run-build.mjs +7 -58
- package/src/utils/shell.mjs +3 -14
- package/src/utils/state-config.mjs +1 -5
- package/src/utils/static-server.mjs +0 -4
- package/src/utils/build-info.mjs +0 -19
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { readFile } from 'fs/promises'
|
|
3
3
|
import { EOL } from 'os'
|
|
4
|
-
import
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import process from 'process'
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
+
import { Project } from '@netlify/build-info'
|
|
8
|
+
// eslint-disable-next-line import/extensions, n/no-missing-import
|
|
9
|
+
import { NodeFS } from '@netlify/build-info/node'
|
|
10
|
+
import { getFramework, listFrameworks } from '@netlify/framework-info'
|
|
7
11
|
import fuzzy from 'fuzzy'
|
|
8
12
|
import getPort from 'get-port'
|
|
9
13
|
import inquirer from 'inquirer'
|
|
14
|
+
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
|
|
10
15
|
|
|
11
|
-
import { detectBuildSettings } from './build-info.mjs'
|
|
12
16
|
import { NETLIFYDEVWARN, chalk, log } from './command-helpers.mjs'
|
|
13
17
|
import { acquirePort } from './dev.mjs'
|
|
14
18
|
import { getInternalFunctionsDir } from './functions/functions.mjs'
|
|
15
|
-
import {
|
|
19
|
+
import { reportError } from './telemetry/report-error.mjs'
|
|
16
20
|
|
|
17
|
-
/** @param {string} str */
|
|
18
21
|
const formatProperty = (str) => chalk.magenta(`'${str}'`)
|
|
19
|
-
/** @param {string} str */
|
|
20
22
|
const formatValue = (str) => chalk.green(`'${str}'`)
|
|
21
23
|
|
|
22
|
-
/**
|
|
23
|
-
* @param {object} options
|
|
24
|
-
* @param {string} options.keyFile
|
|
25
|
-
* @param {string} options.certFile
|
|
26
|
-
* @returns {Promise<{ key: string, cert: string, keyFilePath: string, certFilePath: string }>}
|
|
27
|
-
*/
|
|
28
24
|
const readHttpsSettings = async (options) => {
|
|
29
25
|
if (typeof options !== 'object' || !options.keyFile || !options.certFile) {
|
|
30
26
|
throw new TypeError(
|
|
@@ -42,43 +38,43 @@ const readHttpsSettings = async (options) => {
|
|
|
42
38
|
throw new TypeError(`Certificate file configuration should be a string`)
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
const [key, cert] = await Promise.allSettled([
|
|
41
|
+
const [{ reason: keyError, value: key }, { reason: certError, value: cert }] = await Promise.allSettled([
|
|
42
|
+
readFile(keyFile, 'utf-8'),
|
|
43
|
+
readFile(certFile, 'utf-8'),
|
|
44
|
+
])
|
|
46
45
|
|
|
47
|
-
if (
|
|
48
|
-
throw new Error(`Error reading private key file: ${
|
|
46
|
+
if (keyError) {
|
|
47
|
+
throw new Error(`Error reading private key file: ${keyError.message}`)
|
|
49
48
|
}
|
|
50
|
-
if (
|
|
51
|
-
throw new Error(`Error reading certificate file: ${
|
|
49
|
+
if (certError) {
|
|
50
|
+
throw new Error(`Error reading certificate file: ${certError.message}`)
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
return { key
|
|
53
|
+
return { key, cert, keyFilePath: path.resolve(keyFile), certFilePath: path.resolve(certFile) }
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* @param {import('../commands/dev/types.js').DevConfig} devConfig The devConfig
|
|
60
|
-
* @param {keyof import('../commands/dev/types.js').DevConfig} property The property to validate
|
|
61
|
-
* @param {'string' | 'number'} type The type it should have
|
|
62
|
-
*/
|
|
63
|
-
function validateProperty(devConfig, property, type) {
|
|
64
|
-
// eslint-disable-next-line valid-typeof
|
|
65
|
-
if (devConfig[property] && typeof devConfig[property] !== type) {
|
|
56
|
+
const validateStringProperty = ({ devConfig, property }) => {
|
|
57
|
+
if (devConfig[property] && typeof devConfig[property] !== 'string') {
|
|
66
58
|
const formattedProperty = formatProperty(property)
|
|
67
59
|
throw new TypeError(
|
|
68
|
-
`Invalid ${formattedProperty} option provided in config. The value of ${formattedProperty} option must be
|
|
60
|
+
`Invalid ${formattedProperty} option provided in config. The value of ${formattedProperty} option must be a string`,
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const validateNumberProperty = ({ devConfig, property }) => {
|
|
66
|
+
if (devConfig[property] && typeof devConfig[property] !== 'number') {
|
|
67
|
+
const formattedProperty = formatProperty(property)
|
|
68
|
+
throw new TypeError(
|
|
69
|
+
`Invalid ${formattedProperty} option provided in config. The value of ${formattedProperty} option must be an integer`,
|
|
69
70
|
)
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
* @param {object} config
|
|
76
|
-
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
77
|
-
*/
|
|
78
74
|
const validateFrameworkConfig = ({ devConfig }) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
validateStringProperty({ devConfig, property: 'command' })
|
|
76
|
+
validateNumberProperty({ devConfig, property: 'port' })
|
|
77
|
+
validateNumberProperty({ devConfig, property: 'targetPort' })
|
|
82
78
|
|
|
83
79
|
if (devConfig.targetPort && devConfig.targetPort === devConfig.port) {
|
|
84
80
|
throw new Error(
|
|
@@ -89,11 +85,6 @@ const validateFrameworkConfig = ({ devConfig }) => {
|
|
|
89
85
|
}
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
/**
|
|
93
|
-
* @param {object} config
|
|
94
|
-
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
95
|
-
* @param {number=} config.detectedPort
|
|
96
|
-
*/
|
|
97
88
|
const validateConfiguredPort = ({ detectedPort, devConfig }) => {
|
|
98
89
|
if (devConfig.port && devConfig.port === detectedPort) {
|
|
99
90
|
const formattedPort = formatProperty('port')
|
|
@@ -106,22 +97,13 @@ const validateConfiguredPort = ({ detectedPort, devConfig }) => {
|
|
|
106
97
|
const DEFAULT_PORT = 8888
|
|
107
98
|
const DEFAULT_STATIC_PORT = 3999
|
|
108
99
|
|
|
109
|
-
|
|
110
|
-
* Logs a message that it was unable to determine the dist directory and falls back to the workingDir
|
|
111
|
-
* @param {string} workingDir
|
|
112
|
-
*/
|
|
113
|
-
const getDefaultDist = (workingDir) => {
|
|
100
|
+
const getDefaultDist = () => {
|
|
114
101
|
log(`${NETLIFYDEVWARN} Unable to determine public folder to serve files from. Using current working directory`)
|
|
115
102
|
log(`${NETLIFYDEVWARN} Setup a netlify.toml file with a [dev] section to specify your dev server settings.`)
|
|
116
103
|
log(`${NETLIFYDEVWARN} See docs at: https://cli.netlify.com/netlify-dev#project-detection`)
|
|
117
|
-
return
|
|
104
|
+
return process.cwd()
|
|
118
105
|
}
|
|
119
106
|
|
|
120
|
-
/**
|
|
121
|
-
* @param {object} config
|
|
122
|
-
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
123
|
-
* @returns {Promise<number>}
|
|
124
|
-
*/
|
|
125
107
|
const getStaticServerPort = async ({ devConfig }) => {
|
|
126
108
|
const port = await acquirePort({
|
|
127
109
|
configuredPort: devConfig.staticServerPort,
|
|
@@ -134,16 +116,16 @@ const getStaticServerPort = async ({ devConfig }) => {
|
|
|
134
116
|
|
|
135
117
|
/**
|
|
136
118
|
*
|
|
137
|
-
* @param {object}
|
|
138
|
-
* @param {import('../commands/dev/types.js').DevConfig}
|
|
139
|
-
* @param {import('commander').OptionValues}
|
|
140
|
-
* @param {string}
|
|
141
|
-
* @returns {Promise<
|
|
119
|
+
* @param {object} param0
|
|
120
|
+
* @param {import('../commands/dev/types.js').DevConfig} param0.devConfig
|
|
121
|
+
* @param {import('commander').OptionValues} param0.options
|
|
122
|
+
* @param {string} param0.projectDir
|
|
123
|
+
* @returns {Promise<import('./types.js').BaseServerSettings>}
|
|
142
124
|
*/
|
|
143
|
-
const handleStaticServer = async ({ devConfig,
|
|
144
|
-
|
|
125
|
+
const handleStaticServer = async ({ devConfig, options, projectDir }) => {
|
|
126
|
+
validateNumberProperty({ devConfig, property: 'staticServerPort' })
|
|
145
127
|
|
|
146
|
-
if (
|
|
128
|
+
if (options.dir) {
|
|
147
129
|
log(`${NETLIFYDEVWARN} Using simple static server because ${formatProperty('--dir')} flag was specified`)
|
|
148
130
|
} else if (devConfig.framework === '#static') {
|
|
149
131
|
log(
|
|
@@ -161,8 +143,8 @@ const handleStaticServer = async ({ devConfig, flags, workingDir }) => {
|
|
|
161
143
|
)
|
|
162
144
|
}
|
|
163
145
|
|
|
164
|
-
const dist =
|
|
165
|
-
log(`${NETLIFYDEVWARN} Running static server from "${relative(dirname(
|
|
146
|
+
const dist = options.dir || devConfig.publish || getDefaultDist()
|
|
147
|
+
log(`${NETLIFYDEVWARN} Running static server from "${path.relative(path.dirname(projectDir), dist)}"`)
|
|
166
148
|
|
|
167
149
|
const frameworkPort = await getStaticServerPort({ devConfig })
|
|
168
150
|
return {
|
|
@@ -175,38 +157,118 @@ const handleStaticServer = async ({ devConfig, flags, workingDir }) => {
|
|
|
175
157
|
|
|
176
158
|
/**
|
|
177
159
|
* Retrieves the settings from a framework
|
|
178
|
-
* @param {import('
|
|
160
|
+
* @param {import('./types.js').FrameworkInfo} framework
|
|
179
161
|
* @returns {import('./types.js').BaseServerSettings}
|
|
180
162
|
*/
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
163
|
+
const getSettingsFromFramework = (framework) => {
|
|
164
|
+
const {
|
|
165
|
+
build: { directory: dist },
|
|
166
|
+
dev: {
|
|
167
|
+
commands: [command],
|
|
168
|
+
pollingStrategies = [],
|
|
169
|
+
port: frameworkPort,
|
|
170
|
+
},
|
|
171
|
+
env = {},
|
|
172
|
+
name: frameworkName,
|
|
173
|
+
plugins,
|
|
174
|
+
staticAssetsDirectory: staticDir,
|
|
175
|
+
} = framework
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
command,
|
|
179
|
+
frameworkPort,
|
|
180
|
+
dist: staticDir || dist,
|
|
181
|
+
framework: frameworkName,
|
|
182
|
+
env,
|
|
183
|
+
pollingStrategies: pollingStrategies.map(({ name }) => name),
|
|
184
|
+
plugins,
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const hasDevCommand = (framework) => Array.isArray(framework.dev.commands) && framework.dev.commands.length !== 0
|
|
190
189
|
|
|
191
190
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* @param {import('../commands/base-command.mjs').default} command
|
|
191
|
+
* The new build setting detection with build systems and frameworks combined
|
|
192
|
+
* @param {string} projectDir
|
|
195
193
|
*/
|
|
196
|
-
const
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
194
|
+
const detectSettings = async (projectDir) => {
|
|
195
|
+
const fs = new NodeFS()
|
|
196
|
+
const project = new Project(fs, projectDir)
|
|
197
|
+
|
|
198
|
+
return await project.getBuildSettings()
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
*
|
|
203
|
+
* @param {import('./types.js').BaseServerSettings | undefined} frameworkSettings
|
|
204
|
+
* @param {import('@netlify/build-info').Settings[]} newSettings
|
|
205
|
+
* @param {Record<string, Record<string, any>>} [metadata]
|
|
206
|
+
*/
|
|
207
|
+
const detectChangesInNewSettings = (frameworkSettings, newSettings, metadata) => {
|
|
208
|
+
/** @type {string[]} */
|
|
209
|
+
const message = ['']
|
|
210
|
+
const [setting] = newSettings
|
|
211
|
+
|
|
212
|
+
if (frameworkSettings?.framework !== setting?.framework.name) {
|
|
213
|
+
message.push(
|
|
214
|
+
`- Framework does not match:`,
|
|
215
|
+
` [old]: ${frameworkSettings?.framework}`,
|
|
216
|
+
` [new]: ${setting?.framework.name}`,
|
|
217
|
+
'',
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (frameworkSettings?.command !== setting?.devCommand) {
|
|
222
|
+
message.push(
|
|
223
|
+
`- command does not match:`,
|
|
224
|
+
` [old]: ${frameworkSettings?.command}`,
|
|
225
|
+
` [new]: ${setting?.devCommand}`,
|
|
226
|
+
'',
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (frameworkSettings?.dist !== setting?.dist) {
|
|
231
|
+
message.push(`- dist does not match:`, ` [old]: ${frameworkSettings?.dist}`, ` [new]: ${setting?.dist}`, '')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (frameworkSettings?.frameworkPort !== setting?.frameworkPort) {
|
|
235
|
+
message.push(
|
|
236
|
+
`- frameworkPort does not match:`,
|
|
237
|
+
` [old]: ${frameworkSettings?.frameworkPort}`,
|
|
238
|
+
` [new]: ${setting?.frameworkPort}`,
|
|
239
|
+
'',
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (message.length !== 0) {
|
|
244
|
+
reportError(
|
|
245
|
+
{
|
|
246
|
+
name: 'NewSettingsDetectionMismatch',
|
|
247
|
+
errorMessage: 'New Settings detection does not match old one',
|
|
248
|
+
message: message.join('\n'),
|
|
249
|
+
},
|
|
250
|
+
{ severity: 'info', metadata },
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const detectFrameworkSettings = async ({ projectDir }) => {
|
|
256
|
+
const projectFrameworks = await listFrameworks({ projectDir })
|
|
257
|
+
const frameworks = projectFrameworks.filter((framework) => hasDevCommand(framework))
|
|
258
|
+
|
|
259
|
+
if (frameworks.length === 1) {
|
|
260
|
+
return getSettingsFromFramework(frameworks[0])
|
|
200
261
|
}
|
|
201
262
|
|
|
202
|
-
if (
|
|
263
|
+
if (frameworks.length > 1) {
|
|
203
264
|
/** multiple matching detectors, make the user choose */
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
265
|
+
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
266
|
+
const scriptInquirerOptions = formatSettingsArrForInquirer(frameworks)
|
|
267
|
+
const { chosenFramework } = await inquirer.prompt({
|
|
268
|
+
name: 'chosenFramework',
|
|
269
|
+
message: `Multiple possible start commands found`,
|
|
208
270
|
type: 'autocomplete',
|
|
209
|
-
source(
|
|
271
|
+
source(_, input) {
|
|
210
272
|
if (!input || input === '') {
|
|
211
273
|
return scriptInquirerOptions
|
|
212
274
|
}
|
|
@@ -214,31 +276,25 @@ const detectFrameworkSettings = async (command) => {
|
|
|
214
276
|
return filterSettings(scriptInquirerOptions, input)
|
|
215
277
|
},
|
|
216
278
|
})
|
|
217
|
-
// TODO: do better logging here with the framework command or port
|
|
218
279
|
log(
|
|
219
280
|
`Add ${formatProperty(
|
|
220
|
-
`framework = "${
|
|
281
|
+
`framework = "${chosenFramework.id}"`,
|
|
221
282
|
)} to the [dev] section of your netlify.toml to avoid this selection prompt next time`,
|
|
222
283
|
)
|
|
223
284
|
|
|
224
|
-
return
|
|
285
|
+
return getSettingsFromFramework(chosenFramework)
|
|
225
286
|
}
|
|
226
287
|
}
|
|
227
288
|
|
|
228
|
-
|
|
229
|
-
* @param {import('../commands/dev/types.js').DevConfig} devConfig
|
|
230
|
-
*/
|
|
231
|
-
const hasCommandAndTargetPort = (devConfig) => devConfig.command && devConfig.targetPort
|
|
289
|
+
const hasCommandAndTargetPort = ({ devConfig }) => devConfig.command && devConfig.targetPort
|
|
232
290
|
|
|
233
291
|
/**
|
|
234
292
|
* Creates settings for the custom framework
|
|
235
|
-
* @param {
|
|
236
|
-
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
237
|
-
* @param {string} config.workingDir
|
|
293
|
+
* @param {*} param0
|
|
238
294
|
* @returns {import('./types.js').BaseServerSettings}
|
|
239
295
|
*/
|
|
240
|
-
const handleCustomFramework = ({ devConfig
|
|
241
|
-
if (!hasCommandAndTargetPort(devConfig)) {
|
|
296
|
+
const handleCustomFramework = ({ devConfig }) => {
|
|
297
|
+
if (!hasCommandAndTargetPort({ devConfig })) {
|
|
242
298
|
throw new Error(
|
|
243
299
|
`${formatProperty('command')} and ${formatProperty('targetPort')} properties are required when ${formatProperty(
|
|
244
300
|
'framework',
|
|
@@ -248,20 +304,13 @@ const handleCustomFramework = ({ devConfig, workingDir }) => {
|
|
|
248
304
|
return {
|
|
249
305
|
command: devConfig.command,
|
|
250
306
|
frameworkPort: devConfig.targetPort,
|
|
251
|
-
dist: devConfig.publish || getDefaultDist(
|
|
307
|
+
dist: devConfig.publish || getDefaultDist(),
|
|
252
308
|
framework: '#custom',
|
|
253
309
|
pollingStrategies: devConfig.pollingStrategies || [],
|
|
254
310
|
}
|
|
255
311
|
}
|
|
256
312
|
|
|
257
|
-
|
|
258
|
-
* Merges the framework settings with the devConfig
|
|
259
|
-
* @param {object} config
|
|
260
|
-
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
261
|
-
* @param {string} config.workingDir
|
|
262
|
-
* @param {Partial<import('./types.js').BaseServerSettings>=} config.frameworkSettings
|
|
263
|
-
*/
|
|
264
|
-
const mergeSettings = async ({ devConfig, frameworkSettings = {}, workingDir }) => {
|
|
313
|
+
const mergeSettings = async ({ devConfig, frameworkSettings = {} }) => {
|
|
265
314
|
const {
|
|
266
315
|
command: frameworkCommand,
|
|
267
316
|
dist,
|
|
@@ -278,7 +327,7 @@ const mergeSettings = async ({ devConfig, frameworkSettings = {}, workingDir })
|
|
|
278
327
|
return {
|
|
279
328
|
command,
|
|
280
329
|
frameworkPort: useStaticServer ? await getStaticServerPort({ devConfig }) : frameworkPort,
|
|
281
|
-
dist: devConfig.publish || dist || getDefaultDist(
|
|
330
|
+
dist: devConfig.publish || dist || getDefaultDist(),
|
|
282
331
|
framework,
|
|
283
332
|
env,
|
|
284
333
|
pollingStrategies,
|
|
@@ -288,65 +337,68 @@ const mergeSettings = async ({ devConfig, frameworkSettings = {}, workingDir })
|
|
|
288
337
|
|
|
289
338
|
/**
|
|
290
339
|
* Handles a forced framework and retrieves the settings for it
|
|
291
|
-
* @param {
|
|
292
|
-
* @param {import('../commands/dev/types.js').DevConfig} config.devConfig
|
|
293
|
-
* @param {import('@netlify/build-info').Project} config.project
|
|
294
|
-
* @param {string} config.workingDir
|
|
295
|
-
* @param {string=} config.workspacePackage
|
|
340
|
+
* @param {*} param0
|
|
296
341
|
* @returns {Promise<import('./types.js').BaseServerSettings>}
|
|
297
342
|
*/
|
|
298
|
-
const handleForcedFramework = async ({ devConfig,
|
|
343
|
+
const handleForcedFramework = async ({ devConfig, projectDir }) => {
|
|
299
344
|
// this throws if `devConfig.framework` is not a supported framework
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
const frameworkSettings = getSettingsFromDetectedSettings(settings)
|
|
303
|
-
return mergeSettings({ devConfig, workingDir, frameworkSettings })
|
|
345
|
+
const frameworkSettings = getSettingsFromFramework(await getFramework(devConfig.framework, { projectDir }))
|
|
346
|
+
return mergeSettings({ devConfig, frameworkSettings })
|
|
304
347
|
}
|
|
305
348
|
|
|
306
349
|
/**
|
|
307
350
|
* Get the server settings based on the flags and the devConfig
|
|
308
351
|
* @param {import('../commands/dev/types.js').DevConfig} devConfig
|
|
309
|
-
* @param {import('commander').OptionValues}
|
|
310
|
-
* @param {
|
|
352
|
+
* @param {import('commander').OptionValues} options
|
|
353
|
+
* @param {string} projectDir
|
|
354
|
+
* @param {Record<string, Record<string, any>>} [metadata]
|
|
311
355
|
* @returns {Promise<import('./types.js').ServerSettings>}
|
|
312
356
|
*/
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
validateProperty(devConfig, 'framework', 'string')
|
|
357
|
+
const detectServerSettings = async (devConfig, options, projectDir, metadata) => {
|
|
358
|
+
validateStringProperty({ devConfig, property: 'framework' })
|
|
316
359
|
|
|
317
360
|
/** @type {Partial<import('./types.js').BaseServerSettings>} */
|
|
318
361
|
let settings = {}
|
|
319
362
|
|
|
320
|
-
if (
|
|
363
|
+
if (options.dir || devConfig.framework === '#static') {
|
|
321
364
|
// serving files statically without a framework server
|
|
322
|
-
settings = await handleStaticServer({
|
|
365
|
+
settings = await handleStaticServer({ options, devConfig, projectDir })
|
|
323
366
|
} else if (devConfig.framework === '#auto') {
|
|
324
367
|
// this is the default CLI behavior
|
|
325
368
|
|
|
326
|
-
const runDetection = !hasCommandAndTargetPort(devConfig)
|
|
327
|
-
const frameworkSettings = runDetection ? await detectFrameworkSettings(
|
|
369
|
+
const runDetection = !hasCommandAndTargetPort({ devConfig })
|
|
370
|
+
const frameworkSettings = runDetection ? await detectFrameworkSettings({ projectDir }) : undefined
|
|
371
|
+
const newSettings = runDetection ? await detectSettings(projectDir) : undefined
|
|
372
|
+
|
|
373
|
+
// just report differences in the settings
|
|
374
|
+
detectChangesInNewSettings(frameworkSettings, newSettings || [], {
|
|
375
|
+
...metadata,
|
|
376
|
+
settings: {
|
|
377
|
+
projectDir,
|
|
378
|
+
devConfig,
|
|
379
|
+
options,
|
|
380
|
+
old: frameworkSettings,
|
|
381
|
+
settings: newSettings,
|
|
382
|
+
},
|
|
383
|
+
})
|
|
384
|
+
|
|
328
385
|
if (frameworkSettings === undefined && runDetection) {
|
|
329
386
|
log(`${NETLIFYDEVWARN} No app server detected. Using simple static server`)
|
|
330
|
-
settings = await handleStaticServer({
|
|
387
|
+
settings = await handleStaticServer({ options, devConfig, projectDir })
|
|
331
388
|
} else {
|
|
332
389
|
validateFrameworkConfig({ devConfig })
|
|
333
|
-
settings = await mergeSettings({ devConfig, frameworkSettings
|
|
390
|
+
settings = await mergeSettings({ devConfig, frameworkSettings })
|
|
334
391
|
}
|
|
335
392
|
|
|
336
|
-
settings.plugins = frameworkSettings
|
|
393
|
+
settings.plugins = frameworkSettings && frameworkSettings.plugins
|
|
337
394
|
} else if (devConfig.framework === '#custom') {
|
|
338
395
|
validateFrameworkConfig({ devConfig })
|
|
339
396
|
// when the users wants to configure `command` and `targetPort`
|
|
340
|
-
settings = handleCustomFramework({ devConfig
|
|
397
|
+
settings = handleCustomFramework({ devConfig })
|
|
341
398
|
} else if (devConfig.framework) {
|
|
342
399
|
validateFrameworkConfig({ devConfig })
|
|
343
400
|
// this is when the user explicitly configures a framework, e.g. `framework = "gatsby"`
|
|
344
|
-
settings = await handleForcedFramework({
|
|
345
|
-
devConfig,
|
|
346
|
-
project: command.project,
|
|
347
|
-
workingDir: command.workingDir,
|
|
348
|
-
workspacePackage: command.workspacePackage,
|
|
349
|
-
})
|
|
401
|
+
settings = await handleForcedFramework({ devConfig, projectDir })
|
|
350
402
|
}
|
|
351
403
|
|
|
352
404
|
validateConfiguredPort({ devConfig, detectedPort: settings.frameworkPort })
|
|
@@ -357,7 +409,7 @@ const detectServerSettings = async (devConfig, flags, command) => {
|
|
|
357
409
|
errorMessage: `Could not acquire required ${formatProperty('port')}`,
|
|
358
410
|
})
|
|
359
411
|
const functionsDir = devConfig.functions || settings.functions
|
|
360
|
-
const internalFunctionsDir = await getInternalFunctionsDir({ base:
|
|
412
|
+
const internalFunctionsDir = await getInternalFunctionsDir({ base: projectDir })
|
|
361
413
|
const shouldStartFunctionsServer = Boolean(functionsDir || internalFunctionsDir)
|
|
362
414
|
|
|
363
415
|
return {
|
|
@@ -382,16 +434,15 @@ const filterSettings = function (scriptInquirerOptions, input) {
|
|
|
382
434
|
return scriptInquirerOptions.filter((t) => filteredSettingNames.has(t.name))
|
|
383
435
|
}
|
|
384
436
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}))
|
|
437
|
+
const formatSettingsArrForInquirer = function (frameworks) {
|
|
438
|
+
const formattedArr = frameworks.map((framework) =>
|
|
439
|
+
framework.dev.commands.map((command) => ({
|
|
440
|
+
name: `[${chalk.yellow(framework.name)}] '${command}'`,
|
|
441
|
+
value: { ...framework, commands: [command] },
|
|
442
|
+
short: `${framework.name}-${command}`,
|
|
443
|
+
})),
|
|
444
|
+
)
|
|
445
|
+
return formattedArr.flat()
|
|
395
446
|
}
|
|
396
447
|
|
|
397
448
|
/**
|
|
@@ -18,7 +18,7 @@ const FRAMEWORK_PORT_TIMEOUT = 6e5
|
|
|
18
18
|
/**
|
|
19
19
|
* Start a static server if the `useStaticServer` is provided or a framework specific server
|
|
20
20
|
* @param {object} config
|
|
21
|
-
* @param {import('./types
|
|
21
|
+
* @param {Partial<import('./types').ServerSettings>} config.settings
|
|
22
22
|
* @returns {Promise<StartReturnObject>}
|
|
23
23
|
*/
|
|
24
24
|
export const startFrameworkServer = async function ({ settings }) {
|
|
@@ -46,7 +46,7 @@ export const startFrameworkServer = async function ({ settings }) {
|
|
|
46
46
|
host: 'localhost',
|
|
47
47
|
output: 'silent',
|
|
48
48
|
timeout: FRAMEWORK_PORT_TIMEOUT,
|
|
49
|
-
...(settings.pollingStrategies
|
|
49
|
+
...(settings.pollingStrategies.includes('HTTP') && { protocol: 'http' }),
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
if (!port.open) {
|
|
@@ -37,13 +37,6 @@ export const getFunctionsDistPath = async ({ base }) => {
|
|
|
37
37
|
return isDirectory ? path : null
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
* Retrieves the internal functions directory and creates it if ensureExists is provided
|
|
42
|
-
* @param {object} config
|
|
43
|
-
* @param {string} config.base
|
|
44
|
-
* @param {boolean=} config.ensureExists
|
|
45
|
-
* @returns
|
|
46
|
-
*/
|
|
47
40
|
export const getInternalFunctionsDir = async ({ base, ensureExists }) => {
|
|
48
41
|
const path = resolve(base, getPathInProject([INTERNAL_FUNCTIONS_FOLDER]))
|
|
49
42
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { dirname } from 'path'
|
|
3
|
+
import process from 'process'
|
|
3
4
|
import util from 'util'
|
|
4
5
|
|
|
5
6
|
import { findUp } from 'find-up'
|
|
@@ -13,14 +14,14 @@ import { log } from './command-helpers.mjs'
|
|
|
13
14
|
*
|
|
14
15
|
* @param {object} config
|
|
15
16
|
* @param {string} [config.remoteName]
|
|
16
|
-
* @param {string} config.workingDir
|
|
17
17
|
* @returns
|
|
18
18
|
*/
|
|
19
|
-
const getRepoData = async function ({ remoteName
|
|
19
|
+
const getRepoData = async function ({ remoteName } = {}) {
|
|
20
20
|
try {
|
|
21
|
+
const cwd = process.cwd()
|
|
21
22
|
const [gitConfig, gitDirectory] = await Promise.all([
|
|
22
|
-
util.promisify(gitconfiglocal)(
|
|
23
|
-
findUp('.git', { cwd
|
|
23
|
+
util.promisify(gitconfiglocal)(cwd),
|
|
24
|
+
findUp('.git', { cwd, type: 'directory' }),
|
|
24
25
|
])
|
|
25
26
|
|
|
26
27
|
if (!gitDirectory || !gitConfig || !gitConfig.remote || Object.keys(gitConfig.remote).length === 0) {
|
|
@@ -29,7 +30,7 @@ const getRepoData = async function ({ remoteName, workingDir }) {
|
|
|
29
30
|
|
|
30
31
|
const baseGitPath = dirname(gitDirectory)
|
|
31
32
|
|
|
32
|
-
if (
|
|
33
|
+
if (cwd !== baseGitPath) {
|
|
33
34
|
log(`Git directory located in ${baseGitPath}`)
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -207,7 +207,7 @@ export const configGithub = async ({ command, repoName, repoOwner, siteId }) =>
|
|
|
207
207
|
const { netlify } = command
|
|
208
208
|
const {
|
|
209
209
|
api,
|
|
210
|
-
cachedConfig: { configPath },
|
|
210
|
+
cachedConfig: { configPath, env },
|
|
211
211
|
config,
|
|
212
212
|
globalConfig,
|
|
213
213
|
repositoryRoot,
|
|
@@ -220,7 +220,7 @@ export const configGithub = async ({ command, repoName, repoOwner, siteId }) =>
|
|
|
220
220
|
repositoryRoot,
|
|
221
221
|
siteRoot,
|
|
222
222
|
config,
|
|
223
|
-
|
|
223
|
+
env,
|
|
224
224
|
})
|
|
225
225
|
await saveNetlifyToml({ repositoryRoot, config, configPath, baseDir, buildCmd, buildDir, functionsDir })
|
|
226
226
|
|