shakapacker 9.0.0.beta.2 → 9.0.0.beta.4

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.
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.