shakapacker 8.0.2 → 9.2.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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintignore +1 -0
  3. data/.eslintrc.fast.js +40 -0
  4. data/.eslintrc.js +48 -0
  5. data/.github/STATUS.md +1 -0
  6. data/.github/workflows/claude-code-review.yml +54 -0
  7. data/.github/workflows/claude.yml +50 -0
  8. data/.github/workflows/dummy.yml +9 -4
  9. data/.github/workflows/generator.yml +32 -10
  10. data/.github/workflows/node.yml +23 -1
  11. data/.github/workflows/ruby.yml +33 -2
  12. data/.github/workflows/test-bundlers.yml +170 -0
  13. data/.gitignore +20 -0
  14. data/.husky/pre-commit +2 -0
  15. data/.npmignore +56 -0
  16. data/.prettierignore +3 -0
  17. data/.rubocop.yml +1 -0
  18. data/.yalcignore +26 -0
  19. data/CHANGELOG.md +302 -16
  20. data/CLAUDE.md +29 -0
  21. data/CONTRIBUTING.md +138 -20
  22. data/Gemfile.lock +83 -89
  23. data/README.md +343 -105
  24. data/Rakefile +39 -4
  25. data/TODO.md +50 -0
  26. data/TODO_v9.md +87 -0
  27. data/bin/export-bundler-config +11 -0
  28. data/conductor-setup.sh +70 -0
  29. data/conductor.json +7 -0
  30. data/docs/cdn_setup.md +379 -0
  31. data/docs/common-upgrades.md +615 -0
  32. data/docs/css-modules-export-mode.md +512 -0
  33. data/docs/deployment.md +62 -9
  34. data/docs/optional-peer-dependencies.md +198 -0
  35. data/docs/peer-dependencies.md +60 -0
  36. data/docs/react.md +6 -14
  37. data/docs/releasing.md +197 -0
  38. data/docs/rspack.md +190 -0
  39. data/docs/rspack_migration_guide.md +305 -0
  40. data/docs/subresource_integrity.md +54 -0
  41. data/docs/transpiler-migration.md +209 -0
  42. data/docs/transpiler-performance.md +179 -0
  43. data/docs/troubleshooting.md +157 -22
  44. data/docs/typescript-migration.md +379 -0
  45. data/docs/typescript.md +99 -0
  46. data/docs/using_esbuild_loader.md +3 -3
  47. data/docs/using_swc_loader.md +112 -10
  48. data/docs/v6_upgrade.md +10 -0
  49. data/docs/v8_upgrade.md +3 -5
  50. data/docs/v9_upgrade.md +458 -0
  51. data/gemfiles/Gemfile-rails.6.0.x +2 -1
  52. data/gemfiles/Gemfile-rails.6.1.x +1 -1
  53. data/gemfiles/Gemfile-rails.7.0.x +2 -2
  54. data/gemfiles/Gemfile-rails.7.1.x +1 -2
  55. data/gemfiles/Gemfile-rails.7.2.x +11 -0
  56. data/gemfiles/Gemfile-rails.8.0.x +11 -0
  57. data/lib/install/bin/export-bundler-config +11 -0
  58. data/lib/install/bin/shakapacker +4 -6
  59. data/lib/install/bin/shakapacker-dev-server +1 -1
  60. data/lib/install/config/rspack/rspack.config.js +6 -0
  61. data/lib/install/config/rspack/rspack.config.ts +7 -0
  62. data/lib/install/config/shakapacker.yml +25 -5
  63. data/lib/install/config/webpack/webpack.config.ts +7 -0
  64. data/lib/install/package.json +38 -0
  65. data/lib/install/template.rb +194 -44
  66. data/lib/shakapacker/bundler_switcher.rb +329 -0
  67. data/lib/shakapacker/compiler.rb +2 -1
  68. data/lib/shakapacker/compiler_strategy.rb +2 -2
  69. data/lib/shakapacker/configuration.rb +173 -2
  70. data/lib/shakapacker/dev_server_runner.rb +29 -8
  71. data/lib/shakapacker/digest_strategy.rb +2 -1
  72. data/lib/shakapacker/doctor.rb +905 -0
  73. data/lib/shakapacker/helper.rb +64 -16
  74. data/lib/shakapacker/manifest.rb +10 -3
  75. data/lib/shakapacker/mtime_strategy.rb +1 -1
  76. data/lib/shakapacker/railtie.rb +4 -4
  77. data/lib/shakapacker/rspack_runner.rb +19 -0
  78. data/lib/shakapacker/runner.rb +159 -10
  79. data/lib/shakapacker/swc_migrator.rb +384 -0
  80. data/lib/shakapacker/utils/manager.rb +15 -2
  81. data/lib/shakapacker/version.rb +1 -1
  82. data/lib/shakapacker/version_checker.rb +2 -2
  83. data/lib/shakapacker/webpack_runner.rb +6 -43
  84. data/lib/shakapacker.rb +22 -11
  85. data/lib/tasks/shakapacker/doctor.rake +8 -0
  86. data/lib/tasks/shakapacker/export_bundler_config.rake +72 -0
  87. data/lib/tasks/shakapacker/install.rake +12 -2
  88. data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
  89. data/lib/tasks/shakapacker/switch_bundler.rake +82 -0
  90. data/lib/tasks/shakapacker.rake +2 -0
  91. data/package/.npmignore +4 -0
  92. data/package/babel/preset.ts +56 -0
  93. data/package/config.ts +175 -0
  94. data/package/configExporter/cli.ts +683 -0
  95. data/package/configExporter/configDocs.ts +102 -0
  96. data/package/configExporter/fileWriter.ts +92 -0
  97. data/package/configExporter/index.ts +5 -0
  98. data/package/configExporter/types.ts +36 -0
  99. data/package/configExporter/yamlSerializer.ts +266 -0
  100. data/package/{dev_server.js → dev_server.ts} +8 -5
  101. data/package/env.ts +92 -0
  102. data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +30 -0
  103. data/package/environments/{base.js → base.ts} +56 -60
  104. data/package/environments/development.ts +90 -0
  105. data/package/environments/production.ts +80 -0
  106. data/package/environments/test.ts +53 -0
  107. data/package/environments/types.ts +98 -0
  108. data/package/esbuild/index.ts +42 -0
  109. data/package/index.d.ts +3 -60
  110. data/package/index.ts +55 -0
  111. data/package/loaders.d.ts +28 -0
  112. data/package/optimization/rspack.ts +36 -0
  113. data/package/optimization/webpack.ts +57 -0
  114. data/package/plugins/rspack.ts +103 -0
  115. data/package/plugins/webpack.ts +62 -0
  116. data/package/rspack/index.ts +64 -0
  117. data/package/rules/{babel.js → babel.ts} +2 -2
  118. data/package/rules/{coffee.js → coffee.ts} +1 -1
  119. data/package/rules/css.ts +3 -0
  120. data/package/rules/{erb.js → erb.ts} +1 -1
  121. data/package/rules/esbuild.ts +10 -0
  122. data/package/rules/file.ts +40 -0
  123. data/package/rules/{jscommon.js → jscommon.ts} +4 -4
  124. data/package/rules/{less.js → less.ts} +4 -4
  125. data/package/rules/raw.ts +25 -0
  126. data/package/rules/rspack.ts +176 -0
  127. data/package/rules/{sass.js → sass.ts} +7 -3
  128. data/package/rules/{stylus.js → stylus.ts} +4 -8
  129. data/package/rules/swc.ts +10 -0
  130. data/package/rules/webpack.ts +16 -0
  131. data/package/swc/index.ts +56 -0
  132. data/package/types/README.md +88 -0
  133. data/package/types/index.ts +61 -0
  134. data/package/types.ts +108 -0
  135. data/package/utils/configPath.ts +6 -0
  136. data/package/utils/debug.ts +49 -0
  137. data/package/utils/defaultConfigPath.ts +4 -0
  138. data/package/utils/errorCodes.ts +219 -0
  139. data/package/utils/errorHelpers.ts +143 -0
  140. data/package/utils/getStyleRule.ts +64 -0
  141. data/package/utils/helpers.ts +85 -0
  142. data/package/utils/{inliningCss.js → inliningCss.ts} +3 -3
  143. data/package/utils/pathValidation.ts +139 -0
  144. data/package/utils/requireOrError.ts +15 -0
  145. data/package/utils/snakeToCamelCase.ts +5 -0
  146. data/package/utils/typeGuards.ts +342 -0
  147. data/package/utils/validateDependencies.ts +61 -0
  148. data/package/webpack-types.d.ts +33 -0
  149. data/package/webpackDevServerConfig.ts +117 -0
  150. data/package-lock.json +13047 -0
  151. data/package.json +154 -18
  152. data/scripts/remove-use-strict.js +45 -0
  153. data/scripts/type-check-no-emit.js +27 -0
  154. data/test/helpers.js +1 -1
  155. data/test/package/config.test.js +43 -0
  156. data/test/package/env.test.js +42 -7
  157. data/test/package/environments/base.test.js +5 -1
  158. data/test/package/rules/babel.test.js +16 -0
  159. data/test/package/rules/esbuild.test.js +1 -1
  160. data/test/package/rules/raw.test.js +40 -7
  161. data/test/package/rules/swc.test.js +1 -1
  162. data/test/package/rules/webpack.test.js +35 -0
  163. data/test/package/staging.test.js +4 -3
  164. data/test/package/transpiler-defaults.test.js +127 -0
  165. data/test/peer-dependencies.sh +85 -0
  166. data/test/scripts/remove-use-strict.test.js +125 -0
  167. data/test/typescript/build.test.js +118 -0
  168. data/test/typescript/environments.test.js +107 -0
  169. data/test/typescript/pathValidation.test.js +142 -0
  170. data/test/typescript/securityValidation.test.js +182 -0
  171. data/tools/README.md +124 -0
  172. data/tools/css-modules-v9-codemod.js +179 -0
  173. data/tsconfig.eslint.json +16 -0
  174. data/tsconfig.json +38 -0
  175. data/yarn.lock +4165 -2706
  176. metadata +129 -41
  177. data/package/babel/preset.js +0 -37
  178. data/package/config.js +0 -54
  179. data/package/env.js +0 -48
  180. data/package/environments/development.js +0 -13
  181. data/package/environments/production.js +0 -88
  182. data/package/environments/test.js +0 -3
  183. data/package/esbuild/index.js +0 -40
  184. data/package/index.js +0 -40
  185. data/package/rules/css.js +0 -3
  186. data/package/rules/esbuild.js +0 -10
  187. data/package/rules/file.js +0 -29
  188. data/package/rules/index.js +0 -20
  189. data/package/rules/raw.js +0 -5
  190. data/package/rules/swc.js +0 -10
  191. data/package/swc/index.js +0 -50
  192. data/package/utils/configPath.js +0 -4
  193. data/package/utils/defaultConfigPath.js +0 -2
  194. data/package/utils/getStyleRule.js +0 -40
  195. data/package/utils/helpers.js +0 -58
  196. data/package/utils/snakeToCamelCase.js +0 -5
  197. data/package/webpackDevServerConfig.js +0 -71
  198. data/test/package/rules/index.test.js +0 -16
data/README.md CHANGED
@@ -1,13 +1,20 @@
1
- # Shakapacker (v8)
1
+ # Shakapacker (v9)
2
2
 
3
- _Official, actively maintained successor to [rails/webpacker](https://github.com/rails/webpacker).ShakaCode stands behind the long-term maintenance and development of this project for the Rails community._
3
+ ---
4
+
5
+ _🚀 Shakapacker 9 supports [Rspack](https://rspack.rs/)! 10x faster than webpack!_
6
+
7
+ ---
8
+
9
+ _Official, actively maintained successor to [rails/webpacker](https://github.com/rails/webpacker). ShakaCode stands behind the long-term maintenance and development of this project for the Rails community._
4
10
 
5
- * ⚠️ See the [6-stable](https://github.com/shakacode/shakapacker/tree/6-stable) branch for Shakapacker v6.x code and documentation. :warning:
6
- * See [V8 Upgrade](./docs/v8_upgrade.md) for upgrading from the v7 release.
7
- * See [V7 Upgrade](./docs/v7_upgrade.md) for upgrading from the v6 release.
8
- * See [V6 Upgrade](./docs/v6_upgrade.md) for upgrading from v5 or prior v6 releases.
11
+ - ⚠️ See the [6-stable](https://github.com/shakacode/shakapacker/tree/6-stable) branch for Shakapacker v6.x code and documentation. :warning:
12
+ - **See [V9 Upgrade](./docs/v9_upgrade.md) for upgrading from the v8 release.**
13
+ - See [V8 Upgrade](./docs/v8_upgrade.md) for upgrading from the v7 release.
14
+ - See [V7 Upgrade](./docs/v7_upgrade.md) for upgrading from the v6 release.
15
+ - See [V6 Upgrade](./docs/v6_upgrade.md) for upgrading from v5 or prior v6 releases.
9
16
 
10
- [![Ruby specs](https://github.com/shakacode/shakapacker/workflows/Ruby%20specs/badge.svg)](https://github.com/shakacode/shakapacker/actions)
17
+ [![Ruby based checks](https://github.com/shakacode/shakapacker/workflows/Ruby%20based%20checks/badge.svg)](https://github.com/shakacode/shakapacker/actions)
11
18
  [![Jest specs](https://github.com/shakacode/shakapacker/workflows/Jest%20specs/badge.svg)](https://github.com/shakacode/shakapacker/actions)
12
19
  [![Rubocop](https://github.com/shakacode/shakapacker/workflows/Rubocop/badge.svg)](https://github.com/shakacode/shakapacker/actions)
13
20
  [![JS lint](https://github.com/shakacode/shakapacker/workflows/JS%20lint/badge.svg)](https://github.com/shakacode/shakapacker/actions)
@@ -27,9 +34,10 @@ See a comparison of [Shakapacker with jsbundling-rails](https://github.com/rails
27
34
  For discussions, see our [Slack Channel](https://reactrails.slack.com/join/shared_invite/enQtNjY3NTczMjczNzYxLTlmYjdiZmY3MTVlMzU2YWE0OWM0MzNiZDI0MzdkZGFiZTFkYTFkOGVjODBmOWEyYWQ3MzA2NGE1YWJjNmVlMGE).
28
35
 
29
36
  ---
37
+
30
38
  ## ShakaCode Support
31
39
 
32
- [ShakaCode](https://www.shakacode.com) focuses on helping Ruby on Rails teams use React and Webpack better. We can upgrade your project and improve your development and customer experiences, allowing you to focus on building new features or fixing bugs instead.
40
+ [ShakaCode](https://www.shakacode.com) focuses on helping Ruby on Rails teams use React and Webpack better. We can upgrade your project and improve your development and customer experiences, allowing you to focus on building new features or fixing bugs instead.
33
41
 
34
42
  For an overview of working with us, see our [Client Engagement Model](https://www.shakacode.com/blog/client-engagement-model/) article and [how we bill for time](https://www.shakacode.com/blog/shortcut-jira-trello-github-toggl-time-and-task-tracking/).
35
43
 
@@ -38,6 +46,7 @@ We also specialize in helping development teams lower infrastructure and CI cost
38
46
  If you think ShakaCode can help your project, [click here](https://meetings.hubspot.com/justingordon/30-minute-consultation) to book a call with [Justin Gordon](mailto:justin@shakacode.com), the creator of React on Rails and Shakapacker.
39
47
 
40
48
  Here's a testimonial of how ShakaCode can help from [Florian Gößler](https://github.com/FGoessler) of [Blinkist](https://www.blinkist.com/), January 2, 2023:
49
+
41
50
  > Hey Justin 👋
42
51
  >
43
52
  > I just wanted to let you know that we today shipped the webpacker to shakapacker upgrades and it all seems to be running smoothly! Thanks again for all your support and your teams work! 😍
@@ -53,50 +62,50 @@ Read the [full review here](https://clutch.co/profile/shakacode#reviews?sort_by=
53
62
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
54
63
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
55
64
 
56
- - [Prerequisites](#prerequisites)
57
- - [Features](#features)
58
- - [Optional support](#optional-support)
59
- - [Installation](#installation)
60
- - [Rails v6+](#rails-v6)
61
- - [Concepts](#concepts)
62
- - [Usage](#usage)
63
- - [Configuration and Code](#configuration-and-code)
64
- - [View Helpers](#view-helpers)
65
- - [View Helpers `javascript_pack_tag` and `stylesheet_pack_tag`](#view-helpers-javascript_pack_tag-and-stylesheet_pack_tag)
66
- - [View Helpers `append_javascript_pack_tag`, `prepend_javascript_pack_tag` and `append_stylesheet_pack_tag`](#view-helper-append_javascript_pack_tag-prepend_javascript_pack_tag-and-append_stylesheet_pack_tag)
67
- - [View Helper: `asset_pack_path`](#view-helper-asset_pack_path)
68
- - [View Helper: `image_pack_tag`](#view-helper-image_pack_tag)
69
- - [View Helper: `favicon_pack_tag`](#view-helper-favicon_pack_tag)
70
- - [View Helper: `preload_pack_asset`](#view-helper-preload_pack_asset)
71
- - [Images in Stylesheets](#images-in-stylesheets)
72
- - [Server-Side Rendering (SSR)](#server-side-rendering-ssr)
73
- - [Development](#development)
74
- - [Automatic Webpack Code Building](#automatic-webpack-code-building)
75
- - [Compiler strategies](#compiler-strategies)
76
- - [Common Development Commands](#common-development-commands)
77
- - [Webpack Configuration](#webpack-configuration)
78
- - [Babel configuration](#babel-configuration)
79
- - [SWC configuration](#swc-configuration)
80
- - [esbuild loader configuration](#esbuild-loader-configuration)
81
- - [Integrations](#integrations)
82
- - [React](#react)
83
- - [Typescript](#typescript)
84
- - [CSS](#css)
85
- - [Postcss](#postcss)
86
- - [Sass](#sass)
87
- - [Less](#less)
88
- - [Stylus](#stylus)
89
- - [CoffeeScript](#coffeescript)
90
- - [Other frameworks](#other-frameworks)
91
- - [Custom Rails environments](#custom-rails-environments)
92
- - [Upgrading](#upgrading)
93
- - [Paths](#paths)
94
- - [Additional paths](#additional-paths)
95
- - [Deployment](#deployment)
96
- - [Example Apps](#example-apps)
97
- - [Troubleshooting](#troubleshooting)
98
- - [Contributing](#contributing)
99
- - [License](#license)
65
+ - [Prerequisites](#prerequisites)
66
+ - [Features](#features)
67
+ - [Optional support](#optional-support)
68
+ - [Installation](#installation)
69
+ - [Rails v6+](#rails-v6)
70
+ - [Concepts](#concepts)
71
+ - [Usage](#usage)
72
+ - [Configuration and Code](#configuration-and-code)
73
+ - [View Helpers](#view-helpers)
74
+ - [View Helpers `javascript_pack_tag` and `stylesheet_pack_tag`](#view-helpers-javascript_pack_tag-and-stylesheet_pack_tag)
75
+ - [View Helpers `append_javascript_pack_tag`, `prepend_javascript_pack_tag` and `append_stylesheet_pack_tag`](#view-helper-append_javascript_pack_tag-prepend_javascript_pack_tag-and-append_stylesheet_pack_tag)
76
+ - [View Helper: `asset_pack_path`](#view-helper-asset_pack_path)
77
+ - [View Helper: `image_pack_tag`](#view-helper-image_pack_tag)
78
+ - [View Helper: `favicon_pack_tag`](#view-helper-favicon_pack_tag)
79
+ - [View Helper: `preload_pack_asset`](#view-helper-preload_pack_asset)
80
+ - [Images in Stylesheets](#images-in-stylesheets)
81
+ - [Server-Side Rendering (SSR)](#server-side-rendering-ssr)
82
+ - [Development](#development)
83
+ - [Automatic Webpack Code Building](#automatic-webpack-code-building)
84
+ - [Compiler strategies](#compiler-strategies)
85
+ - [Common Development Commands](#common-development-commands)
86
+ - [Webpack Configuration](#webpack-configuration)
87
+ - [Babel configuration](#babel-configuration)
88
+ - [SWC configuration](#swc-configuration)
89
+ - [esbuild loader configuration](#esbuild-loader-configuration)
90
+ - [Integrations](#integrations)
91
+ - [React](#react)
92
+ - [Typescript](#typescript)
93
+ - [CSS](#css)
94
+ - [Postcss](#postcss)
95
+ - [Sass](#sass)
96
+ - [Less](#less)
97
+ - [Stylus](#stylus)
98
+ - [CoffeeScript](#coffeescript)
99
+ - [Other frameworks](#other-frameworks)
100
+ - [Custom Rails environments](#custom-rails-environments)
101
+ - [Upgrading](#upgrading)
102
+ - [Paths](#paths)
103
+ - [Additional paths](#additional-paths)
104
+ - [Deployment](#deployment)
105
+ - [Example Apps](#example-apps)
106
+ - [Troubleshooting](#troubleshooting)
107
+ - [Contributing](#contributing)
108
+ - [License](#license)
100
109
  - [Supporters](#supporters)
101
110
 
102
111
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -108,6 +117,7 @@ Read the [full review here](https://clutch.co/profile/shakacode#reviews?sort_by=
108
117
  - Node.js 14+
109
118
 
110
119
  ## Features
120
+
111
121
  - Rails view helpers that fully support Webpack output, including HMR and code splitting.
112
122
  - Convenient but not required webpack configuration. The only requirement is that your webpack configuration creates a manifest.
113
123
  - HMR with the `shakapacker-dev-server`, such as for hot-reloading React!
@@ -120,17 +130,20 @@ Read the [full review here](https://clutch.co/profile/shakacode#reviews?sort_by=
120
130
  - Extensible and configurable. For example, all major dependencies are specified as peers, so you can upgrade easily.
121
131
 
122
132
  ### Optional support
123
- _Requires extra packages to be installed._
124
- - React
125
- - TypeScript
126
- - Stylesheets - Sass, Less, Stylus and Css, PostCSS
127
- - CoffeeScript
133
+
134
+ _Requires extra packages to be installed._
135
+
136
+ - React
137
+ - TypeScript
138
+ - Stylesheets - Sass, Less, Stylus and Css, PostCSS
139
+ - CoffeeScript
128
140
 
129
141
  ## Installation
130
142
 
131
143
  ### Rails v6+
132
144
 
133
145
  With Rails v6+, skip JavaScript for a new app and follow below Manual Installation Steps to manually add the `shakapacker` gem to your Gemfile.
146
+
134
147
  ```bash
135
148
  rails new myapp --skip-javascript
136
149
  ```
@@ -172,7 +185,7 @@ If you wish to use [Yarn PnP](https://yarnpkg.com/features/pnp) you will need to
172
185
  > [!NOTE]
173
186
  >
174
187
  > The rest of the documentation will only reference `npm` when providing commands such as to install optional packages except in cases where
175
- > a particular package manager requires a very different command; otherwise it should be safe to just replace `npm` with the name of your
188
+ > a particular package manager requires a very different command; otherwise it should be safe to just replace `npm` with the name of your
176
189
  > preferred package manager when running the command
177
190
 
178
191
  Note, in v6+, most JS packages are peer dependencies. Thus, the installer will add the packages:
@@ -194,6 +207,101 @@ Note, in v6+, most JS packages are peer dependencies. Thus, the installer will a
194
207
  Previously, these "webpack" and "babel" packages were direct dependencies for `shakapacker`. By
195
208
  making these peer dependencies, you have control over the versions used in your webpack and babel configs.
196
209
 
210
+ ### Optional Peer Dependencies
211
+
212
+ All peer dependencies in Shakapacker are marked as optional via `peerDependenciesMeta`. This design decision ensures:
213
+
214
+ - **No warnings during package installation** when dependencies are not needed
215
+ - **Clear visibility of supported package versions** for upgrades
216
+ - **Flexibility to choose only the tools you need** (webpack vs rspack, babel vs swc vs esbuild)
217
+
218
+ The optional peer dependencies approach means you only install what you actually use, while still maintaining
219
+ version compatibility constraints when you do install those packages.
220
+
221
+ #### Required Dependencies by Configuration
222
+
223
+ Depending on your setup, you'll need different subsets of the optional peer dependencies:
224
+
225
+ **For Webpack + Babel (traditional setup):**
226
+
227
+ ```json
228
+ {
229
+ "dependencies": {
230
+ "shakapacker": "^9.0.0",
231
+ "@babel/core": "^7.17.9",
232
+ "@babel/plugin-transform-runtime": "^7.17.0",
233
+ "@babel/preset-env": "^7.16.11",
234
+ "@babel/runtime": "^7.17.9",
235
+ "babel-loader": "^8.2.4",
236
+ "compression-webpack-plugin": "^9.0.0",
237
+ "terser-webpack-plugin": "^5.3.1",
238
+ "webpack": "^5.76.0",
239
+ "webpack-assets-manifest": "^5.0.6",
240
+ "webpack-cli": "^5.0.0",
241
+ "webpack-dev-server": "^5.0.0"
242
+ }
243
+ }
244
+ ```
245
+
246
+ **For Webpack + SWC (faster alternative):**
247
+
248
+ ```json
249
+ {
250
+ "dependencies": {
251
+ "shakapacker": "^9.0.0",
252
+ "@swc/core": "^1.3.0",
253
+ "swc-loader": "^0.2.0",
254
+ "compression-webpack-plugin": "^9.0.0",
255
+ "terser-webpack-plugin": "^5.3.1",
256
+ "webpack": "^5.76.0",
257
+ "webpack-assets-manifest": "^5.0.6",
258
+ "webpack-cli": "^5.0.0",
259
+ "webpack-dev-server": "^5.0.0"
260
+ }
261
+ }
262
+ ```
263
+
264
+ **For Rspack + SWC (10x faster bundling):**
265
+
266
+ ```json
267
+ {
268
+ "dependencies": {
269
+ "shakapacker": "^9.0.0",
270
+ "@rspack/core": "^1.0.0",
271
+ "@rspack/cli": "^1.0.0",
272
+ "@swc/core": "^1.3.0",
273
+ "swc-loader": "^0.2.0",
274
+ "rspack-manifest-plugin": "^5.0.0"
275
+ }
276
+ }
277
+ ```
278
+
279
+ **Quick tip:** You can easily switch between webpack and rspack using:
280
+
281
+ ```bash
282
+ rails shakapacker:switch_bundler rspack --install-deps
283
+ # or with rake (note the -- separator)
284
+ rake shakapacker:switch_bundler rspack -- --install-deps
285
+
286
+ # For faster switching, use --no-uninstall to keep both bundlers installed
287
+ rails shakapacker:switch_bundler webpack --install-deps --no-uninstall
288
+ ```
289
+
290
+ See the [Rspack Migration Guide](./docs/rspack_migration_guide.md) for details.
291
+
292
+ **For CSS/Sass processing (add to any config above):**
293
+
294
+ ```json
295
+ {
296
+ "dependencies": {
297
+ "css-loader": "^6.8.1",
298
+ "mini-css-extract-plugin": "^2.0.0",
299
+ "sass": "^1.50.0",
300
+ "sass-loader": "^13.0.0"
301
+ }
302
+ }
303
+ ```
304
+
197
305
  ## Concepts
198
306
 
199
307
  At its core, Shakapacker's essential function is to:
@@ -211,10 +319,11 @@ You will need your file system to correspond to the setup of your `config/shakap
211
319
  Suppose you have the following configuration:
212
320
 
213
321
  `shakapacker.yml`
322
+
214
323
  ```yml
215
324
  default: &default
216
325
  source_path: app/javascript
217
- source_entry_path: packs
326
+ source_entry_path: packs
218
327
  public_root_path: public
219
328
  public_output_path: packs
220
329
  nested_entries: false
@@ -248,6 +357,7 @@ To enable/disable the usage of contentHash in any node environment (specified us
248
357
  You can use the environment variable `SHAKAPACKER_CONFIG` to enforce a particular path to the config file rather than the default `config/shakapacker.yml`.
249
358
 
250
359
  ### View Helpers
360
+
251
361
  The Shakapacker view helpers generate the script and link tags to get the webpack output onto your views.
252
362
 
253
363
  Be sure to consult the API documentation in the source code of [helper.rb](./lib/shakapacker/helper.rb).
@@ -275,7 +385,8 @@ You can provide multiple packs and other attributes. Note, `defer` defaults to s
275
385
  ```
276
386
 
277
387
  The resulting HTML would look like this:
278
- ```
388
+
389
+ ```html
279
390
  <script src="/packs/vendor-16838bab065ae1e314.js" data-turbo-track="reload" defer></script>
280
391
  <script src="/packs/calendar~runtime-16838bab065ae1e314.js" data-turbo-track="reload" defer></script>
281
392
  <script src="/packs/calendar-1016838bab065ae1e314.js" data-turbo-track="reload" defer"></script>
@@ -287,7 +398,27 @@ In this output, both the calendar and map codes might refer to other common libr
287
398
 
288
399
  Note, the default of "defer" for the `javascript_pack_tag`. You can override that to `false`. If you expose jquery globally with `expose-loader,` by using `import $ from "expose-loader?exposes=$,jQuery!jquery"` in your `app/javascript/application.js`, pass the option `defer: false` to your `javascript_pack_tag`.
289
400
 
290
- **Important:** Pass all your pack names as multiple arguments, not multiple calls, when using `javascript_pack_tag` and the `stylesheet_pack_tag`. Otherwise, you will get duplicated chunks on the page.
401
+ The `javascript_pack_tag` also supports the `async` attribute, which you can enable by passing `async: true`:
402
+
403
+ ```erb
404
+ <%= javascript_pack_tag 'application', async: true %>
405
+ ```
406
+
407
+ This will generate script tags with the `async` attribute, which allows the browser to download and execute the script asynchronously without blocking HTML parsing:
408
+
409
+ ```html
410
+ <script src="/packs/vendor-16838bab065ae1e314.js" async></script>
411
+ <script src="/packs/application~runtime-16838bab065ae1e314.js" async></script>
412
+ <script src="/packs/application-1016838bab065ae1e314.js" async></script>
413
+ ```
414
+
415
+ Note that when using `async: true`, scripts may execute in any order as soon as they're downloaded, which could cause issues if your code has dependencies between files. In most cases, `defer` (the default) is preferred as it maintains execution order.
416
+
417
+ > [!NOTE]
418
+ >
419
+ > When both `async` and `defer` attributes are specified, `async` takes precedence according to HTML5 specifications. So if you pass both `async: true` and `defer: true`, the script tag will use `async`.
420
+
421
+ **Important:** Pass all your pack names as multiple arguments, not multiple calls, when using `javascript_pack_tag` and the `stylesheet_pack_tag`. Otherwise, you will get duplicated chunks on the page.
291
422
 
292
423
  ```erb
293
424
  <%# DO %>
@@ -303,7 +434,7 @@ you may use multiple calls to stylesheet_pack_tag if,
303
434
  say,
304
435
  you require multiple `<style>` tags for different output media:
305
436
 
306
- ``` erb
437
+ ```erb
307
438
  <%= stylesheet_pack_tag 'application', media: 'screen' %>
308
439
  <%= stylesheet_pack_tag 'print', media: 'print' %>
309
440
  ```
@@ -313,18 +444,21 @@ you require multiple `<style>` tags for different output media:
313
444
  If you need to configure your script pack names or stylesheet pack names from the view for a route or partials, then you will need some logic to ensure you call the helpers only once with multiple arguments. The new view helpers, `append_javascript_pack_tag` and `append_stylesheet_pack_tag` can solve this problem. The helper `append_javascript_pack_tag` will queue up script packs when the `javascript_pack_tag` is finally used. Similarly,`append_stylesheet_pack_tag` will queue up style packs when the `stylesheet_pack_tag` is finally used.
314
445
 
315
446
  Main view:
447
+
316
448
  ```erb
317
449
  <% append_javascript_pack_tag 'calendar' %>
318
450
  <% append_stylesheet_pack_tag 'calendar' %>
319
451
  ```
320
452
 
321
453
  Some partial:
454
+
322
455
  ```erb
323
456
  <% append_javascript_pack_tag 'map' %>
324
457
  <% append_stylesheet_pack_tag 'map' %>
325
458
  ```
326
459
 
327
460
  And the main layout has:
461
+
328
462
  ```erb
329
463
  <%= javascript_pack_tag 'application' %>
330
464
  <%= stylesheet_pack_tag 'application' %>
@@ -346,9 +480,9 @@ Thus, you can distribute the logic of what packs are needed for any route. All t
346
480
  The typical issue is that your layout might reference some partials that need to configure packs. A good way to solve this problem is to use `content_for` to ensure that the code to render your partial comes before the call to `javascript_pack_tag`.
347
481
 
348
482
  ```erb
349
- <% content_for :footer do
483
+ <% content_for :footer do
350
484
  render 'shared/footer' %>
351
-
485
+
352
486
  <%= javascript_pack_tag %>
353
487
 
354
488
  <%= content_for :footer %>
@@ -357,16 +491,19 @@ The typical issue is that your layout might reference some partials that need to
357
491
  There is also `prepend_javascript_pack_tag` that will put the entry at the front of the queue. This is handy when you want an entry in the main layout to go before the partial and main layout `append_javascript_pack_tag` entries.
358
492
 
359
493
  Main view:
494
+
360
495
  ```erb
361
496
  <% append_javascript_pack_tag 'map' %>
362
497
  ```
363
498
 
364
499
  Some partial:
500
+
365
501
  ```erb
366
502
  <% append_javascript_pack_tag 'map' %>
367
503
  ```
368
504
 
369
505
  And the main layout has:
506
+
370
507
  ```erb
371
508
  <% prepend_javascript_pack_tag 'main' %>
372
509
  <%= javascript_pack_tag 'application' %>
@@ -383,6 +520,7 @@ For alternative options for setting the additional packs, [see this discussion](
383
520
  #### View Helper: `asset_pack_path`
384
521
 
385
522
  If you want to link a static asset for `<img />` tag, you can use the `asset_pack_path` helper:
523
+
386
524
  ```erb
387
525
  <img src="<%= asset_pack_path 'static/logo.svg' %>" />
388
526
  ```
@@ -390,30 +528,35 @@ If you want to link a static asset for `<img />` tag, you can use the `asset_pac
390
528
  #### View Helper: `image_pack_tag`
391
529
 
392
530
  Or use the dedicated helper:
531
+
393
532
  ```erb
394
533
  <%= image_pack_tag 'application.png', size: '16x10', alt: 'Edit Entry' %>
395
534
  <%= image_pack_tag 'picture.png', srcset: { 'picture-2x.png' => '2x' } %>
396
535
  ```
397
536
 
398
537
  #### View Helper: `favicon_pack_tag`
538
+
399
539
  If you want to create a favicon:
540
+
400
541
  ```erb
401
542
  <%= favicon_pack_tag 'mb-icon.png', rel: 'apple-touch-icon', type: 'image/png' %>
402
543
  ```
403
544
 
404
545
  #### View Helper: `preload_pack_asset`
546
+
405
547
  If you want to preload a static asset in your `<head>`, you can use the `preload_pack_asset` helper:
548
+
406
549
  ```erb
407
550
  <%= preload_pack_asset 'fonts/fa-regular-400.woff2' %>
408
551
  ```
409
552
 
410
-
411
553
  ### Images in Stylesheets
554
+
412
555
  If you want to use images in your stylesheets:
413
556
 
414
557
  ```css
415
558
  .foo {
416
- background-image: url('../images/logo.svg')
559
+ background-image: url("../images/logo.svg");
417
560
  }
418
561
  ```
419
562
 
@@ -493,25 +636,24 @@ end
493
636
 
494
637
  **Note:** Don't forget to prefix `ruby` when running these binstubs on Windows
495
638
 
496
-
497
639
  ### Webpack Configuration
498
640
 
499
641
  First, you don't _need_ to use Shakapacker's webpack configuration. However, the `shakapacker` NPM package provides convenient access to configuration code that reads the `config/shakapacker.yml` file which the view helpers also use. If you have your customized webpack configuration, at the minimum, you must ensure:
500
642
 
501
643
  1. Your output files go to the right directory
502
644
  2. Your output includes a manifest, via package [`webpack-assets-manifest`](https://github.com/webdeveric/webpack-assets-manifest) that maps output names (your 'packs') to the fingerprinted versions, including bundle-splitting dependencies. That's the main secret sauce of Shakapacker!
503
-
645
+
504
646
  The webpack configuration used by Shakapacker lives in `config/webpack/webpack.config.js`; this makes it easy to customize the configuration beyond what's available in `config/shakapacker.yml` by giving you complete control of the final configuration. By default, this file exports the result of `generateWebpackConfig` which handles generating a webpack configuration based on `config/shakapacker.yml`.
505
647
 
506
648
  The easiest way to modify this config is to pass your desired customizations to `generateWebpackConfig` which will use [webpack-merge](https://github.com/survivejs/webpack-merge) to merge them with the configuration generated from `config/shakapacker.yml`:
507
649
 
508
650
  ```js
509
651
  // config/webpack/webpack.config.js
510
- const { generateWebpackConfig } = require('shakapacker')
652
+ const { generateWebpackConfig } = require("shakapacker")
511
653
 
512
654
  const options = {
513
655
  resolve: {
514
- extensions: ['.css', '.ts', '.tsx']
656
+ extensions: [".css", ".ts", ".tsx"]
515
657
  }
516
658
  }
517
659
 
@@ -523,13 +665,13 @@ The `shakapacker` package also exports the `merge` function from [webpack-merge]
523
665
 
524
666
  ```js
525
667
  // config/webpack/webpack.config.js
526
- const { generateWebpackConfig, merge } = require('shakapacker')
668
+ const { generateWebpackConfig, merge } = require("shakapacker")
527
669
 
528
670
  const webpackConfig = generateWebpackConfig()
529
671
 
530
672
  const options = {
531
673
  resolve: {
532
- extensions: ['.css', '.ts', '.tsx']
674
+ extensions: [".css", ".ts", ".tsx"]
533
675
  }
534
676
  }
535
677
 
@@ -547,11 +689,11 @@ You might add separate files to keep your code more organized.
547
689
  module.exports = {
548
690
  resolve: {
549
691
  alias: {
550
- jquery: 'jquery/src/jquery',
551
- vue: 'vue/dist/vue.js',
552
- React: 'react',
553
- ReactDOM: 'react-dom',
554
- vue_resource: 'vue-resource/dist/vue-resource'
692
+ jquery: "jquery/src/jquery",
693
+ vue: "vue/dist/vue.js",
694
+ React: "react",
695
+ ReactDOM: "react-dom",
696
+ vue_resource: "vue-resource/dist/vue-resource"
555
697
  }
556
698
  }
557
699
  }
@@ -562,9 +704,9 @@ Then `require` this file in your `config/webpack/webpack.config.js`:
562
704
  ```js
563
705
  // config/webpack/webpack.config.js
564
706
  // use the new NPM package name, `shakapacker`.
565
- const { generateWebpackConfig } = require('shakapacker')
707
+ const { generateWebpackConfig } = require("shakapacker")
566
708
 
567
- const customConfig = require('./custom')
709
+ const customConfig = require("./custom")
568
710
 
569
711
  module.exports = generateWebpackConfig(customConfig)
570
712
  ```
@@ -573,7 +715,7 @@ If you need access to configs within Shakapacker's configuration, you can import
573
715
 
574
716
  ```js
575
717
  // config/webpack/webpack.config.js
576
- const { generateWebpackConfig } = require('shakapacker')
718
+ const { generateWebpackConfig } = require("shakapacker")
577
719
 
578
720
  const webpackConfig = generateWebpackConfig()
579
721
 
@@ -587,11 +729,12 @@ console.log(JSON.stringify(webpackConfig, undefined, 2))
587
729
  You may want to modify the rules in the default configuration. For instance, if you are using a custom svg loader, you may want to remove `.svg` from the default file loader rules. You can search and filter the default rules like so:
588
730
 
589
731
  ```js
590
- const fileRule = config.module.rules.find(rule => rule.test.test('.svg'));
732
+ const fileRule = config.module.rules.find((rule) => rule.test.test(".svg"))
591
733
  // removing svg from asset file rule's test RegExp
592
- fileRule.test = /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2)$/
734
+ fileRule.test =
735
+ /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2)$/
593
736
  // changing the rule type from 'asset/resource' to 'asset'. See https://webpack.js.org/guides/asset-modules/
594
- fileRule.type = 'asset'
737
+ fileRule.type = "asset"
595
738
  ```
596
739
 
597
740
  ### Babel configuration
@@ -605,8 +748,8 @@ By default, you will find the Shakapacker preset in your `package.json`. Note, y
605
748
  ]
606
749
  },
607
750
  ```
608
- Optionally, you can change your Babel configuration by removing these lines in your `package.json` and adding [a Babel](https://babeljs.io/docs/en/config-files) configuration file](https://babeljs.io/docs/en/config-files) to your project. For an example of customization based on the original, see [Customizing Babel Config](./docs/customizing_babel_config.md).
609
751
 
752
+ Optionally, you can change your Babel configuration by removing these lines in your `package.json` and adding [a Babel configuration file](https://babeljs.io/docs/en/config-files) to your project. For an example of customization based on the original, see [Customizing Babel Config](./docs/customizing_babel_config.md).
610
753
 
611
754
  ### SWC configuration
612
755
 
@@ -620,6 +763,31 @@ You can try out experimental integration with the esbuild-loader. You can read m
620
763
 
621
764
  Please note that if you want opt-in to use esbuild-loader, you can skip [React](#react) integration instructions as it is supported out of the box.
622
765
 
766
+ ### Switching between transpilers
767
+
768
+ To switch between Babel, SWC, or esbuild, or to configure environment-specific transpiler settings, see the [Transpiler Migration Guide](./docs/transpiler-migration.md).
769
+
770
+ ### Debugging Configuration
771
+
772
+ Shakapacker provides a powerful utility to export and analyze your webpack/rspack configuration:
773
+
774
+ ```bash
775
+ # Export all configs for troubleshooting (recommended)
776
+ bin/export-bundler-config --doctor
777
+
778
+ # Or via rake task
779
+ bundle exec rake shakapacker:export_bundler_config -- --doctor
780
+ ```
781
+
782
+ This exports development and production configurations for both client and server bundles to `shakapacker-config-exports/` directory in annotated YAML format. Perfect for:
783
+
784
+ - Debugging configuration issues
785
+ - Comparing webpack vs rspack configs (works with `rake shakapacker:switch_bundler`)
786
+ - Understanding differences between development and production
787
+ - Analyzing client vs server bundle configurations
788
+
789
+ For more options and usage examples, see the [Troubleshooting Guide](./docs/troubleshooting.md#exporting-webpack--rspack-configuration).
790
+
623
791
  ### Integrations
624
792
 
625
793
  Shakapacker out of the box supports JS and static assets (fonts, images etc.) compilation. To enable support for CoffeeScript or TypeScript install relevant packages:
@@ -632,11 +800,13 @@ See also [Customizing Babel Config](./docs/customizing_babel_config.md) for an e
632
800
 
633
801
  #### TypeScript
634
802
 
803
+ **📚 TypeScript Support:** See the **[TypeScript Documentation](./docs/typescript.md)** for type-safe configuration.
804
+
635
805
  ```bash
636
806
  npm install typescript @babel/preset-typescript
637
807
  ```
638
808
 
639
- Babel wont perform any type-checking on TypeScript code. To optionally use type-checking run:
809
+ Babel won't perform any type-checking on TypeScript code. To optionally use type-checking run:
640
810
 
641
811
  ```bash
642
812
  npm install fork-ts-checker-webpack-plugin
@@ -667,12 +837,30 @@ Then modify the webpack config to use it as a plugin:
667
837
 
668
838
  ```js
669
839
  // config/webpack/webpack.config.js
670
- const { generateWebpackConfig } = require("shakapacker");
671
- const ForkTSCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
840
+ const { generateWebpackConfig } = require("shakapacker")
841
+ const ForkTSCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin")
672
842
 
673
843
  module.exports = generateWebpackConfig({
674
- plugins: [new ForkTSCheckerWebpackPlugin()],
675
- });
844
+ plugins: [new ForkTSCheckerWebpackPlugin()]
845
+ })
846
+ ```
847
+
848
+ Optionally, your webpack config file itself can be written in Typescript:
849
+
850
+ ```bash
851
+ npm install ts-node @types/node @types/webpack
852
+ ```
853
+
854
+ ```ts
855
+ // config/webpack/webpack.config.ts
856
+ import { generateWebpackConfig } from "shakapacker"
857
+ import ForkTSCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"
858
+
859
+ const config = generateWebpackConfig({
860
+ plugins: [new ForkTSCheckerWebpackPlugin()]
861
+ })
862
+
863
+ export default config
676
864
  ```
677
865
 
678
866
  #### CSS
@@ -687,11 +875,11 @@ Optionally, add the `CSS` extension to webpack config for easy resolution.
687
875
 
688
876
  ```js
689
877
  // config/webpack/webpack.config.js
690
- const { generateWebpackConfig } = require('shakapacker')
878
+ const { generateWebpackConfig } = require("shakapacker")
691
879
 
692
880
  const customConfig = {
693
881
  resolve: {
694
- extensions: ['.css']
882
+ extensions: [".css"]
695
883
  }
696
884
  }
697
885
 
@@ -708,6 +896,7 @@ npm install postcss postcss-loader
708
896
  ```
709
897
 
710
898
  Optionally add these two plugins if they are required in your `postcss.config.js`:
899
+
711
900
  ```bash
712
901
  npm install postcss-preset-env postcss-flexbugs-fixes
713
902
  ```
@@ -723,16 +912,19 @@ You will also need to install [Dart Sass](https://github.com/sass/dart-sass), [N
723
912
  Please refer to [sass-loader documentation](https://www.npmjs.com/package/sass-loader) and individual packages repos for more information on all the options.
724
913
 
725
914
  ##### Dart Sass
915
+
726
916
  ```bash
727
917
  npm install sass
728
918
  ```
729
919
 
730
920
  ##### Node Sass
921
+
731
922
  ```bash
732
923
  npm install node-sass
733
924
  ```
734
925
 
735
926
  ##### Sass Embedded
927
+
736
928
  ```bash
737
929
  npm install sass-embedded
738
930
  ```
@@ -764,33 +956,34 @@ Please follow Webpack integration guide for the relevant framework or library,
764
956
  3. [Vue](https://vue-loader.vuejs.org/guide/)
765
957
 
766
958
  For example to add Vue support:
959
+
767
960
  ```js
768
961
  // config/webpack/rules/vue.js
769
- const { VueLoaderPlugin } = require('vue-loader')
962
+ const { VueLoaderPlugin } = require("vue-loader")
770
963
 
771
964
  module.exports = {
772
965
  module: {
773
966
  rules: [
774
967
  {
775
968
  test: /\.vue$/,
776
- loader: 'vue-loader'
969
+ loader: "vue-loader"
777
970
  }
778
971
  ]
779
972
  },
780
973
  plugins: [new VueLoaderPlugin()],
781
974
  resolve: {
782
- extensions: ['.vue']
975
+ extensions: [".vue"]
783
976
  }
784
977
  }
785
978
  ```
786
979
 
787
980
  ```js
788
981
  // config/webpack/webpack.config.js
789
- const { generateWebpackConfig, merge } = require('shakapacker')
982
+ const { generateWebpackConfig, merge } = require("shakapacker")
790
983
 
791
984
  const webpackConfig = generateWebpackConfig()
792
985
 
793
- const vueConfig = require('./rules/vue')
986
+ const vueConfig = require("./rules/vue")
794
987
 
795
988
  module.exports = merge(vueConfig, webpackConfig)
796
989
  ```
@@ -874,6 +1067,14 @@ npm install shakapacker@next
874
1067
 
875
1068
  Also, consult the [CHANGELOG](./CHANGELOG.md) for additional upgrade links.
876
1069
 
1070
+ #### Common Upgrade Scenarios
1071
+
1072
+ For step-by-step guides on common migrations, see the [Common Upgrades Guide](./docs/common-upgrades.md):
1073
+
1074
+ - [Migrating Package Managers](./docs/common-upgrades.md#migrating-package-managers) (Yarn ↔ npm, pnpm)
1075
+ - [Migrating from Babel to SWC](./docs/common-upgrades.md#migrating-from-babel-to-swc) (20-70x faster builds)
1076
+ - [Migrating from Webpack to Rspack](./docs/common-upgrades.md#migrating-from-webpack-to-rspack) (5-10x faster builds)
1077
+
877
1078
  ### Paths
878
1079
 
879
1080
  By default, Shakapacker ships with simple conventions for where the JavaScript app files and compiled webpack bundles will go in your Rails app. All these options are configurable from `config/shakapacker.yml` file.
@@ -888,6 +1089,31 @@ source_path: frontend # packs are the files in frontend/
888
1089
  public_output_path: assets/packs # outputs to => public/assets/packs
889
1090
  ```
890
1091
 
1092
+ For server-side rendering (SSR) scenarios where you need to generate bundles that should not be served publicly, you can use the `private_output_path` configuration:
1093
+
1094
+ ```yml
1095
+ # config/shakapacker.yml
1096
+ private_output_path: ssr-generated # outputs to => ssr-generated/
1097
+ ```
1098
+
1099
+ This is particularly useful when working with libraries like React on Rails where server bundles need to be kept separate from client bundles.
1100
+
1101
+ #### Migration Guide for React on Rails Users
1102
+
1103
+ If you're using React on Rails with separate client and server bundles, you can now leverage the `private_output_path` configuration instead of using custom webpack configurations:
1104
+
1105
+ 1. Update your `config/shakapacker.yml`:
1106
+
1107
+ ```yml
1108
+ # Before: both client and server bundles in public/
1109
+ # After: separate directories
1110
+ public_output_path: packs # Client bundles (publicly served)
1111
+ private_output_path: ssr-bundles # Server bundles (not publicly served)
1112
+ ```
1113
+
1114
+ 2. Update your webpack configuration to use the appropriate output path based on the bundle type
1115
+ 3. The validation ensures `private_output_path` and `public_output_path` are different to prevent configuration errors
1116
+
891
1117
  Similarly, you can also control and configure `webpack-dev-server` settings from `config/shakapacker.yml` file:
892
1118
 
893
1119
  ```yml
@@ -908,15 +1134,15 @@ If you are adding Shakapacker to an existing app that has most of the assets ins
908
1134
  add additional paths that webpack should look up when resolving modules:
909
1135
 
910
1136
  ```yml
911
- additional_paths: ['app/assets', 'vendor/assets']
1137
+ additional_paths: ["app/assets", "vendor/assets"]
912
1138
  ```
913
1139
 
914
1140
  You can then import these items inside your modules like so:
915
1141
 
916
1142
  ```js
917
1143
  // Note it's relative to parent directory i.e. app/assets
918
- import 'stylesheets/main'
919
- import 'images/rails.png'
1144
+ import "stylesheets/main"
1145
+ import "images/rails.png"
920
1146
  ```
921
1147
 
922
1148
  Assets put in these folders will also have their path stripped just like with the `source_path`.
@@ -929,7 +1155,6 @@ A file in `app/assets/images/image.svg` with `additional_paths: ['app/assets']`
929
1155
 
930
1156
  **Also note:** While importing assets living outside your `source_path` defined in shakapacker.yml (like, for instance, assets under `app/assets`) from within your packs using _relative_ paths like `import '../../assets/javascripts/file.js'` will work in development, Shakapacker won't recompile the bundle in production unless a file that lives in one of it's watched paths has changed (check out `Shakapacker::MtimeStrategy#latest_modified_timestamp` or `Shakapacker::DigestStrategy#watched_files_digest` depending on strategy configured by `compiler_strategy` option in `shakapacker.yml`). That's why you'd need to add `app/assets` to the additional_paths as stated above and use `import 'javascripts/file.js'` instead.
931
1157
 
932
-
933
1158
  ## Deployment
934
1159
 
935
1160
  Shakapacker hooks up a new `shakapacker:compile` task to `assets:precompile`, which gets run whenever you run `assets:precompile`. If you are not using Sprockets, `shakapacker:compile` is automatically aliased to `assets:precompile`. Similar to sprockets both rake tasks will compile packs in production mode but will use `RAILS_ENV` to load configuration from `config/shakapacker.yml` (if available).
@@ -955,11 +1180,24 @@ pnpm install --frozen-lockfile
955
1180
  bun install --frozen-lockfile
956
1181
  ```
957
1182
 
958
- If you are using a CDN setup, Shakapacker does NOT use the `ASSET_HOST` environment variable to prefix URLs for assets during bundle compilation. You must use the `SHAKAPACKER_ASSET_HOST` environment variable instead (`WEBPACKER_ASSET_HOST` if you're using any version of Webpacker or Shakapacker before Shakapacker v7).
1183
+ ### CDN
1184
+
1185
+ Shakapacker supports serving JavaScript bundles and assets from a CDN. The key configuration is setting the `SHAKAPACKER_ASSET_HOST` environment variable (NOT the Rails `ASSET_HOST` variable).
1186
+
1187
+ For detailed CDN setup instructions, including CloudFlare configuration, troubleshooting, and advanced setups, see the [CDN Setup Guide](./docs/cdn_setup.md).
1188
+
1189
+ **Quick example:**
1190
+
1191
+ ```bash
1192
+ export SHAKAPACKER_ASSET_HOST=https://cdn.example.com
1193
+ RAILS_ENV=production bundle exec rails assets:precompile
1194
+ ```
1195
+
1196
+ For more deployment documentation, see [Deployment](./docs/deployment.md).
959
1197
 
960
1198
  ## Example Apps
961
- * [React on Rails Tutorial With SSR, HMR fast refresh, and TypeScript](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh)
962
1199
 
1200
+ - [React on Rails Tutorial With SSR, HMR fast refresh, and TypeScript](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh)
963
1201
 
964
1202
  ## Troubleshooting
965
1203
 
@@ -972,7 +1210,7 @@ We encourage you to contribute to Shakapacker! See [CONTRIBUTING](CONTRIBUTING.m
972
1210
  ## License
973
1211
 
974
1212
  Shakapacker is released under the [MIT License](https://opensource.org/licenses/MIT).
975
-
1213
+
976
1214
  ## Supporters
977
1215
 
978
1216
  The following companies support our Open Source projects, and ShakaCode uses their products!
@@ -980,8 +1218,8 @@ The following companies support our Open Source projects, and ShakaCode uses the
980
1218
  <br />
981
1219
  <br />
982
1220
 
983
- <a href="https://www.jetbrains.com">
984
- <img src="https://user-images.githubusercontent.com/4244251/184881139-42e4076b-024b-4b30-8c60-c3cd0e758c0a.png" alt="JetBrains" height="120px">
1221
+ <a href="https://jb.gg/OpenSource" style="margin-right: 20px;">
1222
+ <img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.png" alt="JetBrains" height="120px">
985
1223
  </a>
986
1224
  <a href="https://scoutapp.com">
987
1225
  <picture>