shakapacker 9.1.0 → 9.3.0.beta.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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +6 -9
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +6 -8
  4. data/.github/workflows/claude-code-review.yml +4 -5
  5. data/.github/workflows/claude.yml +1 -2
  6. data/.github/workflows/dummy.yml +4 -4
  7. data/.github/workflows/generator.yml +9 -9
  8. data/.github/workflows/node.yml +11 -2
  9. data/.github/workflows/ruby.yml +16 -16
  10. data/.github/workflows/test-bundlers.yml +9 -9
  11. data/.gitignore +7 -0
  12. data/CHANGELOG.md +50 -4
  13. data/CLAUDE.md +6 -1
  14. data/CONTRIBUTING.md +0 -1
  15. data/Gemfile.lock +1 -1
  16. data/README.md +35 -14
  17. data/TODO.md +10 -2
  18. data/TODO_v9.md +13 -3
  19. data/bin/export-bundler-config +11 -0
  20. data/conductor-setup.sh +1 -1
  21. data/conductor.json +1 -1
  22. data/docs/cdn_setup.md +13 -8
  23. data/docs/common-upgrades.md +2 -1
  24. data/docs/configuration.md +630 -0
  25. data/docs/css-modules-export-mode.md +120 -100
  26. data/docs/customizing_babel_config.md +16 -16
  27. data/docs/deployment.md +68 -6
  28. data/docs/developing_shakapacker.md +6 -0
  29. data/docs/optional-peer-dependencies.md +9 -4
  30. data/docs/peer-dependencies.md +17 -6
  31. data/docs/precompile_hook.md +342 -0
  32. data/docs/react.md +57 -47
  33. data/docs/releasing.md +195 -0
  34. data/docs/rspack.md +25 -21
  35. data/docs/rspack_migration_guide.md +363 -8
  36. data/docs/sprockets.md +1 -0
  37. data/docs/style_loader_vs_mini_css.md +12 -12
  38. data/docs/subresource_integrity.md +13 -7
  39. data/docs/transpiler-performance.md +40 -19
  40. data/docs/troubleshooting.md +122 -23
  41. data/docs/typescript-migration.md +48 -39
  42. data/docs/typescript.md +12 -8
  43. data/docs/using_esbuild_loader.md +10 -10
  44. data/docs/v6_upgrade.md +33 -20
  45. data/docs/v7_upgrade.md +8 -6
  46. data/docs/v8_upgrade.md +13 -12
  47. data/docs/v9_upgrade.md +2 -1
  48. data/eslint.config.fast.js +134 -0
  49. data/eslint.config.js +140 -0
  50. data/knip.ts +54 -0
  51. data/lib/install/bin/export-bundler-config +11 -0
  52. data/lib/install/bin/shakapacker +1 -1
  53. data/lib/install/bin/shakapacker-dev-server +1 -1
  54. data/lib/install/config/shakapacker.yml +16 -5
  55. data/lib/shakapacker/bundler_switcher.rb +7 -0
  56. data/lib/shakapacker/compiler.rb +80 -0
  57. data/lib/shakapacker/configuration.rb +56 -2
  58. data/lib/shakapacker/dev_server_runner.rb +140 -1
  59. data/lib/shakapacker/doctor.rb +302 -57
  60. data/lib/shakapacker/instance.rb +8 -3
  61. data/lib/shakapacker/rspack_runner.rb +1 -1
  62. data/lib/shakapacker/runner.rb +245 -9
  63. data/lib/shakapacker/version.rb +1 -1
  64. data/lib/shakapacker/webpack_runner.rb +1 -1
  65. data/lib/shakapacker.rb +10 -0
  66. data/lib/tasks/shakapacker/doctor.rake +42 -2
  67. data/lib/tasks/shakapacker/export_bundler_config.rake +72 -0
  68. data/package/babel/preset.ts +7 -4
  69. data/package/config.ts +42 -30
  70. data/package/configExporter/cli.ts +1274 -0
  71. data/package/configExporter/configDocs.ts +102 -0
  72. data/package/configExporter/configFile.ts +520 -0
  73. data/package/configExporter/fileWriter.ts +96 -0
  74. data/package/configExporter/index.ts +13 -0
  75. data/package/configExporter/types.ts +70 -0
  76. data/package/configExporter/yamlSerializer.ts +280 -0
  77. data/package/dev_server.ts +1 -1
  78. data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +11 -5
  79. data/package/environments/base.ts +18 -13
  80. data/package/environments/development.ts +1 -1
  81. data/package/environments/production.ts +4 -1
  82. data/package/index.d.ts +50 -3
  83. data/package/index.d.ts.template +50 -0
  84. data/package/index.ts +7 -7
  85. data/package/loaders.d.ts +2 -2
  86. data/package/optimization/rspack.ts +1 -1
  87. data/package/plugins/rspack.ts +15 -4
  88. data/package/plugins/webpack.ts +7 -3
  89. data/package/rspack/index.ts +10 -2
  90. data/package/rules/raw.ts +3 -2
  91. data/package/rules/sass.ts +1 -1
  92. data/package/types/README.md +15 -13
  93. data/package/types/index.ts +5 -5
  94. data/package/types.ts +0 -1
  95. data/package/utils/defaultConfigPath.ts +4 -1
  96. data/package/utils/errorCodes.ts +129 -100
  97. data/package/utils/errorHelpers.ts +34 -29
  98. data/package/utils/getStyleRule.ts +5 -2
  99. data/package/utils/helpers.ts +21 -11
  100. data/package/utils/pathValidation.ts +43 -35
  101. data/package/utils/requireOrError.ts +1 -1
  102. data/package/utils/snakeToCamelCase.ts +1 -1
  103. data/package/utils/typeGuards.ts +132 -83
  104. data/package/utils/validateDependencies.ts +1 -1
  105. data/package/webpack-types.d.ts +3 -3
  106. data/package/webpackDevServerConfig.ts +22 -10
  107. data/package-lock.json +2 -2
  108. data/package.json +37 -28
  109. data/scripts/type-check-no-emit.js +1 -1
  110. data/test/configExporter/configFile.test.js +392 -0
  111. data/test/configExporter/integration.test.js +275 -0
  112. data/test/helpers.js +1 -1
  113. data/test/package/configExporter.test.js +154 -0
  114. data/test/package/helpers.test.js +2 -2
  115. data/test/package/rules/sass-version-parsing.test.js +71 -0
  116. data/test/package/rules/sass.test.js +2 -4
  117. data/test/package/rules/sass1.test.js +1 -3
  118. data/test/package/rules/sass16.test.js +23 -0
  119. data/tools/README.md +15 -5
  120. data/tsconfig.eslint.json +2 -9
  121. data/yarn.lock +1635 -1442
  122. metadata +29 -3
  123. data/.eslintignore +0 -5
@@ -117,6 +117,17 @@ class Shakapacker::Configuration
117
117
  assets_bundler == "webpack"
118
118
  end
119
119
 
120
+ def precompile_hook
121
+ hook = fetch(:precompile_hook)
122
+ return nil if hook.nil? || (hook.is_a?(String) && hook.strip.empty?)
123
+
124
+ unless hook.is_a?(String)
125
+ raise "Shakapacker configuration error: precompile_hook must be a string, got #{hook.class}"
126
+ end
127
+
128
+ hook.strip
129
+ end
130
+
120
131
  def javascript_transpiler
121
132
  # Show deprecation warning if using old 'webpack_loader' key
122
133
  if data.has_key?(:webpack_loader) && !data.has_key?(:javascript_transpiler)
@@ -137,6 +148,14 @@ class Shakapacker::Configuration
137
148
  javascript_transpiler
138
149
  end
139
150
 
151
+ def assets_bundler_config_path
152
+ custom_path = fetch(:assets_bundler_config_path)
153
+ return custom_path if custom_path
154
+
155
+ # Default paths based on bundler type
156
+ rspack? ? "config/rspack" : "config/webpack"
157
+ end
158
+
140
159
  private
141
160
 
142
161
  def default_javascript_transpiler
@@ -255,7 +274,21 @@ class Shakapacker::Configuration
255
274
  rescue ArgumentError
256
275
  YAML.load_file(config_path.to_s)
257
276
  end
258
- symbolized_config = config[env].deep_symbolize_keys
277
+
278
+ # Try to find environment-specific configuration with fallback
279
+ # Fallback order: requested env → production
280
+ if config[env]
281
+ env_config = config[env]
282
+ elsif config["production"]
283
+ log_fallback(env, "production")
284
+ env_config = config["production"]
285
+ else
286
+ # No suitable configuration found - rely on bundled defaults
287
+ log_fallback(env, "none (will use bundled defaults)")
288
+ env_config = nil
289
+ end
290
+
291
+ symbolized_config = env_config&.deep_symbolize_keys || {}
259
292
 
260
293
  return symbolized_config
261
294
  rescue Errno::ENOENT => e
@@ -280,7 +313,10 @@ class Shakapacker::Configuration
280
313
  rescue ArgumentError
281
314
  YAML.load_file(path)
282
315
  end
283
- HashWithIndifferentAccess.new(config[env] || config[Shakapacker::DEFAULT_ENV])
316
+ # Load defaults from bundled shakapacker.yml (always has all environments)
317
+ # Note: This differs from load() which reads user's config and may be missing environments
318
+ # Fallback to production ensures staging and other custom envs get production-like defaults
319
+ HashWithIndifferentAccess.new(config[env] || config["production"])
284
320
  end
285
321
  end
286
322
 
@@ -289,4 +325,22 @@ class Shakapacker::Configuration
289
325
 
290
326
  path
291
327
  end
328
+
329
+ def log_fallback(requested_env, fallback_env)
330
+ message = "Shakapacker environment '#{requested_env}' not found in #{config_path}, " \
331
+ "falling back to '#{fallback_env}'"
332
+
333
+ # Try to use the logger if available, otherwise fall back to stdout
334
+ begin
335
+ if Shakapacker.respond_to?(:logger) && Shakapacker.logger
336
+ Shakapacker.logger.info(message)
337
+ else
338
+ puts message
339
+ end
340
+ rescue NameError, NoMethodError
341
+ # If logger access fails (e.g., circular dependency in standalone runner context),
342
+ # fall back to stdout so the message still gets displayed
343
+ puts message
344
+ end
345
+ end
292
346
  end
@@ -4,13 +4,150 @@ require "socket"
4
4
  require_relative "configuration"
5
5
  require_relative "dev_server"
6
6
  require_relative "runner"
7
+ require_relative "version"
7
8
 
8
9
  module Shakapacker
9
10
  class DevServerRunner < Shakapacker::Runner
10
11
  def self.run(argv)
12
+ # Show Shakapacker help and exit (don't call bundler)
13
+ if argv.include?("--help") || argv.include?("-h")
14
+ print_help
15
+ exit(0)
16
+ elsif argv.include?("--version") || argv.include?("-v")
17
+ print_version
18
+ exit(0)
19
+ end
20
+
11
21
  new(argv).run
12
22
  end
13
23
 
24
+ def self.print_help
25
+ puts <<~HELP
26
+ ================================================================================
27
+ SHAKAPACKER DEV SERVER - Development Server with Hot Module Replacement
28
+ ================================================================================
29
+
30
+ Usage: bin/shakapacker-dev-server [options]
31
+
32
+ Shakapacker-specific options:
33
+ -h, --help Show this help message
34
+ -v, --version Show Shakapacker version
35
+ --debug-shakapacker Enable Node.js debugging (--inspect-brk)
36
+
37
+ Examples:
38
+ bin/shakapacker-dev-server # Start dev server
39
+ bin/shakapacker-dev-server --no-hot # Disable HMR
40
+ bin/shakapacker-dev-server --open # Open browser automatically
41
+ bin/shakapacker-dev-server --debug-shakapacker # Debug with Node inspector
42
+
43
+ HELP
44
+
45
+ print_dev_server_help
46
+
47
+ puts <<~HELP
48
+
49
+ Options managed by Shakapacker (configured in config/shakapacker.yml):
50
+ --host Set from dev_server.host (default: localhost)
51
+ --port Set from dev_server.port (default: 3035)
52
+ --https Set from dev_server.server (http or https)
53
+ --config Set automatically to config/webpack/webpack.config.js
54
+ or config/rspack/rspack.config.js
55
+
56
+ Note: CLI flags for --host, --port, and --https are NOT supported.
57
+ Configure these in config/shakapacker.yml instead.
58
+ HELP
59
+ end
60
+
61
+ def self.print_dev_server_help
62
+ bundler_type, bundler_help = get_dev_server_help
63
+
64
+ if bundler_help
65
+ bundler_name = bundler_type == :rspack ? "RSPACK" : "WEBPACK"
66
+ puts "=" * 80
67
+ puts "AVAILABLE #{bundler_name} DEV SERVER OPTIONS (Passed directly to #{bundler_name.downcase})"
68
+ puts "=" * 80
69
+ puts
70
+ puts filter_managed_options(bundler_help)
71
+ puts
72
+ puts "For complete documentation:"
73
+ if bundler_type == :rspack
74
+ puts " https://rspack.dev/config/dev-server"
75
+ else
76
+ puts " https://webpack.js.org/configuration/dev-server/"
77
+ end
78
+ else
79
+ puts "For complete documentation:"
80
+ puts " Webpack: https://webpack.js.org/configuration/dev-server/"
81
+ puts " Rspack: https://rspack.dev/config/dev-server"
82
+ end
83
+ end
84
+
85
+ def self.get_dev_server_help
86
+ Runner.execute_bundler_command("serve", "--help") { |stdout| stdout }
87
+ end
88
+
89
+ # Filter dev server help output to remove Shakapacker-managed options
90
+ #
91
+ # This method processes the raw help output from webpack-dev-server/rspack serve
92
+ # and removes options that Shakapacker manages automatically:
93
+ # - --config (set from config/webpack or config/rspack)
94
+ # - --host, --port (set from config/shakapacker.yml dev_server settings)
95
+ # - --help, --version (shown separately in Shakapacker's help)
96
+ #
97
+ # The filtering uses skip_until_blank to track multi-line option descriptions
98
+ # and skip them entirely when the option header matches a managed option.
99
+ #
100
+ # Note: This relies on dev server help format conventions. If webpack-dev-server
101
+ # or rspack significantly changes their help output format, this may need adjustment.
102
+ def self.filter_managed_options(help_text)
103
+ lines = help_text.lines
104
+ filtered_lines = []
105
+ skip_until_blank = false
106
+
107
+ lines.each do |line|
108
+ # Skip options that Shakapacker manages and their descriptions
109
+ # These options are shown in the "Options managed by Shakapacker" section
110
+ if line.match?(/^\s*(-c,\s*)?--config\b/) ||
111
+ line.match?(/^\s*--configName\b/) ||
112
+ line.match?(/^\s*--configLoader\b/) ||
113
+ line.match?(/^\s*--nodeEnv\b/) ||
114
+ line.match?(/^\s*--host\b/) ||
115
+ line.match?(/^\s*--port\b/) ||
116
+ line.match?(/^\s*--https\b/) ||
117
+ line.match?(/^\s*(-h,\s*)?--help\b/) ||
118
+ line.match?(/^\s*(-v,\s*)?--version\b/)
119
+ skip_until_blank = true
120
+ next
121
+ end
122
+
123
+ # Continue skipping lines that are part of a filtered option's description
124
+ # Reset when we hit a blank line or the start of a new option (starts with -)
125
+ if skip_until_blank
126
+ if line.strip.empty? || line.match?(/^\s*-/)
127
+ skip_until_blank = false
128
+ else
129
+ next
130
+ end
131
+ end
132
+
133
+ filtered_lines << line
134
+ end
135
+
136
+ filtered_lines.join
137
+ end
138
+
139
+ def self.print_version
140
+ puts "Shakapacker #{Shakapacker::VERSION}"
141
+ puts "Framework: Rails #{Rails.version}" if defined?(Rails)
142
+
143
+ # Try to get bundler version
144
+ bundler_type, bundler_version = Runner.get_bundler_version
145
+ if bundler_version
146
+ bundler_name = bundler_type == :rspack ? "Rspack" : "Webpack"
147
+ puts "Bundler: #{bundler_name} #{bundler_version}"
148
+ end
149
+ end
150
+
14
151
  def run
15
152
  load_config
16
153
  detect_unsupported_switches!
@@ -96,8 +233,10 @@ module Shakapacker
96
233
  cmd += @argv
97
234
 
98
235
  Dir.chdir(@app_path) do
99
- Kernel.exec env, *cmd
236
+ system(env, *cmd)
100
237
  end
238
+
239
+ exit($?.exitstatus || 1) unless $?.success?
101
240
  end
102
241
 
103
242
  def build_cmd