Skip to content

Commit

Permalink
Rework importmap
Browse files Browse the repository at this point in the history
Skypack seems abandoned:
- skypackjs/skypack-cdn#365
- skypackjs/skypack-cdn#362

importmap-rails switched logic to always download: rails/importmap-rails#217

But it doesn't work for complex bigger packages. There's a WIP PR to address this: rails/importmap-rails#235

So I decided to use the new rails-importmap approach where I can, and switch to jsdelivr where I have to.

I've pinned to major versions and jsdelivr should take care of everything else. I've also updated the rake task to check for major version updates.
  • Loading branch information
miharekar committed Mar 30, 2024
1 parent 63dde91 commit a0d03d2
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ GEM
rack
ast (2.4.2)
aws-eventstream (1.3.0)
aws-partitions (1.903.0)
aws-partitions (1.904.0)
aws-sdk-core (3.191.5)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
Expand Down
14 changes: 8 additions & 6 deletions config/importmap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"

# use rails importmap:update to update these to the latest version
pin "stimulus-autocomplete", to: "https://cdn.skypack.dev/pin/[email protected]/mode=imports/optimized/stimulus-autocomplete.js" # source: https://cdn.skypack.dev/stimulus-autocomplete
pin "el-transition", to: "https://cdn.skypack.dev/pin/[email protected]/mode=imports/optimized/el-transition.js" # source: https://cdn.skypack.dev/el-transition
pin "highcharts", to: "https://cdn.skypack.dev/pin/[email protected]/mode=imports/unoptimized/es-modules/masters/highcharts.src.js" # source: https://cdn.skypack.dev/highcharts/es-modules/masters/highcharts.src.js
pin "highcharts-annotations", to: "https://cdn.skypack.dev/pin/[email protected]/mode=imports/unoptimized/es-modules/masters/modules/annotations.src.js" # source: https://cdn.skypack.dev/highcharts/es-modules/masters/modules/annotations.src.js
pin "highlight.js", to: "https://cdn.skypack.dev/pin/[email protected]/mode=imports/optimized/highlightjs.js" # source: https://cdn.skypack.dev/highlight.js
# use bin/importmap update to update these to the latest version
pin "stimulus-autocomplete" # @3.1.0
pin "el-transition" # @0.0.7

# use rails importmap:check to check for major version changes
pin "highcharts", to: "https://cdn.jsdelivr.net/npm/highcharts@11/es-modules/masters/highcharts.src.js"
pin "highcharts-annotations", to: "https://cdn.jsdelivr.net/npm/highcharts@11/es-modules/masters/modules/annotations.src.js"
pin "highlight.js", to: "https://cdn.jsdelivr.net/npm/highlight.js@11/+esm"

pin_all_from "app/javascript/channels", under: "channels"
pin_all_from "app/javascript/controllers", under: "controllers"
Expand Down
50 changes: 50 additions & 0 deletions lib/tasks/check_importmap.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require "concurrent"

class ImportMapChecker
attr_reader :file, :content, :mutex

def initialize
@file = Rails.root.join("config/importmap.rb")
@content = File.read(file)
@mutex = Mutex.new
end

def check
futures.each(&:value)
end

private

def futures
@futures ||= content.split("\n").filter_map { |line| create_future(line) }
end

def create_future(line)
return unless line.include?("jsdelivr")

Concurrent::Future.execute do
current_url = line[/to: "(.*)"/, 1]
non_versioned_url = current_url.sub(/@[\d]+\//, "/")
current_version = URI(current_url)
latest_version = URI(non_versioned_url)

current = Net::HTTP.get_response(URI(current_version))
if current.is_a?(Net::HTTPSuccess)
latest = Net::HTTP.get_response(URI(latest_version))
if latest.is_a?(Net::HTTPSuccess)
puts "There is a new major version of #{current_url} available" if current.body != latest.body
else
puts "Could not fetch #{latest_version}"
end
else
puts "Could not fetch #{current_version}"
end
end
end
end

namespace :importmap do
task check: :environment do
ImportMapChecker.new.check
end
end
55 changes: 0 additions & 55 deletions lib/tasks/update_importmap.rake

This file was deleted.

62 changes: 62 additions & 0 deletions vendor/javascript/el-transition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export async function enter(element, transitionName = null) {
element.classList.remove('hidden')
await transition('enter', element, transitionName)
}

export async function leave(element, transitionName = null) {
await transition('leave', element, transitionName)
element.classList.add('hidden')
}

export async function toggle(element, transitionName = null) {
if (element.classList.contains('hidden')) {
await enter(element, transitionName)
} else {
await leave(element, transitionName)
}
}

async function transition(direction, element, animation) {
const dataset = element.dataset
const animationClass = animation ? `${animation}-${direction}` : direction
let transition = `transition${direction.charAt(0).toUpperCase() + direction.slice(1)}`
const genesis = dataset[transition] ? dataset[transition].split(" ") : [animationClass]
const start = dataset[`${transition}Start`] ? dataset[`${transition}Start`].split(" ") : [`${animationClass}-start`]
const end = dataset[`${transition}End`] ? dataset[`${transition}End`].split(" ") : [`${animationClass}-end`]

addClasses(element, genesis)
addClasses(element, start)
await nextFrame()
removeClasses(element, start)
addClasses(element, end);
await afterTransition(element)
removeClasses(element, end)
removeClasses(element, genesis)
}

function addClasses(element, classes) {
element.classList.add(...classes)
}

function removeClasses(element, classes) {
element.classList.remove(...classes)
}

function nextFrame() {
return new Promise(resolve => {
requestAnimationFrame(() => {
requestAnimationFrame(resolve)
});
});
}

function afterTransition(element) {
return new Promise(resolve => {
// safari return string with comma separate values
const computedDuration = getComputedStyle(element).transitionDuration.split(",")[0]
const duration = Number(computedDuration.replace('s', '')) * 1000;
setTimeout(() => {
resolve()
}, duration)
});
}
Loading

0 comments on commit a0d03d2

Please sign in to comment.