shakapacker 8.4.0 → 9.7.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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/address-review.md +206 -0
  3. data/.claude/commands/update-changelog.md +354 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +6 -9
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +6 -8
  6. data/.github/STATUS.md +1 -0
  7. data/.github/actionlint-matcher.json +17 -0
  8. data/.github/workflows/claude-code-review.yml +45 -0
  9. data/.github/workflows/claude.yml +55 -0
  10. data/.github/workflows/dummy.yml +18 -5
  11. data/.github/workflows/eslint-validation.yml +46 -0
  12. data/.github/workflows/generator.yml +38 -22
  13. data/.github/workflows/node.yml +116 -2
  14. data/.github/workflows/ruby.yml +57 -15
  15. data/.github/workflows/test-bundlers.yml +180 -0
  16. data/.gitignore +27 -0
  17. data/.husky/pre-commit +2 -0
  18. data/.npmignore +56 -0
  19. data/.prettierignore +7 -0
  20. data/.rubocop.yml +2 -0
  21. data/.yalcignore +26 -0
  22. data/CHANGELOG.md +487 -19
  23. data/CLAUDE.md +63 -0
  24. data/CONTRIBUTING.md +268 -21
  25. data/ESLINT_TECHNICAL_DEBT.md +165 -0
  26. data/README.md +497 -137
  27. data/Rakefile +44 -4
  28. data/TODO.md +58 -0
  29. data/TODO_v9.md +97 -0
  30. data/bin/conductor-exec +24 -0
  31. data/bin/shakapacker-config +11 -0
  32. data/conductor-setup.sh +147 -0
  33. data/conductor.json +9 -0
  34. data/docs/api-reference.md +519 -0
  35. data/docs/cdn_setup.md +384 -0
  36. data/docs/common-upgrades.md +695 -0
  37. data/docs/configuration.md +845 -0
  38. data/docs/css-modules-export-mode.md +566 -0
  39. data/docs/customizing_babel_config.md +16 -16
  40. data/docs/deployment.md +78 -7
  41. data/docs/developing_shakapacker.md +6 -0
  42. data/docs/early_hints.md +433 -0
  43. data/docs/early_hints_manual_api.md +454 -0
  44. data/docs/feature_testing.md +492 -0
  45. data/docs/node_package_api.md +70 -0
  46. data/docs/optional-peer-dependencies.md +203 -0
  47. data/docs/peer-dependencies.md +71 -0
  48. data/docs/precompile_hook.md +486 -0
  49. data/docs/preventing_fouc.md +132 -0
  50. data/docs/react.md +58 -48
  51. data/docs/releasing.md +288 -0
  52. data/docs/rspack.md +218 -0
  53. data/docs/rspack_migration_guide.md +862 -0
  54. data/docs/sprockets.md +1 -0
  55. data/docs/style_loader_vs_mini_css.md +12 -12
  56. data/docs/subresource_integrity.md +13 -7
  57. data/docs/transpiler-migration.md +212 -0
  58. data/docs/transpiler-performance.md +200 -0
  59. data/docs/troubleshooting.md +272 -24
  60. data/docs/typescript-migration.md +388 -0
  61. data/docs/typescript.md +103 -0
  62. data/docs/using_esbuild_loader.md +12 -12
  63. data/docs/using_swc_loader.md +121 -16
  64. data/docs/v6_upgrade.md +42 -19
  65. data/docs/v7_upgrade.md +8 -6
  66. data/docs/v8_upgrade.md +13 -12
  67. data/docs/v9_upgrade.md +616 -0
  68. data/eslint.config.fast.js +254 -0
  69. data/eslint.config.js +309 -0
  70. data/jest.config.js +8 -1
  71. data/knip.ts +61 -0
  72. data/lib/install/bin/shakapacker +4 -6
  73. data/lib/install/bin/shakapacker-config +11 -0
  74. data/lib/install/bin/shakapacker-dev-server +1 -1
  75. data/lib/install/binstubs.rb +6 -2
  76. data/lib/install/config/rspack/rspack.config.js +6 -0
  77. data/lib/install/config/rspack/rspack.config.ts +7 -0
  78. data/lib/install/config/shakapacker.yml +75 -12
  79. data/lib/install/config/webpack/webpack.config.ts +7 -0
  80. data/lib/install/package.json +38 -0
  81. data/lib/install/template.rb +207 -45
  82. data/lib/shakapacker/build_config_loader.rb +147 -0
  83. data/lib/shakapacker/bundler_switcher.rb +415 -0
  84. data/lib/shakapacker/compiler.rb +87 -0
  85. data/lib/shakapacker/configuration.rb +475 -6
  86. data/lib/shakapacker/dev_server.rb +88 -1
  87. data/lib/shakapacker/dev_server_runner.rb +240 -6
  88. data/lib/shakapacker/doctor.rb +1191 -0
  89. data/lib/shakapacker/env.rb +19 -3
  90. data/lib/shakapacker/helper.rb +411 -14
  91. data/lib/shakapacker/install/env.rb +33 -0
  92. data/lib/shakapacker/instance.rb +93 -4
  93. data/lib/shakapacker/manifest.rb +167 -30
  94. data/lib/shakapacker/railtie.rb +4 -0
  95. data/lib/shakapacker/rspack_runner.rb +19 -0
  96. data/lib/shakapacker/runner.rb +668 -9
  97. data/lib/shakapacker/swc_migrator.rb +384 -0
  98. data/lib/shakapacker/utils/manager.rb +2 -0
  99. data/lib/shakapacker/utils/version_syntax_converter.rb +1 -1
  100. data/lib/shakapacker/version.rb +1 -1
  101. data/lib/shakapacker/version_checker.rb +1 -1
  102. data/lib/shakapacker/webpack_runner.rb +4 -42
  103. data/lib/shakapacker.rb +159 -1
  104. data/lib/tasks/shakapacker/binstubs.rake +4 -2
  105. data/lib/tasks/shakapacker/check_binstubs.rake +2 -2
  106. data/lib/tasks/shakapacker/doctor.rake +48 -0
  107. data/lib/tasks/shakapacker/export_bundler_config.rake +68 -0
  108. data/lib/tasks/shakapacker/install.rake +16 -4
  109. data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
  110. data/lib/tasks/shakapacker/switch_bundler.rake +72 -0
  111. data/lib/tasks/shakapacker.rake +2 -0
  112. data/package/.npmignore +4 -0
  113. data/package/babel/preset.ts +59 -0
  114. data/package/config.ts +189 -0
  115. data/package/configExporter/buildValidator.ts +906 -0
  116. data/package/configExporter/cli.ts +1748 -0
  117. data/package/configExporter/configDocs.ts +102 -0
  118. data/package/configExporter/configFile.ts +663 -0
  119. data/package/configExporter/fileWriter.ts +112 -0
  120. data/package/configExporter/index.ts +15 -0
  121. data/package/configExporter/types.ts +159 -0
  122. data/package/configExporter/yamlSerializer.ts +391 -0
  123. data/package/dev_server.ts +27 -0
  124. data/package/env.ts +92 -0
  125. data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +36 -0
  126. data/package/environments/base.ts +147 -0
  127. data/package/environments/development.ts +88 -0
  128. data/package/environments/production.ts +82 -0
  129. data/package/environments/test.ts +55 -0
  130. data/package/environments/types.ts +98 -0
  131. data/package/esbuild/index.ts +40 -0
  132. data/package/index.d.ts +68 -93
  133. data/package/index.d.ts.template +72 -0
  134. data/package/index.ts +104 -0
  135. data/package/loaders.d.ts +28 -0
  136. data/package/optimization/rspack.ts +36 -0
  137. data/package/optimization/webpack.ts +55 -0
  138. data/package/plugins/envFilter.ts +82 -0
  139. data/package/plugins/rspack.ts +119 -0
  140. data/package/plugins/webpack.ts +82 -0
  141. data/package/rspack/index.ts +91 -0
  142. data/package/rules/{babel.js → babel.ts} +2 -2
  143. data/package/rules/{coffee.js → coffee.ts} +1 -1
  144. data/package/rules/css.ts +3 -0
  145. data/package/rules/{erb.js → erb.ts} +1 -1
  146. data/package/rules/esbuild.ts +10 -0
  147. data/package/rules/file.ts +41 -0
  148. data/package/rules/{jscommon.js → jscommon.ts} +5 -4
  149. data/package/rules/{less.js → less.ts} +4 -4
  150. data/package/rules/raw.ts +28 -0
  151. data/package/rules/rspack.ts +174 -0
  152. data/package/rules/sass.ts +21 -0
  153. data/package/rules/{stylus.js → stylus.ts} +4 -8
  154. data/package/rules/swc.ts +10 -0
  155. data/package/rules/{index.js → webpack.ts} +1 -2
  156. data/package/swc/index.ts +54 -0
  157. data/package/types/README.md +90 -0
  158. data/package/types/index.ts +69 -0
  159. data/package/types.ts +105 -0
  160. data/package/utils/bundlerUtils.ts +232 -0
  161. data/package/utils/configPath.ts +6 -0
  162. data/package/utils/debug.ts +45 -0
  163. data/package/utils/defaultConfigPath.ts +7 -0
  164. data/package/utils/ensureManifestExists.ts +17 -0
  165. data/package/utils/errorCodes.ts +249 -0
  166. data/package/utils/errorHelpers.ts +152 -0
  167. data/package/utils/getStyleRule.ts +75 -0
  168. data/package/utils/helpers.ts +99 -0
  169. data/package/utils/{inliningCss.js → inliningCss.ts} +3 -3
  170. data/package/utils/pathValidation.ts +207 -0
  171. data/package/utils/requireOrError.ts +24 -0
  172. data/package/utils/snakeToCamelCase.ts +5 -0
  173. data/package/utils/typeGuards.ts +388 -0
  174. data/package/utils/validateDependencies.ts +61 -0
  175. data/package/webpack-types.d.ts +33 -0
  176. data/package/webpackDevServerConfig.ts +130 -0
  177. data/package.json +157 -18
  178. data/scripts/remove-use-strict.js +44 -0
  179. data/scripts/type-check-no-emit.js +27 -0
  180. data/shakapacker.gemspec +4 -2
  181. data/sig/shakapacker/commands.rbs +35 -0
  182. data/sig/shakapacker/compiler.rbs +65 -0
  183. data/sig/shakapacker/compiler_strategy.rbs +41 -0
  184. data/sig/shakapacker/configuration.rbs +140 -0
  185. data/sig/shakapacker/dev_server.rbs +56 -0
  186. data/sig/shakapacker/env.rbs +25 -0
  187. data/sig/shakapacker/helper.rbs +98 -0
  188. data/sig/shakapacker/instance.rbs +46 -0
  189. data/sig/shakapacker/manifest.rbs +69 -0
  190. data/sig/shakapacker/version.rbs +4 -0
  191. data/sig/shakapacker.rbs +66 -0
  192. data/test/configExporter/buildValidator.test.js +1295 -0
  193. data/test/configExporter/configFile.test.js +393 -0
  194. data/test/configExporter/integration.test.js +262 -0
  195. data/test/helpers.js +1 -1
  196. data/test/package/bundlerUtils.rspack.test.js +145 -0
  197. data/test/package/bundlerUtils.test.js +97 -0
  198. data/test/package/config.test.js +14 -0
  199. data/test/package/configExporter/cli.test.js +440 -0
  200. data/test/package/configExporter/types.test.js +163 -0
  201. data/test/package/configExporter.test.js +491 -0
  202. data/test/package/env.test.js +42 -7
  203. data/test/package/environments/base.test.js +14 -4
  204. data/test/package/helpers.test.js +2 -2
  205. data/test/package/plugins/envFiltering.test.js +453 -0
  206. data/test/package/plugins/webpackSubresourceIntegrity.test.js +89 -0
  207. data/test/package/rspack/index.test.js +293 -0
  208. data/test/package/rspack/optimization.test.js +86 -0
  209. data/test/package/rspack/plugins.test.js +185 -0
  210. data/test/package/rspack/rules.test.js +229 -0
  211. data/test/package/rules/babel.test.js +65 -38
  212. data/test/package/rules/esbuild.test.js +13 -4
  213. data/test/package/rules/file.test.js +7 -1
  214. data/test/package/rules/raw.test.js +40 -7
  215. data/test/package/rules/sass-version-parsing.test.js +71 -0
  216. data/test/package/rules/sass.test.js +11 -6
  217. data/test/package/rules/sass1.test.js +8 -5
  218. data/test/package/rules/sass16.test.js +24 -0
  219. data/test/package/rules/swc.test.js +50 -39
  220. data/test/package/rules/webpack.test.js +35 -0
  221. data/test/package/staging.test.js +4 -3
  222. data/test/package/transpiler-defaults.test.js +169 -0
  223. data/test/package/utils/ensureManifestExists.test.js +51 -0
  224. data/test/package/yamlSerializer.test.js +204 -0
  225. data/test/peer-dependencies.sh +85 -0
  226. data/test/resolver.js +34 -3
  227. data/test/scripts/remove-use-strict.test.js +125 -0
  228. data/test/typescript/build.test.js +118 -0
  229. data/test/typescript/environments.test.js +107 -0
  230. data/test/typescript/pathValidation.test.js +186 -0
  231. data/test/typescript/requireOrError.test.js +49 -0
  232. data/test/typescript/securityValidation.test.js +182 -0
  233. data/tools/README.md +134 -0
  234. data/tools/css-modules-v9-codemod.js +179 -0
  235. data/tsconfig.eslint.json +9 -0
  236. data/tsconfig.json +38 -0
  237. data/yarn.lock +3202 -1097
  238. metadata +212 -44
  239. data/.eslintignore +0 -4
  240. data/.eslintrc.js +0 -36
  241. data/Gemfile.lock +0 -251
  242. data/package/babel/preset.js +0 -48
  243. data/package/config.js +0 -56
  244. data/package/dev_server.js +0 -23
  245. data/package/env.js +0 -48
  246. data/package/environments/base.js +0 -171
  247. data/package/environments/development.js +0 -13
  248. data/package/environments/production.js +0 -88
  249. data/package/environments/test.js +0 -3
  250. data/package/esbuild/index.js +0 -40
  251. data/package/index.js +0 -40
  252. data/package/rules/css.js +0 -3
  253. data/package/rules/esbuild.js +0 -10
  254. data/package/rules/file.js +0 -29
  255. data/package/rules/raw.js +0 -5
  256. data/package/rules/sass.js +0 -18
  257. data/package/rules/swc.js +0 -10
  258. data/package/swc/index.js +0 -50
  259. data/package/utils/configPath.js +0 -4
  260. data/package/utils/defaultConfigPath.js +0 -2
  261. data/package/utils/getStyleRule.js +0 -40
  262. data/package/utils/helpers.js +0 -62
  263. data/package/utils/snakeToCamelCase.js +0 -5
  264. data/package/webpackDevServerConfig.js +0 -71
  265. data/test/package/rules/index.test.js +0 -16
data/CLAUDE.md ADDED
@@ -0,0 +1,63 @@
1
+ # Shakapacker Project Guidelines
2
+
3
+ ## Critical Requirements
4
+
5
+ - **ALWAYS end all files with a trailing newline character.** This is required by the project's linting rules.
6
+ - **ALWAYS use `bundle exec` prefix when running Ruby commands** (rubocop, rspec, rake, etc.)
7
+ - **ALWAYS run `bundle exec rubocop` before committing Ruby changes**
8
+ - **ALWAYS run `yarn lint` before committing JavaScript changes**
9
+
10
+ ## Testing
11
+
12
+ - Run corresponding RSpec tests when changing source files
13
+ - For example, when changing `lib/shakapacker/foo.rb`, run `spec/shakapacker/foo_spec.rb`
14
+ - Run the full test suite with `bundle exec rspec` before pushing
15
+ - **Use explicit RSpec spy assertions** - prefer `have_received`/`not_to have_received` over indirect counter patterns
16
+ - Good: `expect(Open3).to have_received(:capture3).with(anything, hook_command, anything)`
17
+ - Good: `expect(Open3).not_to have_received(:capture3).with(anything, hook_command, anything)`
18
+ - Avoid: `call_count += 1` followed by `expect(call_count).to eq(1)`
19
+
20
+ ## Code Style
21
+
22
+ - Follow existing code conventions in the file you're editing
23
+ - Use the project's existing patterns and utilities
24
+ - No unnecessary comments unless requested
25
+ - Keep changes focused and minimal - avoid extraneous diffs
26
+
27
+ ## Git Workflow
28
+
29
+ - Create feature branches for all changes
30
+ - Never push directly to main branch
31
+ - Create small, focused PRs that are easy to review
32
+ - Always create a PR immediately after pushing changes
33
+
34
+ ## Changelog
35
+
36
+ - **Update CHANGELOG.md for user-visible changes only** (features, bug fixes, breaking changes, deprecations, performance improvements)
37
+ - **Do NOT add entries for**: linting, formatting, refactoring, tests, or documentation fixes
38
+ - **Format**: `[PR #123](https://github.com/shakacode/shakapacker/pull/123) by [username](https://github.com/username)` (Shakapacker uses `#` in PR links)
39
+ - **Use `/update-changelog` command** for guided changelog updates with automatic formatting
40
+ - **Version management**: Run `bundle exec rake update_changelog` after releases to update version headers
41
+ - **Examples**: Run `grep -A 3 "^### " CHANGELOG.md | head -30` to see real formatting examples
42
+
43
+ ## Open Source Maintainability
44
+
45
+ - **Prefer removing complexity over adding configuration.** If a default causes problems, consider removing the default rather than adding an option to disable it.
46
+ - **Every config option is maintenance surface.** Prefer convention over configuration. Don't add options for <10% of users — let them customize via existing extension points (e.g., custom webpack config).
47
+ - **"No is temporary, yes is forever."** Adding a feature creates a permanent maintenance obligation. Reject features that solve one user's niche problem but add complexity for everyone.
48
+ - **Security-safe defaults over convenient defaults.** Don't ship permissive defaults (e.g., `Access-Control-Allow-Origin: *`) just for convenience — make users opt in to less-secure configurations.
49
+ - **Don't refactor adjacent code in feature PRs.** Keep PRs focused. If you spot something to clean up, do it in a separate PR.
50
+
51
+ ## Shakapacker-Specific
52
+
53
+ - This gem supports both webpack and rspack configurations
54
+ - Test changes with both bundlers when modifying core functionality
55
+ - Be aware of the dual package.json/Gemfile dependency management
56
+
57
+ ## Conductor Environment
58
+
59
+ - **Version manager support**: The setup script detects mise, asdf, or direct PATH tools (rbenv/nvm/nodenv)
60
+ - **bin/conductor-exec**: Use this wrapper for commands when tool versions aren't detected correctly in Conductor's non-interactive shell
61
+ - Example: `bin/conductor-exec bundle exec rubocop`
62
+ - The wrapper uses `mise exec` if mise is available, otherwise falls back to direct execution
63
+ - **conductor.json scripts** already use this wrapper, so you typically don't need to use it manually
data/CONTRIBUTING.md CHANGED
@@ -3,6 +3,7 @@
3
3
  Thank you for your interest in contributing to Shakapacker! We welcome all contributions that align with our project goals and values. To ensure a smooth and productive collaboration, please follow these guidelines.
4
4
 
5
5
  ## Contents
6
+
6
7
  - [Reporting Issues](#reporting-issues)
7
8
  - [Submitting Pull Requests](#submitting-pull-requests)
8
9
  - [Setting Up a Development Environment](#setting-up-a-development-environment)
@@ -10,46 +11,218 @@ Thank you for your interest in contributing to Shakapacker! We welcome all contr
10
11
  - [Testing the generator](#testing-the-generator)
11
12
 
12
13
  ## Reporting Issues
14
+
13
15
  If you encounter any issues with the project, please first check the existing issues (including closed ones). If the issues is not reported before, please opening an issue on our GitHub repository. Please provide a clear and detailed description of the issue, including steps to reproduce it. Creating a demo repository to demonstrate the issue would be ideal (and in some cases necessary).
14
16
 
15
17
  If looking to contribute to the project by fixing existing issues, we recommend looking at issues, particularly with the "[help wanted](https://github.com/shakacode/shakapacker/issues?q=is%3Aissue+label%3A%22help+wanted%22)" label.
16
18
 
17
19
  ## Submitting Pull Requests
20
+
18
21
  We welcome pull requests that fix bugs, add new features, or improve existing ones. Before submitting a pull request, please make sure to:
19
22
 
20
- - Open an issue about what you want to propose before start working on.
21
- - Fork the repository and create a new branch for your changes.
22
- - Write clear and concise commit messages.
23
- - Follow our code style guidelines.
24
- - Write tests for your changes and [make sure all tests pass](#making-sure-your-changes-pass-all-tests).
25
- - Update the documentation as needed.
26
- - Update CHANGELOG.md if the changes affect public behavior of the project.
23
+ - Open an issue about what you want to propose before start working on.
24
+ - Fork the repository and create a new branch for your changes.
25
+ - Write clear and concise commit messages.
26
+ - Follow our code style guidelines.
27
+ - Write tests for your changes and [make sure all tests pass](#making-sure-your-changes-pass-all-tests).
28
+ - Update the documentation as needed.
29
+ - Update CHANGELOG.md if the changes affect public behavior of the project.
30
+ - Update RBS type signatures in `sig/` directory if you modify public APIs.
31
+
32
+ ---
33
+
34
+ ## Git Hooks (Optional)
35
+
36
+ This project includes configuration for git hooks via `husky` and `lint-staged`, but they are **opt-in for contributors**.
37
+
38
+ **Why are hooks optional?** As a library project, we don't enforce git hooks because:
39
+
40
+ - Different contributors may have different workflows
41
+ - Forcing hooks can interfere with contributor tooling
42
+ - CI/CD handles the final validation
43
+
44
+ To enable pre-commit hooks locally:
45
+
46
+ ```bash
47
+ npx husky install
48
+ npx husky add .husky/pre-commit "npx lint-staged"
49
+ ```
27
50
 
28
51
  ---
52
+
53
+ ## RBS Type Signatures
54
+
55
+ Shakapacker includes RBS type signatures for all public APIs in the `sig/` directory. These signatures provide static type checking and improved IDE support.
56
+
57
+ ### When to Update RBS Files
58
+
59
+ Update RBS signatures when you:
60
+
61
+ - Add new public methods or classes
62
+ - Change method signatures (parameters, return types)
63
+ - Modify public APIs
64
+ - Add or remove public attributes
65
+
66
+ ### RBS File Structure
67
+
68
+ ```
69
+ sig/
70
+ ├── shakapacker.rbs # Main Shakapacker module
71
+ └── shakapacker/
72
+ ├── configuration.rbs # Configuration class
73
+ ├── helper.rbs # View helper module
74
+ ├── manifest.rbs # Manifest class
75
+ ├── compiler.rbs # Compiler class
76
+ └── ... # Other components
77
+ ```
78
+
79
+ ### Validating RBS Signatures
80
+
81
+ To validate your RBS signatures:
82
+
83
+ ```bash
84
+ # Install RBS if not already installed
85
+ gem install rbs
86
+
87
+ # Validate all signatures
88
+ rbs validate
89
+
90
+ # Check a specific file
91
+ rbs validate sig/shakapacker/configuration.rbs
92
+ ```
93
+
94
+ ### RBS Best Practices
95
+
96
+ 1. **Use specific types** instead of `untyped` when possible
97
+ 2. **Document optional parameters** with `?` prefix
98
+ 3. **Use union types** for methods that can return multiple types (e.g., `String | nil`)
99
+ 4. **Keep signatures in sync** with implementation changes
100
+ 5. **Test with type checkers** like [Steep](https://github.com/soutaro/steep) when possible
101
+ 6. **Use `void` vs `nil` appropriately**:
102
+ - Use `void` when the return value is expected to be discarded (e.g., `initialize`)
103
+ - Use `nil` when a method explicitly returns nil as a meaningful value
104
+ 7. **Module singleton methods**: For modules using `extend self`, use `module ModuleName : _Singleton` to indicate all methods are module-level singleton methods
105
+
106
+ ### Example RBS Signature
107
+
108
+ ```rbs
109
+ # Good: Specific types with documentation
110
+ class Shakapacker::Configuration
111
+ def initialize: (
112
+ root_path: Pathname,
113
+ config_path: Pathname,
114
+ env: ActiveSupport::StringInquirer,
115
+ ?bundler_override: String?
116
+ ) -> void
117
+
118
+ def source_path: () -> Pathname
119
+ def webpack?: () -> bool
120
+ def assets_bundler: () -> String
121
+ end
122
+
123
+ # Module with singleton methods (using extend self)
124
+ module Shakapacker : _Singleton
125
+ def self.config: () -> Configuration
126
+ def self.compile: () -> bool
127
+ end
128
+
129
+ # Avoid: Overly generic types
130
+ class Shakapacker::Configuration
131
+ def initialize: (**untyped) -> void
132
+ def source_path: () -> untyped
133
+ end
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Linting and Code Quality
139
+
140
+ ### Running Linters
141
+
142
+ ```bash
143
+ # Full linting with type checking (slower but thorough)
144
+ yarn lint
145
+
146
+ # Fast linting without type checking (for quick feedback)
147
+ yarn lint:fast
148
+
149
+ # With caching for better performance
150
+ yarn lint --cache
151
+ ```
152
+
153
+ **Performance Note:** TypeScript ESLint uses type-aware linting for better type safety, which can be slower on large codebases. Use `yarn lint:fast` during development for quick feedback.
154
+
155
+ ---
156
+
29
157
  ## Setting Up a Development Environment
30
158
 
31
- 1. Install [Yarn](https://classic.yarnpkg.com/)
159
+ 1. Install [Yarn](https://classic.yarnpkg.com/) & [yalc](https://github.com/wclr/yalc)
32
160
  2. To test your changes on a Rails test project do the following steps:
33
161
  - For Ruby gem, update `Gemfile` and point the `shakapacker` to the locally developing Shakapacker project:
34
- ```ruby
35
- gem 'shakapacker', path: "relative_or_absolute_path_to_local_shakapacker"
36
- ```
162
+ ```ruby
163
+ gem 'shakapacker', path: "relative_or_absolute_path_to_local_shakapacker"
164
+ ```
37
165
  - For npm package, use `yalc` with following steps:
38
- ```bash
39
- # In Shakapacker root directory
40
- yalc publish
41
- # In Rails app for testing
42
- yalc link shakapacker
43
-
44
- # After every change in shakapacker, run the following in Shakapacker directory
45
- yalc push # or yalc publish --push
46
- ```
166
+
167
+ ```bash
168
+ # In Shakapacker root directory
169
+ yalc publish
170
+ # In Rails app for testing
171
+ yalc link shakapacker
172
+
173
+ # After every change in shakapacker, run the following in Shakapacker directory
174
+ yalc push # or yalc publish --push
175
+ ```
176
+
47
177
  3. Run the following commands to set up the development environment.
48
178
  ```
49
179
  bundle install
50
180
  yarn install
181
+ yarn prepare:husky # Set up pre-commit hooks for linting
51
182
  ```
52
183
 
184
+ ## Understanding Optional Peer Dependencies
185
+
186
+ Shakapacker uses optional peer dependencies (via `peerDependenciesMeta`) for maximum flexibility:
187
+
188
+ - **All peer dependencies are optional** - Users only install what they need
189
+ - **No installation warnings** - Package managers won't warn about missing optional dependencies
190
+ - **Version constraints still apply** - When a package is installed, version compatibility is enforced
191
+
192
+ ### TypeScript Declaration Files and Optional Dependencies
193
+
194
+ When importing types from optional peer dependencies, we use `@ts-ignore` directives:
195
+
196
+ ```typescript
197
+ // @ts-ignore: webpack is an optional peer dependency (using type-only import)
198
+ import type { Configuration } from "webpack"
199
+ ```
200
+
201
+ This ensures that typecheck downstream won't fail if lib checks are on regardless of if `webpack` is available.
202
+
203
+ ### When modifying dependencies:
204
+
205
+ 1. Add new peer dependencies to both `peerDependencies` and `peerDependenciesMeta` (marking as optional)
206
+ 2. Keep version ranges synchronized between `devDependencies` and `peerDependencies`
207
+ 3. Test with multiple package managers: `npm`, `yarn`, and `pnpm`
208
+ 4. If adding type-only imports from optional dependencies, use the `@ts-ignore` pattern shown above
209
+
210
+ ### Testing peer dependency changes:
211
+
212
+ ```bash
213
+ # Test with npm (no warnings expected)
214
+ cd /tmp && mkdir test-npm && cd test-npm
215
+ npm init -y && npm install /path/to/shakapacker
216
+
217
+ # Test with yarn (no warnings expected)
218
+ cd /tmp && mkdir test-yarn && cd test-yarn
219
+ yarn init -y && yarn add /path/to/shakapacker
220
+
221
+ # Test with pnpm (no warnings expected)
222
+ cd /tmp && mkdir test-pnpm && cd test-pnpm
223
+ pnpm init && pnpm add /path/to/shakapacker
224
+ ```
225
+
53
226
  ## Making sure your changes pass all tests
54
227
 
55
228
  There are several specs, covering different aspects of Shakapacker gem. You may run them locally or rely on GitHub CI actions configured to test the gem functionality if different Ruby, Rails, and Node environment.
@@ -101,6 +274,7 @@ bundle exec rake run_spec:gem
101
274
  ```
102
275
 
103
276
  #### 4.4 Run only Shakapacker gem specs for backward compatibility
277
+
104
278
  These specs are to check Shakapacker v7 backward compatibility with v6.x
105
279
 
106
280
  ```
@@ -108,6 +282,7 @@ bundle exec rake run_spec:gem_bc
108
282
  ```
109
283
 
110
284
  #### 4.5 Run dummy app test
285
+
111
286
  For this, you need `yalc` to be installed on your local machine
112
287
 
113
288
  ```
@@ -115,6 +290,7 @@ bundle exec rake run_spec:dummy
115
290
  ```
116
291
 
117
292
  #### 4.6 Testing the installer
293
+
118
294
  To ensure that your installer works as expected, either you can run `bundle exec rake run_spec:install`, or take the following manual testing steps:
119
295
 
120
296
  1. Update the `Gemfile` so that gem `shakapacker` has a line like this, pointing to your developing Shakapacker:
@@ -124,4 +300,75 @@ To ensure that your installer works as expected, either you can run `bundle exec
124
300
  2. Run `bundle install` to install the updated gem.
125
301
  3. Run `bundle exec rails shakapacker:install` to confirm that you got the right changes.
126
302
 
127
- **Note:** Ensure that you use bundle exec otherwise the installed shakapacker gem will run and not the one you are working on.
303
+ **Note:** Ensure that you use bundle exec otherwise the installed shakapacker gem will run and not the one you are working on.
304
+
305
+ ## CI Workflows
306
+
307
+ Shakapacker uses GitHub Actions for continuous integration. The CI workflows use **Yarn** as the package manager for consistency and reliability.
308
+
309
+ ### Package Manager Choice
310
+
311
+ The project uses Yarn in CI workflows for the following reasons:
312
+
313
+ - Deterministic dependency resolution with `yarn.lock`
314
+ - Faster installation with offline mirror support
315
+ - Better workspace support for monorepo-style testing
316
+ - Consistent behavior across different Node.js versions
317
+
318
+ ### Key CI Workflow Files
319
+
320
+ - `.github/workflows/test-bundlers.yml` - Tests webpack, rspack, and bundler switching
321
+ - `.github/workflows/ruby.yml` - Ruby test suite across Ruby/Rails versions
322
+ - `.github/workflows/node.yml` - Node.js test suite across Node versions
323
+ - `.github/workflows/generator.yml` - Generator installation tests
324
+ - `.github/workflows/dummy.yml` - Dummy app integration tests
325
+ - `.github/workflows/eslint-validation.yml` - ESLint configuration validation
326
+
327
+ All workflows use:
328
+
329
+ ```yaml
330
+ - uses: actions/setup-node@v4
331
+ with:
332
+ cache: "yarn"
333
+ cache-dependency-path: spec/dummy/yarn.lock
334
+ ```
335
+
336
+ And install dependencies with:
337
+
338
+ ```bash
339
+ yarn install
340
+ ```
341
+
342
+ ### CI Optimization: Path Filtering
343
+
344
+ To reduce CI costs and execution time, workflows use **path filtering** to run only when relevant files change:
345
+
346
+ - **Ruby workflow** - Only runs when Ruby files, gemspecs, Gemfile, or RuboCop config changes
347
+ - **Node workflow** - Only runs when JS/TS files, package.json, or Node config changes
348
+ - **Generator specs** - Only runs when generator-related files change
349
+ - **Dummy specs** - Only runs when dummy app or lib files change
350
+ - **Test bundlers** - Only runs when code affecting bundler integration changes
351
+
352
+ This means documentation-only PRs (e.g., only changing `README.md`) will skip all test workflows entirely.
353
+
354
+ **Important:** The full test suite always runs on pushes to the `main` branch to ensure the main branch is always thoroughly tested.
355
+
356
+ ### Manual Workflow Execution
357
+
358
+ All workflows can be triggered manually via the GitHub Actions UI using the "Run workflow" button. This is useful for:
359
+
360
+ - Re-running tests after a temporary CI failure
361
+ - Testing workflows on specific branches without creating a PR
362
+ - Running full test suites on PRs that would normally skip certain workflows
363
+
364
+ ### Conditional Linting
365
+
366
+ The Node workflow includes conditional execution of actionlint (GitHub Actions linter):
367
+
368
+ - Only downloads and runs when `.github/workflows/*` files change
369
+ - Saves time by skipping on most PRs
370
+ - Includes caching for faster execution when needed
371
+
372
+ ### Testing with Other Package Managers
373
+
374
+ While CI uses Yarn, the gem supports all major package managers (npm, yarn, pnpm, bun). Generator specs test against all package managers to ensure compatibility.
@@ -0,0 +1,165 @@
1
+ # ESLint Technical Debt Documentation
2
+
3
+ This document tracks the ESLint errors currently suppressed in the codebase and outlines the plan to address them.
4
+
5
+ ## Current Approach
6
+
7
+ **As of 2025-10-14**: All TypeScript files in `package/` directory are temporarily excluded from linting via the ignore pattern `package/**/*.ts` in `eslint.config.js`. This allows the project to adopt ESLint configuration without requiring immediate fixes to all existing issues.
8
+
9
+ **Latest Update**: Auto-fixed 28 style violations in `package/configExporter/cli.ts` including unnecessary type assertions, string concatenation to template literals, and object destructuring (reduced from 77 to 49 errors).
10
+
11
+ ## Current Linting Status
12
+
13
+ **Files currently linted** (`test/**/*.js`, `scripts/*.js`):
14
+
15
+ - ✅ **0 errors** (CI passing)
16
+ - ⚠️ **3 warnings** (acceptable, won't block CI)
17
+ - 1x unused eslint-disable directive in `scripts/remove-use-strict.js`
18
+ - 2x jest/no-disabled-tests in test files (expected for conditional test skipping)
19
+
20
+ **TypeScript files** (currently ignored via `package/**/*.ts`):
21
+
22
+ - **Estimated suppressed errors: ~163** (from sample analysis)
23
+ - TypeScript type-safety issues: ~114 (70%)
24
+ - Style/convention issues: ~49 (30%)
25
+
26
+ **Target**: Reduce suppressed errors by 50% within Q1 2025
27
+ **Last Updated**: 2025-10-18
28
+
29
+ ## Priority Matrix
30
+
31
+ | Category | Impact | Effort | Priority | Count |
32
+ | ------------------------------------ | ------ | ------ | -------- | ----- |
33
+ | `@typescript-eslint/no-explicit-any` | High | High | P1 | 22 |
34
+ | `@typescript-eslint/no-unsafe-*` | High | High | P1 | 85 |
35
+ | `config.ts` type safety | High | Medium | P1 | 7 |
36
+ | `no-param-reassign` | Medium | Low | P2 | 0 |
37
+ | `class-methods-use-this` | Low | Low | P3 | 0 |
38
+ | `no-nested-ternary` | Low | Low | P3 | 0 |
39
+ | `import/prefer-default-export` | Low | Medium | P3 | 9 |
40
+ | `global-require` | Medium | High | P2 | 3 |
41
+ | Other style issues | Low | Low | P3 | 31 |
42
+
43
+ ## Categories of Suppressed Errors
44
+
45
+ ### 1. TypeScript Type Safety (Requires Major Refactoring)
46
+
47
+ #### `@typescript-eslint/no-explicit-any` (22 instances)
48
+
49
+ **Files affected:** `configExporter/`, `config.ts`, `utils/`
50
+ **Why suppressed:** These require careful type definitions and potentially breaking API changes
51
+ **Fix strategy:** Create proper type definitions for configuration objects and YAML parsing
52
+
53
+ #### `@typescript-eslint/no-unsafe-*` (85 instances)
54
+
55
+ - `no-unsafe-assignment`: 47 instances
56
+ - `no-unsafe-member-access`: 20 instances
57
+ - `no-unsafe-call`: 8 instances
58
+ - `no-unsafe-return`: 8 instances
59
+ - `no-unsafe-argument`: 7 instances
60
+ **Why suppressed:** These stem from `any` types and dynamic property access
61
+ **Fix strategy:** Requires comprehensive type refactoring alongside `no-explicit-any` fixes
62
+
63
+ ### 2. Module System (Potential Breaking Changes)
64
+
65
+ #### `global-require` (3 instances)
66
+
67
+ **Files affected:** `configExporter/cli.ts`
68
+ **Why suppressed:** Dynamic require calls are needed for conditional module loading
69
+ **Fix strategy:** Would require converting to ES modules with dynamic imports
70
+
71
+ #### `import/prefer-default-export` (9 instances)
72
+
73
+ **Files affected:** Multiple single-export modules
74
+ **Why suppressed:** Adding default exports alongside named exports could break consumers
75
+ **Fix strategy:** Can be fixed non-breaking by adding default exports that match named exports
76
+
77
+ ### 3. Code Style (Can Be Fixed)
78
+
79
+ #### `class-methods-use-this` (0 instances)
80
+
81
+ ✅ **FIXED** - All FileWriter methods that didn't use instance state have been converted to static methods
82
+
83
+ #### `no-nested-ternary` (0 instances)
84
+
85
+ ✅ **FIXED** - All nested ternary expressions have been refactored to if-else statements for better readability
86
+
87
+ #### `no-param-reassign` (0 instances)
88
+
89
+ ✅ **FIXED** - Refactored `applyDefaults` function to return new objects instead of mutating parameters
90
+
91
+ #### `no-underscore-dangle` (2 instances)
92
+
93
+ **Fix strategy:** Rename variables or add exceptions for Node internals
94
+
95
+ ### 4. Control Flow
96
+
97
+ #### `no-await-in-loop` (1 instance)
98
+
99
+ **Fix strategy:** Use `Promise.all()` for parallel execution
100
+
101
+ #### `no-continue` (1 instance)
102
+
103
+ **Fix strategy:** Refactor loop logic
104
+
105
+ ## Recommended Approach
106
+
107
+ ### Phase 1: Non-Breaking Fixes
108
+
109
+ ✅ Completed:
110
+
111
+ - Fixed `no-use-before-define` by reordering functions
112
+ - Fixed redundant type constituents with `string & {}` pattern
113
+ - Added proper type annotations for `requireOrError` calls
114
+ - Configured appropriate global rule disables (`no-console`, `no-restricted-syntax`)
115
+ - ✅ **Fixed `class-methods-use-this`** - Converted FileWriter methods to static methods
116
+ - ✅ **Fixed `no-nested-ternary`** - Refactored to if-else statements for better readability
117
+ - ✅ **Fixed `no-param-reassign`** - Refactored `applyDefaults` to return new objects instead of mutating parameters
118
+ - ✅ **Auto-fixed style violations in cli.ts** (2025-10-18):
119
+ - Removed unnecessary type assertions (`@typescript-eslint/no-unnecessary-type-assertion`)
120
+ - Used object destructuring (`prefer-destructuring`)
121
+ - Converted string concatenation to template literals (`prefer-template`)
122
+ - Removed unused eslint-disable directives
123
+ - Fixed `no-else-return` violations
124
+
125
+ 🔧 Could still fix (low risk):
126
+
127
+ - `no-useless-escape` - Remove unnecessary escapes
128
+ - Unused variables - Remove or prefix with underscore
129
+
130
+ ### Phase 2: Follow-up PRs (Non-Breaking)
131
+
132
+ - Systematic type safety improvements file by file
133
+ - Add explicit type definitions for configuration objects
134
+ - Replace `any` with `unknown` where possible
135
+
136
+ ### Phase 3: Future Major Version (Breaking Changes)
137
+
138
+ - Convert `export =` to `export default`
139
+ - Convert `require()` to ES6 imports
140
+ - Full TypeScript strict mode compliance
141
+ - Provide codemod for automatic migration
142
+
143
+ ## Configuration Strategy
144
+
145
+ The current approach uses file-specific overrides to suppress errors in affected files while maintaining strict checking elsewhere. This allows:
146
+
147
+ 1. New code to follow strict standards
148
+ 2. Gradual refactoring of existing code
149
+ 3. Clear visibility of technical debt
150
+
151
+ ## Issue Tracking
152
+
153
+ GitHub issues should be created for each category:
154
+
155
+ 1. [ ] Issue: Type safety refactoring for configExporter module
156
+ 2. [ ] Issue: Type safety for dynamic config loading
157
+ 3. [ ] Issue: Convert class methods to static where appropriate
158
+ 4. [ ] Issue: Module system modernization (ES6 modules)
159
+ 5. [ ] Issue: Create codemod for breaking changes migration
160
+
161
+ ## Notes
162
+
163
+ - All suppressed errors are documented in `eslint.config.js` with TODO comments
164
+ - The suppressions are scoped to specific files to prevent spreading technical debt
165
+ - New code should not add to these suppressions