shakapacker 9.3.0.beta.2 → 9.3.0.beta.4
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.
- checksums.yaml +4 -4
- data/ESLINT_TECHNICAL_DEBT.md +13 -14
- data/Gemfile.lock +1 -1
- data/README.md +9 -6
- data/docs/configuration.md +101 -0
- data/docs/preventing_fouc.md +132 -0
- data/docs/troubleshooting.md +4 -0
- data/eslint.config.js +2 -6
- data/lib/shakapacker/build_config_loader.rb +147 -0
- data/lib/shakapacker/configuration.rb +6 -2
- data/lib/shakapacker/dev_server_runner.rb +73 -0
- data/lib/shakapacker/runner.rb +239 -14
- data/lib/shakapacker/version.rb +1 -1
- data/package/configExporter/buildValidator.ts +2 -2
- data/package/configExporter/cli.ts +251 -160
- data/package/configExporter/configFile.ts +182 -46
- data/package/configExporter/fileWriter.ts +8 -1
- data/package/configExporter/types.ts +2 -0
- data/package/utils/pathValidation.ts +3 -3
- data/package-lock.json +2 -2
- data/package.json +1 -1
- data/test/configExporter/configFile.test.js +3 -2
- data/test/configExporter/integration.test.js +14 -27
- metadata +6 -4
- /data/bin/{export-bundler-config → shakapacker-config} +0 -0
- /data/lib/install/bin/{export-bundler-config → shakapacker-config} +0 -0
@@ -101,20 +101,21 @@ export async function run(args: string[]): Promise<number> {
|
|
101
101
|
setupNodePath(appRoot)
|
102
102
|
|
103
103
|
// Apply defaults
|
104
|
-
applyDefaults(options)
|
104
|
+
const resolvedOptions = applyDefaults(options)
|
105
105
|
|
106
106
|
// Validate after defaults are applied
|
107
|
-
if (
|
107
|
+
if (resolvedOptions.annotate && resolvedOptions.format !== "yaml") {
|
108
108
|
throw new Error(
|
109
109
|
"Annotation requires YAML format. Use --no-annotate or --format=yaml."
|
110
110
|
)
|
111
111
|
}
|
112
112
|
|
113
113
|
// Validate --build requires config file
|
114
|
-
if (
|
115
|
-
const loader = new ConfigFileLoader(
|
114
|
+
if (resolvedOptions.build) {
|
115
|
+
const loader = new ConfigFileLoader(resolvedOptions.configFile)
|
116
116
|
if (!loader.exists()) {
|
117
|
-
const configPath =
|
117
|
+
const configPath =
|
118
|
+
resolvedOptions.configFile || "config/shakapacker-builds.yml"
|
118
119
|
throw new Error(
|
119
120
|
`--build requires a config file but ${configPath} not found. Run --init to create it.`
|
120
121
|
)
|
@@ -122,17 +123,17 @@ export async function run(args: string[]): Promise<number> {
|
|
122
123
|
}
|
123
124
|
|
124
125
|
// Execute based on mode
|
125
|
-
if (
|
126
|
-
await runDoctorMode(
|
127
|
-
} else if (
|
126
|
+
if (resolvedOptions.doctor) {
|
127
|
+
await runDoctorMode(resolvedOptions, appRoot)
|
128
|
+
} else if (resolvedOptions.stdout) {
|
128
129
|
// Explicit stdout mode
|
129
|
-
await runStdoutMode(
|
130
|
-
} else if (
|
130
|
+
await runStdoutMode(resolvedOptions, appRoot)
|
131
|
+
} else if (resolvedOptions.output) {
|
131
132
|
// Save to single file
|
132
|
-
await runSingleFileMode(
|
133
|
+
await runSingleFileMode(resolvedOptions, appRoot)
|
133
134
|
} else {
|
134
135
|
// Default: save to directory
|
135
|
-
await runSaveMode(
|
136
|
+
await runSaveMode(resolvedOptions, appRoot)
|
136
137
|
}
|
137
138
|
|
138
139
|
return 0
|
@@ -153,61 +154,75 @@ Exports webpack or rspack configuration in a verbose, human-readable format
|
|
153
154
|
for comparison and analysis.
|
154
155
|
|
155
156
|
QUICK START (for troubleshooting):
|
156
|
-
bin/
|
157
|
+
bin/shakapacker-config --doctor
|
157
158
|
|
158
159
|
Exports annotated YAML configs for both development and production.
|
159
160
|
Creates separate files for client and server bundles.
|
160
161
|
Best for debugging, AI analysis, and comparing configurations.`
|
161
162
|
)
|
162
|
-
|
163
|
+
// Build Configuration Options (most important - users interact with these most)
|
164
|
+
.option("init", {
|
163
165
|
type: "boolean",
|
164
166
|
default: false,
|
165
167
|
description:
|
166
|
-
"
|
168
|
+
"Generate config/shakapacker-builds.yml (use with --ssr for SSR builds)"
|
167
169
|
})
|
168
|
-
.option("
|
169
|
-
type: "
|
170
|
-
|
171
|
-
|
170
|
+
.option("ssr", {
|
171
|
+
type: "boolean",
|
172
|
+
default: false,
|
173
|
+
description: "Include SSR builds when using --init"
|
172
174
|
})
|
173
|
-
.option("
|
175
|
+
.option("list-builds", {
|
174
176
|
type: "boolean",
|
175
177
|
default: false,
|
176
|
-
description: "
|
178
|
+
description: "List all available builds from config file"
|
177
179
|
})
|
178
|
-
.option("
|
180
|
+
.option("build", {
|
179
181
|
type: "string",
|
180
|
-
|
181
|
-
description: "Specify bundler (auto-detected if not provided)"
|
182
|
+
description: "Export config for specific build from config file"
|
182
183
|
})
|
183
|
-
.option("
|
184
|
+
.option("all-builds", {
|
185
|
+
type: "boolean",
|
186
|
+
default: false,
|
187
|
+
description: "Export all builds from config file"
|
188
|
+
})
|
189
|
+
.option("config-file", {
|
184
190
|
type: "string",
|
185
|
-
choices: ["development", "production", "test"] as const,
|
186
191
|
description:
|
187
|
-
"
|
192
|
+
"Path to config file (default: config/shakapacker-builds.yml)"
|
188
193
|
})
|
189
|
-
|
194
|
+
// Validation Options
|
195
|
+
.option("validate", {
|
190
196
|
type: "boolean",
|
191
197
|
default: false,
|
192
|
-
description:
|
198
|
+
description:
|
199
|
+
"Validate all builds by running webpack/rspack (requires config file)"
|
193
200
|
})
|
194
|
-
.option("
|
201
|
+
.option("validate-build", {
|
202
|
+
type: "string",
|
203
|
+
description: "Validate specific build from config file"
|
204
|
+
})
|
205
|
+
// Troubleshooting
|
206
|
+
.option("doctor", {
|
195
207
|
type: "boolean",
|
196
208
|
default: false,
|
197
|
-
description:
|
209
|
+
description:
|
210
|
+
"Export all configs for troubleshooting (uses config file builds if available)"
|
211
|
+
})
|
212
|
+
// Output Options
|
213
|
+
.option("save-dir", {
|
214
|
+
type: "string",
|
215
|
+
description:
|
216
|
+
"Directory for output files (default: shakapacker-config-exports)"
|
198
217
|
})
|
199
218
|
.option("output", {
|
200
219
|
type: "string",
|
201
220
|
description: "Output to specific file instead of directory"
|
202
221
|
})
|
203
|
-
.option("
|
204
|
-
type: "
|
205
|
-
default:
|
206
|
-
|
207
|
-
if (value === "null" || value === null) return null
|
208
|
-
return typeof value === "number" ? value : parseInt(String(value), 10)
|
209
|
-
},
|
210
|
-
description: "Inspection depth (use 'null' for unlimited)"
|
222
|
+
.option("stdout", {
|
223
|
+
type: "boolean",
|
224
|
+
default: false,
|
225
|
+
description: "Output to stdout instead of saving to files"
|
211
226
|
})
|
212
227
|
.option("format", {
|
213
228
|
type: "string",
|
@@ -219,53 +234,54 @@ QUICK START (for troubleshooting):
|
|
219
234
|
description:
|
220
235
|
"Enable inline documentation (YAML only, default with --doctor or file output)"
|
221
236
|
})
|
237
|
+
.option("depth", {
|
238
|
+
type: "number",
|
239
|
+
default: 20,
|
240
|
+
coerce: (value: number | string) => {
|
241
|
+
if (value === "null" || value === null) return null
|
242
|
+
return typeof value === "number" ? value : parseInt(String(value), 10)
|
243
|
+
},
|
244
|
+
description: "Inspection depth (use 'null' for unlimited)"
|
245
|
+
})
|
222
246
|
.option("verbose", {
|
223
247
|
type: "boolean",
|
224
248
|
default: false,
|
225
249
|
description: "Show full output without compact mode"
|
226
250
|
})
|
227
|
-
|
228
|
-
|
229
|
-
default: false,
|
230
|
-
description: "Generate sample .bundler-config.yml with examples"
|
231
|
-
})
|
232
|
-
.option("config-file", {
|
233
|
-
type: "string",
|
234
|
-
description: "Path to config file (default: .bundler-config.yml)"
|
235
|
-
})
|
236
|
-
.option("build", {
|
251
|
+
// Bundler Options
|
252
|
+
.option("bundler", {
|
237
253
|
type: "string",
|
238
|
-
|
239
|
-
|
240
|
-
.option("list-builds", {
|
241
|
-
type: "boolean",
|
242
|
-
default: false,
|
243
|
-
description: "List all available builds from config file"
|
254
|
+
choices: ["webpack", "rspack"] as const,
|
255
|
+
description: "Specify bundler (auto-detected if not provided)"
|
244
256
|
})
|
245
|
-
.option("
|
257
|
+
.option("webpack", {
|
246
258
|
type: "boolean",
|
247
259
|
default: false,
|
248
|
-
description: "
|
260
|
+
description: "Use webpack (overrides config file)"
|
249
261
|
})
|
250
|
-
.option("
|
262
|
+
.option("rspack", {
|
251
263
|
type: "boolean",
|
252
264
|
default: false,
|
253
|
-
description:
|
254
|
-
"Validate all builds by running webpack/rspack (requires config file)"
|
265
|
+
description: "Use rspack (overrides config file)"
|
255
266
|
})
|
256
|
-
|
267
|
+
// Legacy/Fallback Options (when no config file exists)
|
268
|
+
.option("env", {
|
257
269
|
type: "string",
|
258
|
-
|
270
|
+
choices: ["development", "production", "test"] as const,
|
271
|
+
description:
|
272
|
+
"Node environment (fallback when no config file exists, ignored with --doctor or --build)"
|
259
273
|
})
|
260
|
-
.option("
|
274
|
+
.option("client-only", {
|
261
275
|
type: "boolean",
|
262
276
|
default: false,
|
263
|
-
description:
|
277
|
+
description:
|
278
|
+
"Generate only client config (fallback when no config file exists)"
|
264
279
|
})
|
265
|
-
.option("
|
280
|
+
.option("server-only", {
|
266
281
|
type: "boolean",
|
267
282
|
default: false,
|
268
|
-
description:
|
283
|
+
description:
|
284
|
+
"Generate only server config (fallback when no config file exists)"
|
269
285
|
})
|
270
286
|
.check((argv) => {
|
271
287
|
if (argv.webpack && argv.rspack) {
|
@@ -303,6 +319,11 @@ QUICK START (for troubleshooting):
|
|
303
319
|
"--validate cannot be used with --build or --all-builds."
|
304
320
|
)
|
305
321
|
}
|
322
|
+
if (argv.ssr && !argv.init) {
|
323
|
+
throw new Error(
|
324
|
+
"--ssr can only be used with --init. Use: bin/shakapacker-config --init --ssr"
|
325
|
+
)
|
326
|
+
}
|
306
327
|
return true
|
307
328
|
})
|
308
329
|
.help("help")
|
@@ -310,31 +331,27 @@ QUICK START (for troubleshooting):
|
|
310
331
|
.epilogue(
|
311
332
|
`Examples:
|
312
333
|
|
313
|
-
# Config File Workflow
|
314
|
-
bin/
|
315
|
-
bin/
|
316
|
-
bin/
|
317
|
-
bin/
|
318
|
-
bin/
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
#
|
323
|
-
#
|
324
|
-
#
|
325
|
-
|
326
|
-
|
327
|
-
bin/
|
328
|
-
bin/
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
bin/
|
333
|
-
bin/
|
334
|
-
|
335
|
-
# View config in terminal (stdout)
|
336
|
-
bin/export-bundler-config --stdout
|
337
|
-
bin/export-bundler-config --output=config.yaml # Save to specific file`
|
334
|
+
# Config File Workflow (recommended)
|
335
|
+
bin/shakapacker-config --init # Create config file
|
336
|
+
bin/shakapacker-config --init --ssr # Create config with SSR builds
|
337
|
+
bin/shakapacker-config --list-builds # List available builds
|
338
|
+
bin/shakapacker-config --build=dev # Export specific build
|
339
|
+
bin/shakapacker-config --all-builds --save-dir=./configs
|
340
|
+
bin/shakapacker-config --build=dev --rspack # Override bundler
|
341
|
+
|
342
|
+
# Troubleshooting
|
343
|
+
bin/shakapacker-config --doctor # Export all configs for debugging
|
344
|
+
# If config file exists: exports all builds from config
|
345
|
+
# If no config file: exports dev/prod client/server configs
|
346
|
+
|
347
|
+
# Validate builds (requires config file)
|
348
|
+
bin/shakapacker-config --validate # Validate all builds
|
349
|
+
bin/shakapacker-config --validate-build=dev # Validate specific build
|
350
|
+
bin/shakapacker-config --validate --verbose # Validate with full logs
|
351
|
+
|
352
|
+
# Advanced output options
|
353
|
+
bin/shakapacker-config --build=dev --stdout # View in terminal
|
354
|
+
bin/shakapacker-config --build=dev --output=config.yaml # Save to specific file`
|
338
355
|
)
|
339
356
|
.strict()
|
340
357
|
.parseSync()
|
@@ -363,6 +380,7 @@ QUICK START (for troubleshooting):
|
|
363
380
|
stdout: argv.stdout,
|
364
381
|
annotate: argv.annotate,
|
365
382
|
init: argv.init,
|
383
|
+
ssr: argv.ssr,
|
366
384
|
configFile: argv["config-file"],
|
367
385
|
build: argv.build,
|
368
386
|
listBuilds: argv["list-builds"],
|
@@ -372,29 +390,43 @@ QUICK START (for troubleshooting):
|
|
372
390
|
}
|
373
391
|
}
|
374
392
|
|
375
|
-
function applyDefaults(options: ExportOptions):
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
393
|
+
function applyDefaults(options: ExportOptions): ExportOptions {
|
394
|
+
const updatedOptions = { ...options }
|
395
|
+
|
396
|
+
if (updatedOptions.doctor) {
|
397
|
+
if (updatedOptions.format === undefined) updatedOptions.format = "yaml"
|
398
|
+
if (updatedOptions.annotate === undefined) updatedOptions.annotate = true
|
399
|
+
} else if (!updatedOptions.stdout && !updatedOptions.output) {
|
380
400
|
// Default mode: save to directory
|
381
|
-
if (
|
382
|
-
if (
|
401
|
+
if (updatedOptions.format === undefined) updatedOptions.format = "yaml"
|
402
|
+
if (updatedOptions.annotate === undefined) updatedOptions.annotate = true
|
383
403
|
} else {
|
384
|
-
if (
|
385
|
-
if (
|
404
|
+
if (updatedOptions.format === undefined) updatedOptions.format = "inspect"
|
405
|
+
if (updatedOptions.annotate === undefined) updatedOptions.annotate = false
|
386
406
|
}
|
387
407
|
|
388
408
|
// Set default save directory for file output modes
|
389
|
-
if (
|
390
|
-
|
409
|
+
if (
|
410
|
+
!updatedOptions.stdout &&
|
411
|
+
!updatedOptions.output &&
|
412
|
+
!updatedOptions.saveDir
|
413
|
+
) {
|
414
|
+
updatedOptions.saveDir = resolve(
|
415
|
+
process.cwd(),
|
416
|
+
"shakapacker-config-exports"
|
417
|
+
)
|
391
418
|
}
|
419
|
+
|
420
|
+
return updatedOptions
|
392
421
|
}
|
393
422
|
|
394
423
|
function runInitCommand(options: ExportOptions): number {
|
395
|
-
const configPath = options.configFile || "
|
424
|
+
const configPath = options.configFile || "config/shakapacker-builds.yml"
|
396
425
|
const fullPath = resolve(process.cwd(), configPath)
|
397
426
|
|
427
|
+
// Check if SSR variant is requested via --ssr flag
|
428
|
+
const ssrMode = options.ssr || false
|
429
|
+
|
398
430
|
if (existsSync(fullPath)) {
|
399
431
|
console.error(
|
400
432
|
`[Config Exporter] Error: Config file already exists: ${fullPath}`
|
@@ -405,22 +437,78 @@ function runInitCommand(options: ExportOptions): number {
|
|
405
437
|
return 1
|
406
438
|
}
|
407
439
|
|
408
|
-
|
440
|
+
// Create bin stub if it doesn't exist
|
441
|
+
const binStubPath = resolve(process.cwd(), "bin/shakapacker-config")
|
442
|
+
const createdStub = !existsSync(binStubPath)
|
443
|
+
if (createdStub) {
|
444
|
+
createBinStub(binStubPath)
|
445
|
+
}
|
446
|
+
|
447
|
+
const sampleConfig = generateSampleConfigFile(ssrMode)
|
409
448
|
writeFileSync(fullPath, sampleConfig, "utf8")
|
410
449
|
|
411
450
|
console.log(`[Config Exporter] ✅ Created config file: ${fullPath}`)
|
451
|
+
if (ssrMode) {
|
452
|
+
console.log(
|
453
|
+
`[Config Exporter] ℹ️ Generated SSR build configuration (5 builds)`
|
454
|
+
)
|
455
|
+
} else {
|
456
|
+
console.log(
|
457
|
+
`[Config Exporter] ℹ️ Generated standard build configuration (3 builds)`
|
458
|
+
)
|
459
|
+
console.log(
|
460
|
+
`[Config Exporter] 💡 Uncomment SSR builds in the file if needed, or regenerate with: bin/shakapacker-config --init --ssr`
|
461
|
+
)
|
462
|
+
}
|
463
|
+
|
464
|
+
if (createdStub) {
|
465
|
+
console.log(`[Config Exporter] ✅ Created bin stub: ${binStubPath}`)
|
466
|
+
}
|
467
|
+
|
412
468
|
console.log(`\nNext steps:`)
|
413
|
-
console.log(` 1.
|
414
|
-
console.log(
|
415
|
-
` 2. List available builds: bin/export-bundler-config --list-builds`
|
416
|
-
)
|
417
|
-
console.log(
|
418
|
-
` 3. Export a build: bin/export-bundler-config --build=<name> --save\n`
|
419
|
-
)
|
469
|
+
console.log(` 1. List available builds: bin/shakapacker --list-builds`)
|
470
|
+
console.log(` 2. Run a build: bin/shakapacker --build <name>\n`)
|
420
471
|
|
421
472
|
return 0
|
422
473
|
}
|
423
474
|
|
475
|
+
function createBinStub(binStubPath: string): void {
|
476
|
+
const binDir = dirname(binStubPath)
|
477
|
+
const { mkdirSync, chmodSync } = require("fs")
|
478
|
+
|
479
|
+
// Ensure bin directory exists
|
480
|
+
if (!existsSync(binDir)) {
|
481
|
+
mkdirSync(binDir, { recursive: true })
|
482
|
+
}
|
483
|
+
|
484
|
+
const stubContent = `#!/usr/bin/env ruby
|
485
|
+
# frozen_string_literal: true
|
486
|
+
|
487
|
+
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
|
488
|
+
ENV["NODE_ENV"] ||= "development"
|
489
|
+
|
490
|
+
require "pathname"
|
491
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
492
|
+
Pathname.new(__FILE__).realpath)
|
493
|
+
|
494
|
+
require "bundler/setup"
|
495
|
+
|
496
|
+
APP_ROOT = File.expand_path("..", __dir__)
|
497
|
+
Dir.chdir(APP_ROOT) do
|
498
|
+
exec "node", "./node_modules/.bin/shakapacker-config", *ARGV
|
499
|
+
end
|
500
|
+
`
|
501
|
+
|
502
|
+
writeFileSync(binStubPath, stubContent, { mode: 0o755 })
|
503
|
+
|
504
|
+
// Make executable
|
505
|
+
try {
|
506
|
+
chmodSync(binStubPath, 0o755)
|
507
|
+
} catch (e) {
|
508
|
+
// chmod might fail on some systems, but mode in writeFileSync should handle it
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
424
512
|
function runListBuildsCommand(options: ExportOptions): number {
|
425
513
|
try {
|
426
514
|
const loader = new ConfigFileLoader(options.configFile)
|
@@ -440,7 +528,7 @@ async function runValidateCommand(options: ExportOptions): Promise<number> {
|
|
440
528
|
// Validate that config file exists
|
441
529
|
const loader = new ConfigFileLoader(options.configFile)
|
442
530
|
if (!loader.exists()) {
|
443
|
-
const configPath = options.configFile || "
|
531
|
+
const configPath = options.configFile || "config/shakapacker-builds.yml"
|
444
532
|
throw new Error(
|
445
533
|
`Config file ${configPath} not found. Run --init to create it.`
|
446
534
|
)
|
@@ -473,7 +561,7 @@ async function runValidateCommand(options: ExportOptions): Promise<number> {
|
|
473
561
|
// Handle empty builds edge case
|
474
562
|
if (buildsToValidate.length === 0) {
|
475
563
|
throw new Error(
|
476
|
-
`No builds found in config file. Add at least one build to
|
564
|
+
`No builds found in config file. Add at least one build to config/shakapacker-builds.yml or run --init to see examples.`
|
477
565
|
)
|
478
566
|
}
|
479
567
|
}
|
@@ -575,11 +663,12 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
575
663
|
setupNodePath(appRoot)
|
576
664
|
|
577
665
|
// Apply defaults
|
578
|
-
applyDefaults(options)
|
666
|
+
const resolvedOptions = applyDefaults(options)
|
579
667
|
|
580
|
-
const loader = new ConfigFileLoader(
|
668
|
+
const loader = new ConfigFileLoader(resolvedOptions.configFile)
|
581
669
|
if (!loader.exists()) {
|
582
|
-
const configPath =
|
670
|
+
const configPath =
|
671
|
+
resolvedOptions.configFile || "config/shakapacker-builds.yml"
|
583
672
|
throw new Error(
|
584
673
|
`Config file ${configPath} not found. Run --init to create it.`
|
585
674
|
)
|
@@ -592,7 +681,7 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
592
681
|
`\n📦 Exporting ${buildNames.length} builds from config file...\n`
|
593
682
|
)
|
594
683
|
|
595
|
-
const targetDir =
|
684
|
+
const targetDir = resolvedOptions.saveDir! // Set by applyDefaults
|
596
685
|
const createdFiles: string[] = []
|
597
686
|
|
598
687
|
// Export each build
|
@@ -604,16 +693,16 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
604
693
|
restoreBuildEnvironmentVariables(savedEnv)
|
605
694
|
|
606
695
|
// Create a modified options object for this build
|
607
|
-
const buildOptions = { ...
|
696
|
+
const buildOptions = { ...resolvedOptions, build: buildName }
|
608
697
|
const configs = await loadConfigsForEnv(undefined, buildOptions, appRoot)
|
609
698
|
|
610
699
|
for (const { config: cfg, metadata } of configs) {
|
611
|
-
const output = formatConfig(cfg, metadata,
|
700
|
+
const output = formatConfig(cfg, metadata, resolvedOptions, appRoot)
|
612
701
|
const filename = FileWriter.generateFilename(
|
613
702
|
metadata.bundler,
|
614
703
|
metadata.environment,
|
615
704
|
metadata.configType,
|
616
|
-
|
705
|
+
resolvedOptions.format!,
|
617
706
|
metadata.buildName
|
618
707
|
)
|
619
708
|
|
@@ -662,63 +751,65 @@ async function runDoctorMode(
|
|
662
751
|
|
663
752
|
const createdFiles: string[] = []
|
664
753
|
|
665
|
-
// Check if config file exists
|
666
|
-
const configFilePath = options.configFile || "
|
754
|
+
// Check if config file exists - always use it for doctor mode
|
755
|
+
const configFilePath = options.configFile || "config/shakapacker-builds.yml"
|
667
756
|
const loader = new ConfigFileLoader(configFilePath)
|
668
757
|
|
669
758
|
if (loader.exists()) {
|
670
759
|
try {
|
671
760
|
const configData = loader.load()
|
672
|
-
|
673
|
-
console.log(
|
674
|
-
"\nUsing builds from config file (shakapacker_doctor_default_builds_here: true)...\n"
|
675
|
-
)
|
676
|
-
// Use config file builds
|
677
|
-
const buildNames = Object.keys(configData.builds)
|
761
|
+
console.log(`\nUsing builds from ${configFilePath}...\n`)
|
678
762
|
|
679
|
-
|
680
|
-
|
763
|
+
// Use config file builds
|
764
|
+
const buildNames = Object.keys(configData.builds)
|
681
765
|
|
682
|
-
|
683
|
-
|
684
|
-
restoreBuildEnvironmentVariables(savedEnv)
|
766
|
+
for (const buildName of buildNames) {
|
767
|
+
console.log(`\n📦 Loading build: ${buildName}`)
|
685
768
|
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
appRoot
|
690
|
-
)
|
769
|
+
// Clear and restore environment to prevent leakage between builds
|
770
|
+
clearBuildEnvironmentVariables()
|
771
|
+
restoreBuildEnvironmentVariables(savedEnv)
|
691
772
|
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
metadata.configType,
|
698
|
-
options.format!,
|
699
|
-
metadata.buildName
|
700
|
-
)
|
701
|
-
const fullPath = resolve(targetDir, filename)
|
702
|
-
FileWriter.writeSingleFile(fullPath, output)
|
703
|
-
createdFiles.push(fullPath)
|
704
|
-
}
|
705
|
-
}
|
773
|
+
const configs = await loadConfigsForEnv(
|
774
|
+
undefined,
|
775
|
+
{ ...options, build: buildName },
|
776
|
+
appRoot
|
777
|
+
)
|
706
778
|
|
707
|
-
|
708
|
-
|
709
|
-
|
779
|
+
for (const { config, metadata } of configs) {
|
780
|
+
const output = formatConfig(config, metadata, options, appRoot)
|
781
|
+
const filename = FileWriter.generateFilename(
|
782
|
+
metadata.bundler,
|
783
|
+
metadata.environment,
|
784
|
+
metadata.configType,
|
785
|
+
options.format!,
|
786
|
+
metadata.buildName
|
787
|
+
)
|
788
|
+
const fullPath = resolve(targetDir, filename)
|
789
|
+
FileWriter.writeSingleFile(fullPath, output)
|
790
|
+
createdFiles.push(fullPath)
|
791
|
+
}
|
710
792
|
}
|
793
|
+
|
794
|
+
// Print summary and exit early
|
795
|
+
printDoctorSummary(createdFiles, targetDir)
|
796
|
+
return
|
711
797
|
} catch (error: unknown) {
|
712
|
-
// If config file exists but is invalid,
|
798
|
+
// If config file exists but is invalid, show error and exit
|
713
799
|
const errorMessage =
|
714
800
|
error instanceof Error ? error.message : String(error)
|
715
|
-
console.
|
716
|
-
console.
|
801
|
+
console.error(`\n❌ Config file found but invalid: ${errorMessage}`)
|
802
|
+
console.error(
|
803
|
+
`Fix the config file or run: bin/shakapacker-config --init\n`
|
804
|
+
)
|
805
|
+
throw error
|
717
806
|
}
|
718
807
|
}
|
719
808
|
|
720
|
-
//
|
721
|
-
console.log(
|
809
|
+
// No config file found - suggest creating one
|
810
|
+
console.log(`\n⚠️ No build config file found at ${configFilePath}`)
|
811
|
+
console.log(`Run: bin/shakapacker-config --init to create one.\n`)
|
812
|
+
console.log("Exporting default development and production configs...")
|
722
813
|
console.log("")
|
723
814
|
|
724
815
|
const configsToExport = [
|