shakapacker 8.0.2 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.eslintignore +1 -0
- data/.eslintrc.fast.js +40 -0
- data/.eslintrc.js +48 -0
- data/.github/STATUS.md +1 -0
- data/.github/workflows/claude-code-review.yml +54 -0
- data/.github/workflows/claude.yml +50 -0
- data/.github/workflows/dummy.yml +9 -4
- data/.github/workflows/generator.yml +32 -10
- data/.github/workflows/node.yml +23 -1
- data/.github/workflows/ruby.yml +33 -2
- data/.github/workflows/test-bundlers.yml +170 -0
- data/.gitignore +20 -0
- data/.husky/pre-commit +2 -0
- data/.npmignore +56 -0
- data/.prettierignore +3 -0
- data/.rubocop.yml +1 -0
- data/.yalcignore +26 -0
- data/CHANGELOG.md +302 -16
- data/CLAUDE.md +29 -0
- data/CONTRIBUTING.md +138 -20
- data/Gemfile.lock +83 -89
- data/README.md +343 -105
- data/Rakefile +39 -4
- data/TODO.md +50 -0
- data/TODO_v9.md +87 -0
- data/bin/export-bundler-config +11 -0
- data/conductor-setup.sh +70 -0
- data/conductor.json +7 -0
- data/docs/cdn_setup.md +379 -0
- data/docs/common-upgrades.md +615 -0
- data/docs/css-modules-export-mode.md +512 -0
- data/docs/deployment.md +62 -9
- data/docs/optional-peer-dependencies.md +198 -0
- data/docs/peer-dependencies.md +60 -0
- data/docs/react.md +6 -14
- data/docs/releasing.md +197 -0
- data/docs/rspack.md +190 -0
- data/docs/rspack_migration_guide.md +305 -0
- data/docs/subresource_integrity.md +54 -0
- data/docs/transpiler-migration.md +209 -0
- data/docs/transpiler-performance.md +179 -0
- data/docs/troubleshooting.md +157 -22
- data/docs/typescript-migration.md +379 -0
- data/docs/typescript.md +99 -0
- data/docs/using_esbuild_loader.md +3 -3
- data/docs/using_swc_loader.md +112 -10
- data/docs/v6_upgrade.md +10 -0
- data/docs/v8_upgrade.md +3 -5
- data/docs/v9_upgrade.md +458 -0
- data/gemfiles/Gemfile-rails.6.0.x +2 -1
- data/gemfiles/Gemfile-rails.6.1.x +1 -1
- data/gemfiles/Gemfile-rails.7.0.x +2 -2
- data/gemfiles/Gemfile-rails.7.1.x +1 -2
- data/gemfiles/Gemfile-rails.7.2.x +11 -0
- data/gemfiles/Gemfile-rails.8.0.x +11 -0
- data/lib/install/bin/export-bundler-config +11 -0
- data/lib/install/bin/shakapacker +4 -6
- data/lib/install/bin/shakapacker-dev-server +1 -1
- data/lib/install/config/rspack/rspack.config.js +6 -0
- data/lib/install/config/rspack/rspack.config.ts +7 -0
- data/lib/install/config/shakapacker.yml +25 -5
- data/lib/install/config/webpack/webpack.config.ts +7 -0
- data/lib/install/package.json +38 -0
- data/lib/install/template.rb +194 -44
- data/lib/shakapacker/bundler_switcher.rb +329 -0
- data/lib/shakapacker/compiler.rb +2 -1
- data/lib/shakapacker/compiler_strategy.rb +2 -2
- data/lib/shakapacker/configuration.rb +173 -2
- data/lib/shakapacker/dev_server_runner.rb +29 -8
- data/lib/shakapacker/digest_strategy.rb +2 -1
- data/lib/shakapacker/doctor.rb +905 -0
- data/lib/shakapacker/helper.rb +64 -16
- data/lib/shakapacker/manifest.rb +10 -3
- data/lib/shakapacker/mtime_strategy.rb +1 -1
- data/lib/shakapacker/railtie.rb +4 -4
- data/lib/shakapacker/rspack_runner.rb +19 -0
- data/lib/shakapacker/runner.rb +159 -10
- data/lib/shakapacker/swc_migrator.rb +384 -0
- data/lib/shakapacker/utils/manager.rb +15 -2
- data/lib/shakapacker/version.rb +1 -1
- data/lib/shakapacker/version_checker.rb +2 -2
- data/lib/shakapacker/webpack_runner.rb +6 -43
- data/lib/shakapacker.rb +22 -11
- data/lib/tasks/shakapacker/doctor.rake +8 -0
- data/lib/tasks/shakapacker/export_bundler_config.rake +72 -0
- data/lib/tasks/shakapacker/install.rake +12 -2
- data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
- data/lib/tasks/shakapacker/switch_bundler.rake +82 -0
- data/lib/tasks/shakapacker.rake +2 -0
- data/package/.npmignore +4 -0
- data/package/babel/preset.ts +56 -0
- data/package/config.ts +175 -0
- data/package/configExporter/cli.ts +683 -0
- data/package/configExporter/configDocs.ts +102 -0
- data/package/configExporter/fileWriter.ts +92 -0
- data/package/configExporter/index.ts +5 -0
- data/package/configExporter/types.ts +36 -0
- data/package/configExporter/yamlSerializer.ts +266 -0
- data/package/{dev_server.js → dev_server.ts} +8 -5
- data/package/env.ts +92 -0
- data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +30 -0
- data/package/environments/{base.js → base.ts} +56 -60
- data/package/environments/development.ts +90 -0
- data/package/environments/production.ts +80 -0
- data/package/environments/test.ts +53 -0
- data/package/environments/types.ts +98 -0
- data/package/esbuild/index.ts +42 -0
- data/package/index.d.ts +3 -60
- data/package/index.ts +55 -0
- data/package/loaders.d.ts +28 -0
- data/package/optimization/rspack.ts +36 -0
- data/package/optimization/webpack.ts +57 -0
- data/package/plugins/rspack.ts +103 -0
- data/package/plugins/webpack.ts +62 -0
- data/package/rspack/index.ts +64 -0
- data/package/rules/{babel.js → babel.ts} +2 -2
- data/package/rules/{coffee.js → coffee.ts} +1 -1
- data/package/rules/css.ts +3 -0
- data/package/rules/{erb.js → erb.ts} +1 -1
- data/package/rules/esbuild.ts +10 -0
- data/package/rules/file.ts +40 -0
- data/package/rules/{jscommon.js → jscommon.ts} +4 -4
- data/package/rules/{less.js → less.ts} +4 -4
- data/package/rules/raw.ts +25 -0
- data/package/rules/rspack.ts +176 -0
- data/package/rules/{sass.js → sass.ts} +7 -3
- data/package/rules/{stylus.js → stylus.ts} +4 -8
- data/package/rules/swc.ts +10 -0
- data/package/rules/webpack.ts +16 -0
- data/package/swc/index.ts +56 -0
- data/package/types/README.md +88 -0
- data/package/types/index.ts +61 -0
- data/package/types.ts +108 -0
- data/package/utils/configPath.ts +6 -0
- data/package/utils/debug.ts +49 -0
- data/package/utils/defaultConfigPath.ts +4 -0
- data/package/utils/errorCodes.ts +219 -0
- data/package/utils/errorHelpers.ts +143 -0
- data/package/utils/getStyleRule.ts +64 -0
- data/package/utils/helpers.ts +85 -0
- data/package/utils/{inliningCss.js → inliningCss.ts} +3 -3
- data/package/utils/pathValidation.ts +139 -0
- data/package/utils/requireOrError.ts +15 -0
- data/package/utils/snakeToCamelCase.ts +5 -0
- data/package/utils/typeGuards.ts +342 -0
- data/package/utils/validateDependencies.ts +61 -0
- data/package/webpack-types.d.ts +33 -0
- data/package/webpackDevServerConfig.ts +117 -0
- data/package-lock.json +13047 -0
- data/package.json +154 -18
- data/scripts/remove-use-strict.js +45 -0
- data/scripts/type-check-no-emit.js +27 -0
- data/test/helpers.js +1 -1
- data/test/package/config.test.js +43 -0
- data/test/package/env.test.js +42 -7
- data/test/package/environments/base.test.js +5 -1
- data/test/package/rules/babel.test.js +16 -0
- data/test/package/rules/esbuild.test.js +1 -1
- data/test/package/rules/raw.test.js +40 -7
- data/test/package/rules/swc.test.js +1 -1
- data/test/package/rules/webpack.test.js +35 -0
- data/test/package/staging.test.js +4 -3
- data/test/package/transpiler-defaults.test.js +127 -0
- data/test/peer-dependencies.sh +85 -0
- data/test/scripts/remove-use-strict.test.js +125 -0
- data/test/typescript/build.test.js +118 -0
- data/test/typescript/environments.test.js +107 -0
- data/test/typescript/pathValidation.test.js +142 -0
- data/test/typescript/securityValidation.test.js +182 -0
- data/tools/README.md +124 -0
- data/tools/css-modules-v9-codemod.js +179 -0
- data/tsconfig.eslint.json +16 -0
- data/tsconfig.json +38 -0
- data/yarn.lock +4165 -2706
- metadata +129 -41
- data/package/babel/preset.js +0 -37
- data/package/config.js +0 -54
- data/package/env.js +0 -48
- data/package/environments/development.js +0 -13
- data/package/environments/production.js +0 -88
- data/package/environments/test.js +0 -3
- data/package/esbuild/index.js +0 -40
- data/package/index.js +0 -40
- data/package/rules/css.js +0 -3
- data/package/rules/esbuild.js +0 -10
- data/package/rules/file.js +0 -29
- data/package/rules/index.js +0 -20
- data/package/rules/raw.js +0 -5
- data/package/rules/swc.js +0 -10
- data/package/swc/index.js +0 -50
- data/package/utils/configPath.js +0 -4
- data/package/utils/defaultConfigPath.js +0 -2
- data/package/utils/getStyleRule.js +0 -40
- data/package/utils/helpers.js +0 -58
- data/package/utils/snakeToCamelCase.js +0 -5
- data/package/webpackDevServerConfig.js +0 -71
- data/test/package/rules/index.test.js +0 -16
data/Rakefile
CHANGED
|
@@ -14,16 +14,51 @@ namespace :run_spec do
|
|
|
14
14
|
sh("bundle exec rspec spec/shakapacker/*_spec.rb")
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
desc "Run specs in the dummy app"
|
|
17
|
+
desc "Run specs in the dummy app with webpack"
|
|
18
18
|
task :dummy do
|
|
19
|
-
puts "Running dummy app specs"
|
|
19
|
+
puts "Running dummy app specs with webpack"
|
|
20
20
|
spec_dummy_dir = Pathname.new(File.join("spec", "dummy")).realpath
|
|
21
21
|
Bundler.with_unbundled_env do
|
|
22
22
|
sh_in_dir(".", "yalc publish")
|
|
23
23
|
sh_in_dir(spec_dummy_dir, [
|
|
24
24
|
"bundle install",
|
|
25
25
|
"yalc link shakapacker",
|
|
26
|
-
"
|
|
26
|
+
"npm install",
|
|
27
|
+
"bin/test-bundler webpack",
|
|
28
|
+
"NODE_ENV=test RAILS_ENV=test bin/shakapacker",
|
|
29
|
+
"bundle exec rspec"
|
|
30
|
+
])
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc "Run specs in the dummy app with rspack"
|
|
35
|
+
task :dummy_with_rspack do
|
|
36
|
+
puts "Running dummy app specs with rspack"
|
|
37
|
+
spec_dummy_dir = Pathname.new(File.join("spec", "dummy")).realpath
|
|
38
|
+
Bundler.with_unbundled_env do
|
|
39
|
+
sh_in_dir(".", "yalc publish")
|
|
40
|
+
sh_in_dir(spec_dummy_dir, [
|
|
41
|
+
"bundle install",
|
|
42
|
+
"yalc link shakapacker",
|
|
43
|
+
"npm install",
|
|
44
|
+
"bin/test-bundler rspack",
|
|
45
|
+
"NODE_ENV=test RAILS_ENV=test bin/shakapacker",
|
|
46
|
+
"bundle exec rspec"
|
|
47
|
+
])
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
desc "Run specs in the dummy-rspack app"
|
|
52
|
+
task :dummy_rspack do
|
|
53
|
+
puts "Running dummy-rspack app specs"
|
|
54
|
+
spec_dummy_dir = Pathname.new(File.join("spec", "dummy-rspack")).realpath
|
|
55
|
+
Bundler.with_unbundled_env do
|
|
56
|
+
sh_in_dir(".", "yalc publish")
|
|
57
|
+
sh_in_dir(spec_dummy_dir, [
|
|
58
|
+
"bundle install",
|
|
59
|
+
"yalc link shakapacker",
|
|
60
|
+
"npm install",
|
|
61
|
+
"NODE_ENV=test RAILS_ENV=test npm exec --no -- rspack build --config config/rspack/rspack.config.js",
|
|
27
62
|
"bundle exec rspec"
|
|
28
63
|
])
|
|
29
64
|
end
|
|
@@ -35,7 +70,7 @@ namespace :run_spec do
|
|
|
35
70
|
end
|
|
36
71
|
|
|
37
72
|
desc "Run all specs"
|
|
38
|
-
task all_specs: %i[gem dummy generator] do
|
|
73
|
+
task all_specs: %i[gem dummy dummy_with_rspack dummy_rspack generator] do
|
|
39
74
|
puts "Completed all RSpec tests"
|
|
40
75
|
end
|
|
41
76
|
end
|
data/TODO.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# TypeScript Migration Status
|
|
2
|
+
|
|
3
|
+
## ✅ Completed (PR #602)
|
|
4
|
+
- Enhanced `package/index.d.ts` with comprehensive type definitions
|
|
5
|
+
- Added TypeScript type packages for better IDE support
|
|
6
|
+
- Improved Config and DevServerConfig interfaces
|
|
7
|
+
- Added missing properties (private_output_path, inline_css, env_prefix, etc.)
|
|
8
|
+
- All tests passing
|
|
9
|
+
- Zero JavaScript modifications (no whitespace changes)
|
|
10
|
+
- Full backward compatibility maintained
|
|
11
|
+
|
|
12
|
+
## 📋 Next Steps (Issue #605)
|
|
13
|
+
|
|
14
|
+
### Phase 2: Core Module Conversion
|
|
15
|
+
- [ ] Convert `package/config.js` to TypeScript
|
|
16
|
+
- [ ] Convert `package/env.js` to TypeScript
|
|
17
|
+
- [ ] Convert `package/index.js` to TypeScript
|
|
18
|
+
- [ ] Convert `package/utils/helpers.js` to TypeScript
|
|
19
|
+
|
|
20
|
+
### Phase 3: Environment & Build System
|
|
21
|
+
- [ ] Convert environment files (base, development, production, test)
|
|
22
|
+
- [ ] Convert dev_server.js
|
|
23
|
+
- [ ] Convert webpackDevServerConfig.js
|
|
24
|
+
|
|
25
|
+
### Phase 4: Rules & Loaders (PR #620) ✅
|
|
26
|
+
- [x] Convert all files in `package/rules/`
|
|
27
|
+
- [x] Convert all files in `package/plugins/`
|
|
28
|
+
- [x] Convert all files in `package/optimization/`
|
|
29
|
+
|
|
30
|
+
### Phase 5: Framework-Specific Modules ✅
|
|
31
|
+
- [x] Convert rspack support files
|
|
32
|
+
- [x] Convert swc support files
|
|
33
|
+
- [x] Convert esbuild support files
|
|
34
|
+
- [x] Convert babel preset
|
|
35
|
+
|
|
36
|
+
### Phase 6: Final Cleanup ✅
|
|
37
|
+
- [x] Add TypeScript linting with @typescript-eslint
|
|
38
|
+
- [x] Verify strict mode is enabled (already configured)
|
|
39
|
+
- [x] Update documentation
|
|
40
|
+
|
|
41
|
+
## Why Gradual Migration?
|
|
42
|
+
- **Lower risk**: Each phase can be tested independently
|
|
43
|
+
- **Team learning**: Get familiar with TypeScript incrementally
|
|
44
|
+
- **Immediate value**: Type definitions already provide IDE benefits
|
|
45
|
+
- **No breaking changes**: Users unaffected during migration
|
|
46
|
+
|
|
47
|
+
## Related Links
|
|
48
|
+
- Original issue: #200
|
|
49
|
+
- Initial PR: #602
|
|
50
|
+
- Next steps issue: #605
|
data/TODO_v9.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Shakapacker v9 TODO List
|
|
2
|
+
|
|
3
|
+
## CSS Modules Configuration Alignment
|
|
4
|
+
|
|
5
|
+
### Problem
|
|
6
|
+
Current CSS modules configuration causes TypeScript/webpack warnings because of default vs named export mismatch.
|
|
7
|
+
|
|
8
|
+
### Current Behavior (v8)
|
|
9
|
+
- CSS modules use default export: `import styles from './styles.module.css'`
|
|
10
|
+
- This causes warnings but works at runtime
|
|
11
|
+
- Warning example: `export 'default' (imported as 'style') was not found in './HelloWorld.module.css'`
|
|
12
|
+
|
|
13
|
+
### Proposed v9 Change
|
|
14
|
+
Align with Next.js and modern tooling by using named exports:
|
|
15
|
+
|
|
16
|
+
1. **Update css-loader configuration:**
|
|
17
|
+
```javascript
|
|
18
|
+
{
|
|
19
|
+
loader: 'css-loader',
|
|
20
|
+
options: {
|
|
21
|
+
modules: {
|
|
22
|
+
namedExport: true,
|
|
23
|
+
exportLocalsConvention: 'camelCaseOnly' // Must be 'camelCaseOnly' or 'dashesOnly' with namedExport: true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Note:** Using `exportLocalsConvention: 'camelCase'` with `namedExport: true` will cause a build error.
|
|
30
|
+
css-loader only allows `'camelCaseOnly'` or `'dashesOnly'` when named exports are enabled.
|
|
31
|
+
|
|
32
|
+
2. **Update TypeScript types:**
|
|
33
|
+
- Ensure proper typing for CSS modules with named exports
|
|
34
|
+
- May need to update or generate `.d.ts` files for CSS modules
|
|
35
|
+
|
|
36
|
+
3. **Migration guide for users:**
|
|
37
|
+
- Document the breaking change
|
|
38
|
+
- Provide codemod or migration script to update imports from:
|
|
39
|
+
```javascript
|
|
40
|
+
import styles from './styles.module.css'
|
|
41
|
+
styles.className
|
|
42
|
+
```
|
|
43
|
+
to:
|
|
44
|
+
```javascript
|
|
45
|
+
import * as styles from './styles.module.css'
|
|
46
|
+
// or
|
|
47
|
+
import { className } from './styles.module.css'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Benefits
|
|
51
|
+
- Eliminates webpack/TypeScript warnings
|
|
52
|
+
- Better tree-shaking potential
|
|
53
|
+
- More explicit about what CSS classes are being used
|
|
54
|
+
- Easier interoperability with frameworks that support named exports
|
|
55
|
+
|
|
56
|
+
### Implementation Notes
|
|
57
|
+
- This is a BREAKING CHANGE and appropriate for major version bump
|
|
58
|
+
- Need to test with both webpack and rspack
|
|
59
|
+
- Consider providing a compatibility mode via configuration option
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Related Issues from PR #597
|
|
64
|
+
|
|
65
|
+
### React Component Not Rendering (spec/dummy) - RESOLVED ✅
|
|
66
|
+
- **Issue**: React component was not rendering due to CSS module import mismatch
|
|
67
|
+
- **Symptoms**:
|
|
68
|
+
- Component wasn't rendering "Hello, Stranger!"
|
|
69
|
+
- Input field not rendered, making interactive test fail
|
|
70
|
+
- Only the static H1 "Hello, World!" was visible
|
|
71
|
+
- **Resolution**:
|
|
72
|
+
- Fixed CSS module import syntax from `import style from` to `import * as style from`
|
|
73
|
+
- This matched webpack's named exports configuration for CSS modules
|
|
74
|
+
- Tests now pass with both React 18.3.1 and webpack/rspack configurations
|
|
75
|
+
- **Root Cause**: CSS module import/export mismatch
|
|
76
|
+
- Webpack was configured to use named exports for CSS modules
|
|
77
|
+
- TypeScript code was using default import syntax
|
|
78
|
+
- This caused `style` to be undefined, breaking SSR and client rendering
|
|
79
|
+
- **Status**: FIXED
|
|
80
|
+
- All tests re-enabled and passing
|
|
81
|
+
- Both SSR and client-side rendering working
|
|
82
|
+
- Interactive functionality restored
|
|
83
|
+
|
|
84
|
+
### Test Infrastructure
|
|
85
|
+
- Successfully implemented dual bundler support (webpack/rspack)
|
|
86
|
+
- test-bundler script working well with status command
|
|
87
|
+
- Consider adding more comprehensive tests for both bundlers
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Minimal shim - all logic is in the TypeScript module
|
|
4
|
+
const { run } = require('shakapacker/configExporter')
|
|
5
|
+
|
|
6
|
+
run(process.argv.slice(2))
|
|
7
|
+
.then((exitCode) => process.exit(exitCode))
|
|
8
|
+
.catch((error) => {
|
|
9
|
+
console.error(error.message)
|
|
10
|
+
process.exit(1)
|
|
11
|
+
})
|
data/conductor-setup.sh
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
echo "🔧 Setting up Shakapacker workspace..."
|
|
5
|
+
|
|
6
|
+
# Set up Ruby version if asdf is available
|
|
7
|
+
if command -v asdf &> /dev/null; then
|
|
8
|
+
echo "📝 Using asdf Ruby version management..."
|
|
9
|
+
# Ensure we have the right Ruby version file
|
|
10
|
+
echo "ruby 3.3.4" > .tool-versions
|
|
11
|
+
# Use asdf exec to run commands with the right Ruby version
|
|
12
|
+
BUNDLE_CMD="asdf exec bundle"
|
|
13
|
+
else
|
|
14
|
+
BUNDLE_CMD="bundle"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Check for required tools
|
|
18
|
+
if ! $BUNDLE_CMD --version &> /dev/null; then
|
|
19
|
+
echo "❌ Error: Ruby bundler is not installed"
|
|
20
|
+
echo "Please install bundler first: gem install bundler"
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if ! command -v yarn &> /dev/null; then
|
|
25
|
+
echo "❌ Error: Yarn is not installed"
|
|
26
|
+
echo "Please install yarn first"
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Install Ruby dependencies
|
|
31
|
+
echo "📦 Installing Ruby dependencies..."
|
|
32
|
+
$BUNDLE_CMD install
|
|
33
|
+
|
|
34
|
+
# Install JavaScript dependencies
|
|
35
|
+
echo "📦 Installing JavaScript dependencies..."
|
|
36
|
+
yarn install
|
|
37
|
+
|
|
38
|
+
# Set up Husky git hooks
|
|
39
|
+
echo "🪝 Setting up Husky git hooks..."
|
|
40
|
+
npx husky
|
|
41
|
+
if [ ! -f .husky/pre-commit ]; then
|
|
42
|
+
echo "Creating pre-commit hook..."
|
|
43
|
+
cat > .husky/pre-commit << 'EOF'
|
|
44
|
+
#!/usr/bin/env sh
|
|
45
|
+
npx lint-staged
|
|
46
|
+
EOF
|
|
47
|
+
chmod +x .husky/pre-commit
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Copy environment files if they exist in root
|
|
51
|
+
if [ -n "${CONDUCTOR_ROOT_PATH:-}" ]; then
|
|
52
|
+
if [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; then
|
|
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
|
|
62
|
+
|
|
63
|
+
echo "✅ Workspace setup complete!"
|
|
64
|
+
echo ""
|
|
65
|
+
echo "Available commands:"
|
|
66
|
+
echo " - Run tests: bundle exec rspec"
|
|
67
|
+
echo " - Run specific test suites: bundle exec rake run_spec:gem"
|
|
68
|
+
echo " - Run JavaScript tests: yarn test"
|
|
69
|
+
echo " - Lint JavaScript: yarn lint"
|
|
70
|
+
echo " - Lint Ruby: bundle exec rubocop"
|
data/conductor.json
ADDED
data/docs/cdn_setup.md
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# CDN Setup Guide for Shakapacker
|
|
2
|
+
|
|
3
|
+
This guide explains how to configure Shakapacker to serve your JavaScript bundles and other assets from a Content Delivery Network (CDN) like CloudFlare, CloudFront, or Fastly.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Configuration Methods](#configuration-methods)
|
|
9
|
+
- [Step-by-Step Setup](#step-by-step-setup)
|
|
10
|
+
- [CloudFlare Specific Setup](#cloudflare-specific-setup)
|
|
11
|
+
- [Verification](#verification)
|
|
12
|
+
- [Troubleshooting](#troubleshooting)
|
|
13
|
+
- [Advanced Configuration](#advanced-configuration)
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
When using a CDN with Shakapacker, your compiled JavaScript bundles and other assets will be served from the CDN's edge servers instead of your application server. This provides:
|
|
18
|
+
|
|
19
|
+
- **Reduced latency** for users around the world
|
|
20
|
+
- **Decreased load** on your application servers
|
|
21
|
+
- **Better caching** and faster asset delivery
|
|
22
|
+
- **Improved scalability** for high-traffic applications
|
|
23
|
+
|
|
24
|
+
## Configuration Methods
|
|
25
|
+
|
|
26
|
+
Shakapacker supports CDN configuration through three methods (in order of precedence):
|
|
27
|
+
|
|
28
|
+
1. **Environment Variable** (highest priority): `SHAKAPACKER_ASSET_HOST`
|
|
29
|
+
2. **Shakapacker Configuration File**: `asset_host` setting in `config/shakapacker.yml`
|
|
30
|
+
3. **Rails Configuration**: `Rails.application.config.asset_host`
|
|
31
|
+
|
|
32
|
+
## Step-by-Step Setup
|
|
33
|
+
|
|
34
|
+
### 1. Configure Your CDN
|
|
35
|
+
|
|
36
|
+
First, set up your CDN to pull assets from your application's `/packs` directory. The exact steps depend on your CDN provider, but generally you'll need to:
|
|
37
|
+
|
|
38
|
+
1. Create a CDN distribution/zone
|
|
39
|
+
2. Set your application's domain as the origin server
|
|
40
|
+
3. Configure the CDN to cache files from `/packs/*` path
|
|
41
|
+
4. Note your CDN URL (e.g., `https://cdn.example.com` or `https://d1234567890.cloudfront.net`)
|
|
42
|
+
|
|
43
|
+
### 2. Configure Shakapacker Asset Host
|
|
44
|
+
|
|
45
|
+
Choose one of the following methods:
|
|
46
|
+
|
|
47
|
+
#### Option A: Using Environment Variable (Recommended for Production)
|
|
48
|
+
|
|
49
|
+
Set the `SHAKAPACKER_ASSET_HOST` environment variable:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# For production deployment
|
|
53
|
+
export SHAKAPACKER_ASSET_HOST=https://cdn.example.com
|
|
54
|
+
|
|
55
|
+
# Or in your .env file
|
|
56
|
+
SHAKAPACKER_ASSET_HOST=https://cdn.example.com
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Option B: Using shakapacker.yml
|
|
60
|
+
|
|
61
|
+
Add the `asset_host` setting to your `config/shakapacker.yml`:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
production:
|
|
65
|
+
# ... other settings ...
|
|
66
|
+
asset_host: https://cdn.example.com
|
|
67
|
+
|
|
68
|
+
# You can also set different CDN hosts per environment
|
|
69
|
+
staging:
|
|
70
|
+
asset_host: https://staging-cdn.example.com
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### Option C: Using Rails Configuration
|
|
74
|
+
|
|
75
|
+
Configure in your Rails environment file (e.g., `config/environments/production.rb`):
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
Rails.application.configure do
|
|
79
|
+
# ... other settings ...
|
|
80
|
+
|
|
81
|
+
# This will be used by Shakapacker if SHAKAPACKER_ASSET_HOST
|
|
82
|
+
# and asset_host in shakapacker.yml are not set
|
|
83
|
+
config.action_controller.asset_host = 'https://cdn.example.com'
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Compile Assets
|
|
88
|
+
|
|
89
|
+
During deployment, compile your assets as usual:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# The SHAKAPACKER_ASSET_HOST will be used during compilation
|
|
93
|
+
# to set the webpack publicPath
|
|
94
|
+
RAILS_ENV=production bundle exec rails assets:precompile
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This ensures that:
|
|
98
|
+
- Webpack's `publicPath` is set to your CDN URL
|
|
99
|
+
- Dynamic imports and code-split chunks load from the CDN
|
|
100
|
+
- Asset manifest references use CDN URLs
|
|
101
|
+
|
|
102
|
+
### 4. Deploy and Sync Assets
|
|
103
|
+
|
|
104
|
+
After compilation, ensure your compiled assets in `public/packs` are accessible to your CDN:
|
|
105
|
+
|
|
106
|
+
- **Push CDN**: Upload the files to your CDN's storage
|
|
107
|
+
- **Pull CDN**: Deploy your application normally; the CDN will pull assets on first request
|
|
108
|
+
|
|
109
|
+
## CloudFlare Specific Setup
|
|
110
|
+
|
|
111
|
+
For CloudFlare CDN setup:
|
|
112
|
+
|
|
113
|
+
### 1. Create a CloudFlare Account and Add Your Domain
|
|
114
|
+
|
|
115
|
+
1. Sign up for CloudFlare (if you haven't already)
|
|
116
|
+
2. Add your domain to CloudFlare
|
|
117
|
+
3. Update your domain's nameservers to CloudFlare's
|
|
118
|
+
|
|
119
|
+
### 2. Configure Page Rules for Assets
|
|
120
|
+
|
|
121
|
+
Create a page rule for your assets:
|
|
122
|
+
|
|
123
|
+
1. Go to **Page Rules** in CloudFlare dashboard
|
|
124
|
+
2. Create a new rule for `*yourdomain.com/packs/*`
|
|
125
|
+
3. Set the following settings:
|
|
126
|
+
- **Cache Level**: Cache Everything
|
|
127
|
+
- **Edge Cache TTL**: 1 month (or your preference)
|
|
128
|
+
- **Browser Cache TTL**: 1 month
|
|
129
|
+
|
|
130
|
+
### 3. Set Up CloudFlare for Assets Only (Optional)
|
|
131
|
+
|
|
132
|
+
If you want CloudFlare to only serve your assets (not your entire site):
|
|
133
|
+
|
|
134
|
+
1. Create a CNAME record: `cdn.yourdomain.com` → `yourdomain.com`
|
|
135
|
+
2. Set CloudFlare proxy (orange cloud) ON for this record
|
|
136
|
+
3. Configure Shakapacker:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
export SHAKAPACKER_ASSET_HOST=https://cdn.yourdomain.com
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 4. Configure CloudFlare Settings
|
|
143
|
+
|
|
144
|
+
Recommended CloudFlare settings for assets:
|
|
145
|
+
|
|
146
|
+
- **SSL/TLS**: Full or Full (Strict)
|
|
147
|
+
- **Caching Level**: Standard or Aggressive
|
|
148
|
+
- **Browser Cache TTL**: Respect Existing Headers
|
|
149
|
+
- **Always Online**: On
|
|
150
|
+
- **Auto Minify**: OFF (Shakapacker already minifies)
|
|
151
|
+
|
|
152
|
+
## Verification
|
|
153
|
+
|
|
154
|
+
To verify your CDN setup is working:
|
|
155
|
+
|
|
156
|
+
### 1. Check Compiled Assets
|
|
157
|
+
|
|
158
|
+
After compilation, inspect a compiled JavaScript file:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Look for the publicPath setting in your compiled bundles
|
|
162
|
+
grep -r "publicPath" public/packs/js/
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
You should see your CDN URL in the publicPath configuration.
|
|
166
|
+
|
|
167
|
+
### 2. Check Page Source
|
|
168
|
+
|
|
169
|
+
In production, view your page source and verify script tags use CDN URLs:
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<!-- Correct: Assets loading from CDN -->
|
|
173
|
+
<script src="https://cdn.example.com/packs/js/application-abc123.js"></script>
|
|
174
|
+
|
|
175
|
+
<!-- Wrong: Assets loading from relative path -->
|
|
176
|
+
<script src="/packs/js/application-abc123.js"></script>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 3. Check Network Tab
|
|
180
|
+
|
|
181
|
+
1. Open browser DevTools
|
|
182
|
+
2. Go to Network tab
|
|
183
|
+
3. Reload the page
|
|
184
|
+
4. Verify JavaScript files are loaded from CDN domain
|
|
185
|
+
|
|
186
|
+
### 4. Check Dynamic Imports
|
|
187
|
+
|
|
188
|
+
If using code splitting, verify dynamic chunks load from CDN:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// This dynamic import should load from CDN
|
|
192
|
+
import('./components/HeavyComponent').then(module => {
|
|
193
|
+
// Check Network tab - chunk should load from CDN
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Troubleshooting
|
|
198
|
+
|
|
199
|
+
### Assets Not Loading from CDN
|
|
200
|
+
|
|
201
|
+
**Problem**: Assets are still loading from your application domain.
|
|
202
|
+
|
|
203
|
+
**Solutions**:
|
|
204
|
+
1. Ensure you set `SHAKAPACKER_ASSET_HOST` **before** running `assets:precompile`
|
|
205
|
+
2. Clear Rails cache: `rails tmp:cache:clear`
|
|
206
|
+
3. Check the manifest.json file includes CDN URLs:
|
|
207
|
+
```bash
|
|
208
|
+
cat public/packs/manifest.json
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### CORS Errors
|
|
212
|
+
|
|
213
|
+
**Problem**: Browser shows CORS errors when loading assets from CDN.
|
|
214
|
+
|
|
215
|
+
**Solutions**:
|
|
216
|
+
1. Configure your CDN to add CORS headers:
|
|
217
|
+
```
|
|
218
|
+
Access-Control-Allow-Origin: *
|
|
219
|
+
```
|
|
220
|
+
2. Or configure for specific domain:
|
|
221
|
+
```
|
|
222
|
+
Access-Control-Allow-Origin: https://yourdomain.com
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Fonts Not Loading
|
|
226
|
+
|
|
227
|
+
**Problem**: Web fonts fail to load from CDN due to CORS.
|
|
228
|
+
|
|
229
|
+
**Solutions**:
|
|
230
|
+
1. Ensure CDN sends proper CORS headers for font files
|
|
231
|
+
2. In CloudFlare, create a page rule for `*.woff2`, `*.woff`, `*.ttf` files with CORS headers
|
|
232
|
+
3. Consider hosting fonts separately or using base64 encoding
|
|
233
|
+
|
|
234
|
+
### Development Environment Issues
|
|
235
|
+
|
|
236
|
+
**Problem**: CDN URLs appearing in development environment.
|
|
237
|
+
|
|
238
|
+
**Solution**: Only set `SHAKAPACKER_ASSET_HOST` in production:
|
|
239
|
+
|
|
240
|
+
```ruby
|
|
241
|
+
# config/environments/development.rb
|
|
242
|
+
# Ensure asset_host is NOT set in development
|
|
243
|
+
|
|
244
|
+
# config/environments/production.rb
|
|
245
|
+
# Set asset_host only in production
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Advanced Configuration
|
|
249
|
+
|
|
250
|
+
### Using Different CDNs for Different Assets
|
|
251
|
+
|
|
252
|
+
You can use Rails asset host proc for dynamic CDN selection:
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
# config/environments/production.rb
|
|
256
|
+
config.action_controller.asset_host = Proc.new do |source|
|
|
257
|
+
if source =~ /\.(js|css)$/
|
|
258
|
+
'https://js-css-cdn.example.com'
|
|
259
|
+
else
|
|
260
|
+
'https://images-cdn.example.com'
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### CDN with Integrity Hashes
|
|
266
|
+
|
|
267
|
+
When using Subresource Integrity (SRI) with CDN:
|
|
268
|
+
|
|
269
|
+
```yaml
|
|
270
|
+
# config/shakapacker.yml
|
|
271
|
+
production:
|
|
272
|
+
asset_host: https://cdn.example.com
|
|
273
|
+
integrity:
|
|
274
|
+
enabled: true
|
|
275
|
+
hash_functions: ["sha384"]
|
|
276
|
+
cross_origin: "anonymous"
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Ensure your CDN serves files with CORS headers:
|
|
280
|
+
```
|
|
281
|
+
Access-Control-Allow-Origin: *
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Multiple CDN Domains for Parallel Downloads
|
|
285
|
+
|
|
286
|
+
For HTTP/1.1 optimization (less relevant with HTTP/2):
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
# config/environments/production.rb
|
|
290
|
+
config.action_controller.asset_host = Proc.new do |source|
|
|
291
|
+
"https://cdn#{Digest::MD5.hexdigest(source)[0..2].to_i(16) % 4}.example.com"
|
|
292
|
+
end
|
|
293
|
+
# This creates cdn0.example.com through cdn3.example.com
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Cache Busting
|
|
297
|
+
|
|
298
|
+
Shakapacker automatically includes content hashes in production:
|
|
299
|
+
|
|
300
|
+
```yaml
|
|
301
|
+
# config/shakapacker.yml
|
|
302
|
+
production:
|
|
303
|
+
# This is already true by default in production
|
|
304
|
+
useContentHash: true
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
This ensures CDN caches are invalidated when content changes.
|
|
308
|
+
|
|
309
|
+
### Preloading Critical Assets
|
|
310
|
+
|
|
311
|
+
Use Rails helpers to preload critical assets from CDN:
|
|
312
|
+
|
|
313
|
+
```erb
|
|
314
|
+
<%= preload_pack_asset 'application.js' %>
|
|
315
|
+
<%= preload_pack_asset 'application.css' %>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Security Considerations
|
|
319
|
+
|
|
320
|
+
1. **Use HTTPS**: Always use HTTPS for your CDN URL to prevent mixed content warnings
|
|
321
|
+
2. **Configure CSP**: Update Content Security Policy headers to allow CDN domain:
|
|
322
|
+
```ruby
|
|
323
|
+
# config/initializers/content_security_policy.rb
|
|
324
|
+
Rails.application.config.content_security_policy do |policy|
|
|
325
|
+
policy.script_src :self, 'https://cdn.example.com'
|
|
326
|
+
policy.style_src :self, 'https://cdn.example.com'
|
|
327
|
+
end
|
|
328
|
+
```
|
|
329
|
+
3. **Use SRI**: Enable Subresource Integrity for additional security
|
|
330
|
+
4. **Monitor CDN**: Set up monitoring for CDN availability and performance
|
|
331
|
+
|
|
332
|
+
## Example Configuration
|
|
333
|
+
|
|
334
|
+
Here's a complete example for a production setup with CloudFlare:
|
|
335
|
+
|
|
336
|
+
```yaml
|
|
337
|
+
# config/shakapacker.yml
|
|
338
|
+
production:
|
|
339
|
+
compile: false
|
|
340
|
+
cache_manifest: true
|
|
341
|
+
asset_host: <%= ENV.fetch('SHAKAPACKER_ASSET_HOST', 'https://cdn.example.com') %>
|
|
342
|
+
|
|
343
|
+
# Enable integrity checking
|
|
344
|
+
integrity:
|
|
345
|
+
enabled: true
|
|
346
|
+
hash_functions: ["sha384"]
|
|
347
|
+
cross_origin: "anonymous"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
```ruby
|
|
351
|
+
# config/environments/production.rb
|
|
352
|
+
Rails.application.configure do
|
|
353
|
+
# Fallback if SHAKAPACKER_ASSET_HOST is not set
|
|
354
|
+
config.action_controller.asset_host = 'https://cdn.example.com'
|
|
355
|
+
|
|
356
|
+
# Ensure proper headers for CDN
|
|
357
|
+
config.public_file_server.headers = {
|
|
358
|
+
'Cache-Control' => 'public, max-age=31536000',
|
|
359
|
+
'X-Content-Type-Options' => 'nosniff'
|
|
360
|
+
}
|
|
361
|
+
end
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# Deployment script
|
|
366
|
+
export SHAKAPACKER_ASSET_HOST=https://cdn.example.com
|
|
367
|
+
RAILS_ENV=production bundle exec rails assets:precompile
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Summary
|
|
371
|
+
|
|
372
|
+
Setting up a CDN with Shakapacker involves:
|
|
373
|
+
|
|
374
|
+
1. Configuring your CDN service
|
|
375
|
+
2. Setting the `SHAKAPACKER_ASSET_HOST` environment variable
|
|
376
|
+
3. Compiling assets with the CDN URL
|
|
377
|
+
4. Deploying and verifying the setup
|
|
378
|
+
|
|
379
|
+
The key is ensuring `SHAKAPACKER_ASSET_HOST` is set during asset compilation so webpack's `publicPath` is configured correctly for dynamic imports and code-split chunks.
|