From e54fd542355e75e970d99842e2075a4f212a7802 Mon Sep 17 00:00:00 2001 From: Andrew Seroff Date: Sun, 15 Sep 2024 12:07:52 -0500 Subject: [PATCH] Allows preload to be determined by provided entry_point (#253) * Allows preload to be determined by provided entry_point * entry point defaults and fix * Tests for various preload values * Update README.md --- README.md | 19 +++++++++++++ .../importmap/importmap_tags_helper.rb | 6 ++--- lib/importmap/map.rb | 8 +++--- test/importmap_test.rb | 27 ++++++++++++++++++- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f332366..f4c5bee 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,25 @@ pin "md5", preload: false # file lives in vendor/javascript/md5.js ... ``` +You can also specify which entry points to preload a particular dependency in by providing `preload:` a string or array of strings. + +Example: + +```ruby +# config/importmap.rb +pin "@github/hotkey", to: "@github--hotkey.js", preload: 'application' +pin "md5", preload: ['application', 'alternate'] + +# app/views/layouts/application.html.erb +<%= javascript_importmap_tags 'alternate' %> + +# will include the following link before the importmap is setup: + +... +``` + + + ## Composing import maps By default, Rails loads import map definition from the application's `config/importmap.rb` to the `Importmap::Map` object available at `Rails.application.importmap`. diff --git a/app/helpers/importmap/importmap_tags_helper.rb b/app/helpers/importmap/importmap_tags_helper.rb index c0bb58f..7dc133b 100644 --- a/app/helpers/importmap/importmap_tags_helper.rb +++ b/app/helpers/importmap/importmap_tags_helper.rb @@ -3,7 +3,7 @@ module Importmap::ImportmapTagsHelper def javascript_importmap_tags(entry_point = "application", importmap: Rails.application.importmap) safe_join [ javascript_inline_importmap_tag(importmap.to_json(resolver: self)), - javascript_importmap_module_preload_tags(importmap), + javascript_importmap_module_preload_tags(importmap, entry_point:), javascript_import_module_tag(entry_point) ], "\n" end @@ -24,8 +24,8 @@ def javascript_import_module_tag(*module_names) # Link tags for preloading all modules marked as preload: true in the `importmap` # (defaults to Rails.application.importmap), such that they'll be fetched # in advance by browsers supporting this link type (https://caniuse.com/?search=modulepreload). - def javascript_importmap_module_preload_tags(importmap = Rails.application.importmap) - javascript_module_preload_tag(*importmap.preloaded_module_paths(resolver: self)) + def javascript_importmap_module_preload_tags(importmap = Rails.application.importmap, entry_point: "application") + javascript_module_preload_tag(*importmap.preloaded_module_paths(resolver: self, entry_point:)) end # Link tag(s) for preloading the JavaScript module residing in `*paths`. Will return one link tag per path element. diff --git a/lib/importmap/map.rb b/lib/importmap/map.rb index 43f0421..5d0cd62 100644 --- a/lib/importmap/map.rb +++ b/lib/importmap/map.rb @@ -40,9 +40,9 @@ def pin_all_from(dir, under: nil, to: nil, preload: true) # resolver that has been configured for the `asset_host` you want these resolved paths to use. In case you need to # resolve for different asset hosts, you can pass in a custom `cache_key` to vary the cache used by this method for # the different cases. - def preloaded_module_paths(resolver:, cache_key: :preloaded_module_paths) + def preloaded_module_paths(resolver:, entry_point: "application", cache_key: :preloaded_module_paths) cache_as(cache_key) do - resolve_asset_paths(expanded_preloading_packages_and_directories, resolver: resolver).values + resolve_asset_paths(expanded_preloading_packages_and_directories(entry_point:), resolver:).values end end @@ -118,8 +118,8 @@ def resolve_asset_paths(paths, resolver:) end.compact end - def expanded_preloading_packages_and_directories - expanded_packages_and_directories.select { |name, mapping| mapping.preload } + def expanded_preloading_packages_and_directories(entry_point:) + expanded_packages_and_directories.select { |name, mapping| mapping.preload.in?([true, false]) ? mapping.preload : (Array(mapping.preload) & Array(entry_point)).any? } end def expanded_packages_and_directories diff --git a/test/importmap_test.rb b/test/importmap_test.rb index 15c2290..bfb60b3 100644 --- a/test/importmap_test.rb +++ b/test/importmap_test.rb @@ -8,6 +8,9 @@ def setup pin "editor", to: "rich_text.js", preload: false pin "not_there", to: "nowhere.js", preload: false pin "md5", to: "https://cdn.skypack.dev/md5", preload: true + pin "leaflet", to: "https://cdn.skypack.dev/leaflet", preload: 'application' + pin "chartkick", to: "https://cdn.skypack.dev/chartkick", preload: ['application', 'alternate'] + pin "tinyMCE", to: "https://cdn.skypack.dev/tinymce", preload: 'alternate' pin_all_from "app/javascript/controllers", under: "controllers", preload: true pin_all_from "app/javascript/spina/controllers", under: "controllers/spina", preload: true @@ -78,10 +81,32 @@ def setup end end - test "preloaded modules are included in preload tags" do + test "preloaded modules are included in preload tags when no entry_point specified" do preloading_module_paths = @importmap.preloaded_module_paths(resolver: ApplicationController.helpers).to_s assert_match /md5/, preloading_module_paths assert_match /goodbye_controller/, preloading_module_paths + assert_match /leaflet/, preloading_module_paths + assert_no_match /application/, preloading_module_paths + assert_no_match /tinymce/, preloading_module_paths + end + + test "preloaded modules are included in preload tags based on single entry_point provided" do + preloading_module_paths = @importmap.preloaded_module_paths(resolver: ApplicationController.helpers, entry_point: "alternate").to_s + assert_no_match /leaflet/, preloading_module_paths + assert_match /tinymce/, preloading_module_paths + assert_match /chartkick/, preloading_module_paths + assert_match /md5/, preloading_module_paths + assert_match /goodbye_controller/, preloading_module_paths + assert_no_match /application/, preloading_module_paths + end + + test "preloaded modules are included in preload tags based on multiple entry_points provided" do + preloading_module_paths = @importmap.preloaded_module_paths(resolver: ApplicationController.helpers, entry_point: ["application", "alternate"]).to_s + assert_match /leaflet/, preloading_module_paths + assert_match /tinymce/, preloading_module_paths + assert_match /chartkick/, preloading_module_paths + assert_match /md5/, preloading_module_paths + assert_match /goodbye_controller/, preloading_module_paths assert_no_match /application/, preloading_module_paths end