importmap-rails 2.2.0 → 2.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '079361e5c1e2b84206422fb3f2a5de6f6969c07a29e73d40843986d1549410ce'
4
- data.tar.gz: 61e335f52eacd06ffb635e4400ac68701e58cb57a9edfd7d38cc53a1a173c7a9
3
+ metadata.gz: c286a2385b19e8a170d991478ce228cfb1c0e27eb02fbda6349a889798caa85f
4
+ data.tar.gz: a40cea607756433bf36ad49e291e342f324a303c80e0286e980ee27c6c9001f9
5
5
  SHA512:
6
- metadata.gz: 1c92850ba94cc450f18b1554675737f94eff235e5b51d2922cbb1433a9cd6f3be065a839a72b93661feb7b1f346177b43fbf558a6b9f30445e232f7446e2071a
7
- data.tar.gz: 0be5aa11b95db77526ef6d933eeca0197346ba69ce5ef6a5148fb871eb7f986c050399c177cce0ccd8178dcb05ccd69a6d673b8efabadc382fea79284df7105c
6
+ metadata.gz: 71fc6847c3860c86d611dad36554feab750059128eee5d72961da0cd6bc2ba6ec08dc96358bb7919f487243d7463ca304efbbbf68874d7b58c9b85580d652f75
7
+ data.tar.gz: 59b0d5ce601ef182abd5f1017f414eec8fea35d1e48e270b0edd10bcf0c59cd7c5e52c1af0dab4f98f0ea81972ce82004af3011d1f3399d152ce077fbbd7a7e1
data/README.md CHANGED
@@ -138,73 +138,24 @@ Unpinning and removing "react"
138
138
 
139
139
  ## Subresource Integrity (SRI)
140
140
 
141
- For enhanced security, importmap-rails automatically includes [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) hashes by default when pinning packages. This ensures that JavaScript files loaded from CDNs haven't been tampered with.
142
-
143
- ### Default behavior with integrity
144
-
145
- When you pin a package, integrity hashes are automatically included:
146
-
147
- ```bash
148
- ./bin/importmap pin lodash
149
- Pinning "lodash" to vendor/javascript/lodash.js via download from https://ga.jspm.io/npm:lodash@4.17.21/lodash.js
150
- Using integrity: sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF
151
- ```
152
-
153
- This generates a pin in your `config/importmap.rb` with the integrity hash:
154
-
155
- ```ruby
156
- pin "lodash", integrity: "sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF" # @4.17.21
157
- ```
158
-
159
- ### Opting out of integrity
160
-
161
- If you need to disable integrity checking (not recommended for security reasons), you can use the `--no-integrity` flag:
162
-
163
- ```bash
164
- ./bin/importmap pin lodash --no-integrity
165
- Pinning "lodash" to vendor/javascript/lodash.js via download from https://ga.jspm.io/npm:lodash@4.17.21/lodash.js
166
- ```
167
-
168
- This generates a pin without integrity:
169
-
170
- ```ruby
171
- pin "lodash" # @4.17.21
172
- ```
173
-
174
- ### Adding integrity to existing pins
175
-
176
- If you have existing pins without integrity hashes, you can add them using the `integrity` command:
177
-
178
- ```bash
179
- # Add integrity to specific packages
180
- ./bin/importmap integrity lodash react
181
-
182
- # Add integrity to all pinned packages
183
- ./bin/importmap integrity
184
-
185
- # Update your importmap.rb file with integrity hashes
186
- ./bin/importmap integrity --update
187
- ```
141
+ For enhanced security, importmap-rails supports [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) hashes for packages loaded from external CDNs.
188
142
 
189
143
  ### Automatic integrity for local assets
190
144
 
191
- For local assets served by the Rails asset pipeline (like those created with `pin` or `pin_all_from`), you can use `integrity: true` to automatically calculate integrity hashes from the compiled assets:
145
+ Starting with importmap-rails, **`integrity: true` is the default** for all pins. This automatically calculates integrity hashes for local assets served by the Rails asset pipeline:
192
146
 
193
147
  ```ruby
194
148
  # config/importmap.rb
195
149
 
196
- # Automatically calculate integrity from asset pipeline
197
- pin "application", integrity: true
198
- pin "admin", to: "admin.js", integrity: true
199
-
200
- # Works with pin_all_from too
201
- pin_all_from "app/javascript/controllers", under: "controllers", integrity: true
202
- pin_all_from "app/javascript/lib", under: "lib", integrity: true
150
+ # These all use integrity: true by default
151
+ pin "application" # Auto-calculated integrity
152
+ pin "admin", to: "admin.js" # Auto-calculated integrity
153
+ pin_all_from "app/javascript/controllers", under: "controllers" # Auto-calculated integrity
203
154
 
204
- # Mixed usage
205
- pin "local_module", integrity: true # Auto-calculated
206
- pin "cdn_package", integrity: "sha384-abc123..." # Pre-calculated
207
- pin "no_integrity_package" # No integrity (default)
155
+ # Mixed usage - explicitly controlling integrity
156
+ pin "cdn_package", integrity: "sha384-abc123..." # Pre-calculated hash
157
+ pin "no_integrity_package", integrity: false # Explicitly disable integrity
158
+ pin "nil_integrity_package", integrity: nil # Explicitly disable integrity
208
159
  ```
209
160
 
210
161
  This is particularly useful for:
@@ -212,11 +163,16 @@ This is particularly useful for:
212
163
  * **Bulk operations** with `pin_all_from` where calculating hashes manually would be tedious
213
164
  * **Development workflow** where asset contents change frequently
214
165
 
215
- The `integrity: true` option:
216
- * Uses the Rails asset pipeline's built-in integrity calculation
217
- * Works with both Sprockets and Propshaft
218
- * Automatically updates when assets are recompiled
219
- * Gracefully handles missing assets (returns `nil` for non-existent files)
166
+ This behavior can be disabled by setting `integrity: false` or `integrity: nil`
167
+
168
+ **Important for Propshaft users:** SRI support requires Propshaft 1.2+ and you must configure the integrity hash algorithm in your application:
169
+
170
+ ```ruby
171
+ # config/application.rb or config/environments/*.rb
172
+ config.assets.integrity_hash_algorithm = 'sha256' # or 'sha384', 'sha512'
173
+ ```
174
+
175
+ Without this configuration, integrity will be disabled by default when using Propshaft. Sprockets includes integrity support out of the box.
220
176
 
221
177
  **Example output with `integrity: true`:**
222
178
  ```json
@@ -240,10 +196,14 @@ The integrity hashes are automatically included in your import map and module pr
240
196
  ```json
241
197
  {
242
198
  "imports": {
243
- "lodash": "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js"
199
+ "lodash": "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js",
200
+ "application": "/assets/application-abc123.js",
201
+ "controllers/hello_controller": "/assets/controllers/hello_controller-def456.js"
244
202
  },
245
203
  "integrity": {
246
204
  "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js": "sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF"
205
+ "/assets/application-abc123.js": "sha256-xyz789...",
206
+ "/assets/controllers/hello_controller-def456.js": "sha256-uvw012..."
247
207
  }
248
208
  }
249
209
  ```
@@ -251,22 +211,12 @@ The integrity hashes are automatically included in your import map and module pr
251
211
  **Module preload tags:**
252
212
  ```html
253
213
  <link rel="modulepreload" href="https://ga.jspm.io/npm:lodash@4.17.21/lodash.js" integrity="sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF">
214
+ <link rel="modulepreload" href="/assets/application-abc123.js" integrity="sha256-xyz789...">
215
+ <link rel="modulepreload" href="/assets/controllers/hello_controller-def456.js" integrity="sha256-uvw012...">
254
216
  ```
255
217
 
256
218
  Modern browsers will automatically validate these integrity hashes when loading the JavaScript modules, ensuring the files haven't been modified.
257
219
 
258
- ### Redownloading packages with integrity
259
-
260
- The `pristine` command also includes integrity by default:
261
-
262
- ```bash
263
- # Redownload all packages with integrity (default)
264
- ./bin/importmap pristine
265
-
266
- # Redownload packages without integrity
267
- ./bin/importmap pristine --no-integrity
268
- ```
269
-
270
220
  ## Preloading pinned modules
271
221
 
272
222
  To avoid the waterfall effect where the browser has to load one file after another before it can get to the deepest nested import, importmap-rails uses [modulepreload links](https://developers.google.com/web/updates/2017/12/modulepreload) by default. If you don't want to preload a dependency, because you want to load it on-demand for efficiency, append `preload: false` to the pin.
@@ -13,19 +13,15 @@ class Importmap::Commands < Thor
13
13
  option :env, type: :string, aliases: :e, default: "production"
14
14
  option :from, type: :string, aliases: :f, default: "jspm"
15
15
  option :preload, type: :string, repeatable: true, desc: "Can be used multiple times"
16
- option :integrity, type: :boolean, aliases: :i, default: true, desc: "Include integrity hash from JSPM"
17
16
  def pin(*packages)
18
- with_import_response(packages, env: options[:env], from: options[:from], integrity: options[:integrity]) do |imports, integrity_hashes|
19
- process_imports(imports, integrity_hashes) do |package, url, integrity_hash|
20
- puts %(Pinning "#{package}" to #{packager.vendor_path}/#{package}.js via download from #{url})
17
+ for_each_import(packages, env: options[:env], from: options[:from]) do |package, url|
18
+ puts %(Pinning "#{package}" to #{packager.vendor_path}/#{package}.js via download from #{url})
21
19
 
22
- packager.download(package, url)
20
+ packager.download(package, url)
23
21
 
24
- pin = packager.vendored_pin_for(package, url, options[:preload], integrity: integrity_hash)
22
+ pin = packager.vendored_pin_for(package, url, options[:preload])
25
23
 
26
- log_integrity_usage(integrity_hash)
27
- update_importmap_with_pin(package, pin)
28
- end
24
+ update_importmap_with_pin(package, pin)
29
25
  end
30
26
  end
31
27
 
@@ -33,12 +29,10 @@ class Importmap::Commands < Thor
33
29
  option :env, type: :string, aliases: :e, default: "production"
34
30
  option :from, type: :string, aliases: :f, default: "jspm"
35
31
  def unpin(*packages)
36
- with_import_response(packages, env: options[:env], from: options[:from]) do |imports, _integrity_hashes|
37
- imports.each do |package, url|
38
- if packager.packaged?(package)
39
- puts %(Unpinning and removing "#{package}")
40
- packager.remove(package)
41
- end
32
+ for_each_import(packages, env: options[:env], from: options[:from]) do |package, url|
33
+ if packager.packaged?(package)
34
+ puts %(Unpinning and removing "#{package}")
35
+ packager.remove(package)
42
36
  end
43
37
  end
44
38
  end
@@ -46,18 +40,13 @@ class Importmap::Commands < Thor
46
40
  desc "pristine", "Redownload all pinned packages"
47
41
  option :env, type: :string, aliases: :e, default: "production"
48
42
  option :from, type: :string, aliases: :f, default: "jspm"
49
- option :integrity, type: :boolean, aliases: :i, default: true, desc: "Include integrity hash from JSPM"
50
43
  def pristine
51
44
  packages = prepare_packages_with_versions
52
45
 
53
- with_import_response(packages, env: options[:env], from: options[:from], integrity: options[:integrity]) do |imports, integrity_hashes|
54
- process_imports(imports, integrity_hashes) do |package, url, integrity_hash|
55
- puts %(Downloading "#{package}" to #{packager.vendor_path}/#{package}.js from #{url})
46
+ for_each_import(packages, env: options[:env], from: options[:from]) do |package, url|
47
+ puts %(Downloading "#{package}" to #{packager.vendor_path}/#{package}.js from #{url})
56
48
 
57
- packager.download(package, url)
58
-
59
- log_integrity_usage(integrity_hash)
60
- end
49
+ packager.download(package, url)
61
50
  end
62
51
  end
63
52
 
@@ -118,33 +107,6 @@ class Importmap::Commands < Thor
118
107
  puts npm.packages_with_versions.map { |x| x.join(' ') }
119
108
  end
120
109
 
121
- desc "integrity [*PACKAGES]", "Download and add integrity hashes for packages"
122
- option :env, type: :string, aliases: :e, default: "production"
123
- option :from, type: :string, aliases: :f, default: "jspm"
124
- option :update, type: :boolean, aliases: :u, default: false, desc: "Update importmap.rb with integrity hashes"
125
- def integrity(*packages)
126
- packages = prepare_packages_with_versions(packages)
127
-
128
- with_import_response(packages, env: options[:env], from: options[:from], integrity: true) do |imports, integrity_hashes|
129
- process_imports(imports, integrity_hashes) do |package, url, integrity_hash|
130
- puts %(Getting integrity for "#{package}" from #{url})
131
-
132
- if integrity_hash
133
- puts %( #{package}: #{integrity_hash})
134
-
135
- if options[:update]
136
- pin_with_integrity = packager.pin_for(package, url, integrity: integrity_hash)
137
-
138
- update_importmap_with_pin(package, pin_with_integrity)
139
- puts %( Updated importmap.rb with integrity for "#{package}")
140
- end
141
- else
142
- puts %( No integrity hash available for "#{package}")
143
- end
144
- end
145
- end
146
- end
147
-
148
110
  private
149
111
  def packager
150
112
  @packager ||= Importmap::Packager.new
@@ -162,10 +124,6 @@ class Importmap::Commands < Thor
162
124
  end
163
125
  end
164
126
 
165
- def log_integrity_usage(integrity_hash)
166
- puts %( Using integrity: #{integrity_hash}) if integrity_hash
167
- end
168
-
169
127
  def handle_package_not_found(packages, from)
170
128
  puts "Couldn't find any packages in #{packages.inspect} on #{from}"
171
129
  end
@@ -205,18 +163,11 @@ class Importmap::Commands < Thor
205
163
  end
206
164
  end
207
165
 
208
- def process_imports(imports, integrity_hashes, &block)
209
- imports.each do |package, url|
210
- integrity_hash = integrity_hashes[url]
211
- block.call(package, url, integrity_hash)
212
- end
213
- end
214
-
215
- def with_import_response(packages, **options)
166
+ def for_each_import(packages, **options, &block)
216
167
  response = packager.import(*packages, **options)
217
168
 
218
169
  if response
219
- yield response[:imports], response[:integrity]
170
+ response[:imports].each(&block)
220
171
  else
221
172
  handle_package_not_found(packages, options[:from])
222
173
  end
data/lib/importmap/map.rb CHANGED
@@ -25,12 +25,12 @@ class Importmap::Map
25
25
  self
26
26
  end
27
27
 
28
- def pin(name, to: nil, preload: true, integrity: nil)
28
+ def pin(name, to: nil, preload: true, integrity: true)
29
29
  clear_cache
30
30
  @packages[name] = MappedFile.new(name: name, path: to || "#{name}.js", preload: preload, integrity: integrity)
31
31
  end
32
32
 
33
- def pin_all_from(dir, under: nil, to: nil, preload: true, integrity: nil)
33
+ def pin_all_from(dir, under: nil, to: nil, preload: true, integrity: true)
34
34
  clear_cache
35
35
  @directories[dir] = MappedDir.new(dir: dir, under: under, path: to, preload: preload, integrity: integrity)
36
36
  end
@@ -17,13 +17,12 @@ class Importmap::Packager
17
17
  @vendor_path = Pathname.new(vendor_path)
18
18
  end
19
19
 
20
- def import(*packages, env: "production", from: "jspm", integrity: false)
20
+ def import(*packages, env: "production", from: "jspm")
21
21
  response = post_json({
22
22
  "install" => Array(packages),
23
23
  "flattenScope" => true,
24
24
  "env" => [ "browser", "module", env ],
25
25
  "provider" => normalize_provider(from),
26
- "integrity" => integrity
27
26
  })
28
27
 
29
28
  case response.code
@@ -36,20 +35,19 @@ class Importmap::Packager
36
35
  end
37
36
  end
38
37
 
39
- def pin_for(package, url = nil, preloads: nil, integrity: nil)
38
+ def pin_for(package, url = nil, preloads: nil)
40
39
  to = url ? %(, to: "#{url}") : ""
41
40
  preload_param = preload(preloads)
42
- integrity_param = integrity ? %(, integrity: "#{integrity}") : ""
43
41
 
44
- %(pin "#{package}") + to + preload_param + integrity_param
42
+ %(pin "#{package}") + to + preload_param
45
43
  end
46
44
 
47
- def vendored_pin_for(package, url, preloads = nil, integrity: nil)
45
+ def vendored_pin_for(package, url, preloads = nil)
48
46
  filename = package_filename(package)
49
47
  version = extract_package_version_from(url)
50
48
  to = "#{package}.js" != filename ? filename : nil
51
49
 
52
- pin_for(package, to, preloads: preloads, integrity: integrity) + %( # #{version})
50
+ pin_for(package, to, preloads: preloads) + %( # #{version})
53
51
  end
54
52
 
55
53
  def packaged?(package)
@@ -96,11 +94,9 @@ class Importmap::Packager
96
94
  def extract_parsed_response(response)
97
95
  parsed = JSON.parse(response.body)
98
96
  imports = parsed.dig("map", "imports")
99
- integrity = parsed.dig("map", "integrity") || {}
100
97
 
101
98
  {
102
99
  imports: imports,
103
- integrity: integrity
104
100
  }
105
101
  end
106
102
 
@@ -1,3 +1,3 @@
1
1
  module Importmap
2
- VERSION = "2.2.0"
2
+ VERSION = "2.2.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: importmap-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson