shakapacker 9.5.0 → 9.6.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/workflows/claude-code-review.yml +6 -15
- data/.github/workflows/claude.yml +3 -2
- data/.prettierignore +4 -0
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +32 -4
- data/CLAUDE.md +8 -0
- data/bin/conductor-exec +24 -0
- data/conductor-setup.sh +116 -39
- data/conductor.json +3 -1
- data/docs/early_hints.md +9 -2
- data/docs/precompile_hook.md +46 -0
- data/lib/install/template.rb +8 -4
- data/lib/shakapacker/configuration.rb +1 -1
- data/lib/shakapacker/dev_server_runner.rb +1 -3
- data/lib/shakapacker/helper.rb +2 -0
- data/lib/shakapacker/runner.rb +12 -1
- data/lib/shakapacker/version.rb +1 -1
- data/lib/shakapacker.rb +11 -4
- data/package/config.ts +4 -0
- data/package/rules/file.ts +1 -1
- data/package/rules/sass.ts +1 -0
- data/package/types.ts +1 -0
- data/package.json +1 -1
- data/test/package/config.test.js +11 -0
- data/test/package/rules/file.test.js +4 -0
- data/test/package/rules/sass1.test.js +4 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 16a87e8e339c085afc34f5f70af6fee7aa534590949f02faa1863d9c5e7f9f7d
|
|
4
|
+
data.tar.gz: 19d1f859e00dc29bfe4c593ba1b4a1e5b64c6347fc1b56a2cbabcc8c8020205b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4286284b7cbbec5324ce2ad26c6d6892cfcecae96e31c7324ff0a533f332301b4008e7083592b3b4b639be131758ab6fa5bc81ed46ac0903f2370f20a05fae0
|
|
7
|
+
data.tar.gz: e4e6bfdd5837dabfd9f5d031e5a1d905ca88b6c1d50b1f3d440fb3f3c6a23d0abbec1d8839a769536af52d67eed5657ec602786c824dd57156f1678026ec300e
|
|
@@ -2,7 +2,7 @@ name: Claude Code Review
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
|
-
types: [opened, synchronize]
|
|
5
|
+
types: [opened, synchronize, ready_for_review, reopened]
|
|
6
6
|
# Optional: Only run on specific file changes
|
|
7
7
|
# paths:
|
|
8
8
|
# - "src/**/*.ts"
|
|
@@ -36,18 +36,9 @@ jobs:
|
|
|
36
36
|
uses: anthropics/claude-code-action@v1
|
|
37
37
|
with:
|
|
38
38
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- Potential bugs or issues
|
|
43
|
-
- Performance considerations
|
|
44
|
-
- Security concerns
|
|
45
|
-
- Test coverage
|
|
46
|
-
|
|
47
|
-
Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.
|
|
48
|
-
|
|
49
|
-
Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
|
|
50
|
-
|
|
39
|
+
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
|
40
|
+
plugins: 'code-review@claude-code-plugins'
|
|
41
|
+
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
|
51
42
|
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
52
|
-
# or https://
|
|
53
|
-
|
|
43
|
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
|
44
|
+
|
|
@@ -45,5 +45,6 @@ jobs:
|
|
|
45
45
|
|
|
46
46
|
# Optional: Add claude_args to customize behavior and configuration
|
|
47
47
|
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
48
|
-
# or https://
|
|
49
|
-
# claude_args: '--
|
|
48
|
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
|
49
|
+
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
|
50
|
+
|
data/.prettierignore
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
# Template files that should maintain their original quote style
|
|
2
2
|
lib/install/config/**/*.ts
|
|
3
3
|
lib/install/config/**/*.js
|
|
4
|
+
|
|
5
|
+
# Temporarily ignore workflow files that cannot be modified in PRs due to claude-review validation
|
|
6
|
+
.github/workflows/claude.yml
|
|
7
|
+
.github/workflows/claude-code-review.yml
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -11,7 +11,38 @@
|
|
|
11
11
|
|
|
12
12
|
Changes since the last non-beta release.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **BREAKING: sass-loader now defaults to modern Sass API**. [PR #879](https://github.com/shakacode/shakapacker/pull/879) by [justin808](https://github.com/justin808). The sass-loader configuration now uses `api: "modern"` instead of the deprecated legacy API. This improves compatibility with plugins like sass-resources-loader that require the modern API. If you experience issues after upgrading, you can revert to the legacy API by customizing your webpack config:
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
// config/webpack/webpack.config.js
|
|
20
|
+
const { generateWebpackConfig } = require("shakapacker")
|
|
21
|
+
const config = generateWebpackConfig()
|
|
22
|
+
|
|
23
|
+
// Find and modify sass-loader options
|
|
24
|
+
config.module.rules.forEach((rule) => {
|
|
25
|
+
if (rule.use) {
|
|
26
|
+
rule.use.forEach((loader) => {
|
|
27
|
+
if (loader.loader?.includes("sass-loader")) {
|
|
28
|
+
loader.options.api = "legacy"
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
module.exports = config
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- **Fixed orphaned webpack/rspack processes when foreman receives SIGTERM**. [PR #888](https://github.com/shakacode/shakapacker/pull/888) by [jordan-brough](https://github.com/jordan-brough). When running under foreman, sending SIGTERM to foreman (e.g. `kill <pid>`) would kill the Ruby shakapacker process but leave the webpack/rspack child process running as an orphan. DevServerRunner now uses `exec` to replace the Ruby process entirely, and Runner uses `spawn` with SIGTERM forwarding to ensure the child process is properly terminated.
|
|
40
|
+
- **Fixed installer writing wrong shakapacker version in package.json**. [PR #899](https://github.com/shakacode/shakapacker/pull/899) by [justin808](https://github.com/justin808). The `shakapacker:install` generator now keeps the `package.json` dependency value in sync with the exact version or path that was requested, instead of relying on the post-install value which could differ.
|
|
41
|
+
- **Fixed NODE_ENV=test causing DefinePlugin warnings**. [PR #870](https://github.com/shakacode/shakapacker/pull/870) by [justin808](https://github.com/justin808). When RAILS_ENV=test, Shakapacker now sets NODE_ENV=development instead of NODE_ENV=test. This prevents webpack/rspack DefinePlugin conflicts since these bundlers only recognize "development" and "production" as valid NODE_ENV values.
|
|
42
|
+
|
|
43
|
+
### Documentation
|
|
44
|
+
|
|
45
|
+
- **Added CDN limitation warnings for Early Hints feature**. [PR #878](https://github.com/shakacode/shakapacker/pull/878) by [justin808](https://github.com/justin808). The early hints documentation now prominently notes that most CDNs (Cloudflare, AWS CloudFront, AWS ALB) strip HTTP 103 responses before they reach end users. Debug mode also includes CDN warnings in HTML comments.
|
|
15
46
|
|
|
16
47
|
## [v9.5.0] - January 7, 2026
|
|
17
48
|
|
|
@@ -256,7 +287,6 @@ See the [v9 Upgrade Guide](https://github.com/shakacode/shakapacker/blob/main/do
|
|
|
256
287
|
### ⚠️ Breaking Changes
|
|
257
288
|
|
|
258
289
|
1. **SWC is now the default JavaScript transpiler instead of Babel** ([PR 603](https://github.com/shakacode/shakapacker/pull/603) by [justin808](https://github.com/justin808))
|
|
259
|
-
|
|
260
290
|
- Babel dependencies are no longer included as peer dependencies
|
|
261
291
|
- Improves compilation speed by 20x
|
|
262
292
|
- **Migration for existing projects:**
|
|
@@ -273,7 +303,6 @@ See the [v9 Upgrade Guide](https://github.com/shakacode/shakapacker/blob/main/do
|
|
|
273
303
|
```
|
|
274
304
|
|
|
275
305
|
2. **CSS Modules now use named exports by default** ([PR 599](https://github.com/shakacode/shakapacker/pull/599))
|
|
276
|
-
|
|
277
306
|
- **JavaScript:** Use named imports: `import { className } from './styles.module.css'`
|
|
278
307
|
- **TypeScript:** Use namespace imports: `import * as styles from './styles.module.css'`
|
|
279
308
|
- To keep the old behavior with default imports, see [CSS Modules Export Mode documentation](./docs/css-modules-export-mode.md) for configuration instructions
|
|
@@ -539,7 +568,6 @@ See the [v8 Upgrade Guide](https://github.com/shakacode/shakapacker/blob/main/do
|
|
|
539
568
|
|
|
540
569
|
- Set `source_entry_path` to `packs` and `nested_entries` to `true` in`shakapacker.yml` [PR 284](https://github.com/shakacode/shakapacker/pull/284) by [ahangarha](https://github.com/ahangarha).
|
|
541
570
|
- Dev server configuration is modified to follow [webpack recommended configurations](https://webpack.js.org/configuration/dev-server/) for dev server. [PR276](https://github.com/shakacode/shakapacker/pull/276) by [ahangarha](https://github.com/ahangarha):
|
|
542
|
-
|
|
543
571
|
- Deprecated `https` entry is removed from the default configuration file, allowing to set `server` or `https` as per the project requirements. For more detail, check webpack documentation. The `https` entry can be effective only if there is no `server` entry in the config file.
|
|
544
572
|
- `allowed_hosts` is now set to `auto` instead of `all` by default.
|
|
545
573
|
|
data/CLAUDE.md
CHANGED
|
@@ -45,3 +45,11 @@
|
|
|
45
45
|
- This gem supports both webpack and rspack configurations
|
|
46
46
|
- Test changes with both bundlers when modifying core functionality
|
|
47
47
|
- Be aware of the dual package.json/Gemfile dependency management
|
|
48
|
+
|
|
49
|
+
## Conductor Environment
|
|
50
|
+
|
|
51
|
+
- **Version manager support**: The setup script detects mise, asdf, or direct PATH tools (rbenv/nvm/nodenv)
|
|
52
|
+
- **bin/conductor-exec**: Use this wrapper for commands when tool versions aren't detected correctly in Conductor's non-interactive shell
|
|
53
|
+
- Example: `bin/conductor-exec bundle exec rubocop`
|
|
54
|
+
- The wrapper uses `mise exec` if mise is available, otherwise falls back to direct execution
|
|
55
|
+
- **conductor.json scripts** already use this wrapper, so you typically don't need to use it manually
|
data/bin/conductor-exec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/zsh
|
|
2
|
+
# Wrapper script to run commands in Conductor with proper tool versions
|
|
3
|
+
# Usage: bin/conductor-exec <command> [args...]
|
|
4
|
+
#
|
|
5
|
+
# This is needed because Conductor (and other non-interactive shells) don't
|
|
6
|
+
# source .zshrc, so version manager PATH configuration isn't active by default.
|
|
7
|
+
#
|
|
8
|
+
# - If mise is available: uses `mise exec` for correct tool versions
|
|
9
|
+
# - Otherwise: falls back to direct execution (for asdf/rbenv/nvm users)
|
|
10
|
+
#
|
|
11
|
+
# Examples:
|
|
12
|
+
# bin/conductor-exec ruby --version # Uses correct Ruby version
|
|
13
|
+
# bin/conductor-exec bundle exec rubocop # Correct Ruby for linting
|
|
14
|
+
# bin/conductor-exec git commit -m "msg" # Pre-commit hooks work correctly
|
|
15
|
+
# bin/conductor-exec yarn install # Uses correct Node version
|
|
16
|
+
#
|
|
17
|
+
# See: https://github.com/shakacode/react_on_rails-demos/issues/105
|
|
18
|
+
|
|
19
|
+
if command -v mise &> /dev/null; then
|
|
20
|
+
exec mise exec -- "$@"
|
|
21
|
+
else
|
|
22
|
+
# Fall back to direct execution for non-mise users
|
|
23
|
+
exec "$@"
|
|
24
|
+
fi
|
data/conductor-setup.sh
CHANGED
|
@@ -1,43 +1,124 @@
|
|
|
1
|
-
#!/
|
|
1
|
+
#!/bin/zsh
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
echo "🔧 Setting up Shakapacker workspace..."
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
# Detect and initialize version manager
|
|
7
|
+
# Supports: mise, asdf, or direct PATH (rbenv/nvm/nodenv already in PATH)
|
|
8
|
+
VERSION_MANAGER="none"
|
|
9
|
+
|
|
10
|
+
echo "📋 Detecting version manager..."
|
|
11
|
+
|
|
12
|
+
if command -v mise &> /dev/null; then
|
|
13
|
+
VERSION_MANAGER="mise"
|
|
14
|
+
echo "✅ Found mise"
|
|
15
|
+
# Trust mise config for current directory only
|
|
16
|
+
mise trust 2>/dev/null || true
|
|
17
|
+
elif [[ -f ~/.asdf/asdf.sh ]]; then
|
|
18
|
+
VERSION_MANAGER="asdf"
|
|
19
|
+
source ~/.asdf/asdf.sh
|
|
20
|
+
echo "✅ Found asdf (from ~/.asdf/asdf.sh)"
|
|
21
|
+
elif command -v asdf &> /dev/null; then
|
|
22
|
+
VERSION_MANAGER="asdf"
|
|
23
|
+
# For homebrew-installed asdf
|
|
24
|
+
if [[ -f /opt/homebrew/opt/asdf/libexec/asdf.sh ]]; then
|
|
25
|
+
source /opt/homebrew/opt/asdf/libexec/asdf.sh
|
|
26
|
+
fi
|
|
27
|
+
echo "✅ Found asdf"
|
|
13
28
|
else
|
|
14
|
-
|
|
29
|
+
echo "ℹ️ No version manager detected, using system PATH"
|
|
30
|
+
echo " (Assuming rbenv/nvm/nodenv or system tools are already configured)"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Ensure version config exists for asdf/mise users
|
|
34
|
+
if [[ "$VERSION_MANAGER" != "none" ]] && [[ ! -f .tool-versions ]] && [[ ! -f .mise.toml ]]; then
|
|
35
|
+
echo "📝 Creating .tool-versions from project version files..."
|
|
36
|
+
|
|
37
|
+
# Read Ruby version from .ruby-version or use default
|
|
38
|
+
if [[ -f .ruby-version ]]; then
|
|
39
|
+
RUBY_VER=$(cat .ruby-version | tr -d '[:space:]')
|
|
40
|
+
else
|
|
41
|
+
RUBY_VER="3.3.4" # Default: recent stable Ruby
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Read Node version from .node-version or use default
|
|
45
|
+
if [[ -f .node-version ]]; then
|
|
46
|
+
NODE_VER=$(cat .node-version | tr -d '[:space:]')
|
|
47
|
+
else
|
|
48
|
+
NODE_VER="20.18.0" # Default: LTS Node
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
cat > .tool-versions << EOF
|
|
52
|
+
ruby $RUBY_VER
|
|
53
|
+
nodejs $NODE_VER
|
|
54
|
+
EOF
|
|
55
|
+
echo " Using Ruby $RUBY_VER, Node $NODE_VER"
|
|
15
56
|
fi
|
|
16
57
|
|
|
17
|
-
#
|
|
18
|
-
if
|
|
19
|
-
echo "
|
|
20
|
-
|
|
58
|
+
# Install tools via mise (after .tool-versions exists)
|
|
59
|
+
if [[ "$VERSION_MANAGER" == "mise" ]]; then
|
|
60
|
+
echo "📦 Installing tools via mise..."
|
|
61
|
+
mise install
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Helper function to run commands with the detected version manager
|
|
65
|
+
run_cmd() {
|
|
66
|
+
if [[ "$VERSION_MANAGER" == "mise" ]] && [[ -x "bin/conductor-exec" ]]; then
|
|
67
|
+
bin/conductor-exec "$@"
|
|
68
|
+
else
|
|
69
|
+
"$@"
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Check required tools
|
|
74
|
+
echo "📋 Checking required tools..."
|
|
75
|
+
run_cmd ruby --version >/dev/null 2>&1 || { echo "❌ Error: Ruby is not installed or not in PATH."; exit 1; }
|
|
76
|
+
run_cmd node --version >/dev/null 2>&1 || { echo "❌ Error: Node.js is not installed or not in PATH."; exit 1; }
|
|
77
|
+
|
|
78
|
+
# Check Ruby version
|
|
79
|
+
RUBY_VERSION=$(run_cmd ruby -v | awk '{print $2}')
|
|
80
|
+
MIN_RUBY_VERSION="2.7.0"
|
|
81
|
+
if [[ $(echo -e "$MIN_RUBY_VERSION\n$RUBY_VERSION" | sort -V | head -n1) != "$MIN_RUBY_VERSION" ]]; then
|
|
82
|
+
echo "❌ Error: Ruby version $RUBY_VERSION is too old. Shakapacker requires Ruby >= 2.7.0"
|
|
83
|
+
echo " Please upgrade Ruby using your version manager or system package manager."
|
|
21
84
|
exit 1
|
|
22
85
|
fi
|
|
86
|
+
echo "✅ Ruby version: $RUBY_VERSION"
|
|
23
87
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
88
|
+
# Check Node version
|
|
89
|
+
NODE_VERSION=$(run_cmd node -v | cut -d'v' -f2)
|
|
90
|
+
MIN_NODE_VERSION="14.0.0"
|
|
91
|
+
if [[ $(echo -e "$MIN_NODE_VERSION\n$NODE_VERSION" | sort -V | head -n1) != "$MIN_NODE_VERSION" ]]; then
|
|
92
|
+
echo "❌ Error: Node.js version v$NODE_VERSION is too old. Shakapacker requires Node.js >= 14.0.0"
|
|
93
|
+
echo " Please upgrade Node.js using your version manager or system package manager."
|
|
27
94
|
exit 1
|
|
28
95
|
fi
|
|
96
|
+
echo "✅ Node.js version: v$NODE_VERSION"
|
|
97
|
+
|
|
98
|
+
# Copy any environment files from root if they exist
|
|
99
|
+
if [ -n "${CONDUCTOR_ROOT_PATH:-}" ]; then
|
|
100
|
+
if [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; then
|
|
101
|
+
echo "📝 Copying .env file..."
|
|
102
|
+
cp "$CONDUCTOR_ROOT_PATH/.env" .env
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
if [ -f "$CONDUCTOR_ROOT_PATH/.env.local" ]; then
|
|
106
|
+
echo "📝 Copying .env.local file..."
|
|
107
|
+
cp "$CONDUCTOR_ROOT_PATH/.env.local" .env.local
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
29
110
|
|
|
30
111
|
# Install Ruby dependencies
|
|
31
|
-
echo "
|
|
32
|
-
|
|
112
|
+
echo "💎 Installing Ruby dependencies..."
|
|
113
|
+
run_cmd bundle install
|
|
33
114
|
|
|
34
115
|
# Install JavaScript dependencies
|
|
35
116
|
echo "📦 Installing JavaScript dependencies..."
|
|
36
|
-
yarn install --frozen-lockfile
|
|
117
|
+
run_cmd yarn install --frozen-lockfile
|
|
37
118
|
|
|
38
119
|
# Set up Husky git hooks
|
|
39
120
|
echo "🪝 Setting up Husky git hooks..."
|
|
40
|
-
npx husky
|
|
121
|
+
run_cmd npx husky
|
|
41
122
|
if [ ! -f .husky/pre-commit ]; then
|
|
42
123
|
echo "Creating pre-commit hook..."
|
|
43
124
|
cat > .husky/pre-commit << 'EOF'
|
|
@@ -47,24 +128,20 @@ EOF
|
|
|
47
128
|
chmod +x .husky/pre-commit
|
|
48
129
|
fi
|
|
49
130
|
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
echo "📋 Copying .env file from root..."
|
|
54
|
-
cp "$CONDUCTOR_ROOT_PATH/.env" .env
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
if [ -f "$CONDUCTOR_ROOT_PATH/.env.local" ]; then
|
|
58
|
-
echo "📋 Copying .env.local file from root..."
|
|
59
|
-
cp "$CONDUCTOR_ROOT_PATH/.env.local" .env.local
|
|
60
|
-
fi
|
|
61
|
-
fi
|
|
131
|
+
# Verify linting tools are available
|
|
132
|
+
echo "✅ Verifying linting tools..."
|
|
133
|
+
run_cmd bundle exec rubocop --version
|
|
62
134
|
|
|
63
|
-
echo "
|
|
135
|
+
echo "✨ Workspace setup complete!"
|
|
64
136
|
echo ""
|
|
65
|
-
echo "
|
|
66
|
-
echo "
|
|
67
|
-
echo "
|
|
68
|
-
echo " - Run JavaScript tests
|
|
69
|
-
echo " -
|
|
70
|
-
echo " -
|
|
137
|
+
echo "📚 Key commands:"
|
|
138
|
+
echo " • bundle exec rspec - Run Ruby tests"
|
|
139
|
+
echo " • bundle exec rake run_spec:gem - Run gem-specific tests"
|
|
140
|
+
echo " • yarn test - Run JavaScript tests"
|
|
141
|
+
echo " • yarn lint - Run JavaScript linting"
|
|
142
|
+
echo " • bundle exec rubocop - Run Ruby linting (required before commits)"
|
|
143
|
+
echo ""
|
|
144
|
+
if [[ "$VERSION_MANAGER" == "mise" ]]; then
|
|
145
|
+
echo "💡 Tip: Use 'bin/conductor-exec <command>' if tool versions aren't detected correctly."
|
|
146
|
+
fi
|
|
147
|
+
echo "⚠️ Remember: Always run 'bundle exec rubocop' before committing!"
|
data/conductor.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"scripts": {
|
|
3
3
|
"setup": "./conductor-setup.sh",
|
|
4
|
-
"run": "bundle exec rspec",
|
|
4
|
+
"run": "bin/conductor-exec bundle exec rspec",
|
|
5
|
+
"test": "bin/conductor-exec bundle exec rspec",
|
|
6
|
+
"lint": "bin/conductor-exec bundle exec rubocop && bin/conductor-exec yarn lint",
|
|
5
7
|
"archive": ""
|
|
6
8
|
}
|
|
7
9
|
}
|
data/docs/early_hints.md
CHANGED
|
@@ -4,6 +4,8 @@ This guide shows you how to use HTTP 103 Early Hints with Shakapacker to optimiz
|
|
|
4
4
|
|
|
5
5
|
> **📚 Related Documentation:** For advanced manual control using `send_pack_early_hints` in controllers before expensive work, see [early_hints_manual_api.md](early_hints_manual_api.md).
|
|
6
6
|
|
|
7
|
+
> ⚠️ **CDN Limitation**: Most CDNs (Cloudflare, AWS CloudFront, AWS ALB, etc.) strip HTTP 103 Early Hints before they reach end users. While Shakapacker sends early hints correctly, and your application server (Puma/Thruster) forwards them properly, **CDNs typically strip the 103 response**. End users will only receive the 200 response with Link headers (which arrive too late to provide early hints benefits). This is an industry-wide limitation—even major sites like GitHub, Google, and Shopify don't serve 103 in production through CDNs. For full early hints delivery, you need either direct connections without a CDN, or specific CDN configuration (e.g., Cloudflare's Early Hints feature on paid plans, which works differently by caching Link headers). See [Reverse proxy stripping 103 responses](#reverse-proxy-stripping-103-responses) for configuration details.
|
|
8
|
+
|
|
7
9
|
## What are Early Hints?
|
|
8
10
|
|
|
9
11
|
HTTP 103 Early Hints is emitted **after** Rails has finished rendering but **before** the final response is sent, allowing browsers to begin fetching resources (JS, CSS) prior to receiving the full HTML response. This may significantly improve page load performance or cause an equally significant regression, depending on the page's content.
|
|
@@ -336,8 +338,12 @@ See the [Manual API Guide](early_hints_manual_api.md) for detailed examples and
|
|
|
336
338
|
- **Modern browsers:**
|
|
337
339
|
- Chrome/Edge/Firefox 103+ ✅
|
|
338
340
|
- Safari 16.4+ ✅
|
|
341
|
+
- **Infrastructure that preserves 103 responses:**
|
|
342
|
+
- Direct connections (no CDN) ✅
|
|
343
|
+
- Cloudflare with Early Hints enabled (paid plans, works via Link header caching) ✅
|
|
344
|
+
- Most CDNs/load balancers ❌ (strip 103 responses - see [CDN Limitation](#troubleshooting) above)
|
|
339
345
|
|
|
340
|
-
If requirements not met, feature gracefully degrades with no errors.
|
|
346
|
+
If requirements not met, feature gracefully degrades with no errors. The Link headers will still be present in the 200 response, which may provide some browser prefetching benefits even when 103 is stripped.
|
|
341
347
|
|
|
342
348
|
## Quick Reference
|
|
343
349
|
|
|
@@ -377,8 +383,9 @@ Debug mode adds HTML comments to your page showing:
|
|
|
377
383
|
- What pack names were processed
|
|
378
384
|
- What Link headers were sent
|
|
379
385
|
- HTTP/2 support status
|
|
386
|
+
- CDN warning reminder (since most CDNs strip 103 responses)
|
|
380
387
|
|
|
381
|
-
View page source and look for `<!-- Shakapacker Early Hints
|
|
388
|
+
View page source and look for `<!-- Shakapacker Early Hints -->` comments.
|
|
382
389
|
|
|
383
390
|
**Early hints not appearing:**
|
|
384
391
|
|
data/docs/precompile_hook.md
CHANGED
|
@@ -23,6 +23,52 @@ The precompile hook is especially useful when you need to run commands like:
|
|
|
23
23
|
- **Development**: Runs before `bin/shakapacker --watch` or dev server starts
|
|
24
24
|
- **Production**: Runs before `bundle exec rake assets:precompile`
|
|
25
25
|
|
|
26
|
+
## Choosing an Approach
|
|
27
|
+
|
|
28
|
+
Use `precompile_hook` when your setup should always run preparatory commands right
|
|
29
|
+
before Shakapacker compiles. For React on Rails projects, this is often the
|
|
30
|
+
simplest default.
|
|
31
|
+
|
|
32
|
+
For projects with more custom startup needs (for example, additional build steps
|
|
33
|
+
or strict process ordering in `bin/dev`), you can run those commands explicitly
|
|
34
|
+
before launching long-running processes instead of using `precompile_hook`.
|
|
35
|
+
|
|
36
|
+
### Comparison
|
|
37
|
+
|
|
38
|
+
| Aspect | `precompile_hook` | Explicit setup in `bin/dev` |
|
|
39
|
+
|--------|-------------------|-------------------------------|
|
|
40
|
+
| Best for | Default/consistent pre-build tasks | Custom multi-step dev boot flows |
|
|
41
|
+
| Runs when | Immediately before compilation starts | Wherever you place it in startup script |
|
|
42
|
+
| Production integration | Automatic via `assets:precompile` | Requires explicit production wiring |
|
|
43
|
+
| Process manager complexity | Lower | Higher (you own orchestration) |
|
|
44
|
+
| Debugging | Centralized hook command | Fully explicit command-by-command flow |
|
|
45
|
+
|
|
46
|
+
### `shakapacker_precompile` Interaction
|
|
47
|
+
|
|
48
|
+
`shakapacker_precompile` controls whether Shakapacker compilation is included in
|
|
49
|
+
`assets:precompile`, while `precompile_hook` controls whether a preparatory command
|
|
50
|
+
runs before compilation.
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
# Option A: Default behavior
|
|
54
|
+
shakapacker_precompile: true
|
|
55
|
+
precompile_hook: "bin/shakapacker-precompile-hook"
|
|
56
|
+
|
|
57
|
+
# Option B: You manage compilation elsewhere
|
|
58
|
+
shakapacker_precompile: false
|
|
59
|
+
precompile_hook: "bin/shakapacker-precompile-hook"
|
|
60
|
+
|
|
61
|
+
# Option C: Fully explicit startup flow (no hook)
|
|
62
|
+
shakapacker_precompile: false
|
|
63
|
+
# precompile_hook: not set
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
To temporarily skip only the hook, set:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
SHAKAPACKER_SKIP_PRECOMPILE_HOOK=true
|
|
70
|
+
```
|
|
71
|
+
|
|
26
72
|
## Configuration
|
|
27
73
|
|
|
28
74
|
Add the `precompile_hook` option to your `config/shakapacker.yml`:
|
data/lib/install/template.rb
CHANGED
|
@@ -141,6 +141,9 @@ if (setup_path = Rails.root.join("bin/setup")).exist?
|
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
Dir.chdir(Rails.root) do
|
|
144
|
+
npm_version = Shakapacker::Utils::VersionSyntaxConverter.new.rubygem_to_npm(Shakapacker::VERSION)
|
|
145
|
+
shakapacker_dependency_value = nil
|
|
146
|
+
|
|
144
147
|
# In CI, use the pre-packed tarball if available
|
|
145
148
|
if ENV["SHAKAPACKER_NPM_PACKAGE"]
|
|
146
149
|
package_path = ENV["SHAKAPACKER_NPM_PACKAGE"]
|
|
@@ -167,6 +170,7 @@ Dir.chdir(Rails.root) do
|
|
|
167
170
|
say "📦 Installing shakapacker from local package: #{absolute_path}", :cyan
|
|
168
171
|
begin
|
|
169
172
|
@package_json.manager.add!([absolute_path], type: :production)
|
|
173
|
+
shakapacker_dependency_value = absolute_path
|
|
170
174
|
rescue PackageJson::Error
|
|
171
175
|
say "Shakapacker installation failed 😭 See above for details.", :red
|
|
172
176
|
exit 1
|
|
@@ -174,9 +178,9 @@ Dir.chdir(Rails.root) do
|
|
|
174
178
|
else
|
|
175
179
|
say "⚠️ SHAKAPACKER_NPM_PACKAGE set but file not found: #{absolute_path}", :yellow
|
|
176
180
|
say "Falling back to npm registry...", :yellow
|
|
177
|
-
npm_version = Shakapacker::Utils::VersionSyntaxConverter.new.rubygem_to_npm(Shakapacker::VERSION)
|
|
178
181
|
begin
|
|
179
182
|
@package_json.manager.add!(["shakapacker@#{npm_version}"], type: :production)
|
|
183
|
+
shakapacker_dependency_value = npm_version
|
|
180
184
|
rescue PackageJson::Error
|
|
181
185
|
say "Shakapacker installation failed 😭 See above for details.", :red
|
|
182
186
|
exit 1
|
|
@@ -187,10 +191,10 @@ Dir.chdir(Rails.root) do
|
|
|
187
191
|
exit 1
|
|
188
192
|
end
|
|
189
193
|
else
|
|
190
|
-
npm_version = Shakapacker::Utils::VersionSyntaxConverter.new.rubygem_to_npm(Shakapacker::VERSION)
|
|
191
194
|
say "Installing shakapacker@#{npm_version}"
|
|
192
195
|
begin
|
|
193
196
|
@package_json.manager.add!(["shakapacker@#{npm_version}"], type: :production)
|
|
197
|
+
shakapacker_dependency_value = npm_version
|
|
194
198
|
rescue PackageJson::Error
|
|
195
199
|
say "Shakapacker installation failed 😭 See above for details.", :red
|
|
196
200
|
exit 1
|
|
@@ -201,8 +205,8 @@ Dir.chdir(Rails.root) do
|
|
|
201
205
|
if pj["dependencies"] && pj["dependencies"]["shakapacker"]
|
|
202
206
|
{
|
|
203
207
|
"dependencies" => pj["dependencies"].merge({
|
|
204
|
-
#
|
|
205
|
-
"shakapacker" => pj["dependencies"]["shakapacker"].delete_prefix("^")
|
|
208
|
+
# Keep package.json aligned with the exact source/version this installer requested.
|
|
209
|
+
"shakapacker" => shakapacker_dependency_value || pj["dependencies"]["shakapacker"].delete_prefix("^")
|
|
206
210
|
})
|
|
207
211
|
}
|
|
208
212
|
else
|
|
@@ -189,7 +189,7 @@ class Shakapacker::Configuration
|
|
|
189
189
|
# @return [Pathname, nil] the absolute private output path or nil
|
|
190
190
|
def private_output_path
|
|
191
191
|
private_path = fetch(:private_output_path)
|
|
192
|
-
return nil
|
|
192
|
+
return nil if private_path.blank?
|
|
193
193
|
validate_output_paths!
|
|
194
194
|
root_path.join(private_path)
|
|
195
195
|
end
|
data/lib/shakapacker/helper.rb
CHANGED
|
@@ -657,6 +657,8 @@ module Shakapacker::Helper
|
|
|
657
657
|
end
|
|
658
658
|
store[:debug_buffer] << "<!-- Note: Browsers only process the FIRST 103 response -->"
|
|
659
659
|
store[:debug_buffer] << "<!-- Note: Puma only supports HTTP/1.1 Early Hints (not HTTP/2) -->"
|
|
660
|
+
store[:debug_buffer] << "<!-- CDN Warning: Most CDNs (Cloudflare, AWS CloudFront, AWS ALB) strip 103 responses. -->"
|
|
661
|
+
store[:debug_buffer] << "<!-- Link headers in the 200 response may still provide some browser hints. -->"
|
|
660
662
|
end
|
|
661
663
|
end
|
|
662
664
|
|
data/lib/shakapacker/runner.rb
CHANGED
|
@@ -279,7 +279,18 @@ module Shakapacker
|
|
|
279
279
|
start_time = Time.now unless watch_mode
|
|
280
280
|
|
|
281
281
|
Dir.chdir(@app_path) do
|
|
282
|
-
|
|
282
|
+
child_pid = nil
|
|
283
|
+
trap("TERM") do
|
|
284
|
+
if child_pid
|
|
285
|
+
Process.kill("TERM", child_pid)
|
|
286
|
+
else
|
|
287
|
+
raise SignalException, "TERM" # if there is no child_pid we never spawned the process and can quit as normal
|
|
288
|
+
end
|
|
289
|
+
rescue Errno::ESRCH
|
|
290
|
+
nil
|
|
291
|
+
end
|
|
292
|
+
child_pid = spawn(env, *cmd)
|
|
293
|
+
Process.wait(child_pid)
|
|
283
294
|
end
|
|
284
295
|
|
|
285
296
|
if !watch_mode && start_time
|
data/lib/shakapacker/version.rb
CHANGED
data/lib/shakapacker.rb
CHANGED
|
@@ -42,9 +42,12 @@ module Shakapacker
|
|
|
42
42
|
|
|
43
43
|
# Default environment when RAILS_ENV is not set
|
|
44
44
|
DEFAULT_ENV = "development".freeze
|
|
45
|
-
# Environments that use
|
|
45
|
+
# Environments that use "development" for NODE_ENV
|
|
46
46
|
# All other environments (production, staging, etc.) use "production" for webpack optimizations
|
|
47
|
-
|
|
47
|
+
# Note: Both development and test RAILS_ENV use NODE_ENV=development because
|
|
48
|
+
# webpack/rspack only recognize "development" and "production" values for NODE_ENV.
|
|
49
|
+
# Using "test" causes DefinePlugin conflicts with optimization.nodeEnv.
|
|
50
|
+
DEV_ENVS = %w[development test].freeze
|
|
48
51
|
|
|
49
52
|
# Sets the shared Shakapacker instance
|
|
50
53
|
#
|
|
@@ -94,15 +97,19 @@ module Shakapacker
|
|
|
94
97
|
# Sets NODE_ENV based on RAILS_ENV if not already set
|
|
95
98
|
#
|
|
96
99
|
# Environment mapping:
|
|
97
|
-
# - +development+ and +test+ environments use
|
|
100
|
+
# - +development+ and +test+ environments use "development" for NODE_ENV
|
|
98
101
|
# - All other environments (+production+, +staging+, etc.) use "production" for webpack optimizations
|
|
99
102
|
#
|
|
103
|
+
# Note: We always use "development" (not "test") for test environments because
|
|
104
|
+
# webpack/rspack only recognize "development" and "production" as valid NODE_ENV values.
|
|
105
|
+
# Using "test" causes DefinePlugin conflicts with optimization.nodeEnv.
|
|
106
|
+
#
|
|
100
107
|
# This method is typically called automatically during Rails initialization.
|
|
101
108
|
#
|
|
102
109
|
# @return [String] the NODE_ENV value that was set
|
|
103
110
|
# @api private
|
|
104
111
|
def ensure_node_env!
|
|
105
|
-
ENV["NODE_ENV"] ||=
|
|
112
|
+
ENV["NODE_ENV"] ||= DEV_ENVS.include?(ENV["RAILS_ENV"]) ? "development" : "production"
|
|
106
113
|
end
|
|
107
114
|
|
|
108
115
|
# Temporarily redirects Shakapacker logging to STDOUT
|
data/package/config.ts
CHANGED
|
@@ -111,6 +111,10 @@ if (existsSync(configPath)) {
|
|
|
111
111
|
|
|
112
112
|
config.outputPath = resolve(config.public_root_path, config.public_output_path)
|
|
113
113
|
|
|
114
|
+
if (config.private_output_path) {
|
|
115
|
+
config.privateOutputPath = resolve(config.private_output_path)
|
|
116
|
+
}
|
|
117
|
+
|
|
114
118
|
// Ensure that the publicPath includes our asset host so dynamic imports
|
|
115
119
|
// (code-splitting chunks and static assets) load from the CDN instead of a relative path.
|
|
116
120
|
const getPublicPath = (): string => {
|
data/package/rules/file.ts
CHANGED
|
@@ -8,7 +8,7 @@ const {
|
|
|
8
8
|
export = {
|
|
9
9
|
test: /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2|svg)$/,
|
|
10
10
|
exclude: /\.(js|mjs|jsx|ts|tsx)$/,
|
|
11
|
-
type: "asset
|
|
11
|
+
type: "asset",
|
|
12
12
|
generator: {
|
|
13
13
|
filename: (pathData: { filename?: string }) => {
|
|
14
14
|
// Guard against null/undefined pathData or filename
|
data/package/rules/sass.ts
CHANGED
data/package/types.ts
CHANGED
data/package.json
CHANGED
data/test/package/config.test.js
CHANGED
|
@@ -55,6 +55,17 @@ describe("Config", () => {
|
|
|
55
55
|
)
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
+
test("should return privateOutputPath as absolute path", () => {
|
|
59
|
+
const config = require("../../package/config")
|
|
60
|
+
expect(config.privateOutputPath).toStrictEqual(resolve("ssr-generated"))
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("should not set privateOutputPath when not configured", () => {
|
|
64
|
+
process.env.SHAKAPACKER_CONFIG = "config/shakapacker_manifest_path.yml"
|
|
65
|
+
const config = require("../../package/config")
|
|
66
|
+
expect(config.privateOutputPath).toBeUndefined()
|
|
67
|
+
})
|
|
68
|
+
|
|
58
69
|
test("should have integrity disabled by default", () => {
|
|
59
70
|
const config = require("../../package/config")
|
|
60
71
|
expect(config.integrity.enabled).toBe(false)
|
|
@@ -35,6 +35,10 @@ describe("file", () => {
|
|
|
35
35
|
types.forEach((type) => expect(file.exclude.test(type)).toBe(true))
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
+
test("uses webpack asset module type by default", () => {
|
|
39
|
+
expect(file.type).toBe("asset")
|
|
40
|
+
})
|
|
41
|
+
|
|
38
42
|
test("correct generated output path is returned for top level files", () => {
|
|
39
43
|
const pathData = {
|
|
40
44
|
filename: "app/javascript/image.svg"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shakapacker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 9.
|
|
4
|
+
version: 9.6.0.beta.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Heinemeier Hansson
|
|
@@ -181,6 +181,7 @@ files:
|
|
|
181
181
|
- TODO_v9.md
|
|
182
182
|
- __mocks__/nonexistent/package.json
|
|
183
183
|
- __mocks__/sass-loader/package.json
|
|
184
|
+
- bin/conductor-exec
|
|
184
185
|
- bin/shakapacker-config
|
|
185
186
|
- conductor-setup.sh
|
|
186
187
|
- conductor.json
|
|
@@ -415,7 +416,7 @@ homepage: https://github.com/shakacode/shakapacker
|
|
|
415
416
|
licenses:
|
|
416
417
|
- MIT
|
|
417
418
|
metadata:
|
|
418
|
-
source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.
|
|
419
|
+
source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.6.0.beta.0
|
|
419
420
|
rdoc_options: []
|
|
420
421
|
require_paths:
|
|
421
422
|
- lib
|