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
@@ -0,0 +1,28 @@
1
+ // @ts-ignore: webpack is an optional peer dependency (using type-only import)
2
+ import type { LoaderDefinitionFunction } from 'webpack'
3
+
4
+ export interface ShakapackerLoaderOptions {
5
+ [key: string]: any
6
+ }
7
+
8
+ export interface ShakapackerLoader {
9
+ loader: string
10
+ options?: ShakapackerLoaderOptions
11
+ }
12
+
13
+ export type LoaderResolver = (name: string) => string
14
+
15
+ export interface LoaderConfig {
16
+ test: RegExp | ((value: string) => boolean)
17
+ use: Array<string | ShakapackerLoader | LoaderDefinitionFunction>
18
+ exclude?: RegExp | string | Array<string>
19
+ include?: RegExp | string | Array<string>
20
+ type?: string
21
+ generator?: {
22
+ filename?: string
23
+ publicPath?: string
24
+ }
25
+ }
26
+
27
+ export function resolveLoader(name: string): string
28
+ export function createLoader(config: LoaderConfig): LoaderConfig
@@ -0,0 +1,36 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+ const { error: logError } = require("../utils/debug")
3
+
4
+ const rspack = requireOrError("@rspack/core")
5
+
6
+ interface OptimizationConfig {
7
+ minimize: boolean
8
+ minimizer?: unknown[]
9
+ }
10
+
11
+ const getOptimization = (): OptimizationConfig => {
12
+ // Use Rspack's built-in minification instead of terser-webpack-plugin
13
+ const result: OptimizationConfig = { minimize: true }
14
+ try {
15
+ result.minimizer = [
16
+ new rspack.SwcJsMinimizerRspackPlugin(),
17
+ new rspack.LightningCssMinimizerRspackPlugin()
18
+ ]
19
+ } catch (error: unknown) {
20
+ const errorMessage = error instanceof Error ? error.message : String(error)
21
+ const errorStack = error instanceof Error ? error.stack : ''
22
+ // Log full error with stack trace
23
+ logError(
24
+ `Failed to configure Rspack minimizers: ${errorMessage}\n${errorStack}`
25
+ )
26
+ // Re-throw the error to properly propagate it
27
+ throw new Error(
28
+ `Could not configure Rspack minimizers: ${errorMessage}. Please check that @rspack/core is properly installed.`
29
+ )
30
+ }
31
+ return result
32
+ }
33
+
34
+ export = {
35
+ getOptimization
36
+ }
@@ -0,0 +1,57 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+
3
+ const TerserPlugin = requireOrError("terser-webpack-plugin")
4
+ const { moduleExists } = require("../utils/helpers")
5
+
6
+ const tryCssMinimizer = (): unknown | null => {
7
+ if (
8
+ moduleExists("css-loader") &&
9
+ moduleExists("css-minimizer-webpack-plugin")
10
+ ) {
11
+ const CssMinimizerPlugin = requireOrError("css-minimizer-webpack-plugin")
12
+ return new CssMinimizerPlugin()
13
+ }
14
+
15
+ return null
16
+ }
17
+
18
+ interface OptimizationConfig {
19
+ minimizer: unknown[]
20
+ }
21
+
22
+ const getOptimization = (): OptimizationConfig => {
23
+ return {
24
+ minimizer: [
25
+ tryCssMinimizer(),
26
+ new TerserPlugin({
27
+ // SHAKAPACKER_PARALLEL env var: number of parallel workers, or true for auto (os.cpus().length - 1)
28
+ // If not set or invalid, defaults to true (automatic parallelization)
29
+ parallel: process.env.SHAKAPACKER_PARALLEL
30
+ ? Number.parseInt(process.env.SHAKAPACKER_PARALLEL, 10) || true
31
+ : true,
32
+ terserOptions: {
33
+ parse: {
34
+ // Let terser parse ecma 8 code but always output
35
+ // ES5 compliant code for older browsers
36
+ ecma: 8
37
+ },
38
+ compress: {
39
+ ecma: 5,
40
+ warnings: false,
41
+ comparisons: false
42
+ },
43
+ mangle: { safari10: true },
44
+ output: {
45
+ ecma: 5,
46
+ comments: false,
47
+ ascii_only: true
48
+ }
49
+ }
50
+ })
51
+ ].filter(Boolean)
52
+ }
53
+ }
54
+
55
+ export = {
56
+ getOptimization
57
+ }
@@ -0,0 +1,103 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+
3
+ const { RspackManifestPlugin } = requireOrError("rspack-manifest-plugin")
4
+ const rspack = requireOrError("@rspack/core")
5
+ const config = require("../config")
6
+ const { isProduction } = require("../env")
7
+ const { moduleExists } = require("../utils/helpers")
8
+
9
+ interface ManifestFile {
10
+ name: string
11
+ path: string
12
+ }
13
+
14
+ interface EntrypointAssets {
15
+ js: string[]
16
+ css: string[]
17
+ }
18
+
19
+ interface Manifest {
20
+ entrypoints?: Record<string, { assets: EntrypointAssets }>
21
+ [key: string]: string | { assets: EntrypointAssets } | Record<string, { assets: EntrypointAssets }> | undefined
22
+ }
23
+
24
+ const getPlugins = (): unknown[] => {
25
+ const plugins = [
26
+ new rspack.EnvironmentPlugin(process.env),
27
+ new RspackManifestPlugin({
28
+ fileName: config.manifestPath.split("/").pop(), // Get just the filename
29
+ publicPath: config.publicPathWithoutCDN,
30
+ writeToFileEmit: true,
31
+ // rspack-manifest-plugin uses different option names than webpack-assets-manifest
32
+ generate: (seed: Manifest | null, files: ManifestFile[], entrypoints: Record<string, string[]>) => {
33
+ const manifest: Manifest = seed || {}
34
+
35
+ // Add files mapping first
36
+ files.forEach((file) => {
37
+ manifest[file.name] = file.path
38
+ })
39
+
40
+ // Add entrypoints information compatible with Shakapacker expectations
41
+ const entrypointsManifest: Record<string, { assets: EntrypointAssets }> = {}
42
+ Object.entries(entrypoints).forEach(
43
+ ([entrypointName, entrypointFiles]) => {
44
+ const jsFiles = entrypointFiles
45
+ .filter(
46
+ (file) => file.endsWith(".js") && !file.includes(".hot-update.")
47
+ )
48
+ .map((file) => config.publicPathWithoutCDN + file)
49
+ const cssFiles = entrypointFiles
50
+ .filter(
51
+ (file) =>
52
+ file.endsWith(".css") && !file.includes(".hot-update.")
53
+ )
54
+ .map((file) => config.publicPathWithoutCDN + file)
55
+
56
+ entrypointsManifest[entrypointName] = {
57
+ assets: {
58
+ js: jsFiles,
59
+ css: cssFiles
60
+ }
61
+ }
62
+ }
63
+ )
64
+ manifest.entrypoints = entrypointsManifest
65
+
66
+ return manifest
67
+ }
68
+ })
69
+ ]
70
+
71
+ if (moduleExists("css-loader")) {
72
+ const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
73
+ // Use Rspack's built-in CSS extraction
74
+ const { CssExtractRspackPlugin } = rspack
75
+ plugins.push(
76
+ new CssExtractRspackPlugin({
77
+ filename: `css/[name]${hash}.css`,
78
+ chunkFilename: `css/[id]${hash}.css`,
79
+ // For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
80
+ // the css order warnings can be disabled by setting the ignoreOrder flag.
81
+ ignoreOrder: config.css_extract_ignore_order_warnings,
82
+ // Force writing CSS files to disk in development for Rails compatibility
83
+ emit: true
84
+ })
85
+ )
86
+ }
87
+
88
+ // Use Rspack's built-in SubresourceIntegrityPlugin
89
+ if (config.integrity.enabled) {
90
+ plugins.push(
91
+ new rspack.SubresourceIntegrityPlugin({
92
+ hashFuncNames: config.integrity.hash_functions,
93
+ enabled: isProduction
94
+ })
95
+ )
96
+ }
97
+
98
+ return plugins
99
+ }
100
+
101
+ export = {
102
+ getPlugins
103
+ }
@@ -0,0 +1,62 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+ // TODO: Change to `const { WebpackAssetsManifest }` when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
3
+ const WebpackAssetsManifest = requireOrError("webpack-assets-manifest")
4
+ const webpack = requireOrError("webpack")
5
+ const config = require("../config")
6
+ const { isProduction } = require("../env")
7
+ const { moduleExists } = require("../utils/helpers")
8
+
9
+ const getPlugins = (): unknown[] => {
10
+ // TODO: Remove WebpackAssetsManifestConstructor workaround when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
11
+ const WebpackAssetsManifestConstructor =
12
+ "WebpackAssetsManifest" in WebpackAssetsManifest
13
+ ? WebpackAssetsManifest.WebpackAssetsManifest
14
+ : WebpackAssetsManifest
15
+ const plugins = [
16
+ new webpack.EnvironmentPlugin(process.env),
17
+ new WebpackAssetsManifestConstructor({
18
+ entrypoints: true,
19
+ writeToDisk: true,
20
+ output: config.manifestPath,
21
+ entrypointsUseAssets: true,
22
+ publicPath: config.publicPathWithoutCDN,
23
+ integrity: config.integrity.enabled,
24
+ integrityHashes: config.integrity.hash_functions
25
+ })
26
+ ]
27
+
28
+ if (moduleExists("css-loader") && moduleExists("mini-css-extract-plugin")) {
29
+ const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
30
+ const MiniCssExtractPlugin = requireOrError("mini-css-extract-plugin")
31
+ plugins.push(
32
+ new MiniCssExtractPlugin({
33
+ filename: `css/[name]${hash}.css`,
34
+ chunkFilename: `css/[id]${hash}.css`,
35
+ // For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
36
+ // the css order warnings can be disabled by setting the ignoreOrder flag.
37
+ ignoreOrder: config.css_extract_ignore_order_warnings
38
+ })
39
+ )
40
+ }
41
+
42
+ if (
43
+ config.integrity.enabled &&
44
+ moduleExists("webpack-subresource-integrity")
45
+ ) {
46
+ const SubresourceIntegrityPlugin = requireOrError(
47
+ "webpack-subresource-integrity"
48
+ )
49
+ plugins.push(
50
+ new SubresourceIntegrityPlugin({
51
+ hashFuncNames: config.integrity.hash_functions,
52
+ enabled: isProduction
53
+ })
54
+ )
55
+ }
56
+
57
+ return plugins
58
+ }
59
+
60
+ export = {
61
+ getPlugins
62
+ }
@@ -0,0 +1,64 @@
1
+ /* eslint global-require: 0 */
2
+ /* eslint import/no-dynamic-require: 0 */
3
+
4
+ // Mixed require/import syntax:
5
+ // - Using require() for compiled JS modules that may not have proper ES module exports
6
+ // - Using import for type-only imports and Node.js built-in modules
7
+ const webpackMerge = require("webpack-merge")
8
+ import { resolve } from "path"
9
+ import { existsSync } from "fs"
10
+ import type { RspackConfigWithDevServer } from "../environments/types"
11
+ const config = require("../config")
12
+ const baseConfig = require("../environments/base")
13
+ const devServer = require("../dev_server")
14
+ const env = require("../env")
15
+ const { moduleExists, canProcess } = require("../utils/helpers")
16
+ const inliningCss = require("../utils/inliningCss")
17
+ const { getPlugins } = require("../plugins/rspack")
18
+ const { getOptimization } = require("../optimization/rspack")
19
+ const { validateRspackDependencies } = require("../utils/validateDependencies")
20
+
21
+ const rulesPath = resolve(__dirname, "../rules", "rspack.js")
22
+ const rules = require(rulesPath)
23
+
24
+ const generateRspackConfig = (extraConfig: RspackConfigWithDevServer = {}, ...extraArgs: unknown[]): RspackConfigWithDevServer => {
25
+ // Validate required dependencies first
26
+ validateRspackDependencies()
27
+ if (extraArgs.length > 0) {
28
+ throw new Error(
29
+ "Only one extra config may be passed here - use webpack-merge to merge configs before passing them to Shakapacker"
30
+ )
31
+ }
32
+
33
+ const { nodeEnv } = env
34
+ const path = resolve(__dirname, "../environments", `${nodeEnv}.js`)
35
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
36
+ const environmentConfig = existsSync(path) ? require(path) : baseConfig
37
+
38
+ // Create base rspack config
39
+ const rspackConfig: RspackConfigWithDevServer = {
40
+ ...environmentConfig,
41
+ module: {
42
+ rules
43
+ },
44
+ plugins: getPlugins(),
45
+ optimization: getOptimization()
46
+ }
47
+
48
+ return webpackMerge.merge({}, rspackConfig, extraConfig)
49
+ }
50
+
51
+ // Re-export webpack-merge utilities for backward compatibility
52
+ export { merge, mergeWithCustomize, mergeWithRules, unique } from "webpack-merge"
53
+
54
+ export {
55
+ config, // shakapacker.yml
56
+ devServer,
57
+ generateRspackConfig,
58
+ baseConfig,
59
+ env,
60
+ rules,
61
+ moduleExists,
62
+ canProcess,
63
+ inliningCss
64
+ }
@@ -1,9 +1,9 @@
1
1
  const { loaderMatches } = require("../utils/helpers")
2
- const { webpack_loader: webpackLoader } = require("../config")
2
+ const { javascript_transpiler: javascriptTranspiler } = require("../config")
3
3
  const { isProduction } = require("../env")
4
4
  const jscommon = require("./jscommon")
5
5
 
6
- module.exports = loaderMatches(webpackLoader, "babel", () => ({
6
+ export = loaderMatches(javascriptTranspiler, "babel", () => ({
7
7
  test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
8
8
  ...jscommon,
9
9
  use: [
@@ -1,6 +1,6 @@
1
1
  const { canProcess } = require("../utils/helpers")
2
2
 
3
- module.exports = canProcess("coffee-loader", (resolvedPath) => ({
3
+ export = canProcess("coffee-loader", (resolvedPath: string) => ({
4
4
  test: /\.coffee(\.erb)?$/,
5
5
  use: [{ loader: resolvedPath }]
6
6
  }))
@@ -0,0 +1,3 @@
1
+ const { getStyleRule } = require("../utils/getStyleRule")
2
+
3
+ export = getStyleRule(/\.(css)$/i)
@@ -2,7 +2,7 @@ const { canProcess } = require("../utils/helpers")
2
2
 
3
3
  const runner = /^win/.test(process.platform) ? "ruby " : ""
4
4
 
5
- module.exports = canProcess("rails-erb-loader", (resolvedPath) => ({
5
+ export = canProcess("rails-erb-loader", (resolvedPath: string) => ({
6
6
  test: /\.erb$/,
7
7
  enforce: "pre",
8
8
  exclude: /node_modules/,
@@ -0,0 +1,10 @@
1
+ const { loaderMatches } = require("../utils/helpers")
2
+ const { getEsbuildLoaderConfig } = require("../esbuild")
3
+ const { javascript_transpiler: javascriptTranspiler } = require("../config")
4
+ const jscommon = require("./jscommon")
5
+
6
+ export = loaderMatches(javascriptTranspiler, "esbuild", () => ({
7
+ test: /\.(ts|tsx|js|jsx|mjs|coffee)?(\.erb)?$/,
8
+ ...jscommon,
9
+ use: ({ resource }: { resource: string }) => getEsbuildLoaderConfig(resource)
10
+ }))
@@ -0,0 +1,40 @@
1
+ import { dirname, sep, normalize } from "path"
2
+ const {
3
+ additional_paths: additionalPaths,
4
+ source_path: sourcePath
5
+ } = require("../config")
6
+
7
+ export = {
8
+ test: /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2|svg)$/,
9
+ exclude: /\.(js|mjs|jsx|ts|tsx)$/,
10
+ type: "asset/resource",
11
+ generator: {
12
+ filename: (pathData: { filename?: string }) => {
13
+ // Guard against null/undefined pathData or filename
14
+ if (!pathData || !pathData.filename) {
15
+ return `static/[name]-[hash][ext][query]`
16
+ }
17
+ const path = normalize(dirname(pathData.filename))
18
+ const stripPaths = [...additionalPaths, sourcePath].map((p: string) =>
19
+ normalize(p)
20
+ )
21
+
22
+ const selectedStripPath = stripPaths.find((includePath: string) =>
23
+ path.startsWith(includePath)
24
+ )
25
+
26
+ if (!selectedStripPath) {
27
+ return `static/[name]-[hash][ext][query]`
28
+ }
29
+
30
+ // Split on both forward and backward slashes for cross-platform compatibility
31
+ const folders = path
32
+ .replace(selectedStripPath, "")
33
+ .split(/[\\/]/)
34
+ .filter(Boolean)
35
+
36
+ const foldersWithStatic = ["static", ...folders].join("/")
37
+ return `${foldersWithStatic}/[name]-[hash][ext][query]`
38
+ }
39
+ }
40
+ }
@@ -1,11 +1,11 @@
1
- const { resolve } = require("path")
2
- const { realpathSync } = require("fs")
1
+ import { resolve } from "path"
2
+ import { realpathSync } from "fs"
3
3
  const {
4
4
  source_path: sourcePath,
5
5
  additional_paths: additionalPaths
6
6
  } = require("../config")
7
7
 
8
- const inclusions = [sourcePath, ...additionalPaths].map((p) => {
8
+ const inclusions = [sourcePath, ...additionalPaths].map((p: string) => {
9
9
  try {
10
10
  return realpathSync(p)
11
11
  } catch (e) {
@@ -13,7 +13,7 @@ const inclusions = [sourcePath, ...additionalPaths].map((p) => {
13
13
  }
14
14
  })
15
15
 
16
- module.exports = {
16
+ export = {
17
17
  include: inclusions,
18
18
  exclude: [
19
19
  {
@@ -1,19 +1,19 @@
1
- const path = require("path")
2
1
  const { canProcess } = require("../utils/helpers")
3
- const getStyleRule = require("../utils/getStyleRule")
2
+ const { getStyleRule } = require("../utils/getStyleRule")
4
3
 
5
4
  const {
6
5
  additional_paths: paths,
7
6
  source_path: sourcePath
8
7
  } = require("../config")
9
8
 
10
- module.exports = canProcess("less-loader", (resolvedPath) =>
9
+ export = canProcess("less-loader", (resolvedPath: string) =>
11
10
  getStyleRule(/\.(less)(\.erb)?$/i, [
12
11
  {
13
12
  loader: resolvedPath,
14
13
  options: {
15
14
  lessOptions: {
16
- paths: [path.resolve(__dirname, "node_modules"), sourcePath, ...paths]
15
+ // Additional paths for Less imports (node_modules is resolved automatically)
16
+ paths: [sourcePath, ...paths]
17
17
  },
18
18
  sourceMap: true
19
19
  }
@@ -0,0 +1,25 @@
1
+ const config = require("../config")
2
+
3
+ const rspackRawConfig = () => ({
4
+ resourceQuery: /raw/,
5
+ type: "asset/source"
6
+ })
7
+
8
+ const webpackRawConfig = () => ({
9
+ oneOf: [
10
+ {
11
+ // Match any file with ?raw query parameter
12
+ resourceQuery: /raw/,
13
+ type: "asset/source"
14
+ },
15
+ {
16
+ // Fallback: match .html files without query
17
+ test: /\.html$/,
18
+ exclude: /\.(js|mjs|jsx|ts|tsx)$/,
19
+ type: "asset/source"
20
+ }
21
+ ]
22
+ })
23
+
24
+ export =
25
+ config.assets_bundler === "rspack" ? rspackRawConfig() : webpackRawConfig()