importmap-node 0.1.0
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 +7 -0
- data/lib/importmap/node/installer.rb +198 -0
- data/lib/importmap/node/railtie.rb +15 -0
- data/lib/importmap/node/version.rb +7 -0
- data/lib/importmap-node.rb +5 -0
- data/lib/tasks/importmap_node.rake +26 -0
- metadata +59 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5c5646881534b9345ec18f89096877bdf2997a54eff2ca7d398a11e7031c6cac
|
|
4
|
+
data.tar.gz: b3fb276ee1463143206de177a6b3913377980be5c4bde3e26e9da7f92b07aadb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 63a5f385846268bb9a4c059b2cd35371e9bd87d28f599993da8976c9de9971506e4591fda0f2680e87671e0602771b88d6d5141faa967cab8529eb1f0c8fbe60
|
|
7
|
+
data.tar.gz: fa5b2dacbd647fa39e5860ac179ecc9e92eb2b1a06c225c3bd2e3709230ac1e5ecb4cba87733797c2adb25ed40931a831471f5fb80afaf4842ef67b530cf57c2
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Importmap
|
|
7
|
+
module Node
|
|
8
|
+
class Installer
|
|
9
|
+
JS_DEST = 'vendor/javascript'
|
|
10
|
+
CONFIG_FILE = 'config/importmap_node.json'
|
|
11
|
+
|
|
12
|
+
def initialize(root: Rails.root)
|
|
13
|
+
@root = Pathname.new(root)
|
|
14
|
+
@node_modules = @root.join('node_modules')
|
|
15
|
+
@importmap = @root.join('config', 'importmap.rb')
|
|
16
|
+
@config_file = @root.join(CONFIG_FILE)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def install(package)
|
|
20
|
+
yarn_add(package)
|
|
21
|
+
|
|
22
|
+
pkg_name = resolve_package_name(package)
|
|
23
|
+
pkg_meta = read_package_meta(pkg_name)
|
|
24
|
+
js_files = vendor_js(pkg_name, pkg_meta)
|
|
25
|
+
pin_importmap(pkg_name, js_files)
|
|
26
|
+
record_package(package)
|
|
27
|
+
|
|
28
|
+
summarize(pkg_name, js_files)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def uninstall(package)
|
|
32
|
+
pkg_name = resolve_package_name(package)
|
|
33
|
+
pkg_meta = read_package_meta(pkg_name)
|
|
34
|
+
js_files = vendored_js_files(pkg_name, pkg_meta)
|
|
35
|
+
|
|
36
|
+
yarn_remove(pkg_name)
|
|
37
|
+
delete_files(JS_DEST, js_files)
|
|
38
|
+
unpin_importmap(pkg_name)
|
|
39
|
+
unrecord_package(package)
|
|
40
|
+
|
|
41
|
+
summarize_removal(pkg_name, js_files)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def update
|
|
45
|
+
packages = load_packages
|
|
46
|
+
if packages.empty?
|
|
47
|
+
puts "No packages tracked in #{CONFIG_FILE}."
|
|
48
|
+
return
|
|
49
|
+
end
|
|
50
|
+
yarn_up_dependencies
|
|
51
|
+
puts "Re-vendoring #{packages.size} package(s)..."
|
|
52
|
+
packages.each { |pkg| revendor(pkg) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def yarn_add(package)
|
|
58
|
+
yarn_arg = if package.start_with?('file:')
|
|
59
|
+
path = package.sub(/^file:/, '')
|
|
60
|
+
local_pkg_json = File.expand_path(File.join(path, 'package.json'), @root.to_s)
|
|
61
|
+
name = JSON.parse(File.read(local_pkg_json))['name']
|
|
62
|
+
"#{name}@#{package}"
|
|
63
|
+
else
|
|
64
|
+
package
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
puts "Running: yarn add #{yarn_arg}"
|
|
68
|
+
system("yarn add #{yarn_arg}", chdir: @root.to_s) or raise "yarn add failed for #{package}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def yarn_remove(pkg_name)
|
|
72
|
+
puts "Running: yarn remove #{pkg_name}"
|
|
73
|
+
system("yarn remove #{pkg_name}", chdir: @root.to_s) or raise "yarn remove failed for #{pkg_name}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def yarn_up_dependencies
|
|
77
|
+
pkg_json = @root.join('package.json')
|
|
78
|
+
deps = JSON.parse(pkg_json.read).fetch('dependencies', {}).keys
|
|
79
|
+
return if deps.empty?
|
|
80
|
+
|
|
81
|
+
puts "Running: yarn up #{deps.join(' ')}"
|
|
82
|
+
system("yarn up #{deps.join(' ')}", chdir: @root.to_s) or raise 'yarn up failed'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def revendor(package)
|
|
86
|
+
pkg_name = resolve_package_name(package)
|
|
87
|
+
pkg_meta = read_package_meta(pkg_name)
|
|
88
|
+
js_files = vendor_js(pkg_name, pkg_meta)
|
|
89
|
+
pin_importmap(pkg_name, js_files)
|
|
90
|
+
summarize(pkg_name, js_files)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def resolve_package_name(package)
|
|
94
|
+
if package.start_with?('file:')
|
|
95
|
+
path = package.sub(/^file:/, '')
|
|
96
|
+
local_pkg_json = File.expand_path(File.join(path, 'package.json'), @root.to_s)
|
|
97
|
+
JSON.parse(File.read(local_pkg_json))['name']
|
|
98
|
+
else
|
|
99
|
+
package
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def read_package_meta(pkg_name)
|
|
104
|
+
path = @node_modules.join(pkg_name, 'package.json')
|
|
105
|
+
raise "Cannot find #{path}. Did yarn add succeed?" unless path.exist?
|
|
106
|
+
|
|
107
|
+
JSON.parse(path.read)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def vendor_js(pkg_name, meta)
|
|
111
|
+
file = meta['module'] || meta['main'] || 'index.js'
|
|
112
|
+
src = @node_modules.join(pkg_name, file)
|
|
113
|
+
return [] unless src.exist?
|
|
114
|
+
|
|
115
|
+
dest_dir = @root.join(JS_DEST)
|
|
116
|
+
FileUtils.mkdir_p(dest_dir)
|
|
117
|
+
dest = dest_dir.join(src.basename)
|
|
118
|
+
FileUtils.cp(src, dest)
|
|
119
|
+
[dest.basename.to_s]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def vendored_js_files(pkg_name, meta)
|
|
123
|
+
file = meta['module'] || meta['main'] || 'index.js'
|
|
124
|
+
src = @node_modules.join(pkg_name, file)
|
|
125
|
+
src.exist? ? [src.basename.to_s] : []
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def delete_files(dest, filenames)
|
|
129
|
+
filenames.each do |name|
|
|
130
|
+
path = @root.join(dest, name)
|
|
131
|
+
if path.exist?
|
|
132
|
+
path.delete
|
|
133
|
+
puts " Deleted: #{dest}/#{name}"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def pin_importmap(pkg_name, js_files)
|
|
139
|
+
return if js_files.empty? || !@importmap.exist?
|
|
140
|
+
|
|
141
|
+
content = @importmap.read
|
|
142
|
+
pin_line = "pin \"#{pkg_name}\", to: \"#{js_files.first}\""
|
|
143
|
+
|
|
144
|
+
if content.match?(/pin ['"]#{Regexp.escape(pkg_name)}['"]/)
|
|
145
|
+
new_content = content.gsub(/pin ['"]#{Regexp.escape(pkg_name)}['"][^\n]*/, pin_line)
|
|
146
|
+
@importmap.write(new_content)
|
|
147
|
+
puts " Updated pin: #{pin_line}"
|
|
148
|
+
else
|
|
149
|
+
@importmap.open('a') { |f| f.puts pin_line }
|
|
150
|
+
puts " Added pin: #{pin_line}"
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def unpin_importmap(pkg_name)
|
|
155
|
+
return unless @importmap.exist?
|
|
156
|
+
|
|
157
|
+
content = @importmap.read
|
|
158
|
+
new_content = content.gsub(/\n?pin ['"]#{Regexp.escape(pkg_name)}['"][^\n]*/, '')
|
|
159
|
+
return unless content != new_content
|
|
160
|
+
|
|
161
|
+
@importmap.write(new_content)
|
|
162
|
+
puts " Removed pin for #{pkg_name} from config/importmap.rb"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def summarize(pkg_name, js_files)
|
|
166
|
+
puts "\n#{pkg_name} installed:"
|
|
167
|
+
js_files.each { |f| puts " JS: vendor/javascript/#{f}" }
|
|
168
|
+
puts ' Pinned in config/importmap.rb' unless js_files.empty?
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def summarize_removal(pkg_name, js_files)
|
|
172
|
+
puts "\n#{pkg_name} removed:"
|
|
173
|
+
js_files.each { |f| puts " JS: #{JS_DEST}/#{f}" }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def load_packages
|
|
177
|
+
return [] unless @config_file.exist?
|
|
178
|
+
|
|
179
|
+
JSON.parse(@config_file.read)['packages'] || []
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def record_package(package)
|
|
183
|
+
packages = load_packages
|
|
184
|
+
return if packages.include?(package)
|
|
185
|
+
|
|
186
|
+
packages << package
|
|
187
|
+
@config_file.write(JSON.pretty_generate('packages' => packages))
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def unrecord_package(package)
|
|
191
|
+
packages = load_packages
|
|
192
|
+
return unless packages.delete(package)
|
|
193
|
+
|
|
194
|
+
@config_file.write(JSON.pretty_generate('packages' => packages))
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/railtie'
|
|
4
|
+
|
|
5
|
+
module Importmap
|
|
6
|
+
module Node
|
|
7
|
+
class Railtie < Rails::Railtie
|
|
8
|
+
railtie_name :importmap_node
|
|
9
|
+
|
|
10
|
+
rake_tasks do
|
|
11
|
+
load File.join(__dir__, '..', '..', 'tasks', 'importmap_node.rake')
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :importmap do
|
|
4
|
+
namespace :node do
|
|
5
|
+
desc 'Install a node package and vendor its JS/CSS files. Usage: rails importmap:node:install[package-name-or-url]'
|
|
6
|
+
task :install, [:package] => :environment do |_t, args|
|
|
7
|
+
package = args[:package]
|
|
8
|
+
abort 'Usage: rails importmap:node:install[package-name-or-url]' if package.blank?
|
|
9
|
+
|
|
10
|
+
Importmap::Node::Installer.new.install(package)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc 'Remove a node package and delete its vendored JS files. Usage: rails importmap:node:remove[package-name]'
|
|
14
|
+
task :remove, [:package] => :environment do |_t, args|
|
|
15
|
+
package = args[:package]
|
|
16
|
+
abort 'Usage: rails importmap:node:remove[package-name]' if package.blank?
|
|
17
|
+
|
|
18
|
+
Importmap::Node::Installer.new.uninstall(package)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc 'Re-vendor all packages tracked in config/importmap_node.json'
|
|
22
|
+
task update: :environment do
|
|
23
|
+
Importmap::Node::Installer.new.update
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: importmap-node
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tien
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: railties
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.0'
|
|
26
|
+
email:
|
|
27
|
+
- tieeeeen1994@gmail.com
|
|
28
|
+
executables: []
|
|
29
|
+
extensions: []
|
|
30
|
+
extra_rdoc_files: []
|
|
31
|
+
files:
|
|
32
|
+
- lib/importmap-node.rb
|
|
33
|
+
- lib/importmap/node/installer.rb
|
|
34
|
+
- lib/importmap/node/railtie.rb
|
|
35
|
+
- lib/importmap/node/version.rb
|
|
36
|
+
- lib/tasks/importmap_node.rake
|
|
37
|
+
homepage: https://github.com/tieeeeen1994/importmap-node
|
|
38
|
+
licenses:
|
|
39
|
+
- MIT
|
|
40
|
+
metadata:
|
|
41
|
+
rubygems_mfa_required: 'true'
|
|
42
|
+
rdoc_options: []
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '3.1'
|
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubygems_version: 4.0.7
|
|
57
|
+
specification_version: 4
|
|
58
|
+
summary: Install node packages as vendored assets in Rails via yarn
|
|
59
|
+
test_files: []
|