importmap-rails 0.3.3 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +36 -17
- data/app/assets/javascripts/es-module-shims.js +1 -1
- data/app/assets/javascripts/{es-module-shims@0.12.7.js → es-module-shims@0.12.8.js} +3 -1
- data/lib/importmap/commands.rb +24 -0
- data/lib/importmap/engine.rb +4 -7
- data/lib/importmap/map.rb +26 -13
- data/lib/importmap/pinner.rb +32 -0
- data/lib/importmap/reloader.rb +1 -1
- data/lib/importmap/version.rb +1 -1
- data/lib/install/bin/importmap +4 -0
- data/lib/install/config/importmap.rb +10 -0
- data/lib/install/install.rb +5 -21
- data/lib/tasks/importmap_tasks.rake +6 -0
- metadata +25 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90c8dfc1a293d3e6f5e1fbfdac6a7852a54d4fefe0179874adccccef986ffb70
|
4
|
+
data.tar.gz: f54c20b0877bcf7e0a88cb15ab9a05dbeb81638c0a48a1a16687880e2e651332
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c56e463c75ffb6e1d39d6d7edd2ab1da88d13abd674fe4db7f6cf056a505253800e121ea8cf8880d6f7eca29831340cc6e3c55f79efb66b1da2faf034935f5fd
|
7
|
+
data.tar.gz: 20e1e5e714d63e188ad265f7b01130803bb4c2881aa1b65cccf3adfdcb168f891b9deb7e0f3899a9248c5cf321e47311a1dfaa7f78a5f128f346b164833f1e02
|
data/README.md
CHANGED
@@ -22,32 +22,53 @@ Note: In order to use JavaScript from Rails frameworks like Action Cable, Action
|
|
22
22
|
|
23
23
|
The import map is configured programmatically through the `Rails.application.config.importmap` assignment, which by default is setup in `config/importmap.rb` after running the installer. This file is automatically reloaded in development upon changes, but note that you must restart the server if you remove pins and need them gone from the rendered importmap or list of preloads.
|
24
24
|
|
25
|
-
This programmatically configured import map is inlined in the `<head>` of your application layout using `<%= javascript_importmap_tags %>`, which will setup the JSON configuration inside a `<script type="importmap">` tag. After that, the [es-module-shim](https://github.com/guybedford/es-module-shims) is loaded, and then finally the application entrypoint is imported via `<script type="module">import "application"</script>`. That logical entrypoint, `application`, is mapped in the importmap script tag to the file `app/
|
25
|
+
This programmatically configured import map is inlined in the `<head>` of your application layout using `<%= javascript_importmap_tags %>`, which will setup the JSON configuration inside a `<script type="importmap">` tag. After that, the [es-module-shim](https://github.com/guybedford/es-module-shims) is loaded, and then finally the application entrypoint is imported via `<script type="module">import "application"</script>`. That logical entrypoint, `application`, is mapped in the importmap script tag to the file `app/javascript/application.js`, which is copied and digested by the asset pipeline.
|
26
26
|
|
27
|
-
It's in `app/
|
27
|
+
It's in `app/javascript/application.js` you setup your application by importing any of the modules that have been defined in the import map. You can use the full ESM functionality of importing any particular export of the modules or everything.
|
28
28
|
|
29
29
|
It makes sense to use logical names that match the package names used by NPM, such that if you later want to start transpiling or bundling your code, you'll not have to change any module imports.
|
30
30
|
|
31
31
|
|
32
|
-
##
|
32
|
+
## Using node modules via JavaScript CDNs
|
33
33
|
|
34
|
-
|
34
|
+
Importmap for Rails is designed to be used with JavaScript CDNs for your node package dependencies. The CDNs provide pre-compiled distribution versions ready to use, and offer a fast, efficient way of serving them.
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
You can use the `./bin/importmap` command that's added as part of the install to pin additional packages to your import map. This command uses an API from [JSPM.org](https://jspm.org) to resolve your package dependencies most efficiently, and then add the pins to your `config/importmap.rb` file. It can resolve these dependencies from JSPM itself, but also from other CDNs, like [unpkg.com](https://unpkg.com), [jsdelivr.com](https://www.jsdelivr.com), [skypack.dev](https://www.skypack.dev), etc.
|
37
|
+
|
38
|
+
It works like so:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
./bin/importmap pin react react-dom
|
42
|
+
|
43
|
+
Pinned 'react' to https://ga.jspm.io/npm:react@17.0.2/index.js
|
44
|
+
Pinned 'react-dom' to https://ga.jspm.io/npm:react-dom@17.0.2/index.js
|
45
|
+
Pinned 'object-assign' to https://ga.jspm.io/npm:object-assign@4.1.1/index.js
|
46
|
+
Pinned 'scheduler' to https://ga.jspm.io/npm:scheduler@0.20.2/index.js
|
47
|
+
|
48
|
+
./bin/importmap json
|
49
|
+
|
50
|
+
{
|
51
|
+
"imports": {
|
52
|
+
"application": "/application.js",
|
53
|
+
"react": "https://ga.jspm.io/npm:react@17.0.2/index.js",
|
54
|
+
"react-dom": "https://ga.jspm.io/npm:react-dom@17.0.2/index.js",
|
55
|
+
"object-assign": "https://ga.jspm.io/npm:object-assign@4.1.1/index.js",
|
56
|
+
"scheduler": "https://ga.jspm.io/npm:scheduler@0.20.2/index.js"
|
57
|
+
}
|
58
|
+
}
|
41
59
|
```
|
42
60
|
|
61
|
+
As you can see, the two packages react and react-dom resolve to a total of four dependencies, when resolved via the jspm default.
|
62
|
+
|
43
63
|
Now you can use these in your application.js entrypoint like you would any other module:
|
44
64
|
|
45
65
|
```js
|
46
|
-
import "
|
47
|
-
import
|
48
|
-
console.log(md5("Hash it out"))
|
66
|
+
import React from "react"
|
67
|
+
import ReactDOM from "react-dom"
|
49
68
|
```
|
50
69
|
|
70
|
+
Run `./bin/importmap` to see more options.
|
71
|
+
|
51
72
|
|
52
73
|
## Preloading pinned modules
|
53
74
|
|
@@ -57,16 +78,14 @@ Example:
|
|
57
78
|
|
58
79
|
```ruby
|
59
80
|
# config/importmap.rb
|
60
|
-
|
61
|
-
|
62
|
-
pin "md5", to: "https://cdn.skypack.dev/md5", preload: false
|
63
|
-
end
|
81
|
+
pin "@github/hotkey", to: "https://ga.jspm.io/npm:@github/hotkey@1.4.4/dist/index.js"
|
82
|
+
pin "md5", to: "https://cdn.jsdelivr.net/npm/md5@2.3.0/md5.js", preload: false
|
64
83
|
|
65
84
|
# app/views/layouts/application.html.erb
|
66
85
|
<%= javascript_importmap_tags %>
|
67
86
|
|
68
87
|
# will include the following link before the importmap is setup:
|
69
|
-
<link rel="modulepreload" href="https://
|
88
|
+
<link rel="modulepreload" href="https://ga.jspm.io/npm:@github/hotkey@1.4.4/dist/index.js">
|
70
89
|
...
|
71
90
|
```
|
72
91
|
|
@@ -1 +1 @@
|
|
1
|
-
//= require ./es-module-shims@0.12.
|
1
|
+
//= require ./es-module-shims@0.12.8.js
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/* ES Module Shims 0.12.
|
1
|
+
/* ES Module Shims 0.12.8 */
|
2
2
|
(function () {
|
3
3
|
// Bail on all shimming for Chrome until https://github.com/guybedford/es-module-shims/issues/150
|
4
4
|
if (navigator.userAgent.match("Chrome")) return
|
@@ -643,6 +643,8 @@
|
|
643
643
|
if (link.ep) // ep marker = processed
|
644
644
|
return;
|
645
645
|
link.ep = true;
|
646
|
+
if (fetchCache[link.href])
|
647
|
+
return;
|
646
648
|
fetchCache[link.href] = doFetch(link.href, getFetchOpts(link));
|
647
649
|
}
|
648
650
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "importmap/pinner"
|
3
|
+
|
4
|
+
class Importmap::Commands < Thor
|
5
|
+
desc "pin [*PACKAGES]", "Pin new packages"
|
6
|
+
option :env, type: :string, aliases: :e, default: "production"
|
7
|
+
option :from, type: :string, aliases: :f, default: "jspm"
|
8
|
+
def pin(*packages)
|
9
|
+
if imports = Importmap::Pinner.new.pin(*packages, env: options[:env], from: options[:from])
|
10
|
+
imports.each do |package, url|
|
11
|
+
puts "Pinned '#{package}' to #{url}"
|
12
|
+
end
|
13
|
+
else
|
14
|
+
puts "Couldn't find any packages in #{packages.inspect} on #{options[:provider]}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "json", "Show the full importmap in json"
|
19
|
+
def json
|
20
|
+
puts Rails.application.config.importmap.to_json(resolver: ActionController::Base.helpers)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Importmap::Commands.start(ARGV)
|
data/lib/importmap/engine.rb
CHANGED
@@ -2,19 +2,16 @@ require "importmap/map"
|
|
2
2
|
|
3
3
|
module Importmap
|
4
4
|
class Engine < ::Rails::Engine
|
5
|
-
config.importmap = Importmap::Map.new
|
6
|
-
|
5
|
+
config.importmap = Importmap::Map.new.draw("config/importmap.rb")
|
7
6
|
config.autoload_once_paths = %W( #{root}/app/helpers )
|
8
7
|
|
9
8
|
initializer "importmap.reloader" do |app|
|
10
9
|
app.config.paths.add "config/importmap.rb"
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
reloader.execute
|
15
|
-
app.reloaders << reloader
|
16
|
-
app.reloader.to_run do
|
11
|
+
Importmap::Reloader.new.tap do |reloader|
|
17
12
|
reloader.execute
|
13
|
+
app.reloaders << reloader
|
14
|
+
app.reloader.to_run { reloader.execute }
|
18
15
|
end
|
19
16
|
end
|
20
17
|
|
data/lib/importmap/map.rb
CHANGED
@@ -1,17 +1,30 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
1
3
|
class Importmap::Map
|
2
|
-
attr_reader :
|
4
|
+
attr_reader :packages, :directories
|
3
5
|
attr_accessor :cached
|
4
6
|
|
5
7
|
def initialize
|
6
|
-
@
|
8
|
+
@packages, @directories = {}, {}
|
7
9
|
end
|
8
10
|
|
9
|
-
def draw(&block)
|
10
|
-
|
11
|
+
def draw(path = nil, &block)
|
12
|
+
if path
|
13
|
+
begin
|
14
|
+
instance_eval(File.read(path))
|
15
|
+
rescue Exception => e
|
16
|
+
Rails.logger.error "Unable to parse import map from #{path}: #{e.message}"
|
17
|
+
raise "Unable to parse import map from #{path}: #{e.message}"
|
18
|
+
end
|
19
|
+
else
|
20
|
+
instance_eval(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
self
|
11
24
|
end
|
12
25
|
|
13
26
|
def pin(name, to: nil, preload: true)
|
14
|
-
@
|
27
|
+
@packages[name] = MappedFile.new(name: name, path: to || "#{name}.js", preload: preload)
|
15
28
|
end
|
16
29
|
|
17
30
|
def pin_all_from(dir, under: nil, to: nil, preload: true)
|
@@ -20,19 +33,19 @@ class Importmap::Map
|
|
20
33
|
|
21
34
|
def preloaded_module_paths(resolver:)
|
22
35
|
cache_as(:preloaded_module_paths) do
|
23
|
-
resolve_asset_paths(
|
36
|
+
resolve_asset_paths(expanded_preloading_packages_and_directories, resolver: resolver).values
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
27
40
|
def to_json(resolver:)
|
28
41
|
cache_as(:json) do
|
29
|
-
{ "imports" => resolve_asset_paths(
|
42
|
+
JSON.pretty_generate({ "imports" => resolve_asset_paths(expanded_packages_and_directories, resolver: resolver) })
|
30
43
|
end
|
31
44
|
end
|
32
45
|
|
33
46
|
private
|
34
|
-
MappedFile = Struct.new(:name, :path, :preload, keyword_init: true)
|
35
47
|
MappedDir = Struct.new(:dir, :path, :under, :preload, keyword_init: true)
|
48
|
+
MappedFile = Struct.new(:name, :path, :preload, keyword_init: true)
|
36
49
|
|
37
50
|
def cache_as(name)
|
38
51
|
if (cached && result = instance_variable_get("@cached_#{name}"))
|
@@ -53,12 +66,12 @@ class Importmap::Map
|
|
53
66
|
end.compact
|
54
67
|
end
|
55
68
|
|
56
|
-
def
|
57
|
-
|
69
|
+
def expanded_preloading_packages_and_directories
|
70
|
+
expanded_packages_and_directories.select { |name, mapping| mapping.preload }
|
58
71
|
end
|
59
72
|
|
60
|
-
def
|
61
|
-
@
|
73
|
+
def expanded_packages_and_directories
|
74
|
+
@packages.dup.tap { |expanded| expand_directories_into expanded }
|
62
75
|
end
|
63
76
|
|
64
77
|
def expand_directories_into(paths)
|
@@ -80,7 +93,7 @@ class Importmap::Map
|
|
80
93
|
end
|
81
94
|
|
82
95
|
def module_path_from(filename, mapping)
|
83
|
-
[ mapping.path || mapping.under, filename.to_s ].join("/")
|
96
|
+
[ mapping.path || mapping.under, filename.to_s ].compact.join("/")
|
84
97
|
end
|
85
98
|
|
86
99
|
def find_javascript_files_in_tree(path)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "httparty"
|
2
|
+
|
3
|
+
class Importmap::Pinner
|
4
|
+
include HTTParty
|
5
|
+
base_uri "https://api.jspm.io"
|
6
|
+
|
7
|
+
def pin(*packages, env: "production", from: "jspm")
|
8
|
+
fetch_imports(*packages, env: env, provider: from)&.tap do |imports|
|
9
|
+
imports.each do |package, url|
|
10
|
+
append_to_importmap package, url
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def append_to_importmap(package, url)
|
17
|
+
Rails.root.join("config/importmap.rb").open("a") do |config|
|
18
|
+
config.puts %(pin "#{package}", to: "#{url}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def fetch_imports(*packages, env:, provider:)
|
23
|
+
response = self.class.post("/generate", body: {
|
24
|
+
"install" => Array(packages),
|
25
|
+
"flattenScope" => true,
|
26
|
+
"env" => [ "browser", "module", env ],
|
27
|
+
"provider" => provider.to_s
|
28
|
+
}.to_json)
|
29
|
+
|
30
|
+
response.dig("map", "imports")
|
31
|
+
end
|
32
|
+
end
|
data/lib/importmap/reloader.rb
CHANGED
data/lib/importmap/version.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Use Action Cable channels (remember to import "@rails/actionable" in your application.js)
|
2
|
+
# pin "@rails/actioncable", to: "actioncable.esm.js"
|
3
|
+
# pin_all_from "app/javascript/channels", under: "channels"
|
4
|
+
|
5
|
+
# Use direct uploads for Active Storage (remember to import "@rails/activestorage" in your application.js)
|
6
|
+
# pin "@rails/activestorage", to: "activestorage.esm.js"
|
7
|
+
|
8
|
+
# Use node modules from a JavaScript CDN by running ./bin/importmap
|
9
|
+
|
10
|
+
pin "application"
|
data/lib/install/install.rb
CHANGED
@@ -10,10 +10,7 @@ end
|
|
10
10
|
|
11
11
|
say "Create application.js module as entrypoint"
|
12
12
|
create_file Rails.root.join("app/javascript/application.js") do <<-JS
|
13
|
-
// Configure your import map in config/importmap.rb
|
14
|
-
|
15
|
-
// import "@rails/actioncable"
|
16
|
-
// import "@rails/activestorage"
|
13
|
+
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
17
14
|
JS
|
18
15
|
end
|
19
16
|
|
@@ -21,21 +18,8 @@ say "Ensure JavaScript files are in the asset pipeline manifest"
|
|
21
18
|
append_to_file Rails.root.join("app/assets/config/manifest.js"), %(//= link_tree ../../javascript .js\n)
|
22
19
|
|
23
20
|
say "Configure importmap paths in config/importmap.rb"
|
24
|
-
|
25
|
-
Rails.application.config.importmap.draw do
|
26
|
-
pin "application"
|
27
|
-
|
28
|
-
# Use libraries available via the asset pipeline (locally or via gems).
|
29
|
-
# pin "@rails/actioncable", to: "actioncable.esm.js"
|
30
|
-
# pin "@rails/activestorage", to: "activestorage.esm.js"
|
31
|
-
|
32
|
-
# Use libraries directly from JavaScript CDNs (see https://www.skypack.dev, https://esm.sh, https://www.jsdelivr.com/esm)
|
33
|
-
# pin "vue", to: "https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.esm.browser.js"
|
34
|
-
# pin "d3", to: "https://esm.sh/d3?bundle"
|
21
|
+
copy_file "#{__dir__}/config/importmap.rb", "config/importmap.rb"
|
35
22
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
RUBY
|
41
|
-
end
|
23
|
+
say "Copying binstub"
|
24
|
+
copy_file "#{__dir__}/bin/importmap", "bin/importmap"
|
25
|
+
chmod "bin", 0755 & ~File.umask, verbose: false
|
@@ -3,4 +3,10 @@ namespace :importmap do
|
|
3
3
|
task :install do
|
4
4
|
system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../install/install.rb", __dir__)}"
|
5
5
|
end
|
6
|
+
|
7
|
+
desc "Show the importmap"
|
8
|
+
task :pins do
|
9
|
+
require Rails.root.join("config/environment")
|
10
|
+
puts Rails.application.config.importmap.to_json(resolver: ActionController::Base.helpers)
|
11
|
+
end
|
6
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: importmap-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,7 +24,21 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 6.0.0
|
27
|
-
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: httparty
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.16'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.16'
|
41
|
+
description:
|
28
42
|
email: david@loudthinking.com
|
29
43
|
executables: []
|
30
44
|
extensions: []
|
@@ -34,13 +48,17 @@ files:
|
|
34
48
|
- README.md
|
35
49
|
- Rakefile
|
36
50
|
- app/assets/javascripts/es-module-shims.js
|
37
|
-
- app/assets/javascripts/es-module-shims@0.12.
|
51
|
+
- app/assets/javascripts/es-module-shims@0.12.8.js
|
38
52
|
- app/helpers/importmap/importmap_tags_helper.rb
|
39
53
|
- lib/importmap-rails.rb
|
54
|
+
- lib/importmap/commands.rb
|
40
55
|
- lib/importmap/engine.rb
|
41
56
|
- lib/importmap/map.rb
|
57
|
+
- lib/importmap/pinner.rb
|
42
58
|
- lib/importmap/reloader.rb
|
43
59
|
- lib/importmap/version.rb
|
60
|
+
- lib/install/bin/importmap
|
61
|
+
- lib/install/config/importmap.rb
|
44
62
|
- lib/install/install.rb
|
45
63
|
- lib/shim.js
|
46
64
|
- lib/tasks/importmap_tasks.rake
|
@@ -50,7 +68,7 @@ licenses:
|
|
50
68
|
metadata:
|
51
69
|
homepage_uri: https://github.com/rails/importmap-rails
|
52
70
|
source_code_uri: https://github.com/rails/importmap-rails
|
53
|
-
post_install_message:
|
71
|
+
post_install_message:
|
54
72
|
rdoc_options: []
|
55
73
|
require_paths:
|
56
74
|
- lib
|
@@ -66,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
84
|
version: '0'
|
67
85
|
requirements: []
|
68
86
|
rubygems_version: 3.1.4
|
69
|
-
signing_key:
|
87
|
+
signing_key:
|
70
88
|
specification_version: 4
|
71
89
|
summary: Use ESM with importmap to manage modern JavaScript in Rails without transpiling
|
72
90
|
or bundling.
|