shakapacker 8.4.0 → 9.0.0.beta.2

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/STATUS.md +1 -0
  3. data/.github/workflows/claude-code-review.yml +54 -0
  4. data/.github/workflows/claude.yml +50 -0
  5. data/.github/workflows/dummy.yml +1 -1
  6. data/.github/workflows/generator.yml +4 -14
  7. data/.github/workflows/node.yml +1 -1
  8. data/.rubocop.yml +1 -0
  9. data/CHANGELOG.md +8 -2
  10. data/Gemfile.lock +3 -3
  11. data/README.md +2 -2
  12. data/Rakefile +18 -1
  13. data/docs/css-modules-export-mode.md +288 -0
  14. data/docs/peer-dependencies.md +40 -0
  15. data/docs/rspack.md +190 -0
  16. data/docs/rspack_migration_guide.md +202 -0
  17. data/docs/troubleshooting.md +5 -0
  18. data/docs/using_esbuild_loader.md +3 -3
  19. data/docs/using_swc_loader.md +5 -3
  20. data/lib/install/bin/shakapacker +3 -5
  21. data/lib/install/config/rspack/rspack.config.js +6 -0
  22. data/lib/install/config/shakapacker.yml +6 -2
  23. data/lib/install/package.json +30 -0
  24. data/lib/install/template.rb +12 -2
  25. data/lib/shakapacker/configuration.rb +45 -0
  26. data/lib/shakapacker/dev_server_runner.rb +25 -5
  27. data/lib/shakapacker/manifest.rb +4 -2
  28. data/lib/shakapacker/rspack_runner.rb +19 -0
  29. data/lib/shakapacker/runner.rb +144 -4
  30. data/lib/shakapacker/utils/manager.rb +2 -0
  31. data/lib/shakapacker/version.rb +1 -1
  32. data/lib/shakapacker/version_checker.rb +1 -1
  33. data/lib/shakapacker/webpack_runner.rb +4 -42
  34. data/lib/tasks/shakapacker/install.rake +6 -2
  35. data/package/config.js +24 -0
  36. data/package/environments/base.js +20 -65
  37. data/package/environments/development.js +60 -5
  38. data/package/environments/production.js +29 -51
  39. data/package/environments/test.js +17 -1
  40. data/package/index.d.ts +62 -20
  41. data/package/index.js +4 -2
  42. data/package/optimization/rspack.js +29 -0
  43. data/package/optimization/webpack.js +49 -0
  44. data/package/plugins/rspack.js +88 -0
  45. data/package/plugins/webpack.js +62 -0
  46. data/package/rspack/index.js +57 -0
  47. data/package/rules/babel.js +2 -2
  48. data/package/rules/css.js +1 -1
  49. data/package/rules/esbuild.js +2 -2
  50. data/package/rules/file.js +11 -5
  51. data/package/rules/less.js +1 -1
  52. data/package/rules/raw.js +12 -2
  53. data/package/rules/rspack.js +162 -0
  54. data/package/rules/sass.js +6 -2
  55. data/package/rules/stylus.js +1 -1
  56. data/package/rules/swc.js +2 -2
  57. data/package/utils/debug.js +49 -0
  58. data/package/utils/getStyleRule.js +16 -3
  59. data/package/utils/requireOrError.js +15 -0
  60. data/package/utils/validateDependencies.js +61 -0
  61. data/package/webpackDevServerConfig.js +2 -0
  62. data/package.json +19 -31
  63. data/test/package/environments/base.test.js +1 -1
  64. data/test/package/rules/esbuild.test.js +1 -1
  65. data/test/package/rules/swc.test.js +1 -1
  66. data/test/package/rules/{index.test.js → webpack.test.js} +1 -1
  67. data/yarn.lock +2136 -726
  68. metadata +26 -11
  69. /data/package/rules/{index.js → webpack.js} +0 -0
@@ -0,0 +1,19 @@
1
+ require "shellwords"
2
+
3
+ require_relative "runner"
4
+
5
+ module Shakapacker
6
+ class RspackRunner < Shakapacker::Runner
7
+ def self.run(argv)
8
+ $stdout.sync = true
9
+ ENV["NODE_ENV"] ||= (ENV["RAILS_ENV"] == "production") ? "production" : "development"
10
+ new(argv).run
11
+ end
12
+
13
+ private
14
+
15
+ def build_cmd
16
+ package_json.manager.native_exec_command("rspack")
17
+ end
18
+ end
19
+ end
@@ -1,14 +1,60 @@
1
1
  require_relative "utils/misc"
2
2
  require_relative "utils/manager"
3
+ require_relative "configuration"
3
4
 
4
5
  require "package_json"
6
+ require "pathname"
5
7
 
6
8
  module Shakapacker
7
9
  class Runner
10
+ attr_reader :config
11
+
12
+ # Common commands that don't work with --config option
13
+ BASE_COMMANDS = [
14
+ "help",
15
+ "h",
16
+ "--help",
17
+ "-h",
18
+ "version",
19
+ "v",
20
+ "--version",
21
+ "-v",
22
+ "info",
23
+ "i"
24
+ ].freeze
8
25
  def self.run(argv)
9
26
  $stdout.sync = true
10
27
  ENV["NODE_ENV"] ||= (ENV["RAILS_ENV"] == "production") ? "production" : "development"
11
- new(argv).run
28
+
29
+ # Create a single runner instance to avoid loading configuration twice.
30
+ # We extend it with the appropriate build command based on the bundler type.
31
+ runner = new(argv)
32
+
33
+ if runner.config.rspack?
34
+ require_relative "rspack_runner"
35
+ # Extend the runner instance with rspack-specific methods
36
+ # This avoids creating a new RspackRunner which would reload the configuration
37
+ runner.extend(Module.new do
38
+ def build_cmd
39
+ package_json.manager.native_exec_command("rspack")
40
+ end
41
+
42
+ def assets_bundler_commands
43
+ BASE_COMMANDS + %w[build watch]
44
+ end
45
+ end)
46
+ runner.run
47
+ else
48
+ require_relative "webpack_runner"
49
+ # Extend the runner instance with webpack-specific methods
50
+ # This avoids creating a new WebpackRunner which would reload the configuration
51
+ runner.extend(Module.new do
52
+ def build_cmd
53
+ package_json.manager.native_exec_command("webpack")
54
+ end
55
+ end)
56
+ runner.run
57
+ end
12
58
  end
13
59
 
14
60
  def initialize(argv)
@@ -16,7 +62,12 @@ module Shakapacker
16
62
 
17
63
  @app_path = File.expand_path(".", Dir.pwd)
18
64
  @shakapacker_config = ENV["SHAKAPACKER_CONFIG"] || File.join(@app_path, "config/shakapacker.yml")
19
- @webpack_config = find_webpack_config
65
+ @config = Configuration.new(
66
+ root_path: Pathname.new(@app_path),
67
+ config_path: Pathname.new(@shakapacker_config),
68
+ env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
69
+ )
70
+ @webpack_config = find_assets_bundler_config
20
71
 
21
72
  Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious!
22
73
  end
@@ -25,16 +76,105 @@ module Shakapacker
25
76
  @package_json ||= PackageJson.read(@app_path)
26
77
  end
27
78
 
79
+ def run
80
+ puts "[Shakapacker] Preparing environment for assets bundler execution..."
81
+ env = Shakapacker::Compiler.env
82
+ env["SHAKAPACKER_CONFIG"] = @shakapacker_config
83
+ env["NODE_OPTIONS"] = ENV["NODE_OPTIONS"] || ""
84
+
85
+ cmd = build_cmd
86
+ puts "[Shakapacker] Base command: #{cmd.join(" ")}"
87
+
88
+ if @argv.delete("--debug-shakapacker")
89
+ puts "[Shakapacker] Debug mode enabled (--debug-shakapacker)"
90
+ env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk"
91
+ end
92
+
93
+ if @argv.delete "--trace-deprecation"
94
+ puts "[Shakapacker] Trace deprecation enabled (--trace-deprecation)"
95
+ env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --trace-deprecation"
96
+ end
97
+
98
+ if @argv.delete "--no-deprecation"
99
+ puts "[Shakapacker] Deprecation warnings disabled (--no-deprecation)"
100
+ env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --no-deprecation"
101
+ end
102
+
103
+ # Commands are not compatible with --config option.
104
+ if (@argv & assets_bundler_commands).empty?
105
+ puts "[Shakapacker] Adding config file: #{@webpack_config}"
106
+ cmd += ["--config", @webpack_config]
107
+ else
108
+ puts "[Shakapacker] Skipping config file (running assets bundler command: #{(@argv & assets_bundler_commands).join(", ")})"
109
+ end
110
+
111
+ cmd += @argv
112
+ puts "[Shakapacker] Final command: #{cmd.join(" ")}"
113
+ puts "[Shakapacker] Working directory: #{@app_path}"
114
+
115
+ Dir.chdir(@app_path) do
116
+ Kernel.exec env, *cmd
117
+ end
118
+ end
119
+
120
+ protected
121
+
122
+ def assets_bundler_commands
123
+ BASE_COMMANDS
124
+ end
125
+
28
126
  private
127
+ def find_assets_bundler_config
128
+ if @config.rspack?
129
+ find_rspack_config_with_fallback
130
+ else
131
+ find_webpack_config
132
+ end
133
+ end
134
+
135
+ def find_rspack_config_with_fallback
136
+ # First try rspack-specific paths
137
+ rspack_paths = %w[ts js].map do |ext|
138
+ File.join(@app_path, "config/rspack/rspack.config.#{ext}")
139
+ end
140
+
141
+ puts "[Shakapacker] Looking for Rspack config in: #{rspack_paths.join(", ")}"
142
+ rspack_path = rspack_paths.find { |f| File.exist?(f) }
143
+ if rspack_path
144
+ puts "[Shakapacker] Found Rspack config: #{rspack_path}"
145
+ return rspack_path
146
+ end
147
+
148
+ # Fallback to webpack config with deprecation warning
149
+ webpack_paths = %w[ts js].map do |ext|
150
+ File.join(@app_path, "config/webpack/webpack.config.#{ext}")
151
+ end
152
+
153
+ puts "[Shakapacker] Rspack config not found, checking for webpack config fallback..."
154
+ webpack_path = webpack_paths.find { |f| File.exist?(f) }
155
+ if webpack_path
156
+ $stderr.puts "⚠️ DEPRECATION WARNING: Using webpack config file for Rspack assets bundler."
157
+ $stderr.puts " Please create config/rspack/rspack.config.js and migrate your configuration."
158
+ $stderr.puts " Using: #{webpack_path}"
159
+ return webpack_path
160
+ end
161
+
162
+ # No config found
163
+ $stderr.puts "[Shakapacker] ERROR: rspack config #{rspack_paths.last} not found, please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs or create the missing config file."
164
+ exit(1)
165
+ end
166
+
29
167
  def find_webpack_config
30
168
  possible_paths = %w[ts js].map do |ext|
31
169
  File.join(@app_path, "config/webpack/webpack.config.#{ext}")
32
170
  end
171
+ puts "[Shakapacker] Looking for Webpack config in: #{possible_paths.join(", ")}"
33
172
  path = possible_paths.find { |f| File.exist?(f) }
34
173
  unless path
35
- $stderr.puts "webpack config #{possible_paths.last} not found, please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs or add the missing config file for your custom environment."
36
- exit!
174
+ $stderr.puts "[Shakapacker] ERROR: webpack config #{possible_paths.last} not found, please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs or add the missing config file for your custom environment."
175
+ exit(1)
37
176
  end
177
+ puts "[Shakapacker] Found Webpack config: #{path}"
38
178
  path
39
179
  end
40
180
  end
@@ -58,6 +58,8 @@ module Shakapacker
58
58
  def self.rails_root
59
59
  if defined?(APP_ROOT)
60
60
  Pathname.new(APP_ROOT)
61
+ elsif ENV["APP_ROOT"]
62
+ Pathname.new(ENV["APP_ROOT"])
61
63
  elsif defined?(Rails)
62
64
  Rails.root
63
65
  else
@@ -1,4 +1,4 @@
1
1
  module Shakapacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "8.4.0".freeze
3
+ VERSION = "9.0.0.beta.2".freeze
4
4
  end
@@ -126,7 +126,7 @@ module Shakapacker
126
126
  end
127
127
 
128
128
  def relative_path?
129
- raw.match(%r{(\.\.|\Afile:///)}).present?
129
+ raw.match(%r{(\.\.|\Afile:)}).present?
130
130
  end
131
131
 
132
132
  def git_url?
@@ -4,48 +4,10 @@ require_relative "runner"
4
4
 
5
5
  module Shakapacker
6
6
  class WebpackRunner < Shakapacker::Runner
7
- WEBPACK_COMMANDS = [
8
- "help",
9
- "h",
10
- "--help",
11
- "-h",
12
- "version",
13
- "v",
14
- "--version",
15
- "-v",
16
- "info",
17
- "i"
18
- ].freeze
19
-
20
- def run
21
- env = Shakapacker::Compiler.env
22
- env["SHAKAPACKER_CONFIG"] = @shakapacker_config
23
- env["NODE_OPTIONS"] = ENV["NODE_OPTIONS"] || ""
24
-
25
- cmd = build_cmd
26
-
27
- if @argv.delete("--debug-shakapacker")
28
- env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk"
29
- end
30
-
31
- if @argv.delete "--trace-deprecation"
32
- env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --trace-deprecation"
33
- end
34
-
35
- if @argv.delete "--no-deprecation"
36
- env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --no-deprecation"
37
- end
38
-
39
- # Webpack commands are not compatible with --config option.
40
- if (@argv & WEBPACK_COMMANDS).empty?
41
- cmd += ["--config", @webpack_config]
42
- end
43
-
44
- cmd += @argv
45
-
46
- Dir.chdir(@app_path) do
47
- Kernel.exec env, *cmd
48
- end
7
+ def self.run(argv)
8
+ $stdout.sync = true
9
+ ENV["NODE_ENV"] ||= (ENV["RAILS_ENV"] == "production") ? "production" : "development"
10
+ new(argv).run
49
11
  end
50
12
 
51
13
  private
@@ -2,10 +2,14 @@ install_template_path = File.expand_path("../../install/template.rb", __dir__).f
2
2
  bin_path = ENV["BUNDLE_BIN"] || Rails.root.join("bin")
3
3
 
4
4
  namespace :shakapacker do
5
- desc "Install Shakapacker in this application"
6
- task install: [:check_node] do |task|
5
+ desc "Install Shakapacker in this application (use ASSETS_BUNDLER=rspack for Rspack)"
6
+ task :install, [:bundler] => [:check_node] do |task, args|
7
7
  Shakapacker::Configuration.installing = true
8
8
 
9
+ if args[:bundler] == "rspack" || ENV["ASSETS_BUNDLER"] == "rspack"
10
+ ENV["SHAKAPACKER_ASSETS_BUNDLER"] = "rspack"
11
+ end
12
+
9
13
  prefix = task.name.split(/#|shakapacker:install/).first
10
14
 
11
15
  if Rails::VERSION::MAJOR >= 5
data/package/config.js CHANGED
@@ -53,4 +53,28 @@ if (config.manifest_path) {
53
53
  // Ensure no duplicate hash functions exist in the returned config object
54
54
  config.integrity.hash_functions = [...new Set(config.integrity.hash_functions)]
55
55
 
56
+ // Allow ENV variable to override assets_bundler
57
+ if (process.env.SHAKAPACKER_ASSETS_BUNDLER) {
58
+ config.assets_bundler = process.env.SHAKAPACKER_ASSETS_BUNDLER
59
+ }
60
+
61
+ // Define clear defaults
62
+ const DEFAULT_JAVASCRIPT_TRANSPILER =
63
+ config.assets_bundler === "rspack" ? "swc" : "babel"
64
+
65
+ // Backward compatibility: Add webpack_loader property that maps to javascript_transpiler
66
+ // Show deprecation warning if webpack_loader is used
67
+ if (config.webpack_loader && !config.javascript_transpiler) {
68
+ console.warn(
69
+ "⚠️ DEPRECATION WARNING: The 'webpack_loader' configuration option is deprecated. Please use 'javascript_transpiler' instead as it better reflects its purpose of configuring JavaScript transpilation regardless of the bundler used."
70
+ )
71
+ config.javascript_transpiler = config.webpack_loader
72
+ } else if (!config.javascript_transpiler) {
73
+ config.javascript_transpiler =
74
+ config.webpack_loader || DEFAULT_JAVASCRIPT_TRANSPILER
75
+ }
76
+
77
+ // Ensure webpack_loader is always available for backward compatibility
78
+ config.webpack_loader = config.javascript_transpiler
79
+
56
80
  module.exports = config
@@ -1,16 +1,30 @@
1
1
  /* eslint global-require: 0 */
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
- const { existsSync, readdirSync } = require("fs")
5
4
  const { basename, dirname, join, relative, resolve } = require("path")
5
+ const { existsSync, readdirSync } = require("fs")
6
6
  const extname = require("path-complete-extname")
7
- // TODO: Change to `const { WebpackAssetsManifest }` when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
8
- const WebpackAssetsManifest = require("webpack-assets-manifest")
9
- const webpack = require("webpack")
10
- const rules = require("../rules")
11
7
  const config = require("../config")
12
8
  const { isProduction } = require("../env")
13
- const { moduleExists } = require("../utils/helpers")
9
+
10
+ const pluginsPath = resolve(
11
+ __dirname,
12
+ "..",
13
+ "plugins",
14
+ `${config.assets_bundler}.js`
15
+ )
16
+ const { getPlugins } = require(pluginsPath)
17
+ const rulesPath = resolve(
18
+ __dirname,
19
+ "..",
20
+ "rules",
21
+ `${config.assets_bundler}.js`
22
+ )
23
+ const rules = require(rulesPath)
24
+
25
+ // Don't use contentHash except for production for performance
26
+ // https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
27
+ const hash = isProduction || config.useContentHash ? "-[contenthash]" : ""
14
28
 
15
29
  const getFilesInDirectory = (dir, includeNested) => {
16
30
  if (!existsSync(dir)) {
@@ -73,63 +87,6 @@ const getModulePaths = () => {
73
87
  return result
74
88
  }
75
89
 
76
- // TODO: Remove WebpackAssetsManifestConstructor workaround when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
77
- const WebpackAssetsManifestConstructor =
78
- "WebpackAssetsManifest" in WebpackAssetsManifest
79
- ? WebpackAssetsManifest.WebpackAssetsManifest
80
- : WebpackAssetsManifest
81
- const getPlugins = () => {
82
- const plugins = [
83
- new webpack.EnvironmentPlugin(process.env),
84
- new WebpackAssetsManifestConstructor({
85
- entrypoints: true,
86
- writeToDisk: true,
87
- output: config.manifestPath,
88
- entrypointsUseAssets: true,
89
- publicPath: config.publicPathWithoutCDN,
90
- integrity: config.integrity.enabled,
91
- integrityHashes: config.integrity.hash_functions
92
- })
93
- ]
94
-
95
- if (moduleExists("css-loader") && moduleExists("mini-css-extract-plugin")) {
96
- const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
97
- const MiniCssExtractPlugin = require("mini-css-extract-plugin")
98
- plugins.push(
99
- new MiniCssExtractPlugin({
100
- filename: `css/[name]${hash}.css`,
101
- chunkFilename: `css/[id]${hash}.css`,
102
- // For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
103
- // the css order warnings can be disabled by setting the ignoreOrder flag.
104
- // Read: https://stackoverflow.com/questions/51971857/mini-css-extract-plugin-warning-in-chunk-chunkname-mini-css-extract-plugin-con
105
- ignoreOrder: config.css_extract_ignore_order_warnings
106
- })
107
- )
108
- }
109
-
110
- if (
111
- moduleExists("webpack-subresource-integrity") &&
112
- config.integrity.enabled
113
- ) {
114
- const {
115
- SubresourceIntegrityPlugin
116
- } = require("webpack-subresource-integrity")
117
-
118
- plugins.push(
119
- new SubresourceIntegrityPlugin({
120
- hashFuncNames: config.integrity.hash_functions,
121
- enabled: isProduction
122
- })
123
- )
124
- }
125
-
126
- return plugins
127
- }
128
-
129
- // Don't use contentHash except for production for performance
130
- // https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
131
- const hash = isProduction || config.useContentHash ? "-[contenthash]" : ""
132
-
133
90
  module.exports = {
134
91
  mode: "production",
135
92
  output: {
@@ -160,12 +117,10 @@ module.exports = {
160
117
 
161
118
  optimization: {
162
119
  splitChunks: { chunks: "all" },
163
-
164
120
  runtimeChunk: "single"
165
121
  },
166
122
 
167
123
  module: {
168
- strictExportPresence: true,
169
124
  rules
170
125
  }
171
126
  }
@@ -1,13 +1,68 @@
1
1
  const { merge } = require("webpack-merge")
2
-
2
+ const config = require("../config")
3
3
  const baseConfig = require("./base")
4
4
  const webpackDevServerConfig = require("../webpackDevServerConfig")
5
5
  const { runningWebpackDevServer } = require("../env")
6
+ const { moduleExists } = require("../utils/helpers")
6
7
 
7
- const devConfig = {
8
+ const baseDevConfig = {
8
9
  mode: "development",
9
- devtool: "cheap-module-source-map",
10
- ...(runningWebpackDevServer && { devServer: webpackDevServerConfig() })
10
+ devtool: "cheap-module-source-map"
11
+ }
12
+
13
+ const webpackDevConfig = () => {
14
+ const webpackConfig = {
15
+ ...baseDevConfig,
16
+ ...(runningWebpackDevServer && { devServer: webpackDevServerConfig() })
17
+ }
18
+
19
+ const devServerConfig = webpackDevServerConfig()
20
+ if (
21
+ runningWebpackDevServer &&
22
+ devServerConfig.hot &&
23
+ moduleExists("@pmmmwh/react-refresh-webpack-plugin")
24
+ ) {
25
+ // eslint-disable-next-line global-require
26
+ const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin")
27
+ webpackConfig.plugins = [
28
+ ...(webpackConfig.plugins || []),
29
+ new ReactRefreshWebpackPlugin()
30
+ ]
31
+ }
32
+
33
+ return webpackConfig
11
34
  }
12
35
 
13
- module.exports = merge(baseConfig, devConfig)
36
+ const rspackDevConfig = () => {
37
+ const devServerConfig = webpackDevServerConfig()
38
+ const rspackConfig = {
39
+ ...baseDevConfig,
40
+ devServer: {
41
+ ...devServerConfig,
42
+ devMiddleware: {
43
+ ...devServerConfig.devMiddleware,
44
+ writeToDisk: (filePath) => !filePath.includes(".hot-update.")
45
+ }
46
+ }
47
+ }
48
+
49
+ if (
50
+ runningWebpackDevServer &&
51
+ devServerConfig.hot &&
52
+ moduleExists("@rspack/plugin-react-refresh")
53
+ ) {
54
+ // eslint-disable-next-line global-require
55
+ const ReactRefreshPlugin = require("@rspack/plugin-react-refresh")
56
+ rspackConfig.plugins = [
57
+ ...(rspackConfig.plugins || []),
58
+ new ReactRefreshPlugin()
59
+ ]
60
+ }
61
+
62
+ return rspackConfig
63
+ }
64
+
65
+ const bundlerConfig =
66
+ config.assets_bundler === "rspack" ? rspackDevConfig() : webpackDevConfig()
67
+
68
+ module.exports = merge(baseConfig, bundlerConfig)
@@ -1,47 +1,50 @@
1
1
  /* eslint global-require: 0 */
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
+ const { resolve } = require("path")
4
5
  const { merge } = require("webpack-merge")
5
- const CompressionPlugin = require("compression-webpack-plugin")
6
- const TerserPlugin = require("terser-webpack-plugin")
7
6
  const baseConfig = require("./base")
8
7
  const { moduleExists } = require("../utils/helpers")
9
8
  const config = require("../config")
10
9
 
10
+ const optimizationPath = resolve(
11
+ __dirname,
12
+ "..",
13
+ "optimization",
14
+ `${config.assets_bundler}.js`
15
+ )
16
+ const { getOptimization } = require(optimizationPath)
17
+
18
+ let CompressionPlugin = null
19
+ if (moduleExists("compression-webpack-plugin")) {
20
+ // eslint-disable-next-line global-require
21
+ CompressionPlugin = require("compression-webpack-plugin")
22
+ }
23
+
11
24
  const getPlugins = () => {
12
25
  const plugins = []
13
26
 
14
- plugins.push(
15
- new CompressionPlugin({
16
- filename: "[path][base].gz[query]",
17
- algorithm: "gzip",
18
- test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
19
- })
20
- )
21
-
22
- if ("brotli" in process.versions) {
27
+ if (CompressionPlugin) {
23
28
  plugins.push(
24
29
  new CompressionPlugin({
25
- filename: "[path][base].br[query]",
26
- algorithm: "brotliCompress",
30
+ filename: "[path][base].gz[query]",
31
+ algorithm: "gzip",
27
32
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
28
33
  })
29
34
  )
30
- }
31
35
 
32
- return plugins
33
- }
34
-
35
- const tryCssMinimizer = () => {
36
- if (
37
- moduleExists("css-loader") &&
38
- moduleExists("css-minimizer-webpack-plugin")
39
- ) {
40
- const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
41
- return new CssMinimizerPlugin()
36
+ if ("brotli" in process.versions) {
37
+ plugins.push(
38
+ new CompressionPlugin({
39
+ filename: "[path][base].br[query]",
40
+ algorithm: "brotliCompress",
41
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
42
+ })
43
+ )
44
+ }
42
45
  }
43
46
 
44
- return null
47
+ return plugins
45
48
  }
46
49
 
47
50
  const productionConfig = {
@@ -49,32 +52,7 @@ const productionConfig = {
49
52
  stats: "normal",
50
53
  bail: true,
51
54
  plugins: getPlugins(),
52
- optimization: {
53
- minimizer: [
54
- tryCssMinimizer(),
55
- new TerserPlugin({
56
- parallel: Number.parseInt(process.env.SHAKAPACKER_PARALLEL, 10) || true,
57
- terserOptions: {
58
- parse: {
59
- // Let terser parse ecma 8 code but always output
60
- // ES5 compliant code for older browsers
61
- ecma: 8
62
- },
63
- compress: {
64
- ecma: 5,
65
- warnings: false,
66
- comparisons: false
67
- },
68
- mangle: { safari10: true },
69
- output: {
70
- ecma: 5,
71
- comments: false,
72
- ascii_only: true
73
- }
74
- }
75
- })
76
- ].filter(Boolean)
77
- }
55
+ optimization: getOptimization()
78
56
  }
79
57
 
80
58
  if (config.useContentHash === false) {
@@ -1,3 +1,19 @@
1
+ const { merge } = require("webpack-merge")
2
+ const config = require("../config")
1
3
  const baseConfig = require("./base")
2
4
 
3
- module.exports = baseConfig
5
+ const rspackTestConfig = () => ({
6
+ mode: "development",
7
+ devtool: "cheap-module-source-map",
8
+ // Disable file watching in test mode
9
+ watchOptions: {
10
+ ignored: /node_modules/
11
+ }
12
+ })
13
+
14
+ const webpackTestConfig = () => ({})
15
+
16
+ const bundlerConfig =
17
+ config.assets_bundler === "rspack" ? rspackTestConfig() : webpackTestConfig()
18
+
19
+ module.exports = merge(baseConfig, bundlerConfig)