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.
@@ -11,19 +11,19 @@ import {
11
11
  /**
12
12
  * Loads and validates bundler configuration files
13
13
  * @example
14
- * const loader = new ConfigFileLoader('.bundler-config.yml')
14
+ * const loader = new ConfigFileLoader('config/shakapacker-builds.yml')
15
15
  * const config = loader.load()
16
16
  */
17
17
  export class ConfigFileLoader {
18
18
  private configFilePath: string
19
19
 
20
20
  /**
21
- * @param configFilePath - Path to config file (defaults to .bundler-config.yml in cwd)
21
+ * @param configFilePath - Path to config file (defaults to config/shakapacker-builds.yml in cwd)
22
22
  * @throws Error if path is outside project directory
23
23
  */
24
24
  constructor(configFilePath?: string) {
25
25
  this.configFilePath =
26
- configFilePath || resolve(process.cwd(), ".bundler-config.yml")
26
+ configFilePath || resolve(process.cwd(), "config/shakapacker-builds.yml")
27
27
  this.validateConfigPath()
28
28
  }
29
29
 
@@ -80,7 +80,7 @@ export class ConfigFileLoader {
80
80
  if (!this.exists()) {
81
81
  throw new Error(
82
82
  `Config file not found: ${this.configFilePath}\n` +
83
- `Run 'bin/export-bundler-config --init' to generate a sample config file.`
83
+ `Run 'bin/shakapacker-config --init' to generate a sample config file.`
84
84
  )
85
85
  }
86
86
 
@@ -124,8 +124,16 @@ export class ConfigFileLoader {
124
124
  for (const [name, build] of Object.entries(config.builds)) {
125
125
  // Guard: ensure build is a non-null plain object
126
126
  if (build == null || typeof build !== "object" || Array.isArray(build)) {
127
+ let buildType: string
128
+ if (build === null) {
129
+ buildType = "null"
130
+ } else if (Array.isArray(build)) {
131
+ buildType = "array"
132
+ } else {
133
+ buildType = typeof build
134
+ }
127
135
  throw new Error(
128
- `Invalid build '${name}': must be an object, got ${build === null ? "null" : Array.isArray(build) ? "array" : typeof build}`
136
+ `Invalid build '${name}': must be an object, got ${buildType}`
129
137
  )
130
138
  }
131
139
 
@@ -373,66 +381,97 @@ export class ConfigFileLoader {
373
381
  * Generates a sample configuration file with examples and documentation
374
382
  * @returns YAML content as string ready to be written to file
375
383
  */
376
- export function generateSampleConfigFile(): string {
384
+ export function generateSampleConfigFile(ssr: boolean = false): string {
377
385
  // Using ${'$'} to escape template literal substitution in comments
386
+ if (ssr) {
387
+ return generateSSRConfigFile()
388
+ }
389
+
378
390
  return `# Bundler Build Configurations
379
- # Generated by: bin/export-bundler-config --init
391
+ # Generated by: bin/shakapacker-config --init
380
392
  #
381
- # This file defines build configurations for exporting bundler configs.
382
- # You can define multiple builds with different environments and settings.
383
-
384
- # Use these builds as defaults for --doctor mode (optional)
385
- # When set to true, --doctor will export ALL builds defined below instead of hardcoded defaults
386
- # shakapacker_doctor_default_builds_here: true
387
-
388
- # Default bundler for all builds (can be overridden per-build or with --webpack/--rspack flags)
389
- default_bundler: rspack # Options: webpack | rspack
393
+ # Run builds with: bin/shakapacker --build <name>
394
+ # List builds: bin/shakapacker --list-builds
390
395
 
391
396
  builds:
392
- # ============================================================================
397
+ # ===========================================================================
393
398
  # DEVELOPMENT WITH HMR (Hot Module Replacement)
394
- # ============================================================================
395
- # For Procfile.dev: WEBPACK_SERVE=true bin/shakapacker-dev-server
396
- # Creates client bundle with React Fast Refresh enabled
397
-
399
+ # ===========================================================================
398
400
  dev-hmr:
399
401
  description: Client bundle with HMR (React Fast Refresh)
402
+ dev_server: true # Auto-delegates to bin/shakapacker-dev-server
400
403
  environment:
401
404
  NODE_ENV: development
402
405
  RAILS_ENV: development
403
- WEBPACK_SERVE: "true"
406
+ WEBPACK_SERVE: true
404
407
  outputs:
405
408
  - client
406
409
 
407
- # ============================================================================
408
- # DEVELOPMENT (Standard)
409
- # ============================================================================
410
- # For Procfile.dev-static-assets: bin/shakapacker --watch
411
- # Creates both client and server bundles without HMR
412
-
410
+ # ===========================================================================
411
+ # DEVELOPMENT (Standard - no HMR)
412
+ # ===========================================================================
413
413
  dev:
414
- description: Development client and server bundles (no HMR)
414
+ description: Development client bundle
415
415
  environment:
416
416
  NODE_ENV: development
417
417
  RAILS_ENV: development
418
418
  outputs:
419
419
  - client
420
- - server
421
420
 
422
- # ============================================================================
421
+ # ===========================================================================
423
422
  # PRODUCTION
424
- # ============================================================================
425
- # For asset precompilation: RAILS_ENV=production bin/shakapacker
426
- # Creates optimized production bundles
427
-
423
+ # ===========================================================================
428
424
  prod:
429
- description: Production client and server bundles
425
+ description: Production client bundle
430
426
  environment:
431
427
  NODE_ENV: production
432
428
  RAILS_ENV: production
433
429
  outputs:
434
430
  - client
435
- - server
431
+
432
+ # ===========================================================================
433
+ # REACT ON RAILS WITH SSR (Uncomment to enable)
434
+ # ===========================================================================
435
+ # Run separate client and server bundles for server-side rendering
436
+ # For more info: https://github.com/shakacode/react_on_rails
437
+
438
+ # dev-client-hmr:
439
+ # description: Development client bundle with HMR for SSR
440
+ # dev_server: true
441
+ # environment:
442
+ # NODE_ENV: development
443
+ # RAILS_ENV: development
444
+ # WEBPACK_SERVE: "true"
445
+ # CLIENT_BUNDLE_ONLY: "yes"
446
+ # outputs:
447
+ # - client
448
+
449
+ # dev-server:
450
+ # description: Development server bundle for SSR
451
+ # environment:
452
+ # NODE_ENV: development
453
+ # RAILS_ENV: development
454
+ # SERVER_BUNDLE_ONLY: "yes"
455
+ # outputs:
456
+ # - server
457
+
458
+ # prod-client:
459
+ # description: Production client bundle for SSR
460
+ # environment:
461
+ # NODE_ENV: production
462
+ # RAILS_ENV: production
463
+ # CLIENT_BUNDLE_ONLY: "yes"
464
+ # outputs:
465
+ # - client
466
+
467
+ # prod-server:
468
+ # description: Production server bundle for SSR
469
+ # environment:
470
+ # NODE_ENV: production
471
+ # RAILS_ENV: production
472
+ # SERVER_BUNDLE_ONLY: "yes"
473
+ # outputs:
474
+ # - server
436
475
 
437
476
  # ============================================================================
438
477
  # ADDITIONAL EXAMPLES
@@ -486,35 +525,132 @@ builds:
486
525
  # ============================================================================
487
526
  #
488
527
  # Initialize this config file:
489
- # bin/export-bundler-config --init
528
+ # bin/shakapacker-config --init
490
529
  #
491
530
  # List all available builds:
492
- # bin/export-bundler-config --list-builds
531
+ # bin/shakapacker-config --list-builds
493
532
  #
494
533
  # Export development build configs:
495
- # bin/export-bundler-config --build=dev-hmr --save
534
+ # bin/shakapacker-config --build=dev-hmr
496
535
  # Creates: rspack-dev-hmr-client.yml
497
536
  #
498
- # bin/export-bundler-config --build=dev --save
537
+ # bin/shakapacker-config --build=dev
499
538
  # Creates: rspack-dev-client.yml, rspack-dev-server.yml
500
539
  #
501
540
  # Export production build:
502
- # bin/export-bundler-config --build=prod --save
541
+ # bin/shakapacker-config --build=prod
503
542
  # Creates: rspack-prod-client.yml, rspack-prod-server.yml
504
543
  #
505
544
  # Use webpack instead of default rspack:
506
- # bin/export-bundler-config --build=prod --save --webpack
545
+ # bin/shakapacker-config --build=prod --webpack
507
546
  # Creates: webpack-prod-client.yml, webpack-prod-server.yml
508
547
  #
509
548
  # Export to stdout for inspection (no files created):
510
- # bin/export-bundler-config --build=dev
549
+ # bin/shakapacker-config --build=dev --stdout
511
550
  #
512
551
  # Export to custom directory:
513
- # bin/export-bundler-config --build=prod --save-dir=./debug
552
+ # bin/shakapacker-config --build=prod --save-dir=./debug
514
553
  #
515
554
  # Doctor mode (comprehensive troubleshooting):
516
- # bin/export-bundler-config --doctor
555
+ # bin/shakapacker-config --doctor
517
556
  # Creates files in: shakapacker-config-exports/
518
557
  #
519
558
  `
520
559
  }
560
+
561
+ /**
562
+ * Generates SSR-specific configuration file for React on Rails
563
+ * Includes separate client and server builds for development and production
564
+ * @returns YAML content as string ready to be written to file
565
+ */
566
+ function generateSSRConfigFile(): string {
567
+ return `# Bundler Build Configurations for React on Rails with SSR
568
+ # Generated by: bin/shakapacker-config --init ssr
569
+ #
570
+ # Run builds with: bin/shakapacker --build <name>
571
+ # List builds: bin/shakapacker --list-builds
572
+
573
+ builds:
574
+ # ===========================================================================
575
+ # DEVELOPMENT - CLIENT WITH HMR
576
+ # ===========================================================================
577
+ dev-client-hmr:
578
+ description: Development client bundle with HMR for SSR
579
+ dev_server: true # Auto-delegates to bin/shakapacker-dev-server
580
+ environment:
581
+ NODE_ENV: development
582
+ RAILS_ENV: development
583
+ WEBPACK_SERVE: true
584
+ CLIENT_BUNDLE_ONLY: "yes"
585
+ outputs:
586
+ - client
587
+
588
+ # ===========================================================================
589
+ # DEVELOPMENT - CLIENT (Standard - no HMR)
590
+ # ===========================================================================
591
+ dev-client:
592
+ description: Development client bundle for SSR (no HMR)
593
+ environment:
594
+ NODE_ENV: development
595
+ RAILS_ENV: development
596
+ CLIENT_BUNDLE_ONLY: "yes"
597
+ outputs:
598
+ - client
599
+
600
+ # ===========================================================================
601
+ # DEVELOPMENT - SERVER
602
+ # ===========================================================================
603
+ dev-server:
604
+ description: Development server bundle for SSR
605
+ environment:
606
+ NODE_ENV: development
607
+ RAILS_ENV: development
608
+ SERVER_BUNDLE_ONLY: "yes"
609
+ outputs:
610
+ - server
611
+
612
+ # ===========================================================================
613
+ # PRODUCTION - CLIENT
614
+ # ===========================================================================
615
+ prod-client:
616
+ description: Production client bundle for SSR
617
+ environment:
618
+ NODE_ENV: production
619
+ RAILS_ENV: production
620
+ CLIENT_BUNDLE_ONLY: "yes"
621
+ outputs:
622
+ - client
623
+
624
+ # ===========================================================================
625
+ # PRODUCTION - SERVER
626
+ # ===========================================================================
627
+ prod-server:
628
+ description: Production server bundle for SSR
629
+ environment:
630
+ NODE_ENV: production
631
+ RAILS_ENV: production
632
+ SERVER_BUNDLE_ONLY: "yes"
633
+ outputs:
634
+ - server
635
+
636
+ # ==============================================================================
637
+ # USAGE EXAMPLES
638
+ # ==============================================================================
639
+ #
640
+ # Development with HMR:
641
+ # bin/shakapacker --build dev-client-hmr # Client with HMR
642
+ # bin/shakapacker --build dev-server # Server bundle
643
+ #
644
+ # Development without HMR:
645
+ # bin/shakapacker --build dev-client # Client bundle
646
+ # bin/shakapacker --build dev-server # Server bundle
647
+ #
648
+ # Production:
649
+ # bin/shakapacker --build prod-client # Client bundle
650
+ # bin/shakapacker --build prod-server # Server bundle
651
+ #
652
+ # For more info on React on Rails with SSR:
653
+ # https://github.com/shakacode/react_on_rails
654
+ #
655
+ `
656
+ }
@@ -61,7 +61,14 @@ export class FileWriter {
61
61
  format: "yaml" | "json" | "inspect",
62
62
  buildName?: string
63
63
  ): string {
64
- const ext = format === "yaml" ? "yaml" : format === "json" ? "json" : "txt"
64
+ let ext: string
65
+ if (format === "yaml") {
66
+ ext = "yaml"
67
+ } else if (format === "json") {
68
+ ext = "json"
69
+ } else {
70
+ ext = "txt"
71
+ }
65
72
  const name = buildName || env
66
73
  return `${bundler}-${name}-${configType}.${ext}`
67
74
  }
@@ -14,6 +14,7 @@ export interface ExportOptions {
14
14
  help?: boolean
15
15
  // New config file options
16
16
  init?: boolean
17
+ ssr?: boolean
17
18
  configFile?: string
18
19
  build?: string
19
20
  listBuilds?: boolean
@@ -57,6 +58,7 @@ export interface BundlerConfigFile {
57
58
  export interface BuildConfig {
58
59
  description?: string
59
60
  bundler?: "webpack" | "rspack"
61
+ dev_server?: boolean
60
62
  environment?: Record<string, string>
61
63
  bundler_env?: Record<string, string | boolean>
62
64
  outputs?: string[]
@@ -14,11 +14,11 @@ export function isPathTraversalSafe(inputPath: string): boolean {
14
14
  if (inputPath.includes("\0")) return false
15
15
 
16
16
  const dangerousPatterns = [
17
- /\.\.[\/\\]/, // ../ or ..\
17
+ /\.\.[/\\]/, // ../ or ..\
18
18
  /^\//, // POSIX absolute
19
- /^[A-Za-z]:[\/\\]/, // Windows absolute (C:\ or C:/)
19
+ /^[A-Za-z]:[/\\]/, // Windows absolute (C:\ or C:/)
20
20
  /^\\\\/, // Windows UNC (\\server\share)
21
- /~[\/\\]/, // Home directory expansion
21
+ /~[/\\]/, // Home directory expansion
22
22
  /%2e%2e/i // URL encoded traversal
23
23
  ]
24
24
 
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "shakapacker",
3
- "version": "9.3.0-beta.2",
3
+ "version": "9.3.0-beta.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "shakapacker",
9
- "version": "9.3.0-beta.2",
9
+ "version": "9.3.0-beta.4",
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.2",
3
+ "version": "9.3.0-beta.4",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "homepage": "https://github.com/shakacode/shakapacker",
6
6
  "bugs": {
@@ -22,7 +22,8 @@ describe("ConfigFileLoader", () => {
22
22
  if (!existsSync(testDir)) {
23
23
  mkdirSync(testDir, { recursive: true })
24
24
  }
25
- configPath = join(testDir, ".bundler-config.yml")
25
+ mkdirSync(join(testDir, "config"), { recursive: true })
26
+ configPath = join(testDir, "config/shakapacker-builds.yml")
26
27
  })
27
28
 
28
29
  afterEach(() => {
@@ -369,9 +370,9 @@ builds:
369
370
  describe("generateSampleConfigFile", () => {
370
371
  it("should generate valid YAML string", () => {
371
372
  const content = generateSampleConfigFile()
372
- expect(content).toContain("default_bundler:")
373
373
  expect(content).toContain("builds:")
374
374
  expect(content).toContain("dev-hmr:")
375
+ expect(content).toContain("dev_server: true")
375
376
  expect(content).toContain("dev:")
376
377
  expect(content).toContain("prod:")
377
378
  })
@@ -10,9 +10,9 @@ const { execSync } = require("child_process")
10
10
 
11
11
  describe("Config Exporter Integration Tests", () => {
12
12
  const testDir = resolve(__dirname, "../tmp/integration-test")
13
- const configPath = join(testDir, ".bundler-config.yml")
13
+ const configPath = join(testDir, "config/shakapacker-builds.yml")
14
14
  const outputDir = join(testDir, "output")
15
- const binPath = resolve(__dirname, "../../bin/export-bundler-config")
15
+ const binPath = resolve(__dirname, "../../bin/shakapacker-config")
16
16
 
17
17
  beforeEach(() => {
18
18
  // Create test directory
@@ -20,6 +20,7 @@ describe("Config Exporter Integration Tests", () => {
20
20
  rmSync(testDir, { recursive: true, force: true })
21
21
  }
22
22
  mkdirSync(testDir, { recursive: true })
23
+ mkdirSync(join(testDir, "config"), { recursive: true })
23
24
 
24
25
  // Create minimal package.json
25
26
  writeFileSync(
@@ -155,13 +156,10 @@ builds:
155
156
  })
156
157
  })
157
158
 
158
- describe("--doctor mode with shakapacker_doctor_default_builds_here", () => {
159
- it("should use config file builds when flag is set", () => {
160
- // Create config with custom builds and the flag
159
+ describe("--doctor mode with config file", () => {
160
+ it("should always use config file builds when config exists", () => {
161
+ // Create config with custom builds
161
162
  const configContent = `
162
- shakapacker_doctor_default_builds_here: true
163
- default_bundler: webpack
164
-
165
163
  builds:
166
164
  custom-dev:
167
165
  description: Custom development
@@ -187,9 +185,9 @@ builds:
187
185
  { encoding: "utf8" }
188
186
  )
189
187
 
190
- // Verify it used config builds, not hardcoded ones
188
+ // Verify it used config builds
191
189
  expect(result).toContain(
192
- "Using builds from config file (shakapacker_doctor_default_builds_here: true)"
190
+ "Using builds from config/shakapacker-builds.yml"
193
191
  )
194
192
  expect(result).toContain("custom-dev")
195
193
  expect(result).toContain("custom-prod")
@@ -201,20 +199,8 @@ builds:
201
199
  expect(files).toContain("webpack-custom-prod-client.yaml")
202
200
  })
203
201
 
204
- it("should use hardcoded builds when flag is not set", () => {
205
- // Create config WITHOUT the flag
206
- const configContent = `
207
- default_bundler: webpack
208
-
209
- builds:
210
- custom-dev:
211
- description: Custom development
212
- environment:
213
- NODE_ENV: development
214
- outputs:
215
- - client
216
- `
217
- writeFileSync(configPath, configContent)
202
+ it("should use fallback builds when no config file exists", () => {
203
+ // Don't create config file
218
204
 
219
205
  // Run --doctor command
220
206
  const result = execSync(
@@ -222,11 +208,12 @@ builds:
222
208
  { encoding: "utf8" }
223
209
  )
224
210
 
225
- // Verify it used hardcoded builds (development-hmr, development, production)
226
- expect(result).toContain("development-hmr")
211
+ // Verify it warns and uses hardcoded fallback builds
212
+ expect(result).toContain("No build config file found")
213
+ expect(result).toContain("bin/shakapacker-config --init")
214
+ expect(result).toContain("development (HMR)")
227
215
  expect(result).toContain("development")
228
216
  expect(result).toContain("production")
229
- expect(result).not.toContain("custom-dev")
230
217
  })
231
218
  })
232
219
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shakapacker
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.3.0.beta.2
4
+ version: 9.3.0.beta.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -168,7 +168,7 @@ files:
168
168
  - TODO_v9.md
169
169
  - __mocks__/nonexistent/package.json
170
170
  - __mocks__/sass-loader/package.json
171
- - bin/export-bundler-config
171
+ - bin/shakapacker-config
172
172
  - conductor-setup.sh
173
173
  - conductor.json
174
174
  - config/README.md
@@ -183,6 +183,7 @@ files:
183
183
  - docs/optional-peer-dependencies.md
184
184
  - docs/peer-dependencies.md
185
185
  - docs/precompile_hook.md
186
+ - docs/preventing_fouc.md
186
187
  - docs/react.md
187
188
  - docs/releasing.md
188
189
  - docs/rspack.md
@@ -213,8 +214,8 @@ files:
213
214
  - jest.config.js
214
215
  - knip.ts
215
216
  - lib/install/application.js
216
- - lib/install/bin/export-bundler-config
217
217
  - lib/install/bin/shakapacker
218
+ - lib/install/bin/shakapacker-config
218
219
  - lib/install/bin/shakapacker-dev-server
219
220
  - lib/install/binstubs.rb
220
221
  - lib/install/config/rspack/rspack.config.js
@@ -226,6 +227,7 @@ files:
226
227
  - lib/install/template.rb
227
228
  - lib/shakapacker.rb
228
229
  - lib/shakapacker/base_strategy.rb
230
+ - lib/shakapacker/build_config_loader.rb
229
231
  - lib/shakapacker/bundler_switcher.rb
230
232
  - lib/shakapacker/commands.rb
231
233
  - lib/shakapacker/compiler.rb
@@ -380,7 +382,7 @@ homepage: https://github.com/shakacode/shakapacker
380
382
  licenses:
381
383
  - MIT
382
384
  metadata:
383
- source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.3.0.beta.2
385
+ source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.3.0.beta.4
384
386
  rdoc_options: []
385
387
  require_paths:
386
388
  - lib
File without changes