shakapacker 8.3.0 → 9.0.0.beta.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.
- checksums.yaml +4 -4
- data/.github/STATUS.md +1 -0
- data/.github/workflows/dummy.yml +1 -1
- data/.github/workflows/generator.yml +4 -14
- data/.github/workflows/node.yml +1 -1
- data/CHANGELOG.md +17 -1
- data/Gemfile.lock +3 -3
- data/README.md +3 -3
- data/docs/css-modules-export-mode.md +288 -0
- data/docs/peer-dependencies.md +40 -0
- data/docs/react.md +2 -10
- data/docs/rspack.md +190 -0
- data/docs/subresource_integrity.md +54 -0
- data/docs/troubleshooting.md +5 -0
- data/lib/install/bin/shakapacker +14 -2
- data/lib/install/bin/shakapacker-rspack +13 -0
- data/lib/install/config/rspack/rspack.config.js +6 -0
- data/lib/install/config/shakapacker.yml +16 -3
- data/lib/install/package.json +30 -0
- data/lib/install/template.rb +13 -3
- data/lib/shakapacker/configuration.rb +16 -0
- data/lib/shakapacker/dev_server_runner.rb +17 -7
- data/lib/shakapacker/helper.rb +40 -4
- data/lib/shakapacker/manifest.rb +9 -3
- data/lib/shakapacker/rspack_runner.rb +57 -0
- data/lib/shakapacker/runner.rb +48 -2
- data/lib/shakapacker/version.rb +1 -1
- data/package/config.js +2 -0
- data/package/environments/base.js +16 -48
- data/package/environments/development.js +18 -3
- data/package/environments/production.js +24 -51
- data/package/environments/test.js +15 -1
- data/package/index.d.ts +14 -0
- data/package/index.js +4 -2
- data/package/optimization/rspack.js +25 -0
- data/package/optimization/webpack.js +49 -0
- data/package/plugins/rspack.js +104 -0
- data/package/plugins/webpack.js +62 -0
- data/package/rules/css.js +1 -1
- data/package/rules/file.js +11 -5
- data/package/rules/less.js +1 -1
- data/package/rules/raw.js +11 -1
- data/package/rules/rspack.js +96 -0
- data/package/rules/sass.js +6 -2
- data/package/rules/stylus.js +1 -1
- data/package/utils/getStyleRule.js +16 -3
- data/package/utils/requireOrError.js +15 -0
- data/package.json +19 -26
- data/test/package/config.test.js +40 -0
- data/test/package/environments/base.test.js +1 -1
- data/test/package/rules/{index.test.js → webpack.test.js} +1 -1
- data/yarn.lock +2146 -724
- metadata +22 -11
- /data/package/rules/{index.js → webpack.js} +0 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
# Subresource integrity
|
2
|
+
It's a cryptographic hash that helps browsers check that the served js or css file has not been tampered in any way.
|
3
|
+
|
4
|
+
[MDN - Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
|
5
|
+
|
6
|
+
## Important notes
|
7
|
+
- If you somehow modify the file after the hash was generated, it will automatically be considered as tampered, and the browser will not allow it to be executed.
|
8
|
+
- Enabling subresource integrity generation, will change the structure of `manifest.json`. Keep that in mind if you utilize this file in any other custom implementation.
|
9
|
+
|
10
|
+
Before:
|
11
|
+
```json
|
12
|
+
{
|
13
|
+
"application.js": "/path_to_asset"
|
14
|
+
}
|
15
|
+
```
|
16
|
+
|
17
|
+
After:
|
18
|
+
```json
|
19
|
+
{
|
20
|
+
"application.js": {
|
21
|
+
"src": "/path_to_asset",
|
22
|
+
"integrity": "<sha256-hash> <sha384-hash> <sha512-hash>"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
```
|
26
|
+
|
27
|
+
## Possible CORS issues
|
28
|
+
Enabling subresource integrity for an asset, actually enforces CORS checks on that resource too. Which means that
|
29
|
+
if you haven't set that up properly beforehand, it will probably lead to CORS errors with cached assets.
|
30
|
+
|
31
|
+
[MDN - How browsers handle Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#how_browsers_handle_subresource_integrity)
|
32
|
+
|
33
|
+
## Configuration
|
34
|
+
|
35
|
+
By default, this setting is disabled, to ensure backwards compatibility, and let developers adapt at their own pace.
|
36
|
+
This may change in the future, as it is a very nice security feature, and it should be enabled by default.
|
37
|
+
|
38
|
+
To enable it, just add this in `shakapacker.yml`
|
39
|
+
```yml
|
40
|
+
integrity:
|
41
|
+
enabled: true
|
42
|
+
```
|
43
|
+
|
44
|
+
For further customization, you can also utilize the options `hash_functions` that control the functions used to generate
|
45
|
+
integrity hashes. And `cross_origin` that sets the cross-origin loading attribute.
|
46
|
+
|
47
|
+
```yml
|
48
|
+
integrity:
|
49
|
+
enabled: true
|
50
|
+
hash_functions: ["sha256", "sha384", "sha512"]
|
51
|
+
cross_origin: "anonymous" # or "use-credentials"
|
52
|
+
```
|
53
|
+
|
54
|
+
This will utilize under the hood webpack-subresource-integrity plugin and will modify `manifest.json` to include integrity hashes.
|
data/docs/troubleshooting.md
CHANGED
@@ -17,6 +17,11 @@
|
|
17
17
|
|
18
18
|
4. You can also pass additional options to the command to run the webpack-dev-server and start the webpack-dev-server with the option `--debug-shakapacker`
|
19
19
|
|
20
|
+
5. ChatGPT and other AI tools can consume this output file. Change the NODE_ENV per your needs. Then upload the file to your favorite AI tool.
|
21
|
+
```
|
22
|
+
NODE_ENV=development bin/shakapacker --profile --json > /tmp/webpack-stats.json
|
23
|
+
```
|
24
|
+
|
20
25
|
## Incorrect peer dependencies
|
21
26
|
Shakapacker uses peer dependencies to make it easier to manage what versions are being used for your app, which is especially
|
22
27
|
useful for patching security vulnerabilities. However, not all package managers will actually enforce these versions - notably,
|
data/lib/install/bin/shakapacker
CHANGED
@@ -4,10 +4,22 @@ ENV["RAILS_ENV"] ||= "development"
|
|
4
4
|
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
5
5
|
|
6
6
|
require "bundler/setup"
|
7
|
+
require "pathname"
|
7
8
|
require "shakapacker"
|
8
|
-
require "shakapacker/webpack_runner"
|
9
9
|
|
10
10
|
APP_ROOT = File.expand_path("..", __dir__)
|
11
11
|
Dir.chdir(APP_ROOT) do
|
12
|
-
Shakapacker::
|
12
|
+
config = Shakapacker::Configuration.new(
|
13
|
+
root_path: Pathname.new(APP_ROOT),
|
14
|
+
config_path: Pathname.new(File.join(APP_ROOT, "config/shakapacker.yml")),
|
15
|
+
env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
|
16
|
+
)
|
17
|
+
|
18
|
+
if config.rspack?
|
19
|
+
require "shakapacker/rspack_runner"
|
20
|
+
Shakapacker::RspackRunner.run(ARGV)
|
21
|
+
else
|
22
|
+
require "shakapacker/webpack_runner"
|
23
|
+
Shakapacker::WebpackRunner.run(ARGV)
|
24
|
+
end
|
13
25
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
ENV["RAILS_ENV"] ||= "development"
|
4
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
5
|
+
|
6
|
+
require "bundler/setup"
|
7
|
+
require "shakapacker"
|
8
|
+
require "shakapacker/rspack_runner"
|
9
|
+
|
10
|
+
APP_ROOT = File.expand_path("..", __dir__)
|
11
|
+
Dir.chdir(APP_ROOT) do
|
12
|
+
Shakapacker::RspackRunner.run(ARGV)
|
13
|
+
end
|
@@ -39,10 +39,13 @@ default: &default
|
|
39
39
|
# Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild'
|
40
40
|
webpack_loader: 'babel'
|
41
41
|
|
42
|
+
# Select bundler to use, available options are 'webpack' (default) or 'rspack'
|
43
|
+
bundler: 'webpack'
|
44
|
+
|
42
45
|
# Raises an error if there is a mismatch in the shakapacker gem and npm package being used
|
43
46
|
ensure_consistent_versioning: true
|
44
47
|
|
45
|
-
# Select whether the compiler will use SHA digest ('digest' option) or most
|
48
|
+
# Select whether the compiler will use SHA digest ('digest' option) or most recent modified timestamp ('mtime') to determine freshness
|
46
49
|
compiler_strategy: digest
|
47
50
|
|
48
51
|
# Select whether the compiler will always use a content hash and not just in production
|
@@ -55,6 +58,16 @@ default: &default
|
|
55
58
|
# SHAKAPACKER_ASSET_HOST will override both configurations.
|
56
59
|
# asset_host: custom-path
|
57
60
|
|
61
|
+
# Utilizing webpack-subresource-integrity plugin, will generate integrity hashes for all entries in manifest.json
|
62
|
+
# https://github.com/waysact/webpack-subresource-integrity/tree/main/webpack-subresource-integrity
|
63
|
+
integrity:
|
64
|
+
enabled: false
|
65
|
+
# Which cryptographic function(s) to use, for generating the integrity hash(es). Default sha-384. Other possible values sha256, sha512
|
66
|
+
hash_functions: ["sha384"]
|
67
|
+
# Default "anonymous". Other possible value "use-credentials"
|
68
|
+
# https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#cross-origin_resource_sharing_and_subresource_integrity
|
69
|
+
cross_origin: "anonymous"
|
70
|
+
|
58
71
|
development:
|
59
72
|
<<: *default
|
60
73
|
compile: true
|
@@ -71,7 +84,7 @@ development:
|
|
71
84
|
# Hot Module Replacement updates modules while the application is running without a full reload
|
72
85
|
# Used instead of the `hot` key in https://webpack.js.org/configuration/dev-server/#devserverhot
|
73
86
|
hmr: false
|
74
|
-
# If HMR is on, CSS will
|
87
|
+
# If HMR is on, CSS will be inlined by delivering it as part of the script payload via style-loader. Be sure
|
75
88
|
# that you add style-loader to your project dependencies.
|
76
89
|
#
|
77
90
|
# If you want to instead deliver CSS via <link> with the mini-css-extract-plugin, set inline_css to false.
|
@@ -114,7 +127,7 @@ production:
|
|
114
127
|
# Production depends on precompilation of packs prior to booting for performance.
|
115
128
|
compile: false
|
116
129
|
|
117
|
-
# Use content hash for naming assets. Cannot be overridden
|
130
|
+
# Use content hash for naming assets. Cannot be overridden in production.
|
118
131
|
useContentHash: true
|
119
132
|
|
120
133
|
# Cache manifest.json for performance
|
@@ -0,0 +1,30 @@
|
|
1
|
+
{
|
2
|
+
"rspack": {
|
3
|
+
"@rspack/cli": "^1.0.0",
|
4
|
+
"@rspack/core": "^1.0.0",
|
5
|
+
"rspack-manifest-plugin": "^5.0.0"
|
6
|
+
},
|
7
|
+
"webpack": {
|
8
|
+
"mini-css-extract-plugin": "^2.0.0",
|
9
|
+
"terser-webpack-plugin": "^5.3.1",
|
10
|
+
"webpack": "^5.76.0",
|
11
|
+
"webpack-assets-manifest": "^5.0.6 || ^6.0.0",
|
12
|
+
"webpack-cli": "^4.9.2 || ^5.0.0 || ^6.0.0",
|
13
|
+
"webpack-dev-server": "^4.15.2 || ^5.2.2",
|
14
|
+
"webpack-merge": "^5.8.0 || ^6.0.0",
|
15
|
+
"webpack-subresource-integrity": "^5.1.0"
|
16
|
+
},
|
17
|
+
"common": {
|
18
|
+
"compression-webpack-plugin": "^9.0.0 || ^10.0.0|| ^11.0.0",
|
19
|
+
"css-loader": "^6.0.0 || ^7.0.0",
|
20
|
+
"sass-loader": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
21
|
+
"style-loader": "^3.0.0 || ^4.0.0"
|
22
|
+
},
|
23
|
+
"babel": {
|
24
|
+
"@babel/core": "^7.17.9",
|
25
|
+
"@babel/plugin-transform-runtime": "^7.17.0",
|
26
|
+
"@babel/preset-env": "^7.16.11",
|
27
|
+
"@babel/runtime": "^7.17.9",
|
28
|
+
"babel-loader": "^8.2.4 || ^9.0.0 || ^10.0.0"
|
29
|
+
}
|
30
|
+
}
|
data/lib/install/template.rb
CHANGED
@@ -8,7 +8,6 @@ require "package_json"
|
|
8
8
|
force_option = ENV["FORCE"] ? { force: true } : {}
|
9
9
|
|
10
10
|
copy_file "#{__dir__}/config/shakapacker.yml", "config/shakapacker.yml", force_option
|
11
|
-
remove_file "#{__dir__}/package.json" if force_option[:force]
|
12
11
|
|
13
12
|
say "Copying webpack core config"
|
14
13
|
directory "#{__dir__}/config/webpack", "config/webpack", force_option
|
@@ -112,7 +111,15 @@ rescue PackageJson::Error
|
|
112
111
|
end
|
113
112
|
|
114
113
|
def fetch_peer_dependencies
|
115
|
-
PackageJson.read("#{__dir__}
|
114
|
+
PackageJson.read("#{__dir__}").fetch(ENV["SHAKAPACKER_BUNDLER"] || "webpack")
|
115
|
+
end
|
116
|
+
|
117
|
+
def fetch_common_dependencies
|
118
|
+
ENV["SKIP_COMMON_LOADERS"] ? {} : PackageJson.read("#{__dir__}").fetch("common")
|
119
|
+
end
|
120
|
+
|
121
|
+
def fetch_babel_dependencies
|
122
|
+
ENV["USE_BABEL_PACKAGES"] ? PackageJson.read("#{__dir__}").fetch("babel") : {}
|
116
123
|
end
|
117
124
|
|
118
125
|
Dir.chdir(Rails.root) do
|
@@ -130,13 +137,16 @@ Dir.chdir(Rails.root) do
|
|
130
137
|
end
|
131
138
|
|
132
139
|
peers = fetch_peer_dependencies
|
140
|
+
peers = peers.merge(fetch_common_dependencies)
|
141
|
+
peers = peers.merge(fetch_babel_dependencies)
|
142
|
+
|
133
143
|
dev_dependency_packages = ["webpack-dev-server"]
|
134
144
|
|
135
145
|
dependencies_to_add = []
|
136
146
|
dev_dependencies_to_add = []
|
137
147
|
|
138
148
|
peers.each do |(package, version)|
|
139
|
-
major_version = version.match(/(\d+)/)[1]
|
149
|
+
major_version = version.split("||").last.match(/(\d+)/)[1]
|
140
150
|
entry = "#{package}@#{major_version}"
|
141
151
|
|
142
152
|
if dev_dependency_packages.include? package
|
@@ -88,6 +88,18 @@ class Shakapacker::Configuration
|
|
88
88
|
fetch(:compiler_strategy)
|
89
89
|
end
|
90
90
|
|
91
|
+
def bundler
|
92
|
+
fetch(:bundler) || "webpack"
|
93
|
+
end
|
94
|
+
|
95
|
+
def rspack?
|
96
|
+
bundler == "rspack"
|
97
|
+
end
|
98
|
+
|
99
|
+
def webpack?
|
100
|
+
bundler == "webpack"
|
101
|
+
end
|
102
|
+
|
91
103
|
def fetch(key)
|
92
104
|
data.fetch(key, defaults[key])
|
93
105
|
end
|
@@ -99,6 +111,10 @@ class Shakapacker::Configuration
|
|
99
111
|
)
|
100
112
|
end
|
101
113
|
|
114
|
+
def integrity
|
115
|
+
fetch(:integrity)
|
116
|
+
end
|
117
|
+
|
102
118
|
private
|
103
119
|
def data
|
104
120
|
@data ||= load
|
@@ -75,12 +75,20 @@ module Shakapacker
|
|
75
75
|
env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk --trace-warnings"
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
78
|
+
# Add bundler-specific flags and config
|
79
|
+
bundler = get_bundler_type
|
80
|
+
if bundler == "webpack"
|
81
|
+
cmd += ["--config", @webpack_config]
|
82
|
+
cmd += ["--progress", "--color"] if @pretty
|
83
|
+
# Default behavior of webpack-dev-server is @hot = true
|
84
|
+
cmd += ["--hot", "only"] if @hot == "only"
|
85
|
+
cmd += ["--no-hot"] if !@hot
|
86
|
+
elsif bundler == "rspack"
|
87
|
+
# Only add config for rspack if it's not a rspack-specific command
|
88
|
+
cmd += ["--config", @webpack_config]
|
89
|
+
# Rspack supports --hot but not --no-hot or --progress/--color
|
90
|
+
cmd += ["--hot"] if @hot && @hot != false
|
91
|
+
end
|
84
92
|
|
85
93
|
cmd += @argv
|
86
94
|
|
@@ -90,7 +98,9 @@ module Shakapacker
|
|
90
98
|
end
|
91
99
|
|
92
100
|
def build_cmd
|
93
|
-
|
101
|
+
bundler = get_bundler_type
|
102
|
+
command = bundler == "rspack" ? "rspack" : "webpack"
|
103
|
+
package_json.manager.native_exec_command(command, ["serve"])
|
94
104
|
end
|
95
105
|
end
|
96
106
|
end
|
data/lib/shakapacker/helper.rb
CHANGED
@@ -109,11 +109,11 @@ module Shakapacker::Helper
|
|
109
109
|
@javascript_pack_tag_loaded = true
|
110
110
|
|
111
111
|
capture do
|
112
|
-
|
112
|
+
render_tags(async, :javascript, **options.dup.tap { |o| o[:async] = true })
|
113
113
|
concat "\n" if async.any? && deferred.any?
|
114
|
-
|
114
|
+
render_tags(deferred, :javascript, **options.dup.tap { |o| o[:defer] = true })
|
115
115
|
concat "\n" if sync.any? && deferred.any?
|
116
|
-
|
116
|
+
render_tags(sync, :javascript, options)
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
@@ -166,7 +166,9 @@ module Shakapacker::Helper
|
|
166
166
|
|
167
167
|
@stylesheet_pack_tag_loaded = true
|
168
168
|
|
169
|
-
|
169
|
+
capture do
|
170
|
+
render_tags(requested_packs | appended_packs, :stylesheet, options)
|
171
|
+
end
|
170
172
|
end
|
171
173
|
|
172
174
|
def append_stylesheet_pack_tag(*names)
|
@@ -238,4 +240,38 @@ module Shakapacker::Helper
|
|
238
240
|
rescue
|
239
241
|
path_to_asset(current_shakapacker_instance.manifest.lookup!(name), options)
|
240
242
|
end
|
243
|
+
|
244
|
+
def lookup_integrity(source)
|
245
|
+
(source.respond_to?(:dig) && source.dig("integrity")) || nil
|
246
|
+
end
|
247
|
+
|
248
|
+
def lookup_source(source)
|
249
|
+
(source.respond_to?(:dig) && source.dig("src")) || source
|
250
|
+
end
|
251
|
+
|
252
|
+
# Handles rendering javascript and stylesheet tags with integrity, if that's enabled.
|
253
|
+
def render_tags(sources, type, options)
|
254
|
+
return unless sources.present? || type.present?
|
255
|
+
|
256
|
+
sources.each.with_index do |source, index|
|
257
|
+
tag_source = lookup_source(source)
|
258
|
+
|
259
|
+
if current_shakapacker_instance.config.integrity[:enabled]
|
260
|
+
integrity = lookup_integrity(source)
|
261
|
+
|
262
|
+
if integrity.present?
|
263
|
+
options[:integrity] = integrity
|
264
|
+
options[:crossorigin] = current_shakapacker_instance.config.integrity[:cross_origin]
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
if type == :javascript
|
269
|
+
concat javascript_include_tag(tag_source, **options)
|
270
|
+
else
|
271
|
+
concat stylesheet_link_tag(tag_source, **options)
|
272
|
+
end
|
273
|
+
|
274
|
+
concat "\n" unless index == sources.size - 1
|
275
|
+
end
|
276
|
+
end
|
241
277
|
end
|
data/lib/shakapacker/manifest.rb
CHANGED
@@ -67,7 +67,12 @@ class Shakapacker::Manifest
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def find(name)
|
70
|
-
data[name.to_s].
|
70
|
+
return nil unless data[name.to_s].present?
|
71
|
+
|
72
|
+
return data[name.to_s] unless data[name.to_s].respond_to?(:dig)
|
73
|
+
|
74
|
+
# Try to return src, if that fails, (ex. entrypoints object) return the whole object.
|
75
|
+
data[name.to_s].dig("src") || data[name.to_s]
|
71
76
|
end
|
72
77
|
|
73
78
|
def full_pack_name(name, pack_type)
|
@@ -109,9 +114,10 @@ Shakapacker can't find #{bundle_name} in #{config.manifest_path}. Possible cause
|
|
109
114
|
2. Your app has code with a non-standard extension (like a `.jsx` file) but the extension is not in the `extensions` config in `config/shakapacker.yml`
|
110
115
|
3. You have set compile: false (see `config/shakapacker.yml`) for this environment
|
111
116
|
(unless you are using the `bin/shakapacker -w` or the `bin/shakapacker-dev-server`, in which case maybe you aren't running the dev server in the background?)
|
112
|
-
4. webpack has not yet FINISHED running to reflect updates.
|
117
|
+
4. Your bundler (webpack/rspack) has not yet FINISHED running to reflect updates.
|
113
118
|
5. You have misconfigured Shakapacker's `config/shakapacker.yml` file.
|
114
|
-
6. Your
|
119
|
+
6. Your bundler configuration is not creating a manifest with the expected structure.
|
120
|
+
7. There's a mismatch between your bundler choice (webpack vs rspack) and the manifest format.
|
115
121
|
|
116
122
|
Your manifest contains:
|
117
123
|
#{JSON.pretty_generate(@data)}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
3
|
+
require_relative "runner"
|
4
|
+
|
5
|
+
module Shakapacker
|
6
|
+
class RspackRunner < Shakapacker::Runner
|
7
|
+
RSPACK_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
|
+
# Rspack commands are not compatible with --config option.
|
40
|
+
if (@argv & RSPACK_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
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def build_cmd
|
54
|
+
package_json.manager.native_exec_command("rspack")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/shakapacker/runner.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
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
|
@@ -16,7 +18,12 @@ module Shakapacker
|
|
16
18
|
|
17
19
|
@app_path = File.expand_path(".", Dir.pwd)
|
18
20
|
@shakapacker_config = ENV["SHAKAPACKER_CONFIG"] || File.join(@app_path, "config/shakapacker.yml")
|
19
|
-
@
|
21
|
+
@config = Configuration.new(
|
22
|
+
root_path: Pathname.new(@app_path),
|
23
|
+
config_path: Pathname.new(@shakapacker_config),
|
24
|
+
env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
|
25
|
+
)
|
26
|
+
@webpack_config = find_bundler_config
|
20
27
|
|
21
28
|
Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious!
|
22
29
|
end
|
@@ -26,6 +33,45 @@ module Shakapacker
|
|
26
33
|
end
|
27
34
|
|
28
35
|
private
|
36
|
+
def find_bundler_config
|
37
|
+
if @config.rspack?
|
38
|
+
find_rspack_config_with_fallback
|
39
|
+
else
|
40
|
+
find_webpack_config
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_bundler_type
|
45
|
+
@config.bundler
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_rspack_config_with_fallback
|
49
|
+
# First try rspack-specific paths
|
50
|
+
rspack_paths = %w[ts js].map do |ext|
|
51
|
+
File.join(@app_path, "config/rspack/rspack.config.#{ext}")
|
52
|
+
end
|
53
|
+
|
54
|
+
rspack_path = rspack_paths.find { |f| File.exist?(f) }
|
55
|
+
return rspack_path if rspack_path
|
56
|
+
|
57
|
+
# Fallback to webpack config with deprecation warning
|
58
|
+
webpack_paths = %w[ts js].map do |ext|
|
59
|
+
File.join(@app_path, "config/webpack/webpack.config.#{ext}")
|
60
|
+
end
|
61
|
+
|
62
|
+
webpack_path = webpack_paths.find { |f| File.exist?(f) }
|
63
|
+
if webpack_path
|
64
|
+
$stderr.puts "⚠️ DEPRECATION WARNING: Using webpack config file for Rspack bundler."
|
65
|
+
$stderr.puts " Please create config/rspack/rspack.config.js and migrate your configuration."
|
66
|
+
$stderr.puts " Using: #{webpack_path}"
|
67
|
+
return webpack_path
|
68
|
+
end
|
69
|
+
|
70
|
+
# No config found
|
71
|
+
$stderr.puts "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."
|
72
|
+
exit(1)
|
73
|
+
end
|
74
|
+
|
29
75
|
def find_webpack_config
|
30
76
|
possible_paths = %w[ts js].map do |ext|
|
31
77
|
File.join(@app_path, "config/webpack/webpack.config.#{ext}")
|
@@ -33,7 +79,7 @@ module Shakapacker
|
|
33
79
|
path = possible_paths.find { |f| File.exist?(f) }
|
34
80
|
unless path
|
35
81
|
$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
|
82
|
+
exit(1)
|
37
83
|
end
|
38
84
|
path
|
39
85
|
end
|
data/lib/shakapacker/version.rb
CHANGED
data/package/config.js
CHANGED
@@ -50,5 +50,7 @@ if (config.manifest_path) {
|
|
50
50
|
} else {
|
51
51
|
config.manifestPath = resolve(config.outputPath, "manifest.json")
|
52
52
|
}
|
53
|
+
// Ensure no duplicate hash functions exist in the returned config object
|
54
|
+
config.integrity.hash_functions = [...new Set(config.integrity.hash_functions)]
|
53
55
|
|
54
56
|
module.exports = config
|
@@ -1,16 +1,20 @@
|
|
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
|
-
|
9
|
+
|
10
|
+
const pluginsPath = resolve(__dirname, "..", "plugins", `${config.bundler}.js`)
|
11
|
+
const { getPlugins } = require(pluginsPath)
|
12
|
+
const rulesPath = resolve(__dirname, "..", "rules", `${config.bundler}.js`)
|
13
|
+
const rules = require(rulesPath)
|
14
|
+
|
15
|
+
// Don't use contentHash except for production for performance
|
16
|
+
// https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
|
17
|
+
const hash = isProduction || config.useContentHash ? "-[contenthash]" : ""
|
14
18
|
|
15
19
|
const getFilesInDirectory = (dir, includeNested) => {
|
16
20
|
if (!existsSync(dir)) {
|
@@ -73,45 +77,6 @@ const getModulePaths = () => {
|
|
73
77
|
return result
|
74
78
|
}
|
75
79
|
|
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
|
-
})
|
91
|
-
]
|
92
|
-
|
93
|
-
if (moduleExists("css-loader") && moduleExists("mini-css-extract-plugin")) {
|
94
|
-
const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
|
95
|
-
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
|
96
|
-
plugins.push(
|
97
|
-
new MiniCssExtractPlugin({
|
98
|
-
filename: `css/[name]${hash}.css`,
|
99
|
-
chunkFilename: `css/[id]${hash}.css`,
|
100
|
-
// For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
|
101
|
-
// the css order warnings can be disabled by setting the ignoreOrder flag.
|
102
|
-
// Read: https://stackoverflow.com/questions/51971857/mini-css-extract-plugin-warning-in-chunk-chunkname-mini-css-extract-plugin-con
|
103
|
-
ignoreOrder: config.css_extract_ignore_order_warnings
|
104
|
-
})
|
105
|
-
)
|
106
|
-
}
|
107
|
-
|
108
|
-
return plugins
|
109
|
-
}
|
110
|
-
|
111
|
-
// Don't use contentHash except for production for performance
|
112
|
-
// https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
|
113
|
-
const hash = isProduction || config.useContentHash ? "-[contenthash]" : ""
|
114
|
-
|
115
80
|
module.exports = {
|
116
81
|
mode: "production",
|
117
82
|
output: {
|
@@ -121,7 +86,12 @@ module.exports = {
|
|
121
86
|
// https://webpack.js.org/configuration/output/#outputhotupdatechunkfilename
|
122
87
|
hotUpdateChunkFilename: "js/[id].[fullhash].hot-update.js",
|
123
88
|
path: config.outputPath,
|
124
|
-
publicPath: config.publicPath
|
89
|
+
publicPath: config.publicPath,
|
90
|
+
|
91
|
+
// This is required for SRI to work.
|
92
|
+
crossOriginLoading: config.integrity.enabled
|
93
|
+
? config.integrity.cross_origin
|
94
|
+
: false
|
125
95
|
},
|
126
96
|
entry: getEntryObject(),
|
127
97
|
resolve: {
|
@@ -137,12 +107,10 @@ module.exports = {
|
|
137
107
|
|
138
108
|
optimization: {
|
139
109
|
splitChunks: { chunks: "all" },
|
140
|
-
|
141
110
|
runtimeChunk: "single"
|
142
111
|
},
|
143
112
|
|
144
113
|
module: {
|
145
|
-
strictExportPresence: true,
|
146
114
|
rules
|
147
115
|
}
|
148
116
|
}
|