shakapacker 9.0.0.beta.9 → 9.0.0.beta.11

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.
data/docs/v9_upgrade.md CHANGED
@@ -9,12 +9,38 @@ This guide outlines new features, breaking changes, and migration steps for upgr
9
9
  Shakapacker v9 includes TypeScript definitions for better IDE support and type safety.
10
10
 
11
11
  - **No breaking changes** - JavaScript configs continue to work
12
- - **Optional** - Use TypeScript only if you want it
12
+ - **Optional** - Use TypeScript only if you want it
13
13
  - **Type safety** - Catch configuration errors at compile-time
14
14
  - **IDE support** - Full autocomplete for all options
15
15
 
16
16
  See the [TypeScript Documentation](./typescript.md) for usage examples.
17
17
 
18
+ ### NODE_ENV Default Behavior Fixed
19
+
20
+ **What changed:** NODE_ENV now intelligently defaults based on RAILS_ENV instead of always defaulting to "production".
21
+
22
+ **New behavior:**
23
+
24
+ - When `RAILS_ENV=production` → `NODE_ENV` defaults to `"production"`
25
+ - When `RAILS_ENV=development` or unset → `NODE_ENV` defaults to `"development"`
26
+ - When `RAILS_ENV` is any other value (test, staging, etc.) → `NODE_ENV` defaults to `"development"`
27
+
28
+ **Benefits:**
29
+
30
+ - **Dev server "just works"** - No need to explicitly set NODE_ENV when running the development server
31
+ - **Correct configuration loaded** - Development server now properly loads the development configuration from shakapacker.yml
32
+ - **Fixes port issues** - Dev server uses the configured port (e.g., 3035) instead of defaulting to 8080
33
+ - **Fixes 404 errors** - Assets load correctly without requiring manual NODE_ENV configuration
34
+
35
+ **No action required** - This change improves the default behavior and requires no migration.
36
+
37
+ **If you previously worked around this bug**, you can now remove these workarounds:
38
+
39
+ - Remove `NODE_ENV=development` from your `.env`, `.env.development`, or `.env.local` files
40
+ - Remove `NODE_ENV=development` from your `docker-compose.yml` or Dockerfile
41
+ - Remove custom scripts that set NODE_ENV before running the dev server
42
+ - Remove `NODE_ENV=development` from your `bin/dev` or Procfile.dev
43
+
18
44
  ## Breaking Changes
19
45
 
20
46
  ### 1. CSS Modules Configuration Changed to Named Exports
@@ -25,25 +51,27 @@ See the [TypeScript Documentation](./typescript.md) for usage examples.
25
51
 
26
52
  **Quick Reference: Configuration Options**
27
53
 
28
- | Configuration | namedExport | exportLocalsConvention | CSS: `.my-button` | Export Available | Works With |
29
- |---------------|-------------|------------------------|-------------------|------------------|------------|
30
- | **v9 Default** | `true` | `'camelCaseOnly'` | `.my-button` | `myButton` only | ✅ Named exports |
31
- | **Alternative** | `true` | `'dashesOnly'` | `.my-button` | `'my-button'` only | ✅ Named exports |
32
- | **v8 Style** | `false` | `'camelCase'` | `.my-button` | Both `myButton` AND `'my-button'` | ✅ Default export |
33
- | **❌ Invalid** | `true` | `'camelCase'` | - | - | ❌ Build Error |
54
+ | Configuration | namedExport | exportLocalsConvention | CSS: `.my-button` | Export Available | Works With |
55
+ | --------------- | ----------- | ---------------------- | ----------------- | --------------------------------- | ----------------- |
56
+ | **v9 Default** | `true` | `'camelCaseOnly'` | `.my-button` | `myButton` only | ✅ Named exports |
57
+ | **Alternative** | `true` | `'dashesOnly'` | `.my-button` | `'my-button'` only | ✅ Named exports |
58
+ | **v8 Style** | `false` | `'camelCase'` | `.my-button` | Both `myButton` AND `'my-button'` | ✅ Default export |
59
+ | **❌ Invalid** | `true` | `'camelCase'` | - | - | ❌ Build Error |
34
60
 
35
61
  **JavaScript Projects:**
62
+
36
63
  ```js
37
64
  // Before (v8)
38
- import styles from './Component.module.css';
39
- <button className={styles.button} />
65
+ import styles from "./Component.module.css"
66
+ ;<button className={styles.button} />
40
67
 
41
68
  // After (v9)
42
- import { button } from './Component.module.css';
43
- <button className={button} />
69
+ import { button } from "./Component.module.css"
70
+ ;<button className={button} />
44
71
  ```
45
72
 
46
73
  **TypeScript Projects:**
74
+
47
75
  ```typescript
48
76
  // Before (v8)
49
77
  import styles from './Component.module.css';
@@ -57,6 +85,7 @@ import * as styles from './Component.module.css';
57
85
  **Migration Options:**
58
86
 
59
87
  1. **Update your code** (Recommended):
88
+
60
89
  - JavaScript: Change to named imports (`import { className }`)
61
90
  - TypeScript: Change to namespace imports (`import * as styles`)
62
91
  - Kebab-case class names are automatically converted to camelCase
@@ -66,6 +95,7 @@ import * as styles from './Component.module.css';
66
95
  - This gives you time to migrate gradually
67
96
 
68
97
  **Benefits of the change:**
98
+
69
99
  - Eliminates webpack/TypeScript warnings
70
100
  - Better tree-shaking of unused CSS classes
71
101
  - More explicit about which classes are used
@@ -76,15 +106,17 @@ import * as styles from './Component.module.css';
76
106
  **What changed:** The configuration option has been renamed to better reflect its purpose.
77
107
 
78
108
  **Before (v8):**
109
+
79
110
  ```yml
80
111
  # config/shakapacker.yml
81
- webpack_loader: 'babel'
112
+ webpack_loader: "babel"
82
113
  ```
83
114
 
84
115
  **After (v9):**
116
+
85
117
  ```yml
86
118
  # config/shakapacker.yml
87
- javascript_transpiler: 'babel'
119
+ javascript_transpiler: "babel"
88
120
  ```
89
121
 
90
122
  **Note:** The old `webpack_loader` option is deprecated but still supported with a warning.
@@ -96,38 +128,48 @@ javascript_transpiler: 'babel'
96
128
  **Why:** SWC is 20x faster than Babel while maintaining compatibility with most JavaScript and TypeScript code.
97
129
 
98
130
  **Impact on existing projects:**
131
+
99
132
  - Your project will continue using Babel if you already have babel packages in package.json
100
133
  - To switch to SWC for better performance, see migration options below
101
134
 
102
135
  **Impact on new projects:**
136
+
103
137
  - New installations will use SWC by default
104
138
  - Babel dependencies won't be installed unless explicitly configured
105
139
 
106
140
  ### Migration Options
107
141
 
108
142
  #### Option 1 (Recommended): Switch to SWC
143
+
109
144
  ```yml
110
145
  # config/shakapacker.yml
111
- javascript_transpiler: 'swc'
146
+ javascript_transpiler: "swc"
112
147
  ```
148
+
113
149
  Then install SWC:
150
+
114
151
  ```bash
115
152
  npm install @swc/core swc-loader
116
153
  ```
117
154
 
118
155
  #### Option 2: Keep using Babel
156
+
119
157
  ```yml
120
158
  # config/shakapacker.yml
121
- javascript_transpiler: 'babel'
159
+ javascript_transpiler: "babel"
122
160
  ```
161
+
123
162
  No other changes needed - your existing babel packages will continue to work.
124
163
 
125
164
  #### Option 3: Use esbuild
165
+
126
166
  ```yml
127
167
  # config/shakapacker.yml
128
- javascript_transpiler: 'esbuild'
168
+ javascript_transpiler: "esbuild"
129
169
  ```
170
+
130
171
  Then install esbuild:
172
+
131
173
  ```bash
132
174
  npm install esbuild esbuild-loader
133
175
  ```
@@ -138,7 +180,7 @@ npm install esbuild esbuild-loader
138
180
 
139
181
  ```yml
140
182
  # config/shakapacker.yml
141
- assets_bundler: 'rspack' # or 'webpack' (default)
183
+ assets_bundler: "rspack" # or 'webpack' (default)
142
184
  ```
143
185
 
144
186
  ### 5. All Peer Dependencies Now Optional
@@ -146,16 +188,19 @@ assets_bundler: 'rspack' # or 'webpack' (default)
146
188
  **What changed:** All peer dependencies are now marked as optional via `peerDependenciesMeta`.
147
189
 
148
190
  **Benefits:**
191
+
149
192
  - **No installation warnings** - You won't see peer dependency warnings for packages you don't use
150
193
  - **Install only what you need** - Using webpack? Don't install rspack. Using SWC? Don't install Babel.
151
194
  - **Clear version constraints** - When you do install a package, version compatibility is still enforced
152
195
 
153
196
  **What this means for you:**
197
+
154
198
  - **Existing projects:** No changes needed. Your existing dependencies will continue to work.
155
199
  - **New projects:** The installer only adds the packages you actually need based on your configuration.
156
200
  - **Package manager behavior:** npm, yarn, and pnpm will no longer warn about missing peer dependencies.
157
201
 
158
202
  **Example:** If you're using SWC with webpack, you only need:
203
+
159
204
  ```json
160
205
  {
161
206
  "dependencies": {
@@ -168,6 +213,7 @@ assets_bundler: 'rspack' # or 'webpack' (default)
168
213
  }
169
214
  }
170
215
  ```
216
+
171
217
  You won't get warnings about missing Babel, Rspack, or esbuild packages.
172
218
 
173
219
  ## Migration Steps
@@ -186,22 +232,22 @@ yarn upgrade shakapacker@^9.0.0
186
232
 
187
233
  ```js
188
234
  // Find imports like this:
189
- import styles from './styles.module.css';
235
+ import styles from "./styles.module.css"
190
236
 
191
237
  // Replace with named imports:
192
- import { className1, className2 } from './styles.module.css';
238
+ import { className1, className2 } from "./styles.module.css"
193
239
  ```
194
240
 
195
241
  #### Update TypeScript definitions:
196
242
 
197
243
  ```typescript
198
244
  // Update your CSS module type definitions
199
- declare module '*.module.css' {
245
+ declare module "*.module.css" {
200
246
  // With namedExport: true, css-loader generates individual named exports
201
247
  // TypeScript can't know the exact names at compile time, so we declare
202
248
  // a module with any number of string exports
203
- const classes: { readonly [key: string]: string };
204
- export = classes;
249
+ const classes: { readonly [key: string]: string }
250
+ export = classes
205
251
  // Note: This allows 'import * as styles' but not 'import styles from'
206
252
  // because css-loader with namedExport: true doesn't generate a default export
207
253
  }
@@ -213,13 +259,15 @@ v9 automatically converts kebab-case to camelCase with `exportLocalsConvention:
213
259
 
214
260
  ```css
215
261
  /* styles.module.css */
216
- .my-button { }
217
- .primary-color { }
262
+ .my-button {
263
+ }
264
+ .primary-color {
265
+ }
218
266
  ```
219
267
 
220
268
  ```js
221
269
  // v9 default - camelCase conversion
222
- import { myButton, primaryColor } from './styles.module.css';
270
+ import { myButton, primaryColor } from "./styles.module.css"
223
271
  ```
224
272
 
225
273
  **Alternative: Keep kebab-case names with 'dashesOnly'**
@@ -256,7 +304,7 @@ If you have `webpack_loader` in your configuration:
256
304
  # webpack_loader: 'babel'
257
305
 
258
306
  # NEW:
259
- javascript_transpiler: 'babel'
307
+ javascript_transpiler: "babel"
260
308
  ```
261
309
 
262
310
  ### Step 5: Run Tests
@@ -291,6 +339,7 @@ If you see warnings about CSS module exports, ensure you've updated all imports
291
339
  ### Build Error: exportLocalsConvention Incompatible with namedExport
292
340
 
293
341
  If you see this error:
342
+
294
343
  ```
295
344
  "exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option
296
345
  ```
@@ -312,30 +361,35 @@ If you want to use `'camelCase'` (which exports both original and camelCase vers
312
361
  If you experience unexpected peer dependency warnings after upgrading to v9, you may need to clear your package manager's cache and reinstall dependencies. This ensures the new optional peer dependency configuration takes effect properly.
313
362
 
314
363
  **For npm:**
364
+
315
365
  ```bash
316
366
  rm -rf node_modules package-lock.json
317
367
  npm install
318
368
  ```
319
369
 
320
370
  **For Yarn:**
371
+
321
372
  ```bash
322
373
  rm -rf node_modules yarn.lock
323
374
  yarn install
324
375
  ```
325
376
 
326
377
  **For pnpm:**
378
+
327
379
  ```bash
328
380
  rm -rf node_modules pnpm-lock.yaml
329
381
  pnpm install
330
382
  ```
331
383
 
332
384
  **For Bun:**
385
+
333
386
  ```bash
334
387
  rm -rf node_modules bun.lockb
335
388
  bun install
336
389
  ```
337
390
 
338
391
  **When is this necessary?**
392
+
339
393
  - If you see peer dependency warnings for packages you don't use (e.g., warnings about Babel when using SWC)
340
394
  - If your package manager cached the old dependency resolution from v8
341
395
  - After switching transpilers or bundlers (e.g., from Babel to SWC, or webpack to rspack)
@@ -442,18 +442,17 @@ module Shakapacker
442
442
 
443
443
  def check_swc_config_conflicts
444
444
  swcrc_path = root_path.join(".swcrc")
445
- return unless swcrc_path.exist?
445
+ swc_config_path = root_path.join("config/swc.config.js")
446
446
 
447
- begin
448
- swcrc = JSON.parse(File.read(swcrc_path))
449
- # Check for conflicting jsc.target and env settings
450
- if swcrc.dig("jsc", "target") && swcrc["env"]
451
- @issues << "SWC configuration conflict: .swcrc contains both 'jsc.target' and 'env' settings, which are mutually exclusive. Remove 'jsc.target' from .swcrc"
452
- elsif swcrc.dig("jsc", "target")
453
- @warnings << "SWC configuration: .swcrc contains 'jsc.target' which may conflict with the loader's 'env' setting. Consider removing 'jsc.target' from .swcrc to avoid build errors"
454
- end
455
- rescue JSON::ParserError
456
- @warnings << "SWC configuration: .swcrc exists but contains invalid JSON"
447
+ if swcrc_path.exist?
448
+ @warnings << "SWC configuration: .swcrc file detected. This file completely overrides Shakapacker's default SWC settings and may cause build failures. " \
449
+ "Please migrate to config/swc.config.js which properly merges with Shakapacker defaults. " \
450
+ "To migrate: Move your custom settings from .swcrc to config/swc.config.js (see docs for format). " \
451
+ "See: https://github.com/shakacode/shakapacker/blob/main/docs/using_swc_loader.md"
452
+ end
453
+
454
+ if swc_config_path.exist?
455
+ @info << "SWC configuration: Using config/swc.config.js (recommended). This config is merged with Shakapacker's defaults."
457
456
  end
458
457
  end
459
458
 
@@ -8,8 +8,9 @@ module Shakapacker
8
8
  class SwcMigrator
9
9
  attr_reader :root_path, :logger
10
10
 
11
+ # Babel packages safe to remove when migrating to SWC
12
+ # Note: @babel/core and @babel/eslint-parser are excluded as they may be needed for ESLint
11
13
  BABEL_PACKAGES = [
12
- "@babel/core",
13
14
  "@babel/plugin-proposal-class-properties",
14
15
  "@babel/plugin-proposal-object-rest-spread",
15
16
  "@babel/plugin-syntax-dynamic-import",
@@ -25,6 +26,12 @@ module Shakapacker
25
26
  "babel-plugin-transform-react-remove-prop-types"
26
27
  ].freeze
27
28
 
29
+ # Babel packages that may be needed for ESLint - only remove if user explicitly confirms
30
+ ESLINT_BABEL_PACKAGES = [
31
+ "@babel/core",
32
+ "@babel/eslint-parser"
33
+ ].freeze
34
+
28
35
  SWC_PACKAGES = {
29
36
  "@swc/core" => "^1.7.39",
30
37
  "swc-loader" => "^0.2.6"
@@ -39,23 +46,21 @@ module Shakapacker
39
46
  .eslintrc.json
40
47
  ].freeze
41
48
 
42
- DEFAULT_SWCRC_CONFIG = {
43
- "jsc" => {
44
- "parser" => {
45
- "syntax" => "ecmascript",
46
- "jsx" => true,
47
- "dynamicImport" => true
48
- },
49
- "transform" => {
50
- "react" => {
51
- "runtime" => "automatic"
49
+ DEFAULT_SWC_CONFIG = <<~JS.freeze
50
+ // config/swc.config.js
51
+ // This file is merged with Shakapacker's default SWC configuration
52
+ // See: https://swc.rs/docs/configuration/compilation
53
+
54
+ module.exports = {
55
+ jsc: {
56
+ transform: {
57
+ react: {
58
+ runtime: "automatic"
59
+ }
52
60
  }
53
61
  }
54
- },
55
- "module" => {
56
- "type" => "es6"
57
62
  }
58
- }.freeze
63
+ JS
59
64
 
60
65
  def initialize(root_path, logger: nil)
61
66
  @root_path = Pathname.new(root_path)
@@ -68,7 +73,7 @@ module Shakapacker
68
73
  results = {
69
74
  config_updated: update_shakapacker_config,
70
75
  packages_installed: install_swc_packages,
71
- swcrc_created: create_swcrc,
76
+ swc_config_created: create_swc_config,
72
77
  babel_packages_found: find_babel_packages
73
78
  }
74
79
 
@@ -76,9 +81,9 @@ module Shakapacker
76
81
  logger.info " Note: SWC is approximately 20x faster than Babel for transpilation."
77
82
  logger.info " Please test your application thoroughly after migration."
78
83
  logger.info "\n📝 Configuration Info:"
79
- logger.info " - .swcrc provides base configuration for all environments"
80
- logger.info " - The SWC loader adds automatic environment targeting (via 'env' setting)"
81
- logger.info " - You can customize .swcrc, but avoid setting 'jsc.target' as it conflicts with 'env'"
84
+ logger.info " - config/swc.config.js is merged with Shakapacker's default SWC configuration"
85
+ logger.info " - You can customize config/swc.config.js to add additional options"
86
+ logger.info " - Avoid using .swcrc as it overrides Shakapacker defaults completely"
82
87
 
83
88
  # Show cleanup recommendations if babel packages found
84
89
  if results[:babel_packages_found].any?
@@ -108,20 +113,21 @@ module Shakapacker
108
113
  package_json_path = root_path.join("package.json")
109
114
  unless package_json_path.exist?
110
115
  logger.error "❌ No package.json found"
111
- return { removed_packages: [], config_files_deleted: [] }
116
+ return { removed_packages: [], config_files_deleted: [], preserved_packages: [] }
112
117
  end
113
118
 
114
119
  # Check if ESLint uses Babel parser
120
+ preserved_for_eslint = []
115
121
  if eslint_uses_babel?
116
- logger.info "\n⚠️ WARNING: ESLint configuration detected that may use Babel"
117
- logger.info " If you use @babel/eslint-parser or babel-eslint, you may need to:"
118
- logger.info " 1. Keep @babel/core and related Babel packages for ESLint"
119
- logger.info " 2. Or switch to @typescript-eslint/parser for TypeScript files"
120
- logger.info " 3. Or use espree (ESLint's default parser) for JavaScript files"
121
- logger.info "\n Proceeding with Babel package removal. Check your ESLint config after."
122
+ logger.info "\n⚠️ ESLint configuration detected that uses Babel parser"
123
+ logger.info " Preserving @babel/core and @babel/eslint-parser for ESLint compatibility"
124
+ logger.info " To switch ESLint parser:"
125
+ logger.info " 1. For TypeScript: use @typescript-eslint/parser"
126
+ logger.info " 2. For JavaScript: use espree (ESLint's default parser)"
127
+ preserved_for_eslint = ESLINT_BABEL_PACKAGES
122
128
  end
123
129
 
124
- removed_packages = remove_babel_from_package_json(package_json_path)
130
+ removed_packages = remove_babel_from_package_json(package_json_path, preserve: preserved_for_eslint)
125
131
  deleted_files = delete_babel_config_files
126
132
 
127
133
  if removed_packages.any?
@@ -131,7 +137,7 @@ module Shakapacker
131
137
  logger.info "ℹ️ No Babel packages found to remove"
132
138
  end
133
139
 
134
- { removed_packages: removed_packages, config_files_deleted: deleted_files }
140
+ { removed_packages: removed_packages, config_files_deleted: deleted_files, preserved_packages: preserved_for_eslint }
135
141
  end
136
142
 
137
143
  def find_babel_packages
@@ -144,7 +150,9 @@ module Shakapacker
144
150
  dev_dependencies = package_json["devDependencies"] || {}
145
151
  all_deps = dependencies.merge(dev_dependencies)
146
152
 
147
- found_packages = BABEL_PACKAGES.select { |pkg| all_deps.key?(pkg) }
153
+ # Find all babel packages (including ESLint-related ones for display)
154
+ all_babel_packages = BABEL_PACKAGES + ESLINT_BABEL_PACKAGES
155
+ found_packages = all_babel_packages.select { |pkg| all_deps.key?(pkg) }
148
156
  found_packages
149
157
  rescue JSON::ParserError => e
150
158
  logger.error "Failed to parse package.json: #{e.message}"
@@ -174,6 +182,11 @@ module Shakapacker
174
182
  begin
175
183
  package_json = JSON.parse(File.read(package_json_path))
176
184
  if package_json["eslintConfig"]
185
+ # Check parser field explicitly
186
+ parser = package_json["eslintConfig"]["parser"]
187
+ return true if parser && parser.match?(/@babel\/eslint-parser|babel-eslint/)
188
+
189
+ # Also check entire config for babel parser references (catches nested configs)
177
190
  return true if package_json["eslintConfig"].to_json.match?(/@babel\/eslint-parser|babel-eslint/)
178
191
  end
179
192
 
@@ -254,29 +267,35 @@ module Shakapacker
254
267
  {}
255
268
  end
256
269
 
257
- def create_swcrc
258
- swcrc_path = root_path.join(".swcrc")
259
- if swcrc_path.exist?
260
- logger.info "ℹ️ .swcrc already exists"
270
+ def create_swc_config
271
+ config_dir = root_path.join("config")
272
+ swc_config_path = config_dir.join("swc.config.js")
273
+
274
+ if swc_config_path.exist?
275
+ logger.info "ℹ️ config/swc.config.js already exists"
261
276
  return false
262
277
  end
263
278
 
264
- logger.info "📄 Creating .swcrc configuration..."
265
- File.write(swcrc_path, JSON.pretty_generate(DEFAULT_SWCRC_CONFIG) + "\n")
266
- logger.info " .swcrc created"
279
+ FileUtils.mkdir_p(config_dir) unless config_dir.exist?
280
+
281
+ logger.info "📄 Creating config/swc.config.js..."
282
+ File.write(swc_config_path, DEFAULT_SWC_CONFIG)
283
+ logger.info "✅ config/swc.config.js created"
267
284
  true
268
285
  rescue StandardError => e
269
- logger.error "Failed to create .swcrc: #{e.message}"
286
+ logger.error "Failed to create config/swc.config.js: #{e.message}"
270
287
  false
271
288
  end
272
289
 
273
- def remove_babel_from_package_json(package_json_path)
290
+ def remove_babel_from_package_json(package_json_path, preserve: [])
274
291
  package_json = JSON.parse(File.read(package_json_path))
275
292
  dependencies = package_json["dependencies"] || {}
276
293
  dev_dependencies = package_json["devDependencies"] || {}
277
294
  removed_packages = []
278
295
 
279
296
  BABEL_PACKAGES.each do |package|
297
+ next if preserve.include?(package)
298
+
280
299
  if dependencies.delete(package)
281
300
  removed_packages << package
282
301
  logger.info " - Removed #{package} from dependencies"
@@ -287,6 +306,13 @@ module Shakapacker
287
306
  end
288
307
  end
289
308
 
309
+ # Log preserved packages
310
+ preserve.each do |package|
311
+ if dependencies[package] || dev_dependencies[package]
312
+ logger.info " - Preserved #{package} (needed for ESLint)"
313
+ end
314
+ end
315
+
290
316
  if removed_packages.any?
291
317
  package_json["dependencies"] = dependencies
292
318
  package_json["devDependencies"] = dev_dependencies
@@ -1,4 +1,4 @@
1
1
  module Shakapacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "9.0.0.beta.9".freeze
3
+ VERSION = "9.0.0.beta.11".freeze
4
4
  end
data/lib/shakapacker.rb CHANGED
@@ -6,7 +6,7 @@ require "active_support/tagged_logging"
6
6
  module Shakapacker
7
7
  extend self
8
8
 
9
- DEFAULT_ENV = "production".freeze
9
+ DEFAULT_ENV = "development".freeze
10
10
 
11
11
  def instance=(instance)
12
12
  @instance = instance
data/package/env.ts CHANGED
@@ -6,21 +6,32 @@ const { isFileNotFoundError } = require("./utils/errorHelpers")
6
6
  const { sanitizeEnvValue } = require("./utils/pathValidation")
7
7
 
8
8
  const NODE_ENVIRONMENTS = ["development", "production", "test"] as const
9
- const DEFAULT = "production"
10
9
 
11
10
  // Sanitize environment variables to prevent injection
12
11
  const initialRailsEnv = sanitizeEnvValue(process.env.RAILS_ENV)
13
12
  const rawNodeEnv = sanitizeEnvValue(process.env.NODE_ENV)
14
13
 
14
+ // Default NODE_ENV based on RAILS_ENV to match bin/shakapacker behavior (see lib/shakapacker/runner.rb:27)
15
+ // - RAILS_ENV=production → DEFAULT="production" (safe for production builds)
16
+ // - RAILS_ENV=development, test, staging, or unset → DEFAULT="development" (good DX for dev server)
17
+ // This ensures the dev server works out of the box without requiring NODE_ENV to be set explicitly
18
+ const DEFAULT = initialRailsEnv === "production" ? "production" : "development"
19
+
15
20
  // Validate NODE_ENV strictly
16
21
  const nodeEnv =
17
- rawNodeEnv && NODE_ENVIRONMENTS.includes(rawNodeEnv as typeof NODE_ENVIRONMENTS[number]) ? rawNodeEnv : DEFAULT
22
+ rawNodeEnv &&
23
+ NODE_ENVIRONMENTS.includes(rawNodeEnv as (typeof NODE_ENVIRONMENTS)[number])
24
+ ? rawNodeEnv
25
+ : DEFAULT
18
26
 
19
27
  // Log warning if NODE_ENV was invalid
20
- if (rawNodeEnv && !NODE_ENVIRONMENTS.includes(rawNodeEnv as typeof NODE_ENVIRONMENTS[number])) {
28
+ if (
29
+ rawNodeEnv &&
30
+ !NODE_ENVIRONMENTS.includes(rawNodeEnv as (typeof NODE_ENVIRONMENTS)[number])
31
+ ) {
21
32
  console.warn(
22
33
  `[SHAKAPACKER WARNING] Invalid NODE_ENV value: ${rawNodeEnv}. ` +
23
- `Valid values are: ${NODE_ENVIRONMENTS.join(', ')}. Using default: ${DEFAULT}`
34
+ `Valid values are: ${NODE_ENVIRONMENTS.join(", ")}. Using default: ${DEFAULT}`
24
35
  )
25
36
  }
26
37
 
@@ -42,13 +53,13 @@ try {
42
53
  } catch (defaultError) {
43
54
  throw new Error(
44
55
  `Failed to load Shakapacker configuration.\n` +
45
- `Neither user config (${configPath}) nor default config (${defaultConfigPath}) could be loaded.\n\n` +
46
- `To fix this issue:\n` +
47
- `1. Create a config/shakapacker.yml file in your project\n` +
48
- `2. Or set the SHAKAPACKER_CONFIG environment variable to point to your config file\n` +
49
- `3. Or reinstall Shakapacker to restore the default configuration:\n` +
50
- ` npm install shakapacker --force\n` +
51
- ` yarn add shakapacker --force`
56
+ `Neither user config (${configPath}) nor default config (${defaultConfigPath}) could be loaded.\n\n` +
57
+ `To fix this issue:\n` +
58
+ `1. Create a config/shakapacker.yml file in your project\n` +
59
+ `2. Or set the SHAKAPACKER_CONFIG environment variable to point to your config file\n` +
60
+ `3. Or reinstall Shakapacker to restore the default configuration:\n` +
61
+ ` npm install shakapacker --force\n` +
62
+ ` yarn add shakapacker --force`
52
63
  )
53
64
  }
54
65
  } else {
@@ -61,13 +72,14 @@ const regex = new RegExp(`^(${availableEnvironments})$`, "g")
61
72
 
62
73
  const runningWebpackDevServer = process.env.WEBPACK_SERVE === "true"
63
74
 
64
- const validatedRailsEnv = initialRailsEnv && initialRailsEnv.match(regex) ? initialRailsEnv : DEFAULT
75
+ const validatedRailsEnv =
76
+ initialRailsEnv && initialRailsEnv.match(regex) ? initialRailsEnv : DEFAULT
65
77
 
66
78
  if (initialRailsEnv && validatedRailsEnv !== initialRailsEnv) {
67
79
  /* eslint no-console:0 */
68
80
  console.warn(
69
81
  `[SHAKAPACKER WARNING] Environment '${initialRailsEnv}' not found in the configuration.\n` +
70
- `Using '${DEFAULT}' configuration as a fallback.`
82
+ `Using '${DEFAULT}' configuration as a fallback.`
71
83
  )
72
84
  }
73
85
 
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shakapacker",
3
- "version": "9.0.0-beta.9",
3
+ "version": "9.0.0-beta.11",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "homepage": "https://github.com/shakacode/shakapacker",
6
6
  "bugs": {
@@ -71,6 +71,7 @@ describe("Config", () => {
71
71
  })
72
72
 
73
73
  test("should allow enabling integrity", () => {
74
+ process.env.RAILS_ENV = "production"
74
75
  process.env.SHAKAPACKER_CONFIG = "config/shakapacker_integrity.yml"
75
76
  const config = require("../../package/config")
76
77
 
@@ -78,6 +79,7 @@ describe("Config", () => {
78
79
  })
79
80
 
80
81
  test("should allow configuring hash functions", () => {
82
+ process.env.RAILS_ENV = "production"
81
83
  process.env.SHAKAPACKER_CONFIG = "config/shakapacker_integrity.yml"
82
84
  const config = require("../../package/config")
83
85
 
@@ -89,6 +91,7 @@ describe("Config", () => {
89
91
  })
90
92
 
91
93
  test("should allow configuring crossorigin", () => {
94
+ process.env.RAILS_ENV = "production"
92
95
  process.env.SHAKAPACKER_CONFIG = "config/shakapacker_integrity.yml"
93
96
  const config = require("../../package/config")
94
97