Download importmap Resources at Build Time

Problem

The default loading source of Importmap-rails is CDN, but public CDN is not stable in China. Another method is to download JavaScript to the vender/javascript directory, but this method requires external JavaScript to be checked into the source code management tool, causing the source code size to increase.

Is there a way to delay the download of JavaScript to build time? I found a method through practice.

Solution

Step 1, Modify .gitignore

Add the following content to .gitignore:

/vendor/javascript

This will let git ignore the content downloaded by importmap.

Step 2, use --download

Add the --download parameter when importmap pin, for example:

bin/importmap pin sortablejs --download

This will immediately download the source code of sortablejs, store it in vendor/javascript, and add the following content to config/importmap.rb:

pin "sortablejs" # @1.15.0

This is a normal importmap operation, just no need to submit js to the source code library, and use the content in config/importmap.rb as the configuration.

Step Three, Add rake task

Create a new lib/tasks/importmap.rake file and write the following content:

require "importmap/npm"
require "importmap/packager"

namespace :importmap do
  desc "Download"
  task :download do
    npm = Importmap::Npm.new
    packager = Importmap::Packager.new
    packages = npm.packages_with_versions.map { |item| item.join("@") }
    imports = packager.import(packages)
    imports.each do |package, url|
      puts %(Pinning "#{package}" to #{packager.vendor_path}/#{package}.js via download from #{url})
      packager.download(package, url)
    end
  end
end

Rake::Task["assets:precompile"].enhance(["importmap:download"])

When executing bin/rails assets:precompile, it will first execute bin/rails importmap:download, which will download JavaScript according to the content of config/importmap.rb.

Remember to include the step of bin/rails assets:precompile in Dockerfile, even if you don’t use other build tools.

Step Four, Other Configurations

Add bin/rails importmap:download in other scripts, for example, add it in bin/setup:

puts "\n== Importmap download =="

system! "bin/rails importmap:download"

This is convenient for setting up the development environment.

Conclusion

This article implements the download of importmap resources to the build stage by adding a rake task. You can control the distribution of JavaScript files yourself, and don’t need to submit large external JavaScript files to the source code.

This script does not consider JavaScript dependencies is very complicated.

2 Likes

This is great! Really didn’t want to have to clutter my repo with a bunch of vendor libs. Prefer it to just download at build time. One minor correction:

-imports = packager.import(packages)
+imports = packager.import(*packages)

The import method uses * on the first argument so expects each package as it’s own argument. Therefore if we have a list we need to splat it out.