shakapacker 9.3.0.beta.0 → 9.3.0.beta.2
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/.github/workflows/eslint-validation.yml +46 -0
- data/CHANGELOG.md +56 -2
- data/ESLINT_TECHNICAL_DEBT.md +160 -0
- data/Gemfile.lock +1 -1
- data/docs/common-upgrades.md +80 -0
- data/docs/troubleshooting.md +141 -1
- data/docs/v9_upgrade.md +90 -8
- data/eslint.config.js +123 -7
- data/jest.config.js +8 -1
- data/lib/shakapacker/runner.rb +24 -1
- data/lib/shakapacker/version.rb +1 -1
- data/package/configExporter/buildValidator.ts +883 -0
- data/package/configExporter/cli.ts +194 -27
- data/package/configExporter/fileWriter.ts +12 -12
- data/package/configExporter/index.ts +3 -1
- data/package/configExporter/types.ts +18 -0
- data/package-lock.json +2 -2
- data/package.json +17 -16
- data/test/configExporter/buildValidator.test.js +1295 -0
- data/test/package/configExporter.test.js +4 -8
- data/test/package/environments/base.test.js +6 -3
- data/test/package/rules/babel.test.js +61 -51
- data/test/package/rules/esbuild.test.js +12 -3
- data/test/package/rules/file.test.js +3 -1
- data/test/package/rules/sass.test.js +9 -2
- data/test/package/rules/sass1.test.js +3 -2
- data/test/package/rules/sass16.test.js +3 -2
- data/test/package/rules/swc.test.js +48 -38
- data/yarn.lock +62 -3
- metadata +7 -2
|
@@ -10,6 +10,7 @@ import { ExportOptions, ConfigMetadata, FileOutput } from "./types"
|
|
|
10
10
|
import { YamlSerializer } from "./yamlSerializer"
|
|
11
11
|
import { FileWriter } from "./fileWriter"
|
|
12
12
|
import { ConfigFileLoader, generateSampleConfigFile } from "./configFile"
|
|
13
|
+
import { BuildValidator } from "./buildValidator"
|
|
13
14
|
|
|
14
15
|
// Read version from package.json
|
|
15
16
|
const packageJson = JSON.parse(
|
|
@@ -84,6 +85,11 @@ export async function run(args: string[]): Promise<number> {
|
|
|
84
85
|
return runListBuildsCommand(options)
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// Handle --validate or --validate-build command
|
|
89
|
+
if (options.validate || options.validateBuild) {
|
|
90
|
+
return await runValidateCommand(options)
|
|
91
|
+
}
|
|
92
|
+
|
|
87
93
|
// Handle --all-builds command
|
|
88
94
|
if (options.allBuilds) {
|
|
89
95
|
return runAllBuildsCommand(options)
|
|
@@ -130,8 +136,9 @@ export async function run(args: string[]): Promise<number> {
|
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
return 0
|
|
133
|
-
} catch (error:
|
|
134
|
-
|
|
139
|
+
} catch (error: unknown) {
|
|
140
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
141
|
+
console.error(`[Config Exporter] Error: ${errorMessage}`)
|
|
135
142
|
return 1
|
|
136
143
|
}
|
|
137
144
|
}
|
|
@@ -240,6 +247,16 @@ QUICK START (for troubleshooting):
|
|
|
240
247
|
default: false,
|
|
241
248
|
description: "Export all builds from config file"
|
|
242
249
|
})
|
|
250
|
+
.option("validate", {
|
|
251
|
+
type: "boolean",
|
|
252
|
+
default: false,
|
|
253
|
+
description:
|
|
254
|
+
"Validate all builds by running webpack/rspack (requires config file)"
|
|
255
|
+
})
|
|
256
|
+
.option("validate-build", {
|
|
257
|
+
type: "string",
|
|
258
|
+
description: "Validate specific build from config file"
|
|
259
|
+
})
|
|
243
260
|
.option("webpack", {
|
|
244
261
|
type: "boolean",
|
|
245
262
|
default: false,
|
|
@@ -276,6 +293,16 @@ QUICK START (for troubleshooting):
|
|
|
276
293
|
"--build and --all-builds are mutually exclusive. Use one or the other."
|
|
277
294
|
)
|
|
278
295
|
}
|
|
296
|
+
if (argv.validate && argv["validate-build"]) {
|
|
297
|
+
throw new Error(
|
|
298
|
+
"--validate and --validate-build are mutually exclusive. Use one or the other."
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
if (argv.validate && (argv.build || argv["all-builds"])) {
|
|
302
|
+
throw new Error(
|
|
303
|
+
"--validate cannot be used with --build or --all-builds."
|
|
304
|
+
)
|
|
305
|
+
}
|
|
279
306
|
return true
|
|
280
307
|
})
|
|
281
308
|
.help("help")
|
|
@@ -300,6 +327,11 @@ QUICK START (for troubleshooting):
|
|
|
300
327
|
bin/export-bundler-config --save-dir=./debug
|
|
301
328
|
bin/export-bundler-config # Saves to shakapacker-config-exports/
|
|
302
329
|
|
|
330
|
+
# Validate builds
|
|
331
|
+
bin/export-bundler-config --validate # Validate all builds
|
|
332
|
+
bin/export-bundler-config --validate-build=dev # Validate specific build
|
|
333
|
+
bin/export-bundler-config --validate --verbose # Validate with full logs
|
|
334
|
+
|
|
303
335
|
# View config in terminal (stdout)
|
|
304
336
|
bin/export-bundler-config --stdout
|
|
305
337
|
bin/export-bundler-config --output=config.yaml # Save to specific file`
|
|
@@ -334,7 +366,9 @@ QUICK START (for troubleshooting):
|
|
|
334
366
|
configFile: argv["config-file"],
|
|
335
367
|
build: argv.build,
|
|
336
368
|
listBuilds: argv["list-builds"],
|
|
337
|
-
allBuilds: argv["all-builds"]
|
|
369
|
+
allBuilds: argv["all-builds"],
|
|
370
|
+
validate: argv.validate,
|
|
371
|
+
validateBuild: argv["validate-build"]
|
|
338
372
|
}
|
|
339
373
|
}
|
|
340
374
|
|
|
@@ -392,9 +426,141 @@ function runListBuildsCommand(options: ExportOptions): number {
|
|
|
392
426
|
const loader = new ConfigFileLoader(options.configFile)
|
|
393
427
|
loader.listBuilds()
|
|
394
428
|
return 0
|
|
395
|
-
} catch (error:
|
|
396
|
-
|
|
429
|
+
} catch (error: unknown) {
|
|
430
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
431
|
+
console.error(`[Config Exporter] Error: ${errorMessage}`)
|
|
432
|
+
return 1
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async function runValidateCommand(options: ExportOptions): Promise<number> {
|
|
437
|
+
const savedEnv = saveBuildEnvironmentVariables()
|
|
438
|
+
|
|
439
|
+
try {
|
|
440
|
+
// Validate that config file exists
|
|
441
|
+
const loader = new ConfigFileLoader(options.configFile)
|
|
442
|
+
if (!loader.exists()) {
|
|
443
|
+
const configPath = options.configFile || ".bundler-config.yml"
|
|
444
|
+
throw new Error(
|
|
445
|
+
`Config file ${configPath} not found. Run --init to create it.`
|
|
446
|
+
)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Set up environment
|
|
450
|
+
const appRoot = findAppRoot()
|
|
451
|
+
process.chdir(appRoot)
|
|
452
|
+
setupNodePath(appRoot)
|
|
453
|
+
|
|
454
|
+
const config = loader.load()
|
|
455
|
+
const validator = new BuildValidator({ verbose: options.verbose || false })
|
|
456
|
+
|
|
457
|
+
// Determine which builds to validate
|
|
458
|
+
let buildsToValidate: string[]
|
|
459
|
+
if (options.validateBuild) {
|
|
460
|
+
// Validate specific build
|
|
461
|
+
if (!config.builds[options.validateBuild]) {
|
|
462
|
+
const available = Object.keys(config.builds).join(", ")
|
|
463
|
+
throw new Error(
|
|
464
|
+
`Build '${options.validateBuild}' not found in config file.\n` +
|
|
465
|
+
`Available builds: ${available}`
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
buildsToValidate = [options.validateBuild]
|
|
469
|
+
} else {
|
|
470
|
+
// Validate all builds
|
|
471
|
+
buildsToValidate = Object.keys(config.builds)
|
|
472
|
+
|
|
473
|
+
// Handle empty builds edge case
|
|
474
|
+
if (buildsToValidate.length === 0) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
`No builds found in config file. Add at least one build to .bundler-config.yml or run --init to see examples.`
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
console.log("\n" + "=".repeat(80))
|
|
482
|
+
console.log("🔍 Validating Builds")
|
|
483
|
+
console.log("=".repeat(80))
|
|
484
|
+
console.log(`\nValidating ${buildsToValidate.length} build(s)...\n`)
|
|
485
|
+
|
|
486
|
+
if (options.verbose) {
|
|
487
|
+
console.log("⚡ VERBOSE MODE ENABLED - Full build output will be shown")
|
|
488
|
+
console.log(
|
|
489
|
+
" This includes all webpack/rspack compilation logs, warnings, and progress messages"
|
|
490
|
+
)
|
|
491
|
+
console.log(" Use without --verbose to see only errors and summaries\n")
|
|
492
|
+
console.log("=".repeat(80) + "\n")
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const results = []
|
|
496
|
+
|
|
497
|
+
// Validate each build
|
|
498
|
+
for (const buildName of buildsToValidate) {
|
|
499
|
+
if (options.verbose) {
|
|
500
|
+
console.log("\n" + "=".repeat(80))
|
|
501
|
+
console.log(`📦 VALIDATING BUILD: ${buildName}`)
|
|
502
|
+
console.log("=".repeat(80))
|
|
503
|
+
} else {
|
|
504
|
+
console.log(`\n📦 Validating build: ${buildName}`)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Clear and restore environment to prevent leakage between builds
|
|
508
|
+
clearBuildEnvironmentVariables()
|
|
509
|
+
restoreBuildEnvironmentVariables(savedEnv)
|
|
510
|
+
|
|
511
|
+
// Get the build's environment to use for auto-detection
|
|
512
|
+
const buildConfig = config.builds[buildName]
|
|
513
|
+
const buildEnv =
|
|
514
|
+
buildConfig.environment?.NODE_ENV ||
|
|
515
|
+
(buildConfig.environment?.RAILS_ENV as
|
|
516
|
+
| "development"
|
|
517
|
+
| "production"
|
|
518
|
+
| "test"
|
|
519
|
+
| undefined) ||
|
|
520
|
+
"development"
|
|
521
|
+
|
|
522
|
+
// Auto-detect bundler using the build's environment
|
|
523
|
+
const defaultBundler = await autoDetectBundler(buildEnv, appRoot)
|
|
524
|
+
|
|
525
|
+
// Resolve build config with the correct default bundler
|
|
526
|
+
const resolvedBuild = loader.resolveBuild(
|
|
527
|
+
buildName,
|
|
528
|
+
options,
|
|
529
|
+
defaultBundler
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
// Validate the build
|
|
533
|
+
const result = await validator.validateBuild(resolvedBuild, appRoot)
|
|
534
|
+
results.push(result)
|
|
535
|
+
|
|
536
|
+
// Show immediate feedback
|
|
537
|
+
if (options.verbose) {
|
|
538
|
+
console.log("=".repeat(80))
|
|
539
|
+
}
|
|
540
|
+
if (result.success) {
|
|
541
|
+
console.log(` ✅ Build passed`)
|
|
542
|
+
} else {
|
|
543
|
+
console.log(` ❌ Build failed with ${result.errors.length} error(s)`)
|
|
544
|
+
}
|
|
545
|
+
if (options.verbose) {
|
|
546
|
+
console.log("")
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Print formatted results
|
|
551
|
+
const formattedResults = validator.formatResults(results)
|
|
552
|
+
console.log(formattedResults)
|
|
553
|
+
|
|
554
|
+
// Return exit code based on results
|
|
555
|
+
const hasFailures = results.some((r) => !r.success)
|
|
556
|
+
return hasFailures ? 1 : 0
|
|
557
|
+
} catch (error: unknown) {
|
|
558
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
559
|
+
console.error(`[Config Exporter] Error: ${errorMessage}`)
|
|
397
560
|
return 1
|
|
561
|
+
} finally {
|
|
562
|
+
// Restore original environment
|
|
563
|
+
restoreBuildEnvironmentVariables(savedEnv)
|
|
398
564
|
}
|
|
399
565
|
}
|
|
400
566
|
|
|
@@ -426,7 +592,6 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
|
426
592
|
`\n📦 Exporting ${buildNames.length} builds from config file...\n`
|
|
427
593
|
)
|
|
428
594
|
|
|
429
|
-
const fileWriter = new FileWriter()
|
|
430
595
|
const targetDir = options.saveDir! // Set by applyDefaults
|
|
431
596
|
const createdFiles: string[] = []
|
|
432
597
|
|
|
@@ -444,7 +609,7 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
|
444
609
|
|
|
445
610
|
for (const { config: cfg, metadata } of configs) {
|
|
446
611
|
const output = formatConfig(cfg, metadata, options, appRoot)
|
|
447
|
-
const filename =
|
|
612
|
+
const filename = FileWriter.generateFilename(
|
|
448
613
|
metadata.bundler,
|
|
449
614
|
metadata.environment,
|
|
450
615
|
metadata.configType,
|
|
@@ -453,7 +618,7 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
|
453
618
|
)
|
|
454
619
|
|
|
455
620
|
const fullPath = resolve(targetDir, filename)
|
|
456
|
-
|
|
621
|
+
FileWriter.writeSingleFile(fullPath, output)
|
|
457
622
|
createdFiles.push(fullPath)
|
|
458
623
|
}
|
|
459
624
|
}
|
|
@@ -471,8 +636,9 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
|
471
636
|
console.log("\n" + "=".repeat(80) + "\n")
|
|
472
637
|
|
|
473
638
|
return 0
|
|
474
|
-
} catch (error:
|
|
475
|
-
|
|
639
|
+
} catch (error: unknown) {
|
|
640
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
641
|
+
console.error(`[Config Exporter] Error: ${errorMessage}`)
|
|
476
642
|
return 1
|
|
477
643
|
} finally {
|
|
478
644
|
// Restore original environment
|
|
@@ -492,7 +658,6 @@ async function runDoctorMode(
|
|
|
492
658
|
console.log("🔍 Config Exporter - Doctor Mode")
|
|
493
659
|
console.log("=".repeat(80))
|
|
494
660
|
|
|
495
|
-
const fileWriter = new FileWriter()
|
|
496
661
|
const targetDir = options.saveDir! // Set by applyDefaults
|
|
497
662
|
|
|
498
663
|
const createdFiles: string[] = []
|
|
@@ -526,7 +691,7 @@ async function runDoctorMode(
|
|
|
526
691
|
|
|
527
692
|
for (const { config, metadata } of configs) {
|
|
528
693
|
const output = formatConfig(config, metadata, options, appRoot)
|
|
529
|
-
const filename =
|
|
694
|
+
const filename = FileWriter.generateFilename(
|
|
530
695
|
metadata.bundler,
|
|
531
696
|
metadata.environment,
|
|
532
697
|
metadata.configType,
|
|
@@ -534,7 +699,7 @@ async function runDoctorMode(
|
|
|
534
699
|
metadata.buildName
|
|
535
700
|
)
|
|
536
701
|
const fullPath = resolve(targetDir, filename)
|
|
537
|
-
|
|
702
|
+
FileWriter.writeSingleFile(fullPath, output)
|
|
538
703
|
createdFiles.push(fullPath)
|
|
539
704
|
}
|
|
540
705
|
}
|
|
@@ -543,9 +708,11 @@ async function runDoctorMode(
|
|
|
543
708
|
printDoctorSummary(createdFiles, targetDir)
|
|
544
709
|
return
|
|
545
710
|
}
|
|
546
|
-
} catch (error:
|
|
711
|
+
} catch (error: unknown) {
|
|
547
712
|
// If config file exists but is invalid, warn and fall through to default behavior
|
|
548
|
-
|
|
713
|
+
const errorMessage =
|
|
714
|
+
error instanceof Error ? error.message : String(error)
|
|
715
|
+
console.log(`\n⚠️ Config file found but invalid: ${errorMessage}`)
|
|
549
716
|
console.log("Falling back to default doctor mode...\n")
|
|
550
717
|
}
|
|
551
718
|
}
|
|
@@ -592,7 +759,7 @@ async function runDoctorMode(
|
|
|
592
759
|
* - Filename uses "client" type and "development-hmr" build name to
|
|
593
760
|
* distinguish it from regular development client bundle
|
|
594
761
|
*/
|
|
595
|
-
filename =
|
|
762
|
+
filename = FileWriter.generateFilename(
|
|
596
763
|
metadata.bundler,
|
|
597
764
|
metadata.environment,
|
|
598
765
|
"client",
|
|
@@ -600,7 +767,7 @@ async function runDoctorMode(
|
|
|
600
767
|
"development-hmr"
|
|
601
768
|
)
|
|
602
769
|
} else {
|
|
603
|
-
filename =
|
|
770
|
+
filename = FileWriter.generateFilename(
|
|
604
771
|
metadata.bundler,
|
|
605
772
|
metadata.environment,
|
|
606
773
|
metadata.configType,
|
|
@@ -611,7 +778,7 @@ async function runDoctorMode(
|
|
|
611
778
|
|
|
612
779
|
const fullPath = resolve(targetDir, filename)
|
|
613
780
|
const fileOutput: FileOutput = { filename, content: output, metadata }
|
|
614
|
-
|
|
781
|
+
FileWriter.writeSingleFile(fullPath, output)
|
|
615
782
|
createdFiles.push(fullPath)
|
|
616
783
|
}
|
|
617
784
|
}
|
|
@@ -665,7 +832,6 @@ async function runSaveMode(
|
|
|
665
832
|
const env = options.env || "development"
|
|
666
833
|
console.log(`[Config Exporter] Exporting ${env} configs`)
|
|
667
834
|
|
|
668
|
-
const fileWriter = new FileWriter()
|
|
669
835
|
const targetDir = options.saveDir! // Set by applyDefaults
|
|
670
836
|
const configs = await loadConfigsForEnv(options.env, options, appRoot)
|
|
671
837
|
const createdFiles: string[] = []
|
|
@@ -683,13 +849,13 @@ async function runSaveMode(
|
|
|
683
849
|
appRoot
|
|
684
850
|
)
|
|
685
851
|
const fullPath = resolve(options.output)
|
|
686
|
-
|
|
852
|
+
FileWriter.writeSingleFile(fullPath, output)
|
|
687
853
|
createdFiles.push(fullPath)
|
|
688
854
|
} else {
|
|
689
855
|
// Multi-file output (one per config)
|
|
690
856
|
for (const { config, metadata } of configs) {
|
|
691
857
|
const output = formatConfig(config, metadata, options, appRoot)
|
|
692
|
-
const filename =
|
|
858
|
+
const filename = FileWriter.generateFilename(
|
|
693
859
|
metadata.bundler,
|
|
694
860
|
metadata.environment,
|
|
695
861
|
metadata.configType,
|
|
@@ -697,7 +863,7 @@ async function runSaveMode(
|
|
|
697
863
|
metadata.buildName
|
|
698
864
|
)
|
|
699
865
|
const fullPath = resolve(targetDir, filename)
|
|
700
|
-
|
|
866
|
+
FileWriter.writeSingleFile(fullPath, output)
|
|
701
867
|
createdFiles.push(fullPath)
|
|
702
868
|
}
|
|
703
869
|
}
|
|
@@ -737,9 +903,8 @@ async function runSingleFileMode(
|
|
|
737
903
|
const config = combined.length === 1 ? combined[0] : combined
|
|
738
904
|
const output = formatConfig(config, metadata, options, appRoot)
|
|
739
905
|
|
|
740
|
-
const fileWriter = new FileWriter()
|
|
741
906
|
const filePath = resolve(process.cwd(), options.output!)
|
|
742
|
-
|
|
907
|
+
FileWriter.writeSingleFile(filePath, output)
|
|
743
908
|
}
|
|
744
909
|
|
|
745
910
|
async function loadConfigsForEnv(
|
|
@@ -939,9 +1104,11 @@ async function loadConfigsForEnv(
|
|
|
939
1104
|
const argv = { mode: finalEnv }
|
|
940
1105
|
try {
|
|
941
1106
|
loadedConfig = loadedConfig(envObject, argv)
|
|
942
|
-
} catch (error:
|
|
1107
|
+
} catch (error: unknown) {
|
|
1108
|
+
const errorMessage =
|
|
1109
|
+
error instanceof Error ? error.message : String(error)
|
|
943
1110
|
throw new Error(
|
|
944
|
-
`Failed to execute config function: ${
|
|
1111
|
+
`Failed to execute config function: ${errorMessage}\n` +
|
|
945
1112
|
`Config file: ${configFile}\n` +
|
|
946
1113
|
`Environment: ${JSON.stringify(envObject)}`
|
|
947
1114
|
)
|
|
@@ -1175,7 +1342,7 @@ function loadShakapackerConfig(
|
|
|
1175
1342
|
)
|
|
1176
1343
|
return { bundler, configPath }
|
|
1177
1344
|
}
|
|
1178
|
-
} catch (error:
|
|
1345
|
+
} catch (error: unknown) {
|
|
1179
1346
|
console.warn(
|
|
1180
1347
|
`[Config Exporter] Error loading shakapacker config, defaulting to webpack`
|
|
1181
1348
|
)
|
|
@@ -11,16 +11,16 @@ export class FileWriter {
|
|
|
11
11
|
/**
|
|
12
12
|
* Write multiple config files (one per config in array)
|
|
13
13
|
*/
|
|
14
|
-
writeMultipleFiles(outputs: FileOutput[], targetDir: string): void {
|
|
14
|
+
static writeMultipleFiles(outputs: FileOutput[], targetDir: string): void {
|
|
15
15
|
// Ensure directory exists
|
|
16
|
-
|
|
16
|
+
FileWriter.ensureDirectory(targetDir)
|
|
17
17
|
|
|
18
18
|
// Write each file
|
|
19
19
|
outputs.forEach((output) => {
|
|
20
20
|
const safeName = basename(output.filename)
|
|
21
21
|
const filePath = resolve(targetDir, safeName)
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
FileWriter.validateOutputPath(filePath)
|
|
23
|
+
FileWriter.writeFile(filePath, output.content)
|
|
24
24
|
console.log(`[Config Exporter] Created: ${filePath}`)
|
|
25
25
|
})
|
|
26
26
|
|
|
@@ -32,13 +32,13 @@ export class FileWriter {
|
|
|
32
32
|
/**
|
|
33
33
|
* Write a single file
|
|
34
34
|
*/
|
|
35
|
-
writeSingleFile(filePath: string, content: string): void {
|
|
35
|
+
static writeSingleFile(filePath: string, content: string): void {
|
|
36
36
|
// Ensure parent directory exists
|
|
37
37
|
const dir = dirname(filePath)
|
|
38
|
-
|
|
38
|
+
FileWriter.ensureDirectory(dir)
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
FileWriter.validateOutputPath(filePath)
|
|
41
|
+
FileWriter.writeFile(filePath, content)
|
|
42
42
|
console.log(`[Config Exporter] Created: ${filePath}`)
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -54,7 +54,7 @@ export class FileWriter {
|
|
|
54
54
|
* webpack-dev-client.yaml (with build name)
|
|
55
55
|
* rspack-cypress-dev-server.yaml (with build name)
|
|
56
56
|
*/
|
|
57
|
-
generateFilename(
|
|
57
|
+
static generateFilename(
|
|
58
58
|
bundler: string,
|
|
59
59
|
env: string,
|
|
60
60
|
configType: "client" | "server" | "all" | "client-hmr",
|
|
@@ -66,11 +66,11 @@ export class FileWriter {
|
|
|
66
66
|
return `${bundler}-${name}-${configType}.${ext}`
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
private writeFile(filePath: string, content: string): void {
|
|
69
|
+
private static writeFile(filePath: string, content: string): void {
|
|
70
70
|
writeFileSync(filePath, content, "utf8")
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
private ensureDirectory(dir: string): void {
|
|
73
|
+
private static ensureDirectory(dir: string): void {
|
|
74
74
|
if (!existsSync(dir)) {
|
|
75
75
|
mkdirSync(dir, { recursive: true })
|
|
76
76
|
}
|
|
@@ -79,7 +79,7 @@ export class FileWriter {
|
|
|
79
79
|
/**
|
|
80
80
|
* Validate output path and warn if writing outside cwd
|
|
81
81
|
*/
|
|
82
|
-
validateOutputPath(outputPath: string): void {
|
|
82
|
+
private static validateOutputPath(outputPath: string): void {
|
|
83
83
|
const absPath = resolve(outputPath)
|
|
84
84
|
const cwd = process.cwd()
|
|
85
85
|
|
|
@@ -5,9 +5,11 @@ export type {
|
|
|
5
5
|
FileOutput,
|
|
6
6
|
BundlerConfigFile,
|
|
7
7
|
BuildConfig,
|
|
8
|
-
ResolvedBuildConfig
|
|
8
|
+
ResolvedBuildConfig,
|
|
9
|
+
BuildValidationResult
|
|
9
10
|
} from "./types"
|
|
10
11
|
export { YamlSerializer } from "./yamlSerializer"
|
|
11
12
|
export { FileWriter } from "./fileWriter"
|
|
12
13
|
export { getDocForKey } from "./configDocs"
|
|
13
14
|
export { ConfigFileLoader, generateSampleConfigFile } from "./configFile"
|
|
15
|
+
export { BuildValidator } from "./buildValidator"
|
|
@@ -18,6 +18,9 @@ export interface ExportOptions {
|
|
|
18
18
|
build?: string
|
|
19
19
|
listBuilds?: boolean
|
|
20
20
|
allBuilds?: boolean
|
|
21
|
+
// Validation options
|
|
22
|
+
validate?: boolean
|
|
23
|
+
validateBuild?: string
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
export interface ConfigMetadata {
|
|
@@ -34,6 +37,7 @@ export interface ConfigMetadata {
|
|
|
34
37
|
CLIENT_BUNDLE_ONLY?: string
|
|
35
38
|
SERVER_BUNDLE_ONLY?: string
|
|
36
39
|
WEBPACK_SERVE?: string
|
|
40
|
+
HMR?: string
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -68,3 +72,17 @@ export interface ResolvedBuildConfig {
|
|
|
68
72
|
outputs: string[]
|
|
69
73
|
configFile?: string
|
|
70
74
|
}
|
|
75
|
+
|
|
76
|
+
export interface BuildValidationResult {
|
|
77
|
+
buildName: string
|
|
78
|
+
success: boolean
|
|
79
|
+
errors: string[]
|
|
80
|
+
warnings: string[]
|
|
81
|
+
output: string[]
|
|
82
|
+
outputs?: string[] // Build outputs (e.g., ["client", "server"])
|
|
83
|
+
configFile?: string // Config file path if specified
|
|
84
|
+
outputPath?: string // Output directory where files are written
|
|
85
|
+
startTime?: number // Unix timestamp in milliseconds
|
|
86
|
+
endTime?: number // Unix timestamp in milliseconds
|
|
87
|
+
duration?: number // Duration in milliseconds
|
|
88
|
+
}
|
data/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shakapacker",
|
|
3
|
-
"version": "9.3.0-beta.
|
|
3
|
+
"version": "9.3.0-beta.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "shakapacker",
|
|
9
|
-
"version": "9.3.0-beta.
|
|
9
|
+
"version": "9.3.0-beta.2",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"js-yaml": "^4.1.0",
|
data/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shakapacker",
|
|
3
|
-
"version": "9.3.0-beta.
|
|
3
|
+
"version": "9.3.0-beta.2",
|
|
4
4
|
"description": "Use webpack to manage app-like JavaScript modules in Rails",
|
|
5
5
|
"homepage": "https://github.com/shakacode/shakapacker",
|
|
6
6
|
"bugs": {
|
|
@@ -49,23 +49,11 @@
|
|
|
49
49
|
"yargs": "^17.7.2"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
53
|
+
"@eslint/js": "^9.37.0",
|
|
52
54
|
"@rspack/cli": "^1.5.8",
|
|
53
55
|
"@rspack/core": "^1.5.8",
|
|
54
56
|
"@swc/core": "^1.3.0",
|
|
55
|
-
"babel-loader": "^8.2.4",
|
|
56
|
-
"compression-webpack-plugin": "^9.0.0",
|
|
57
|
-
"css-loader": "^7.1.2",
|
|
58
|
-
"esbuild-loader": "^2.18.0",
|
|
59
|
-
"mini-css-extract-plugin": "^2.9.4",
|
|
60
|
-
"rspack-manifest-plugin": "^5.0.3",
|
|
61
|
-
"sass-loader": "^16.0.5",
|
|
62
|
-
"swc-loader": "^0.1.15",
|
|
63
|
-
"webpack": "5.93.0",
|
|
64
|
-
"webpack-assets-manifest": "^5.0.6",
|
|
65
|
-
"webpack-cli": "^6.0.0",
|
|
66
|
-
"webpack-subresource-integrity": "^5.1.0",
|
|
67
|
-
"@eslint/eslintrc": "^3.2.0",
|
|
68
|
-
"@eslint/js": "^9.37.0",
|
|
69
57
|
"@types/babel__core": "^7.20.5",
|
|
70
58
|
"@types/js-yaml": "^4.0.9",
|
|
71
59
|
"@types/node": "^24.5.2",
|
|
@@ -76,6 +64,10 @@
|
|
|
76
64
|
"@types/yargs": "^17.0.33",
|
|
77
65
|
"@typescript-eslint/eslint-plugin": "^8.46.0",
|
|
78
66
|
"@typescript-eslint/parser": "^8.46.0",
|
|
67
|
+
"babel-loader": "^8.2.4",
|
|
68
|
+
"compression-webpack-plugin": "^9.0.0",
|
|
69
|
+
"css-loader": "^7.1.2",
|
|
70
|
+
"esbuild-loader": "^2.18.0",
|
|
79
71
|
"eslint": "^9.37.0",
|
|
80
72
|
"eslint-config-airbnb": "^19.0.4",
|
|
81
73
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -90,9 +82,18 @@
|
|
|
90
82
|
"knip": "^5.64.2",
|
|
91
83
|
"lint-staged": "^15.2.10",
|
|
92
84
|
"memory-fs": "^0.5.0",
|
|
85
|
+
"mini-css-extract-plugin": "^2.9.4",
|
|
93
86
|
"prettier": "^3.2.5",
|
|
87
|
+
"rspack-manifest-plugin": "^5.0.3",
|
|
88
|
+
"sass-loader": "^16.0.5",
|
|
89
|
+
"swc-loader": "^0.1.15",
|
|
94
90
|
"thenify": "^3.3.1",
|
|
95
|
-
"
|
|
91
|
+
"ts-jest": "^29.4.5",
|
|
92
|
+
"typescript": "^5.9.2",
|
|
93
|
+
"webpack": "5.93.0",
|
|
94
|
+
"webpack-assets-manifest": "^5.0.6",
|
|
95
|
+
"webpack-cli": "^6.0.0",
|
|
96
|
+
"webpack-subresource-integrity": "^5.1.0"
|
|
96
97
|
},
|
|
97
98
|
"peerDependencies": {
|
|
98
99
|
"@babel/core": "^7.17.9",
|