Skip to content

Commit fcef81d

Browse files
Stefan Vermaasgauravtiwari
Stefan Vermaas
authored andcommitted
Have the *_pack_tag support entrypoints (#1735)
* Adds support for split_chunks in the javascript_pack_tag * Updates the documentation to use entrypoints * Added a explicit deprecation notice to the CommonChunks docs * Updates the docs with the correct documentation * Lookup the pack in the entrypoints of the manifest In the previous attempt you had to specify `split_chunks: true` in the options of the `*_pack_tag`. Now the `manifest.rb` looks up the entrypoints when they're present. Without any change to the `*_pack_tag` Webpacker supports `SplitChunks` and `RuntimeChunks`. * Resets the to the previous version.
1 parent f8c9f42 commit fcef81d

File tree

6 files changed

+128
-27
lines changed

6 files changed

+128
-27
lines changed

docs/webpack.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,48 @@ const { environment } = require('@rails/webpacker')
256256
environment.resolvedModules.append('vendor', 'vendor')
257257
```
258258

259-
### Add common chunks
259+
### Add SplitChunks (Webpack V4)
260+
Originally, chunks (and modules imported inside them) were connected by a parent-child relationship in the internal webpack graph. The CommonsChunkPlugin was used to avoid duplicated dependencies across them, but further optimizations were not possible
261+
262+
Since webpack v4, the CommonsChunkPlugin was removed in favor of optimization.splitChunks.
263+
264+
For the full configuration options of SplitChunks, see the [Webpack documentation](https://webpack.js.org/plugins/split-chunks-plugin/).
265+
266+
```js
267+
// config/webpack/environment.js
268+
const WebpackAssetsManifest = require('webpack-assets-manifest');
269+
270+
const splitChunks = {
271+
optimization: {
272+
splitChunks: {
273+
chunks: 'all'
274+
},
275+
},
276+
};
277+
278+
environment.config.merge(splitChunks);
279+
280+
// Should override the existing manifest plugin
281+
environment.plugins.insert(
282+
'Manifest',
283+
new WebpackAssetsManifest({
284+
entrypoints: true, // default in rails is false
285+
writeToDisk: true, // rails defaults copied from webpacker
286+
publicPath: true // rails defaults copied from webpacker
287+
})
288+
)
289+
```
290+
291+
To use the `javascript_pack_tag` or the `stylesheet_pack_tag` with `SplitChunks` or `RuntimeChunks` you can refer to the packs as usual.
292+
293+
```erb
294+
javascript_pack_tag "your-entrypoint-javascript-file"
295+
stylesheet_pack_tag "your-entrypoint-stylesheet-file"
296+
```
297+
298+
For the old configuration with the CommonsChunkPlugin see below. **Note** that this functionality is deprecated in Webpack V4.
299+
300+
### Add common chunks (deprecated in Webpack V4)
260301

261302
The CommonsChunkPlugin is an opt-in feature that creates a separate file (known as a chunk), consisting of common modules shared between multiple entry points. By separating common modules from bundles, the resulting chunked file can be loaded once initially, and stored in the cache for later use. This results in page speed optimizations as the browser can quickly serve the shared code from the cache, rather than being forced to load a larger bundle whenever a new page is visited.
262303

lib/webpacker/helper.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ def stylesheet?(name)
8383
end
8484

8585
def sources_from_pack_manifest(names, type:)
86-
names.map { |name| Webpacker.manifest.lookup!(pack_name_with_extension(name, type: type)) }
87-
end
88-
89-
def pack_name_with_extension(name, type:)
90-
"#{name}#{compute_asset_extname(name.to_s, type: type)}"
86+
names.map { |name| Webpacker.manifest.lookup!(name, type: type) }.flatten
9187
end
9288
end

lib/webpacker/manifest.rb

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,29 @@ def refresh
1818
@data = load
1919
end
2020

21-
def lookup(name)
21+
def lookup(name, pack_type = {})
2222
compile if compiling?
23-
find name
23+
24+
# When using SplitChunks or RuntimeChunks the manifest hash will contain
25+
# an extra object called "entrypoints". When the entrypoints key is not
26+
# present in the manifest, or the name is not found in the entrypoints hash,
27+
# it will raise a NoMethodError. If this happens, we should try to lookup
28+
# a single instance of the pack based on the given name.
29+
begin
30+
manifest_pack_type = manifest_type(pack_type[:type])
31+
manifest_pack_name = manifest_name(name, manifest_pack_type)
32+
33+
# Lookup the pack in the entrypoints of the manifest
34+
find("entrypoints")[manifest_pack_name][manifest_pack_type]
35+
rescue NoMethodError
36+
37+
# Lookup a single instance of the pack
38+
find(full_pack_name(name, pack_type[:type]))
39+
end
2440
end
2541

26-
def lookup!(name)
27-
lookup(name) || handle_missing_entry(name)
42+
def lookup!(name, pack_type = {})
43+
lookup(name, pack_type) || handle_missing_entry(name)
2844
end
2945

3046
private
@@ -36,14 +52,51 @@ def compile
3652
Webpacker.logger.tagged("Webpacker") { compiler.compile }
3753
end
3854

55+
def data
56+
if config.cache_manifest?
57+
@data ||= load
58+
else
59+
refresh
60+
end
61+
end
62+
3963
def find(name)
4064
data[name.to_s].presence
4165
end
4266

67+
def full_pack_name(name, pack_type)
68+
return name unless File.extname(name.to_s).empty?
69+
"#{name}.#{manifest_type(pack_type)}"
70+
end
71+
4372
def handle_missing_entry(name)
4473
raise Webpacker::Manifest::MissingEntryError, missing_file_from_manifest_error(name)
4574
end
4675

76+
def load
77+
if config.public_manifest_path.exist?
78+
JSON.parse config.public_manifest_path.read
79+
else
80+
{}
81+
end
82+
end
83+
84+
# The `manifest_name` method strips of the file extension of the name, because in the
85+
# manifest hash the entrypoints are defined by their pack name without the extension.
86+
# When the user provides a name with a file extension, we want to try to strip it off.
87+
def manifest_name(name, pack_type)
88+
return name if File.extname(name.to_s).empty?
89+
File.basename(name, pack_type)
90+
end
91+
92+
def manifest_type(pack_type)
93+
case pack_type
94+
when :javascript then "js"
95+
when :stylesheet then "css"
96+
else pack_type.to_s
97+
end
98+
end
99+
47100
def missing_file_from_manifest_error(bundle_name)
48101
<<-MSG
49102
Webpacker can't find #{bundle_name} in #{config.public_manifest_path}. Possible causes:
@@ -56,20 +109,4 @@ def missing_file_from_manifest_error(bundle_name)
56109
#{JSON.pretty_generate(@data)}
57110
MSG
58111
end
59-
60-
def data
61-
if config.cache_manifest?
62-
@data ||= load
63-
else
64-
refresh
65-
end
66-
end
67-
68-
def load
69-
if config.public_manifest_path.exist?
70-
JSON.parse config.public_manifest_path.read
71-
else
72-
{}
73-
end
74-
end
75112
end

test/helper_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ def test_javascript_pack_tag_splat
5656
javascript_pack_tag("bootstrap.js", "application.js", defer: true)
5757
end
5858

59+
def test_javascript_pack_tag_split_chunks
60+
assert_equal \
61+
%(<script src="/packs/vendors~application~bootstrap-c20632e7baf2c81200d3.chunk.js"></script>\n) +
62+
%(<script src="/packs/vendors~application-e55f2aae30c07fb6d82a.chunk.js"></script>\n) +
63+
%(<script src="/packs/application-k344a6d59eef8632c9d1.js"></script>),
64+
javascript_pack_tag("application")
65+
end
66+
5967
def test_stylesheet_pack_tag
6068
assert_equal \
6169
%(<link rel="stylesheet" media="screen" href="/packs/bootstrap-c38deda30895059837cf.css" />),

test/manifest_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,14 @@ def test_lookup_nil
2525
def test_lookup_success
2626
assert_equal Webpacker.manifest.lookup("bootstrap.js"), "/packs/bootstrap-300631c4f0e0f9c865bc.js"
2727
end
28+
29+
def test_lookup_entrypoint
30+
application_entrypoints = [
31+
"/packs/vendors~application~bootstrap-c20632e7baf2c81200d3.chunk.js",
32+
"/packs/vendors~application-e55f2aae30c07fb6d82a.chunk.js",
33+
"/packs/application-k344a6d59eef8632c9d1.js"
34+
]
35+
36+
assert_equal Webpacker.manifest.lookup!("application", type: :javascript), application_entrypoints
37+
end
2838
end

test/test_app/public/packs/manifest.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,14 @@
33
"application.css": "/packs/application-dd6b1cd38bfa093df600.css",
44
"bootstrap.js": "/packs/bootstrap-300631c4f0e0f9c865bc.js",
55
"application.js": "/packs/application-k344a6d59eef8632c9d1.js",
6-
"application.png": "/packs/application-k344a6d59eef8632c9d1.png"
6+
"application.png": "/packs/application-k344a6d59eef8632c9d1.png",
7+
"entrypoints": {
8+
"application": {
9+
"js": [
10+
"/packs/vendors~application~bootstrap-c20632e7baf2c81200d3.chunk.js",
11+
"/packs/vendors~application-e55f2aae30c07fb6d82a.chunk.js",
12+
"/packs/application-k344a6d59eef8632c9d1.js"
13+
]
14+
}
15+
}
716
}

0 commit comments

Comments
 (0)