shakapacker 9.6.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.
- checksums.yaml +4 -4
- data/.claude/commands/address-review.md +206 -0
- data/.claude/commands/update-changelog.md +86 -49
- data/.github/workflows/claude-code-review.yml +1 -1
- data/CHANGELOG.md +24 -1
- data/README.md +2 -0
- data/Rakefile +5 -0
- data/docs/node_package_api.md +70 -0
- data/docs/releasing.md +25 -18
- data/docs/rspack.md +25 -1
- data/lib/shakapacker/env.rb +17 -3
- data/lib/shakapacker/runner.rb +2 -1
- data/lib/shakapacker/version.rb +1 -1
- data/package/configExporter/cli.ts +11 -0
- data/package/plugins/webpack.ts +6 -1
- data/package.json +5 -5
- data/test/package/bundlerUtils.rspack.test.js +46 -3
- data/test/package/configExporter.test.js +32 -0
- data/test/package/plugins/webpackSubresourceIntegrity.test.js +89 -0
- data/test/package/rspack/index.test.js +43 -1
- data/yarn.lock +92 -225
- metadata +6 -2
data/docs/releasing.md
CHANGED
|
@@ -47,26 +47,29 @@ The simplest way to release is with no arguments — the task reads the version
|
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
49
|
# Recommended: reads version from CHANGELOG.md (requires step 1)
|
|
50
|
-
bundle exec rake
|
|
50
|
+
bundle exec rake release
|
|
51
51
|
|
|
52
52
|
# For a specific version (overrides CHANGELOG.md detection)
|
|
53
|
-
bundle exec rake "
|
|
53
|
+
bundle exec rake "release[9.1.0]"
|
|
54
54
|
|
|
55
55
|
# For a beta release (note: use period, not dash)
|
|
56
|
-
bundle exec rake "
|
|
56
|
+
bundle exec rake "release[9.2.0.beta.1]" # Creates npm package 9.2.0-beta.1
|
|
57
57
|
|
|
58
58
|
# For a release candidate
|
|
59
|
-
bundle exec rake "
|
|
59
|
+
bundle exec rake "release[9.6.0.rc.0]"
|
|
60
60
|
|
|
61
61
|
# Dry run to test without publishing
|
|
62
|
-
bundle exec rake "
|
|
62
|
+
bundle exec rake "release[9.1.0,true]"
|
|
63
|
+
|
|
64
|
+
# Skip interactive confirmations (for scripted maintainer runs)
|
|
65
|
+
AUTO_CONFIRM=true bundle exec rake release
|
|
63
66
|
|
|
64
67
|
# Override version policy checks (monotonic + changelog/bump consistency)
|
|
65
|
-
RELEASE_VERSION_POLICY_OVERRIDE=true bundle exec rake "
|
|
66
|
-
bundle exec rake "
|
|
68
|
+
RELEASE_VERSION_POLICY_OVERRIDE=true bundle exec rake "release[9.1.0]"
|
|
69
|
+
bundle exec rake "release[9.1.0,false,true]"
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
When called with no arguments, `
|
|
72
|
+
When called with no arguments, `release`:
|
|
70
73
|
|
|
71
74
|
1. Reads the first versioned header from CHANGELOG.md (e.g., `## [v9.6.0]`)
|
|
72
75
|
2. Compares it to the current gem version
|
|
@@ -74,8 +77,9 @@ When called with no arguments, `create_release`:
|
|
|
74
77
|
4. If no new version is found, falls back to a patch bump
|
|
75
78
|
|
|
76
79
|
Dry runs use a temporary git worktree so version bumps and installs do not modify your current checkout.
|
|
80
|
+
Dry runs now also print explicit "skipping confirmation" messages and the would-run GitHub release command.
|
|
77
81
|
|
|
78
|
-
`
|
|
82
|
+
`release` validates release-version policy before publishing:
|
|
79
83
|
|
|
80
84
|
- Target version must be greater than the latest tagged release.
|
|
81
85
|
- If the versioned target changelog section exists (`## [vX.Y.Z...]`; not `UNRELEASED`), it maps to expected bump type:
|
|
@@ -87,11 +91,11 @@ Dry runs use a temporary git worktree so version bumps and installs do not modif
|
|
|
87
91
|
Use override only when needed:
|
|
88
92
|
|
|
89
93
|
- `RELEASE_VERSION_POLICY_OVERRIDE=true`
|
|
90
|
-
- Or task arg override (`
|
|
94
|
+
- Or task arg override (`release[..., ..., true]`)
|
|
91
95
|
|
|
92
96
|
### 3. What the Release Task Does
|
|
93
97
|
|
|
94
|
-
The `
|
|
98
|
+
The `release` task automatically:
|
|
95
99
|
|
|
96
100
|
1. **Validates release prerequisites**:
|
|
97
101
|
- Verifies npm authentication
|
|
@@ -108,7 +112,8 @@ The `create_release` task automatically:
|
|
|
108
112
|
- Prompts for RubyGems OTP (2FA code)
|
|
109
113
|
6. **Updates spec/dummy lockfiles:**
|
|
110
114
|
- Runs `bundle install` to update `Gemfile.lock`
|
|
111
|
-
- Runs `
|
|
115
|
+
- Runs `yarn install` to refresh the Yarn-managed dummy app lockfile
|
|
116
|
+
- Runs `npm install` to keep `package-lock.json` in sync for npm compatibility/testing
|
|
112
117
|
7. **Commits and pushes lockfile changes** automatically
|
|
113
118
|
8. **Creates GitHub release** from CHANGELOG.md (if the matching section exists)
|
|
114
119
|
|
|
@@ -133,24 +138,26 @@ The task automatically converts Ruby gem format to npm semver format:
|
|
|
133
138
|
|
|
134
139
|
```bash
|
|
135
140
|
# Regular release
|
|
136
|
-
bundle exec rake "
|
|
141
|
+
bundle exec rake "release[9.1.0]" # Gem: 9.1.0, npm: 9.1.0
|
|
137
142
|
|
|
138
143
|
# Beta release
|
|
139
|
-
bundle exec rake "
|
|
144
|
+
bundle exec rake "release[9.2.0.beta.1]" # Gem: 9.2.0.beta.1, npm: 9.2.0-beta.1
|
|
140
145
|
|
|
141
146
|
# Release candidate
|
|
142
|
-
bundle exec rake "
|
|
147
|
+
bundle exec rake "release[10.0.0.rc.1]" # Gem: 10.0.0.rc.1, npm: 10.0.0-rc.1
|
|
143
148
|
|
|
144
|
-
# Prerelease: use /update-changelog rc first, then
|
|
145
|
-
bundle exec rake
|
|
149
|
+
# Prerelease: use /update-changelog rc first, then release reads it
|
|
150
|
+
bundle exec rake release # reads v10.0.0-rc.0 from CHANGELOG.md
|
|
146
151
|
```
|
|
147
152
|
|
|
148
153
|
### 5. During the Release
|
|
149
154
|
|
|
155
|
+
If you are running non-interactively, set `AUTO_CONFIRM=true` to skip confirmation prompts.
|
|
156
|
+
|
|
150
157
|
1. When prompted for **npm OTP**, enter your 2FA code from your authenticator app
|
|
151
158
|
2. Accept defaults for release-it options
|
|
152
159
|
3. When prompted for **RubyGems OTP**, enter your 2FA code
|
|
153
|
-
4. If using `
|
|
160
|
+
4. If using `release` with no version, confirm the version detected from CHANGELOG.md (or the computed patch version)
|
|
154
161
|
5. The script will automatically commit and push lockfile updates
|
|
155
162
|
6. The script will automatically create a GitHub release (if CHANGELOG.md section exists)
|
|
156
163
|
|
data/docs/rspack.md
CHANGED
|
@@ -4,9 +4,33 @@ Shakapacker supports [Rspack](https://rspack.rs) as an alternative assets bundle
|
|
|
4
4
|
|
|
5
5
|
**📖 For configuration options, see the [Configuration Guide](./configuration.md)**
|
|
6
6
|
|
|
7
|
+
## Version Compatibility
|
|
8
|
+
|
|
9
|
+
Shakapacker supports both Rspack v1 (`^1.0.0`) and Rspack v2 (`^2.0.0-0`). No configuration changes are needed when upgrading between rspack versions — shakapacker's generated config works with both.
|
|
10
|
+
|
|
11
|
+
**Rspack v2 note:** Rspack v2 ships as a pure ESM package and requires **Node.js 20.19.0+**.
|
|
12
|
+
|
|
13
|
+
**Rspack v1 note:** Rspack v1 itself supports older Node versions, but Shakapacker requires Node 20+.
|
|
14
|
+
|
|
15
|
+
**React refresh plugin note:** `@rspack/plugin-react-refresh` currently remains on the v1 line in Shakapacker peer deps.
|
|
16
|
+
|
|
17
|
+
**Current CI coverage note:** Shakapacker currently validates rspack v2 using `2.0.0-beta.6`. The rspack v2 dev dependencies are intentionally pinned while v2 is in beta and should be revisited when stable `2.0.0` is released.
|
|
18
|
+
|
|
19
|
+
### Why upgrade to Rspack v2?
|
|
20
|
+
|
|
21
|
+
- **Persistent cache with proper invalidation** — Rspack v2 promotes persistent caching (`cache.type: 'filesystem'`) from experimental to stable, with portable cache support (`cache.portable`) and read-only cache for CI (`cache.readonly`). This means fast rebuilds that survive process restarts and are properly invalidated when dependencies change.
|
|
22
|
+
- **Incremental compilation (stable)** — The `incremental` option moves from `experiments` to a top-level config, signaling it's production-ready. Incremental builds skip unchanged work in the dependency graph.
|
|
23
|
+
- **Better tree shaking** — CJS `require()` destructuring and variable property access are now tree-shaken, and Module Federation shares can be tree-shaken.
|
|
24
|
+
- **Unified target configuration** — A single `target` setting now propagates defaults to SWC and LightningCSS automatically, eliminating redundant per-loader configuration.
|
|
25
|
+
- **Stricter export validation** — `exportsPresence` defaults to `'error'`, catching missing or misspelled exports at build time instead of silently producing broken bundles.
|
|
26
|
+
- **React Server Components** — Built-in RSC support for frameworks.
|
|
27
|
+
- **Performance** — Dozens of Rust-level optimizations across every beta release (hash caching, regex fast paths, reduced allocations, rayon parallelism).
|
|
28
|
+
|
|
29
|
+
See the [Rspack v2 breaking changes discussion](https://github.com/web-infra-dev/rspack/discussions/9270) for full details.
|
|
30
|
+
|
|
7
31
|
## Installation
|
|
8
32
|
|
|
9
|
-
|
|
33
|
+
Install the required Rspack dependencies:
|
|
10
34
|
|
|
11
35
|
```bash
|
|
12
36
|
npm install @rspack/core @rspack/cli -D
|
data/lib/shakapacker/env.rb
CHANGED
|
@@ -13,16 +13,30 @@ class Shakapacker::Env
|
|
|
13
13
|
|
|
14
14
|
def inquire
|
|
15
15
|
fallback_env_warning if config_path.exist? && !current
|
|
16
|
-
current || FALLBACK_ENV.inquiry
|
|
16
|
+
(current || FALLBACK_ENV).inquiry
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
private
|
|
20
20
|
def current
|
|
21
|
-
Rails.env
|
|
21
|
+
env = if defined?(Rails) && Rails.respond_to?(:env)
|
|
22
|
+
Rails.env
|
|
23
|
+
else
|
|
24
|
+
ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || Shakapacker::DEFAULT_ENV
|
|
25
|
+
end
|
|
26
|
+
env.presence_in(available_environments)
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def fallback_env_warning
|
|
25
|
-
|
|
30
|
+
env_value = if defined?(Rails) && Rails.respond_to?(:env)
|
|
31
|
+
Rails.env
|
|
32
|
+
else
|
|
33
|
+
ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || Shakapacker::DEFAULT_ENV
|
|
34
|
+
end
|
|
35
|
+
logger.info "RAILS_ENV=#{env_value} environment is not defined in #{config_path}, falling back to #{FALLBACK_ENV} environment"
|
|
36
|
+
rescue NameError, NoMethodError
|
|
37
|
+
# Logger may not be fully functional without Rails (e.g., ActiveSupport::IsolatedExecutionState
|
|
38
|
+
# is not available). Fall back to puts, matching Configuration#log_fallback.
|
|
39
|
+
puts "RAILS_ENV=#{env_value} environment is not defined in #{config_path}, falling back to #{FALLBACK_ENV} environment"
|
|
26
40
|
end
|
|
27
41
|
|
|
28
42
|
def available_environments
|
data/lib/shakapacker/runner.rb
CHANGED
|
@@ -296,7 +296,8 @@ module Shakapacker
|
|
|
296
296
|
if child_pid
|
|
297
297
|
Process.kill("TERM", child_pid)
|
|
298
298
|
else
|
|
299
|
-
|
|
299
|
+
# Signal arrived before spawn completed; re-raise so the process exits normally.
|
|
300
|
+
raise SignalException, "TERM"
|
|
300
301
|
end
|
|
301
302
|
rescue Errno::ESRCH
|
|
302
303
|
nil
|
data/lib/shakapacker/version.rb
CHANGED
|
@@ -712,6 +712,17 @@ async function runAllBuildsCommand(options: ExportOptions): Promise<number> {
|
|
|
712
712
|
// Apply defaults
|
|
713
713
|
const resolvedOptions = applyDefaults(options)
|
|
714
714
|
|
|
715
|
+
// Validate paths for security in all-builds mode.
|
|
716
|
+
// saveDir is always set by applyDefaults(); --output is not used in --all-builds mode.
|
|
717
|
+
safeResolvePath(appRoot, resolvedOptions.saveDir!)
|
|
718
|
+
|
|
719
|
+
// Keep in sync with validation in run()
|
|
720
|
+
if (resolvedOptions.annotate && resolvedOptions.format !== "yaml") {
|
|
721
|
+
throw new Error(
|
|
722
|
+
"Annotation requires YAML format. Use --no-annotate or --format=yaml."
|
|
723
|
+
)
|
|
724
|
+
}
|
|
725
|
+
|
|
715
726
|
const loader = new ConfigFileLoader(resolvedOptions.configFile)
|
|
716
727
|
if (!loader.exists()) {
|
|
717
728
|
const configPath = resolvedOptions.configFile || DEFAULT_CONFIG_FILE
|
data/package/plugins/webpack.ts
CHANGED
|
@@ -58,9 +58,14 @@ const getPlugins = (): unknown[] => {
|
|
|
58
58
|
config.integrity?.enabled &&
|
|
59
59
|
moduleExists("webpack-subresource-integrity")
|
|
60
60
|
) {
|
|
61
|
-
|
|
61
|
+
// webpack-subresource-integrity v5+ exports the plugin as a named export.
|
|
62
|
+
const subresourceIntegrityModule = requireOrError(
|
|
62
63
|
"webpack-subresource-integrity"
|
|
63
64
|
)
|
|
65
|
+
const SubresourceIntegrityPlugin =
|
|
66
|
+
"SubresourceIntegrityPlugin" in subresourceIntegrityModule
|
|
67
|
+
? subresourceIntegrityModule.SubresourceIntegrityPlugin
|
|
68
|
+
: subresourceIntegrityModule
|
|
64
69
|
plugins.push(
|
|
65
70
|
new SubresourceIntegrityPlugin({
|
|
66
71
|
hashFuncNames: config.integrity.hash_functions,
|
data/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shakapacker",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.7.0",
|
|
4
4
|
"description": "Use webpack to manage app-like JavaScript modules in Rails",
|
|
5
5
|
"homepage": "https://github.com/shakacode/shakapacker",
|
|
6
6
|
"bugs": {
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@eslint/eslintrc": "^3.2.0",
|
|
53
53
|
"@eslint/js": "^9.37.0",
|
|
54
|
-
"@rspack/cli": "
|
|
55
|
-
"@rspack/core": "
|
|
54
|
+
"@rspack/cli": "2.0.0-beta.6",
|
|
55
|
+
"@rspack/core": "2.0.0-beta.6",
|
|
56
56
|
"@swc/core": "^1.3.0",
|
|
57
57
|
"@types/babel__core": "^7.20.5",
|
|
58
58
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -99,8 +99,8 @@
|
|
|
99
99
|
"@babel/plugin-transform-runtime": "^7.17.0",
|
|
100
100
|
"@babel/preset-env": "^7.16.11",
|
|
101
101
|
"@babel/runtime": "^7.17.9",
|
|
102
|
-
"@rspack/cli": "^1.0.0",
|
|
103
|
-
"@rspack/core": "^1.0.0",
|
|
102
|
+
"@rspack/cli": "^1.0.0 || ^2.0.0-0",
|
|
103
|
+
"@rspack/core": "^1.0.0 || ^2.0.0-0",
|
|
104
104
|
"@rspack/plugin-react-refresh": "^1.0.0",
|
|
105
105
|
"@swc/core": "^1.3.0",
|
|
106
106
|
"@types/babel__core": "^7.0.0",
|
|
@@ -5,6 +5,43 @@
|
|
|
5
5
|
* then re-require bundlerUtils to exercise the rspack branches.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// Mock requireOrError to provide a fake @rspack/core (v2 is pure ESM, can't be require()'d by Jest)
|
|
9
|
+
jest.mock("../../package/utils/requireOrError", () => {
|
|
10
|
+
const CssExtractRspackPlugin = jest.fn(function (options) {
|
|
11
|
+
this.options = options
|
|
12
|
+
})
|
|
13
|
+
CssExtractRspackPlugin.loader = "css-extract-rspack-loader"
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
requireOrError: (moduleName) => {
|
|
17
|
+
if (moduleName === "@rspack/core") {
|
|
18
|
+
return {
|
|
19
|
+
DefinePlugin: jest.fn(function (definitions) {
|
|
20
|
+
this.definitions = definitions
|
|
21
|
+
}),
|
|
22
|
+
EnvironmentPlugin: jest.fn(function (env) {
|
|
23
|
+
this.env = env
|
|
24
|
+
}),
|
|
25
|
+
ProvidePlugin: jest.fn(function (definitions) {
|
|
26
|
+
this.definitions = definitions
|
|
27
|
+
}),
|
|
28
|
+
HotModuleReplacementPlugin: jest.fn(),
|
|
29
|
+
ProgressPlugin: jest.fn(),
|
|
30
|
+
CssExtractRspackPlugin,
|
|
31
|
+
SubresourceIntegrityPlugin: jest.fn(function (options) {
|
|
32
|
+
this.options = options
|
|
33
|
+
}),
|
|
34
|
+
SwcJsMinimizerRspackPlugin: jest.fn(),
|
|
35
|
+
LightningCssMinimizerRspackPlugin: jest.fn()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return jest
|
|
39
|
+
.requireActual("../../package/utils/requireOrError")
|
|
40
|
+
.requireOrError(moduleName)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
|
|
8
45
|
let bundlerUtils
|
|
9
46
|
|
|
10
47
|
describe("bundlerUtils with rspack", () => {
|
|
@@ -80,7 +117,9 @@ describe("bundlerUtils with rspack", () => {
|
|
|
80
117
|
test("returns rspack DefinePlugin", () => {
|
|
81
118
|
const DefinePlugin = bundlerUtils.getDefinePlugin()
|
|
82
119
|
expect(DefinePlugin).toBeDefined()
|
|
83
|
-
|
|
120
|
+
|
|
121
|
+
const instance = new DefinePlugin({ FOO: "bar" })
|
|
122
|
+
expect(instance.definitions).toStrictEqual({ FOO: "bar" })
|
|
84
123
|
})
|
|
85
124
|
})
|
|
86
125
|
|
|
@@ -88,7 +127,9 @@ describe("bundlerUtils with rspack", () => {
|
|
|
88
127
|
test("returns rspack EnvironmentPlugin", () => {
|
|
89
128
|
const EnvironmentPlugin = bundlerUtils.getEnvironmentPlugin()
|
|
90
129
|
expect(EnvironmentPlugin).toBeDefined()
|
|
91
|
-
|
|
130
|
+
|
|
131
|
+
const instance = new EnvironmentPlugin(["NODE_ENV"])
|
|
132
|
+
expect(instance.env).toStrictEqual(["NODE_ENV"])
|
|
92
133
|
})
|
|
93
134
|
})
|
|
94
135
|
|
|
@@ -96,7 +137,9 @@ describe("bundlerUtils with rspack", () => {
|
|
|
96
137
|
test("returns rspack ProvidePlugin", () => {
|
|
97
138
|
const ProvidePlugin = bundlerUtils.getProvidePlugin()
|
|
98
139
|
expect(ProvidePlugin).toBeDefined()
|
|
99
|
-
|
|
140
|
+
|
|
141
|
+
const instance = new ProvidePlugin({ React: "react" })
|
|
142
|
+
expect(instance.definitions).toStrictEqual({ React: "react" })
|
|
100
143
|
})
|
|
101
144
|
})
|
|
102
145
|
})
|
|
@@ -455,5 +455,37 @@ describe("configExporter", () => {
|
|
|
455
455
|
parseArguments(["--all-builds", "--save-dir=./configs"])
|
|
456
456
|
}).not.toThrow()
|
|
457
457
|
})
|
|
458
|
+
|
|
459
|
+
test("run rejects --all-builds with annotate and non-yaml format", async () => {
|
|
460
|
+
const { run } = require("../../package/configExporter/cli")
|
|
461
|
+
const mockConsoleError = jest
|
|
462
|
+
.spyOn(console, "error")
|
|
463
|
+
.mockImplementation(() => {})
|
|
464
|
+
|
|
465
|
+
const result = await run(["--all-builds", "--annotate", "--format=json"])
|
|
466
|
+
|
|
467
|
+
expect(result).toBe(1)
|
|
468
|
+
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
469
|
+
expect.stringContaining("Annotation requires YAML format")
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
mockConsoleError.mockRestore()
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
test("run validates --all-builds save-dir path traversal", async () => {
|
|
476
|
+
const { run } = require("../../package/configExporter/cli")
|
|
477
|
+
const mockConsoleError = jest
|
|
478
|
+
.spyOn(console, "error")
|
|
479
|
+
.mockImplementation(() => {})
|
|
480
|
+
|
|
481
|
+
const result = await run(["--all-builds", "--save-dir=../outside"])
|
|
482
|
+
|
|
483
|
+
expect(result).toBe(1)
|
|
484
|
+
expect(mockConsoleError).toHaveBeenCalledWith(
|
|
485
|
+
expect.stringContaining("[SHAKAPACKER SECURITY] Path traversal attempt")
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
mockConsoleError.mockRestore()
|
|
489
|
+
})
|
|
458
490
|
})
|
|
459
491
|
})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const loadPluginsWithSriModule = (sriModule) => {
|
|
2
|
+
let getPlugins
|
|
3
|
+
|
|
4
|
+
jest.isolateModules(() => {
|
|
5
|
+
jest.doMock("../../../package/config", () => ({
|
|
6
|
+
manifestPath: "public/packs/manifest.json",
|
|
7
|
+
publicPathWithoutCDN: "/packs/",
|
|
8
|
+
integrity: {
|
|
9
|
+
enabled: true,
|
|
10
|
+
hash_functions: ["sha256"]
|
|
11
|
+
},
|
|
12
|
+
css_extract_ignore_order_warnings: false,
|
|
13
|
+
useContentHash: false
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
jest.doMock("../../../package/env", () => ({
|
|
17
|
+
isProduction: true
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
jest.doMock("../../../package/utils/helpers", () => ({
|
|
21
|
+
moduleExists: (moduleName) =>
|
|
22
|
+
moduleName === "webpack-subresource-integrity"
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
jest.doMock("../../../package/utils/ensureManifestExists", () => ({
|
|
26
|
+
__esModule: true,
|
|
27
|
+
default: jest.fn()
|
|
28
|
+
}))
|
|
29
|
+
|
|
30
|
+
jest.doMock("../../../package/utils/requireOrError", () => ({
|
|
31
|
+
requireOrError: (moduleName) => {
|
|
32
|
+
if (moduleName === "webpack-assets-manifest") {
|
|
33
|
+
return function WebpackAssetsManifest() {}
|
|
34
|
+
}
|
|
35
|
+
if (moduleName === "webpack") {
|
|
36
|
+
return {
|
|
37
|
+
EnvironmentPlugin: function EnvironmentPlugin() {}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (moduleName === "webpack-subresource-integrity") {
|
|
41
|
+
return sriModule
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error(`Unexpected module request: ${moduleName}`)
|
|
45
|
+
}
|
|
46
|
+
}))
|
|
47
|
+
;({ getPlugins } = require("../../../package/plugins/webpack"))
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return getPlugins
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("webpack plugins - webpack-subresource-integrity compatibility", () => {
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
jest.clearAllMocks()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test("supports webpack-subresource-integrity v5 named export", () => {
|
|
59
|
+
const SubresourceIntegrityPlugin = jest.fn(
|
|
60
|
+
function SubresourceIntegrityPluginMock(options) {
|
|
61
|
+
this.options = options
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
const getPlugins = loadPluginsWithSriModule({ SubresourceIntegrityPlugin })
|
|
65
|
+
|
|
66
|
+
getPlugins()
|
|
67
|
+
|
|
68
|
+
expect(SubresourceIntegrityPlugin).toHaveBeenCalledWith({
|
|
69
|
+
hashFuncNames: ["sha256"],
|
|
70
|
+
enabled: true
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test("supports webpack-subresource-integrity default export", () => {
|
|
75
|
+
const SubresourceIntegrityPlugin = jest.fn(
|
|
76
|
+
function SubresourceIntegrityPluginMock(options) {
|
|
77
|
+
this.options = options
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
const getPlugins = loadPluginsWithSriModule(SubresourceIntegrityPlugin)
|
|
81
|
+
|
|
82
|
+
getPlugins()
|
|
83
|
+
|
|
84
|
+
expect(SubresourceIntegrityPlugin).toHaveBeenCalledWith({
|
|
85
|
+
hashFuncNames: ["sha256"],
|
|
86
|
+
enabled: true
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint-disable jest/no-conditional-in-test */
|
|
1
|
+
/* eslint-disable func-names, jest/no-conditional-in-test */
|
|
2
2
|
|
|
3
3
|
const { chdirTestApp } = require("../../helpers")
|
|
4
4
|
|
|
@@ -29,6 +29,48 @@ jest.mock("../../../package/utils/validateDependencies", () => ({
|
|
|
29
29
|
validateRspackDependencies: jest.fn()
|
|
30
30
|
}))
|
|
31
31
|
|
|
32
|
+
// Mock requireOrError to provide a fake @rspack/core (v2 is pure ESM, can't be require()'d by Jest)
|
|
33
|
+
jest.mock("../../../package/utils/requireOrError", () => ({
|
|
34
|
+
requireOrError: (moduleName) => {
|
|
35
|
+
if (moduleName === "@rspack/core") {
|
|
36
|
+
const CssExtractRspackPlugin = jest.fn(function (options) {
|
|
37
|
+
this.options = options
|
|
38
|
+
})
|
|
39
|
+
CssExtractRspackPlugin.loader = "css-extract-rspack-loader"
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
DefinePlugin: jest.fn(function (definitions) {
|
|
43
|
+
this.definitions = definitions
|
|
44
|
+
}),
|
|
45
|
+
EnvironmentPlugin: jest.fn(function (env) {
|
|
46
|
+
this.env = env
|
|
47
|
+
}),
|
|
48
|
+
ProvidePlugin: jest.fn(function (definitions) {
|
|
49
|
+
this.definitions = definitions
|
|
50
|
+
}),
|
|
51
|
+
HotModuleReplacementPlugin: jest.fn(),
|
|
52
|
+
ProgressPlugin: jest.fn(),
|
|
53
|
+
CssExtractRspackPlugin,
|
|
54
|
+
SubresourceIntegrityPlugin: jest.fn(function (options) {
|
|
55
|
+
this.options = options
|
|
56
|
+
}),
|
|
57
|
+
SwcJsMinimizerRspackPlugin: jest.fn(),
|
|
58
|
+
LightningCssMinimizerRspackPlugin: jest.fn()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (moduleName === "rspack-manifest-plugin") {
|
|
62
|
+
return {
|
|
63
|
+
RspackManifestPlugin: jest.fn(function (options) {
|
|
64
|
+
this.options = options
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return jest
|
|
69
|
+
.requireActual("../../../package/utils/requireOrError")
|
|
70
|
+
.requireOrError(moduleName)
|
|
71
|
+
}
|
|
72
|
+
}))
|
|
73
|
+
|
|
32
74
|
describe("rspack/index", () => {
|
|
33
75
|
let rspackIndex
|
|
34
76
|
let validateRspackDependencies
|