shakapacker 9.3.0.beta.0 → 9.3.0.beta.1
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/CHANGELOG.md +56 -2
- data/Gemfile.lock +1 -1
- data/docs/troubleshooting.md +141 -1
- data/jest.config.js +8 -1
- data/lib/shakapacker/version.rb +1 -1
- data/package/configExporter/buildValidator.ts +883 -0
- data/package/configExporter/cli.ts +183 -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 +1292 -0
- 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 +5 -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
|
|
@@ -471,8 +637,9 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
471
637
|
console.log("\n" + "=".repeat(80) + "\n")
|
472
638
|
|
473
639
|
return 0
|
474
|
-
} catch (error:
|
475
|
-
|
640
|
+
} catch (error: unknown) {
|
641
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
642
|
+
console.error(`[Config Exporter] Error: ${errorMessage}`)
|
476
643
|
return 1
|
477
644
|
} finally {
|
478
645
|
// Restore original environment
|
@@ -543,9 +710,11 @@ async function runDoctorMode(
|
|
543
710
|
printDoctorSummary(createdFiles, targetDir)
|
544
711
|
return
|
545
712
|
}
|
546
|
-
} catch (error:
|
713
|
+
} catch (error: unknown) {
|
547
714
|
// If config file exists but is invalid, warn and fall through to default behavior
|
548
|
-
|
715
|
+
const errorMessage =
|
716
|
+
error instanceof Error ? error.message : String(error)
|
717
|
+
console.log(`\n⚠️ Config file found but invalid: ${errorMessage}`)
|
549
718
|
console.log("Falling back to default doctor mode...\n")
|
550
719
|
}
|
551
720
|
}
|
@@ -939,9 +1108,11 @@ async function loadConfigsForEnv(
|
|
939
1108
|
const argv = { mode: finalEnv }
|
940
1109
|
try {
|
941
1110
|
loadedConfig = loadedConfig(envObject, argv)
|
942
|
-
} catch (error:
|
1111
|
+
} catch (error: unknown) {
|
1112
|
+
const errorMessage =
|
1113
|
+
error instanceof Error ? error.message : String(error)
|
943
1114
|
throw new Error(
|
944
|
-
`Failed to execute config function: ${
|
1115
|
+
`Failed to execute config function: ${errorMessage}\n` +
|
945
1116
|
`Config file: ${configFile}\n` +
|
946
1117
|
`Environment: ${JSON.stringify(envObject)}`
|
947
1118
|
)
|
@@ -1175,7 +1346,7 @@ function loadShakapackerConfig(
|
|
1175
1346
|
)
|
1176
1347
|
return { bundler, configPath }
|
1177
1348
|
}
|
1178
|
-
} catch (error:
|
1349
|
+
} catch (error: unknown) {
|
1179
1350
|
console.warn(
|
1180
1351
|
`[Config Exporter] Error loading shakapacker config, defaulting to webpack`
|
1181
1352
|
)
|
@@ -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.1",
|
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.1",
|
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.1",
|
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",
|