Skip to content

Commit f2c0e23

Browse files
committed
Adding directive depends_on_directory
`depends_on_directory` allows you to specify all files (non-recurisve) in a directory to watch for changes. This is helpful in cases where files may be dynamic or there are many files.
1 parent 9909da6 commit f2c0e23

File tree

4 files changed

+108
-5
lines changed

4 files changed

+108
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Get upgrade notes from Sprockets 3.x to 4.x at https://github.com/rails/sprocket
55
## Master
66

77
- Fix for Ruby 2.7 keyword arguments warning in `base.rb`. [#660](https://github.com/rails/sprockets/pull/660)
8+
- Adding new directive `depend_on_directory` [#668](https://github.com/rails/sprockets/pull/668)
89

910
## 4.0.0
1011

README.md

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Here is a list of the available directives:
119119
- [`link_directory`](#link_directory) - Make target directory compile and be publicly available without adding contents to current
120120
- [`link_tree`](#link_tree) - Make target tree compile and be publicly available without adding contents to current
121121
- [`depend_on`](#depend_on) - Recompile current file if target has changed
122+
- [`depend_on_directory`](#depend_on_directory) - Recompile current file if any files in target directory has changed
122123
- [`stub`](#stub) - Ignore target file
123124

124125
You can see what each of these does below.
@@ -239,7 +240,7 @@ The first time this file is compiled the `application.js` output will be written
239240

240241
So, if `b.js` changes it will get recompiled. However instead of having to recompile the other files from `a.js` to `z.js` since they did not change, we can use the prior intermediary files stored in the cached values . If these files were expensive to generate, then this "partial" asset cache strategy can save a lot of time.
241242

242-
Directives such as `require`, `link`, and `depend_on` tell Sprockets what assets need to be re-compiled when a file changes. Files are considered "fresh" based on their mtime on disk and a combination of cache keys.
243+
Directives such as `require`, `link`, `depend_on`, and `depend_on_directory` tell Sprockets what assets need to be re-compiled when a file changes. Files are considered "fresh" based on their mtime on disk and a combination of cache keys.
243244

244245
On Rails you can force a "clean" install by clearing the `public/assets` and `tmp/cache/assets` directories.
245246

@@ -445,11 +446,50 @@ you need to tell sprockets that it needs to re-compile the file if `bar.data` ch
445446
var bar = '<%= File.read("bar.data") %>'
446447
```
447448

449+
To depend on an entire directory containing multiple files, use `depend_on_directory`
450+
448451
### depend_on_asset
449452

450453
`depend_on_asset` *path* works like `depend_on`, but operates
451454
recursively reading the file and following the directives found. This is automatically implied if you use `link`, so consider if it just makes sense using `link` instead of `depend_on_asset`.
452455

456+
### depend_on_directory
457+
458+
`depend_on_directory` *path* declares all files in the given *path* without
459+
including them in the bundle. This is useful when you need to expire an
460+
asset's cache in response to a change in multiple files in a single directory.
461+
462+
All paths are relative to your declaration and must begin with `./`
463+
464+
Also, your must include these directories in your [load path](guides/building_an_asset_processing_framework.md#the-load-path).
465+
466+
**Example:**
467+
468+
If we've got a directory called `data` with files `a.data` and `b.data`
469+
470+
```a.data
471+
A
472+
```
473+
474+
```b.data
475+
B
476+
```
477+
478+
```js.erb
479+
//= depend_on_directory ./data
480+
var a = '<% File.read('data/a.data') %>'
481+
var b = '<% File.read('data/b.data') %>'
482+
```
483+
484+
Would produce:
485+
486+
```js
487+
var a = "A";
488+
var b = "B";
489+
```
490+
491+
You can also see [Index files are proxies for folders](#index-files-are-proxies-for-folders) for another method of organizing folders that will give you more control.
492+
453493
### stub
454494

455495
`stub` *path* excludes that asset and its dependencies from the asset bundle.
@@ -491,9 +531,9 @@ When you modify the `logo.png` on disk, it will force `application.css` to be
491531
recompiled so that the fingerprint will be correct in the generated asset.
492532

493533
You can manually make sprockets depend on any other file that is generated
494-
by sprockets by using the `depend_on` directive. Rails implements the above
495-
feature by auto calling `depend_on` on the original asset when the `asset_url`
496-
is used inside of an asset.
534+
by sprockets by using the `depend_on` or `depend_on_directory` directive. Rails
535+
implements the above feature by auto calling `depend_on` on the original asset
536+
when the `asset_url` is used inside of an asset.
497537

498538
### Styling with Sass and SCSS
499539

lib/sprockets/directive_processor.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,24 @@ def process_depend_on_asset_directive(path)
285285
to_load(resolve(path))
286286
end
287287

288+
# Allows you to state a dependency on a relative directory
289+
# without including it.
290+
#
291+
# This is used for caching purposes. Any changes made to
292+
# the dependency directory will invalidate the cache of the
293+
# source file.
294+
#
295+
# This is useful if you are using ERB and File.read to pull
296+
# in contents from multiple files in a directory.
297+
#
298+
# //= depend_on_directory ./data
299+
#
300+
def process_depend_on_directory_directive(path = ".", accept = nil)
301+
path = expand_relative_dirname(:depend_on_directory, path)
302+
accept = expand_accept_shorthand(accept)
303+
resolve_paths(*@environment.stat_directory_with_dependencies(path), accept: accept)
304+
end
305+
288306
# Allows dependency to be excluded from the asset bundle.
289307
#
290308
# The `path` must be a valid asset and may or may not already
@@ -374,7 +392,7 @@ def resolve_paths(paths, deps, **kargs)
374392
next if subpath == @filename || stat.directory?
375393
uri, deps = @environment.resolve(subpath, **kargs)
376394
@dependencies.merge(deps)
377-
yield uri if uri
395+
yield uri if uri && block_given?
378396
end
379397
end
380398

test/test_asset.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,50 @@ def self.test(name, &block)
123123
end
124124
end
125125
end
126+
127+
test "modify asset's dependency file in directory" do
128+
main = fixture_path('asset/test-main.js.erb')
129+
dep = fixture_path('asset/data/foo.txt')
130+
begin
131+
::FileUtils.mkdir File.dirname(dep)
132+
sandbox main, dep do
133+
write(main, "//= depend_on_directory ./data\n<%= File.read('#{dep}') %>")
134+
write(dep, "a;")
135+
asset = asset('test-main.js')
136+
old_digest = asset.hexdigest
137+
old_uri = asset.uri
138+
assert_equal "a;\n", asset.to_s
139+
140+
write(dep, "b;")
141+
asset = asset('test-main.js')
142+
refute_equal old_digest, asset.hexdigest
143+
refute_equal old_uri, asset.uri
144+
assert_equal "b;\n", asset.to_s
145+
end
146+
ensure
147+
::FileUtils.rmtree File.dirname(dep)
148+
end
149+
end
150+
151+
test "asset's dependency on directory exists" do
152+
main = fixture_path('asset/test-missing-directory.js.erb')
153+
dep = fixture_path('asset/data/foo.txt')
154+
155+
begin
156+
sandbox main, dep, testjs do
157+
::FileUtils.rmtree File.dirname(dep)
158+
write(main, "//= depend_on_directory ./data")
159+
assert_raises(Sprockets::ArgumentError) do
160+
asset('test-missing-directory.js')
161+
end
162+
163+
::FileUtils.mkdir File.dirname(dep)
164+
assert asset('test-missing-directory.js')
165+
end
166+
ensure
167+
::FileUtils.rmtree File.dirname(dep)
168+
end
169+
end
126170
end
127171

128172
class TextStaticAssetTest < Sprockets::TestCase

0 commit comments

Comments
 (0)