hanami-sprockets 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +63 -4
- data/bin/hanami-sprockets +8 -0
- data/hanami-sprockets.gemspec +1 -0
- data/lib/hanami/cli/commands/app/assets/command.rb +45 -0
- data/lib/hanami/cli/commands/app/assets/compile.rb +31 -0
- data/lib/hanami/cli/commands/app/assets/watch.rb +73 -0
- data/lib/hanami/cli/commands/app/assets.rb +15 -0
- data/lib/hanami/sprockets/cli.rb +174 -0
- data/lib/hanami/sprockets/version.rb +1 -1
- data/lib/hanami/sprockets.rb +3 -1
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 423164431eeaf7e1c3809ab78f15b9322b458644726fb505f610be3db9b03981
|
4
|
+
data.tar.gz: 341808d42f74242bd36cb147c575752054e5e4f4feefdac6d3b0cac1e5016c43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a775a3d136a96f5abeed83864d19f3e7b72461b528f2e1ab4af10e8559cbbac2a9fc02f77a1060e7d0c8a7ebb78518c59bc52518e8d95c1edf26e3466c1ca0d3
|
7
|
+
data.tar.gz: 6969306f684ae65c55b8f6c3464152c00cf3514d21164a7d9dc1686fc62ef44e51ac50d9cfc651416a0dc82c057a2191d34b3c0153227db01affe44b85633317
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.2.0] - 2025-10-01
|
8
|
+
### Added
|
9
|
+
- CLI commands: `hanami-sprockets compile` and `hanami-sprockets watch`
|
10
|
+
- Hanami CLI integration: `hanami assets compile` and `hanami assets watch`
|
11
|
+
- Asset watch mode with file monitoring and auto-recompilation
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- CSS custom properties test failures
|
15
|
+
|
7
16
|
## [0.1.0] - 2025-09-29
|
8
17
|
### Added
|
9
18
|
- Initial release
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Hanami::Sprockets
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/hanami-sprockets)
|
4
|
+
|
3
5
|
Drop-in replacement for hanami-assets that uses Sprockets (like Rails) instead of npm/Node.js.
|
4
6
|
|
5
7
|
If you want the Rails asset pipeline in your Hanami app without dealing with npm, this is for you.
|
@@ -24,7 +26,7 @@ gem 'hanami-sprockets'
|
|
24
26
|
And then execute:
|
25
27
|
|
26
28
|
```bash
|
27
|
-
|
29
|
+
bundle install
|
28
30
|
```
|
29
31
|
|
30
32
|
## Basic Usage
|
@@ -52,7 +54,7 @@ assets = Hanami::Assets.new(
|
|
52
54
|
|
53
55
|
Follow Rails conventions:
|
54
56
|
|
55
|
-
```
|
57
|
+
```text
|
56
58
|
app/
|
57
59
|
├── assets/
|
58
60
|
│ ├── stylesheets/
|
@@ -153,6 +155,63 @@ manifest = assets.precompile("/path/to/public/assets")
|
|
153
155
|
puts "Compiled assets:", manifest.assets.keys
|
154
156
|
```
|
155
157
|
|
158
|
+
### Command Line Interface
|
159
|
+
|
160
|
+
The gem includes CLI commands similar to Hanami's asset commands:
|
161
|
+
|
162
|
+
#### Compile Assets
|
163
|
+
|
164
|
+
Compile assets for production deployment:
|
165
|
+
|
166
|
+
```bash
|
167
|
+
bundle exec hanami-sprockets compile
|
168
|
+
```
|
169
|
+
|
170
|
+
With custom output directory:
|
171
|
+
|
172
|
+
```bash
|
173
|
+
bundle exec hanami-sprockets compile -o public/dist
|
174
|
+
```
|
175
|
+
|
176
|
+
#### Watch Assets
|
177
|
+
|
178
|
+
Watch assets for changes during development:
|
179
|
+
|
180
|
+
```bash
|
181
|
+
bundle exec hanami-sprockets watch
|
182
|
+
```
|
183
|
+
|
184
|
+
The watch command monitors your asset directories for changes and automatically recompiles when files are modified. Requires the `listen` gem to be available.
|
185
|
+
|
186
|
+
#### CLI Options
|
187
|
+
|
188
|
+
```bash
|
189
|
+
Usage: hanami-sprockets [COMMAND] [OPTIONS]
|
190
|
+
|
191
|
+
Commands:
|
192
|
+
compile Compile assets for production
|
193
|
+
watch Watch assets for changes and recompile
|
194
|
+
|
195
|
+
Options:
|
196
|
+
-r, --root ROOT Application root directory
|
197
|
+
-o, --output OUTPUT Output directory for compiled assets
|
198
|
+
-h, --help Show help message
|
199
|
+
```
|
200
|
+
|
201
|
+
### Integration with Hanami CLI
|
202
|
+
|
203
|
+
When used within a Hanami application, hanami-sprockets provides command classes that can be automatically discovered by Hanami's CLI system. This allows you to use:
|
204
|
+
|
205
|
+
```bash
|
206
|
+
# Instead of hanami-sprockets compile
|
207
|
+
hanami assets compile
|
208
|
+
|
209
|
+
# Instead of hanami-sprockets watch
|
210
|
+
hanami assets watch
|
211
|
+
```
|
212
|
+
|
213
|
+
These commands integrate seamlessly with Hanami's application structure and automatically discover your app's configuration. The gem provides compatible command classes in the `Hanami::CLI::Commands::App::Assets` namespace that follow Hanami's CLI conventions.
|
214
|
+
|
156
215
|
## Advanced Configuration
|
157
216
|
|
158
217
|
```ruby
|
@@ -209,7 +268,7 @@ Main class for asset management.
|
|
209
268
|
|
210
269
|
Represents a single asset.
|
211
270
|
|
212
|
-
#### Methods
|
271
|
+
#### Asset Methods
|
213
272
|
|
214
273
|
- `#url` - Full URL to asset
|
215
274
|
- `#path` - Path to asset (without base URL)
|
@@ -221,7 +280,7 @@ Represents a single asset.
|
|
221
280
|
|
222
281
|
Template helpers for generating asset HTML tags.
|
223
282
|
|
224
|
-
#### Methods
|
283
|
+
#### Helper Methods
|
225
284
|
|
226
285
|
- `stylesheet_tag(*sources, **options)` - Generate `<link>` tags
|
227
286
|
- `javascript_tag(*sources, **options)` - Generate `<script>` tags
|
data/hanami-sprockets.gemspec
CHANGED
@@ -33,4 +33,5 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_development_dependency "rack-test", "~> 1.1"
|
34
34
|
spec.add_development_dependency "dry-configurable", "~> 1.1"
|
35
35
|
spec.add_development_dependency "dry-inflector", "~> 1.0"
|
36
|
+
spec.add_development_dependency "listen", "~> 3.8"
|
36
37
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
module CLI
|
7
|
+
module Commands
|
8
|
+
module App
|
9
|
+
module Assets
|
10
|
+
class Command
|
11
|
+
def initialize(out: $stdout)
|
12
|
+
@out = out
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(app: nil)
|
16
|
+
assets = create_assets_instance(app)
|
17
|
+
output_dir = default_output_dir(app)
|
18
|
+
|
19
|
+
execute_assets_command(assets, output_dir)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
attr_reader :out
|
25
|
+
|
26
|
+
def create_assets_instance(app)
|
27
|
+
root = app ? app.root : Pathname.pwd
|
28
|
+
config = Hanami::Assets::Config.new(digest: true)
|
29
|
+
Hanami::Assets.new(config: config, root: root.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def default_output_dir(app)
|
33
|
+
root = app ? app.root : Pathname.pwd
|
34
|
+
root.join("public", "assets").to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute_assets_command(assets, output_dir)
|
38
|
+
raise NotImplementedError, "Subclasses must implement #execute_assets_command"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "command"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
module CLI
|
7
|
+
module Commands
|
8
|
+
module App
|
9
|
+
module Assets
|
10
|
+
class Compile < Command
|
11
|
+
def execute_assets_command(assets, output_dir)
|
12
|
+
out.puts "Compiling assets using Sprockets..."
|
13
|
+
|
14
|
+
manifest = assets.precompile(output_dir)
|
15
|
+
|
16
|
+
out.puts "Assets compiled successfully:"
|
17
|
+
manifest.assets.each do |logical_path, digest_path|
|
18
|
+
out.puts " #{logical_path} -> #{digest_path}"
|
19
|
+
end
|
20
|
+
|
21
|
+
out.puts "Output directory: #{output_dir}"
|
22
|
+
rescue => e
|
23
|
+
out.puts "Error compiling assets: #{e.message}"
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "command"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
module CLI
|
7
|
+
module Commands
|
8
|
+
module App
|
9
|
+
module Assets
|
10
|
+
class Watch < Command
|
11
|
+
def execute_assets_command(assets, output_dir)
|
12
|
+
out.puts "Starting Sprockets asset watch mode..."
|
13
|
+
out.puts "Press Ctrl+C to stop"
|
14
|
+
|
15
|
+
require "listen"
|
16
|
+
|
17
|
+
asset_paths = find_asset_paths(assets)
|
18
|
+
|
19
|
+
if asset_paths.empty?
|
20
|
+
out.puts "No asset directories found. Looking for:"
|
21
|
+
%w[app/assets lib/assets vendor/assets].each do |path|
|
22
|
+
out.puts " #{path}"
|
23
|
+
end
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
out.puts "Watching directories:"
|
28
|
+
asset_paths.each { |path| out.puts " #{path}" }
|
29
|
+
|
30
|
+
listener = Listen.to(*asset_paths, only: /\.(css|js|scss|sass|coffee|erb)$/) do |modified, added, removed|
|
31
|
+
out.puts "\nChanges detected:"
|
32
|
+
(modified + added + removed).each { |file| out.puts " #{file}" }
|
33
|
+
|
34
|
+
begin
|
35
|
+
out.puts "Recompiling assets..."
|
36
|
+
assets.precompile(output_dir)
|
37
|
+
out.puts "Assets recompiled successfully"
|
38
|
+
rescue => e
|
39
|
+
out.puts "Error recompiling assets: #{e.message}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
listener.start
|
44
|
+
|
45
|
+
trap("INT") { listener.stop; exit }
|
46
|
+
|
47
|
+
sleep
|
48
|
+
rescue LoadError
|
49
|
+
out.puts "Error: 'listen' gem is required for watch mode."
|
50
|
+
out.puts "Add 'gem \"listen\"' to your Gemfile and run 'bundle install'"
|
51
|
+
raise
|
52
|
+
rescue => e
|
53
|
+
out.puts "Error in watch mode: #{e.message}"
|
54
|
+
raise
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def find_asset_paths(assets)
|
60
|
+
root = Pathname(assets.root)
|
61
|
+
paths = []
|
62
|
+
%w[app/assets lib/assets vendor/assets].each do |relative_path|
|
63
|
+
path = root.join(relative_path)
|
64
|
+
paths << path.to_s if path.exist?
|
65
|
+
end
|
66
|
+
paths
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "pathname"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
module Hanami
|
8
|
+
class Assets
|
9
|
+
class CLI
|
10
|
+
class << self
|
11
|
+
def start(args)
|
12
|
+
new(args).call
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(args)
|
17
|
+
@args = args
|
18
|
+
@command = nil
|
19
|
+
@options = {}
|
20
|
+
@root = Pathname.pwd
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
parse_options
|
25
|
+
|
26
|
+
case @command
|
27
|
+
when "compile"
|
28
|
+
compile
|
29
|
+
when "watch"
|
30
|
+
watch
|
31
|
+
else
|
32
|
+
show_help
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def parse_options
|
39
|
+
parser = OptionParser.new do |opts|
|
40
|
+
opts.banner = "Usage: hanami-sprockets [COMMAND] [OPTIONS]"
|
41
|
+
opts.separator ""
|
42
|
+
opts.separator "Commands:"
|
43
|
+
opts.separator " compile Compile assets for production"
|
44
|
+
opts.separator " watch Watch assets for changes and recompile"
|
45
|
+
opts.separator ""
|
46
|
+
opts.separator "Options:"
|
47
|
+
|
48
|
+
opts.on("-r", "--root ROOT", "Application root directory") do |root|
|
49
|
+
@options[:root] = root
|
50
|
+
@root = Pathname(root)
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on("-o", "--output OUTPUT", "Output directory for compiled assets") do |output|
|
54
|
+
@options[:output] = output
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on("-h", "--help", "Show this help message") do
|
58
|
+
puts opts
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
parser.parse!(@args)
|
65
|
+
@command = @args.shift
|
66
|
+
rescue OptionParser::InvalidOption => e
|
67
|
+
puts "Error: #{e.message}"
|
68
|
+
puts parser
|
69
|
+
exit(1)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def compile
|
74
|
+
puts "Compiling assets..."
|
75
|
+
|
76
|
+
output_dir = @options[:output] || @root.join("public", "assets").to_s
|
77
|
+
|
78
|
+
assets = create_assets_instance
|
79
|
+
manifest = assets.precompile(output_dir)
|
80
|
+
|
81
|
+
puts "Assets compiled successfully:"
|
82
|
+
manifest.assets.each do |logical_path, digest_path|
|
83
|
+
puts " #{logical_path} -> #{digest_path}"
|
84
|
+
end
|
85
|
+
|
86
|
+
puts "Output directory: #{output_dir}"
|
87
|
+
rescue => e
|
88
|
+
puts "Error compiling assets: #{e.message}"
|
89
|
+
exit(1)
|
90
|
+
end
|
91
|
+
|
92
|
+
def watch
|
93
|
+
puts "Starting asset watch mode..."
|
94
|
+
puts "Press Ctrl+C to stop"
|
95
|
+
|
96
|
+
require "listen"
|
97
|
+
|
98
|
+
assets = create_assets_instance
|
99
|
+
asset_paths = find_asset_paths
|
100
|
+
|
101
|
+
if asset_paths.empty?
|
102
|
+
puts "No asset directories found. Looking for:"
|
103
|
+
%w[app/assets lib/assets vendor/assets].each do |path|
|
104
|
+
puts " #{@root.join(path)}"
|
105
|
+
end
|
106
|
+
exit(1)
|
107
|
+
end
|
108
|
+
|
109
|
+
puts "Watching directories:"
|
110
|
+
asset_paths.each { |path| puts " #{path}" }
|
111
|
+
|
112
|
+
listener = Listen.to(*asset_paths, only: /\.(css|js|scss|sass|coffee|erb)$/) do |modified, added, removed|
|
113
|
+
puts "\nChanges detected:"
|
114
|
+
(modified + added + removed).each { |file| puts " #{file}" }
|
115
|
+
|
116
|
+
begin
|
117
|
+
puts "Recompiling assets..."
|
118
|
+
output_dir = @options[:output] || @root.join("public", "assets").to_s
|
119
|
+
assets.precompile(output_dir)
|
120
|
+
puts "Assets recompiled successfully"
|
121
|
+
rescue => e
|
122
|
+
puts "Error recompiling assets: #{e.message}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
listener.start
|
127
|
+
|
128
|
+
trap("INT") { listener.stop; exit }
|
129
|
+
|
130
|
+
sleep
|
131
|
+
rescue LoadError
|
132
|
+
puts "Error: 'listen' gem is required for watch mode."
|
133
|
+
puts "Add 'gem \"listen\"' to your Gemfile and run 'bundle install'"
|
134
|
+
exit(1)
|
135
|
+
rescue => e
|
136
|
+
puts "Error in watch mode: #{e.message}"
|
137
|
+
exit(1)
|
138
|
+
end
|
139
|
+
|
140
|
+
def show_help
|
141
|
+
puts "Usage: hanami-sprockets [COMMAND] [OPTIONS]"
|
142
|
+
puts ""
|
143
|
+
puts "Commands:"
|
144
|
+
puts " compile Compile assets for production"
|
145
|
+
puts " watch Watch assets for changes and recompile"
|
146
|
+
puts ""
|
147
|
+
puts "Options:"
|
148
|
+
puts " -r, --root ROOT Application root directory"
|
149
|
+
puts " -o, --output OUTPUT Output directory for compiled assets"
|
150
|
+
puts " -h, --help Show this help message"
|
151
|
+
puts ""
|
152
|
+
puts "Examples:"
|
153
|
+
puts " hanami-sprockets compile"
|
154
|
+
puts " hanami-sprockets compile -o public/assets"
|
155
|
+
puts " hanami-sprockets watch"
|
156
|
+
puts " hanami-sprockets watch -r /path/to/app"
|
157
|
+
end
|
158
|
+
|
159
|
+
def create_assets_instance
|
160
|
+
config = Hanami::Assets::Config.new(digest: true)
|
161
|
+
Hanami::Assets.new(config: config, root: @root.to_s)
|
162
|
+
end
|
163
|
+
|
164
|
+
def find_asset_paths
|
165
|
+
paths = []
|
166
|
+
%w[app/assets lib/assets vendor/assets].each do |relative_path|
|
167
|
+
path = @root.join(relative_path)
|
168
|
+
paths << path.to_s if path.exist?
|
169
|
+
end
|
170
|
+
paths
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/hanami/sprockets.rb
CHANGED
@@ -22,7 +22,9 @@ module Hanami
|
|
22
22
|
loader.ignore(
|
23
23
|
"#{root}/hanami-sprockets.rb",
|
24
24
|
"#{root}/hanami/sprockets/version.rb",
|
25
|
-
"#{root}/hanami/sprockets/errors.rb"
|
25
|
+
"#{root}/hanami/sprockets/errors.rb",
|
26
|
+
"#{root}/hanami/sprockets/cli.rb",
|
27
|
+
"#{root}/hanami/cli"
|
26
28
|
)
|
27
29
|
loader.enable_reloading if loader.respond_to?(:enable_reloading)
|
28
30
|
loader.inflector = Zeitwerk::GemInflector.new("#{root}/hanami-sprockets.rb")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami-sprockets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Nesbitt
|
@@ -183,22 +183,43 @@ dependencies:
|
|
183
183
|
- - "~>"
|
184
184
|
- !ruby/object:Gem::Version
|
185
185
|
version: '1.0'
|
186
|
+
- !ruby/object:Gem::Dependency
|
187
|
+
name: listen
|
188
|
+
requirement: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - "~>"
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '3.8'
|
193
|
+
type: :development
|
194
|
+
prerelease: false
|
195
|
+
version_requirements: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - "~>"
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '3.8'
|
186
200
|
description: Alternative to hanami-assets that uses Sprockets for asset compilation
|
187
201
|
and management, compatible with existing Sprockets gems
|
188
202
|
email:
|
189
203
|
- andrewnez@gmail.com
|
190
|
-
executables:
|
204
|
+
executables:
|
205
|
+
- hanami-sprockets
|
191
206
|
extensions: []
|
192
207
|
extra_rdoc_files: []
|
193
208
|
files:
|
194
209
|
- CHANGELOG.md
|
195
210
|
- LICENSE.md
|
196
211
|
- README.md
|
212
|
+
- bin/hanami-sprockets
|
197
213
|
- hanami-sprockets.gemspec
|
198
214
|
- lib/hanami-sprockets.rb
|
215
|
+
- lib/hanami/cli/commands/app/assets.rb
|
216
|
+
- lib/hanami/cli/commands/app/assets/command.rb
|
217
|
+
- lib/hanami/cli/commands/app/assets/compile.rb
|
218
|
+
- lib/hanami/cli/commands/app/assets/watch.rb
|
199
219
|
- lib/hanami/sprockets.rb
|
200
220
|
- lib/hanami/sprockets/asset.rb
|
201
221
|
- lib/hanami/sprockets/base_url.rb
|
222
|
+
- lib/hanami/sprockets/cli.rb
|
202
223
|
- lib/hanami/sprockets/config.rb
|
203
224
|
- lib/hanami/sprockets/errors.rb
|
204
225
|
- lib/hanami/sprockets/helpers.rb
|