jetpacker 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.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintignore +4 -0
  3. data/.eslintrc.js +14 -0
  4. data/.gitignore +11 -11
  5. data/.node-version +1 -0
  6. data/.rubocop.yml +125 -0
  7. data/.travis.yml +54 -5
  8. data/CHANGELOG.jetpacker.md +7 -0
  9. data/CHANGELOG.md +1000 -0
  10. data/CONTRIBUTING.md +33 -0
  11. data/Gemfile +9 -3
  12. data/Gemfile.lock +157 -21
  13. data/MIT-LICENSE +20 -0
  14. data/README.md +671 -16
  15. data/Rakefile +8 -3
  16. data/docs/assets.md +119 -0
  17. data/docs/cloud9.md +310 -0
  18. data/docs/css.md +253 -0
  19. data/docs/deployment.md +130 -0
  20. data/docs/docker.md +68 -0
  21. data/docs/engines.md +200 -0
  22. data/docs/env.md +65 -0
  23. data/docs/es6.md +72 -0
  24. data/docs/folder-structure.md +66 -0
  25. data/docs/misc.md +23 -0
  26. data/docs/props.md +223 -0
  27. data/docs/testing.md +137 -0
  28. data/docs/troubleshooting.md +156 -0
  29. data/docs/typescript.md +126 -0
  30. data/docs/v4-upgrade.md +142 -0
  31. data/docs/webpack-dev-server.md +92 -0
  32. data/docs/webpack.md +364 -0
  33. data/docs/yarn.md +23 -0
  34. data/gemfiles/Gemfile-rails-edge +12 -0
  35. data/gemfiles/Gemfile-rails.4.2.x +9 -0
  36. data/gemfiles/Gemfile-rails.5.0.x +9 -0
  37. data/gemfiles/Gemfile-rails.5.1.x +9 -0
  38. data/gemfiles/Gemfile-rails.5.2.x +9 -0
  39. data/gemfiles/Gemfile-rails.6.0.x +9 -0
  40. data/jetpacker.gemspec +28 -22
  41. data/lib/install/angular.rb +23 -0
  42. data/lib/install/bin/webpack +18 -0
  43. data/lib/install/bin/webpack-dev-server +18 -0
  44. data/lib/install/binstubs.rb +4 -0
  45. data/lib/install/coffee.rb +25 -0
  46. data/lib/install/config/.browserslistrc +1 -0
  47. data/lib/install/config/babel.config.js +72 -0
  48. data/lib/install/config/postcss.config.js +12 -0
  49. data/lib/install/config/webpack/development.js +5 -0
  50. data/lib/install/config/webpack/environment.js +3 -0
  51. data/lib/install/config/webpack/production.js +5 -0
  52. data/lib/install/config/webpack/test.js +5 -0
  53. data/lib/install/config/webpacker.yml +96 -0
  54. data/lib/install/elm.rb +39 -0
  55. data/lib/install/erb.rb +25 -0
  56. data/lib/install/examples/angular/hello_angular.js +7 -0
  57. data/lib/install/examples/angular/hello_angular/app/app.component.ts +9 -0
  58. data/lib/install/examples/angular/hello_angular/app/app.module.ts +16 -0
  59. data/lib/install/examples/angular/hello_angular/index.ts +8 -0
  60. data/lib/install/examples/angular/hello_angular/polyfills.ts +73 -0
  61. data/lib/install/examples/coffee/hello_coffee.coffee +4 -0
  62. data/lib/install/examples/elm/Main.elm +55 -0
  63. data/lib/install/examples/elm/hello_elm.js +16 -0
  64. data/lib/install/examples/erb/hello_erb.js.erb +6 -0
  65. data/lib/install/examples/react/babel.config.js +87 -0
  66. data/lib/install/examples/react/hello_react.jsx +26 -0
  67. data/lib/install/examples/react/tsconfig.json +20 -0
  68. data/lib/install/examples/stimulus/application.js +1 -0
  69. data/lib/install/examples/stimulus/controllers/hello_controller.js +18 -0
  70. data/lib/install/examples/stimulus/controllers/index.js +9 -0
  71. data/lib/install/examples/svelte/app.svelte +11 -0
  72. data/lib/install/examples/svelte/hello_svelte.js +20 -0
  73. data/lib/install/examples/typescript/hello_typescript.ts +4 -0
  74. data/lib/install/examples/typescript/tsconfig.json +23 -0
  75. data/lib/install/examples/vue/app.vue +22 -0
  76. data/lib/install/examples/vue/hello_vue.js +72 -0
  77. data/lib/install/javascript/packs/application.js +18 -0
  78. data/lib/install/loaders/coffee.js +6 -0
  79. data/lib/install/loaders/elm.js +25 -0
  80. data/lib/install/loaders/erb.js +11 -0
  81. data/lib/install/loaders/svelte.js +9 -0
  82. data/lib/install/loaders/typescript.js +11 -0
  83. data/lib/install/loaders/vue.js +6 -0
  84. data/lib/install/react.rb +18 -0
  85. data/lib/install/stimulus.rb +12 -0
  86. data/lib/install/svelte.rb +29 -0
  87. data/lib/install/template.rb +55 -0
  88. data/lib/install/typescript.rb +46 -0
  89. data/lib/install/vue.rb +49 -0
  90. data/lib/jetpacker/version.rb +2 -1
  91. data/lib/tasks/installers.rake +37 -0
  92. data/lib/tasks/webpacker.rake +28 -0
  93. data/lib/tasks/webpacker/binstubs.rake +11 -0
  94. data/lib/tasks/webpacker/check_binstubs.rake +12 -0
  95. data/lib/tasks/webpacker/check_node.rake +24 -0
  96. data/lib/tasks/webpacker/check_yarn.rake +24 -0
  97. data/lib/tasks/webpacker/clean.rake +21 -0
  98. data/lib/tasks/webpacker/clobber.rake +16 -0
  99. data/lib/tasks/webpacker/compile.rake +43 -0
  100. data/lib/tasks/webpacker/info.rake +20 -0
  101. data/lib/tasks/webpacker/install.rake +13 -0
  102. data/lib/tasks/webpacker/verify_install.rake +13 -0
  103. data/lib/tasks/webpacker/yarn_install.rake +21 -0
  104. data/lib/webpacker.rb +46 -0
  105. data/lib/webpacker/commands.rb +50 -0
  106. data/lib/webpacker/compiler.rb +107 -0
  107. data/lib/webpacker/configuration.rb +113 -0
  108. data/lib/webpacker/dev_server.rb +66 -0
  109. data/lib/webpacker/dev_server_proxy.rb +31 -0
  110. data/lib/webpacker/dev_server_runner.rb +72 -0
  111. data/lib/webpacker/env.rb +39 -0
  112. data/lib/webpacker/helper.rb +176 -0
  113. data/lib/webpacker/instance.rb +37 -0
  114. data/lib/webpacker/manifest.rb +118 -0
  115. data/lib/webpacker/railtie.rb +98 -0
  116. data/lib/webpacker/rake_tasks.rb +6 -0
  117. data/lib/webpacker/runner.rb +22 -0
  118. data/lib/webpacker/version.rb +4 -0
  119. data/lib/webpacker/webpack_runner.rb +32 -0
  120. data/package.json +82 -0
  121. data/package/__tests__/config.js +55 -0
  122. data/package/__tests__/dev_server.js +43 -0
  123. data/package/__tests__/development.js +30 -0
  124. data/package/__tests__/env.js +46 -0
  125. data/package/__tests__/production.js +29 -0
  126. data/package/__tests__/staging.js +29 -0
  127. data/package/__tests__/test.js +26 -0
  128. data/package/config.js +37 -0
  129. data/package/config_types/__tests__/config_list.js +118 -0
  130. data/package/config_types/__tests__/config_object.js +43 -0
  131. data/package/config_types/config_list.js +75 -0
  132. data/package/config_types/config_object.js +55 -0
  133. data/package/config_types/index.js +7 -0
  134. data/package/dev_server.js +20 -0
  135. data/package/env.js +19 -0
  136. data/package/environments/__tests__/base.js +74 -0
  137. data/package/environments/base.js +166 -0
  138. data/package/environments/development.js +51 -0
  139. data/package/environments/production.js +79 -0
  140. data/package/environments/test.js +3 -0
  141. data/package/index.js +24 -0
  142. data/package/rules/babel.js +21 -0
  143. data/package/rules/css.js +3 -0
  144. data/package/rules/file.js +20 -0
  145. data/package/rules/index.js +20 -0
  146. data/package/rules/module.css.js +3 -0
  147. data/package/rules/module.sass.js +8 -0
  148. data/package/rules/node_modules.js +24 -0
  149. data/package/rules/sass.js +8 -0
  150. data/package/utils/__tests__/deep_assign.js +32 -0
  151. data/package/utils/__tests__/deep_merge.js +10 -0
  152. data/package/utils/__tests__/get_style_rule.js +65 -0
  153. data/package/utils/__tests__/objectify.js +9 -0
  154. data/package/utils/deep_assign.js +22 -0
  155. data/package/utils/deep_merge.js +22 -0
  156. data/package/utils/get_style_rule.js +45 -0
  157. data/package/utils/helpers.js +58 -0
  158. data/package/utils/objectify.js +3 -0
  159. data/test/command_test.rb +33 -0
  160. data/test/compiler_test.rb +75 -0
  161. data/test/configuration_test.rb +108 -0
  162. data/test/dev_server_runner_test.rb +51 -0
  163. data/test/dev_server_test.rb +47 -0
  164. data/test/env_test.rb +23 -0
  165. data/test/helper_test.rb +142 -0
  166. data/test/manifest_test.rb +42 -0
  167. data/test/rake_tasks_test.rb +69 -0
  168. data/test/test_app/Rakefile +3 -0
  169. data/test/test_app/app/javascript/packs/application.js +10 -0
  170. data/test/test_app/bin/webpack +14 -0
  171. data/test/test_app/bin/webpack-dev-server +14 -0
  172. data/test/test_app/config.ru +5 -0
  173. data/test/test_app/config/application.rb +12 -0
  174. data/test/test_app/config/environment.rb +4 -0
  175. data/test/test_app/config/webpack/development.js +0 -0
  176. data/test/test_app/config/webpacker.yml +97 -0
  177. data/test/test_app/config/webpacker_public_root.yml +19 -0
  178. data/test/test_app/package.json +13 -0
  179. data/test/test_app/public/packs/manifest.json +31 -0
  180. data/test/test_app/yarn.lock +11 -0
  181. data/test/test_helper.rb +33 -0
  182. data/test/webpack_runner_test.rb +51 -0
  183. data/test/webpacker_test.rb +13 -0
  184. data/yarn.lock +8321 -0
  185. metadata +267 -29
  186. data/.rspec +0 -3
  187. data/LICENSE.txt +0 -21
  188. data/bin/console +0 -14
  189. data/bin/setup +0 -8
  190. data/lib/jetpacker.rb +0 -6
@@ -0,0 +1,66 @@
1
+ class Webpacker::DevServer
2
+ DEFAULT_ENV_PREFIX = "WEBPACKER_DEV_SERVER".freeze
3
+
4
+ # Configure dev server connection timeout (in seconds), default: 0.01
5
+ # Webpacker.dev_server.connect_timeout = 1
6
+ cattr_accessor(:connect_timeout) { 0.01 }
7
+
8
+ attr_reader :config
9
+
10
+ def initialize(config)
11
+ @config = config
12
+ end
13
+
14
+ def running?
15
+ if config.dev_server.present?
16
+ Socket.tcp(host, port, connect_timeout: connect_timeout).close
17
+ true
18
+ else
19
+ false
20
+ end
21
+ rescue
22
+ false
23
+ end
24
+
25
+ def host
26
+ fetch(:host)
27
+ end
28
+
29
+ def port
30
+ fetch(:port)
31
+ end
32
+
33
+ def https?
34
+ case fetch(:https)
35
+ when true, "true", Hash
36
+ true
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ def protocol
43
+ https? ? "https" : "http"
44
+ end
45
+
46
+ def host_with_port
47
+ "#{host}:#{port}"
48
+ end
49
+
50
+ def pretty?
51
+ fetch(:pretty)
52
+ end
53
+
54
+ def env_prefix
55
+ config.dev_server.fetch(:env_prefix, DEFAULT_ENV_PREFIX)
56
+ end
57
+
58
+ private
59
+ def fetch(key)
60
+ ENV["#{env_prefix}_#{key.upcase}"] || config.dev_server.fetch(key, defaults[key])
61
+ end
62
+
63
+ def defaults
64
+ config.send(:defaults)[:dev_server] || {}
65
+ end
66
+ end
@@ -0,0 +1,31 @@
1
+ require "rack/proxy"
2
+
3
+ class Webpacker::DevServerProxy < Rack::Proxy
4
+ delegate :config, :dev_server, to: :@webpacker
5
+
6
+ def initialize(app = nil, opts = {})
7
+ @webpacker = opts.delete(:webpacker) || Webpacker.instance
8
+ opts[:streaming] = false if Jets.env.test? && !opts.key?(:streaming)
9
+ super
10
+ end
11
+
12
+ def perform_request(env)
13
+ if env["PATH_INFO"].start_with?("/#{public_output_uri_path}") && dev_server.running?
14
+ env["HTTP_HOST"] = env["HTTP_X_FORWARDED_HOST"] = env["HTTP_X_FORWARDED_SERVER"] = dev_server.host_with_port
15
+ env["HTTP_X_FORWARDED_PROTO"] = env["HTTP_X_FORWARDED_SCHEME"] = dev_server.protocol
16
+ unless dev_server.https?
17
+ env["HTTPS"] = env["HTTP_X_FORWARDED_SSL"] = "off"
18
+ end
19
+ env["SCRIPT_NAME"] = ""
20
+
21
+ super(env)
22
+ else
23
+ @app.call(env)
24
+ end
25
+ end
26
+
27
+ private
28
+ def public_output_uri_path
29
+ config.public_output_path.relative_path_from(config.public_path).to_s + "/"
30
+ end
31
+ end
@@ -0,0 +1,72 @@
1
+ require "shellwords"
2
+ require "socket"
3
+ require "webpacker/configuration"
4
+ require "webpacker/dev_server"
5
+ require "webpacker/runner"
6
+
7
+ module Webpacker
8
+ class DevServerRunner < Webpacker::Runner
9
+ def run
10
+ load_config
11
+ detect_port!
12
+ execute_cmd
13
+ end
14
+
15
+ private
16
+ def load_config
17
+ app_root = Pathname.new(@app_path)
18
+
19
+ @config = Configuration.new(
20
+ root_path: app_root,
21
+ config_path: app_root.join("config/webpacker.yml"),
22
+ env: ENV["JETS_ENV"]
23
+ )
24
+
25
+ dev_server = DevServer.new(@config)
26
+
27
+ @hostname = dev_server.host
28
+ @port = dev_server.port
29
+ @pretty = dev_server.pretty?
30
+
31
+ rescue Errno::ENOENT, NoMethodError
32
+ $stdout.puts "webpack dev_server configuration not found in #{@config.config_path}[#{ENV["JETS_ENV"]}]."
33
+ $stdout.puts "Please run bundle exec rails webpacker:install to install Webpacker"
34
+ exit!
35
+ end
36
+
37
+ def detect_port!
38
+ server = TCPServer.new(@hostname, @port)
39
+ server.close
40
+
41
+ rescue Errno::EADDRINUSE
42
+ $stdout.puts "Another program is running on port #{@port}. Set a new port in #{@config.config_path} for dev_server"
43
+ exit!
44
+ end
45
+
46
+ def execute_cmd
47
+ env = Webpacker::Compiler.env
48
+
49
+ cmd = if node_modules_bin_exist?
50
+ ["#{@node_modules_bin_path}/webpack-dev-server"]
51
+ else
52
+ ["yarn", "webpack-dev-server"]
53
+ end
54
+
55
+ if ARGV.include?("--debug")
56
+ cmd = [ "node", "--inspect-brk"] + cmd
57
+ ARGV.delete("--debug")
58
+ end
59
+
60
+ cmd += ["--config", @webpack_config]
61
+ cmd += ["--progress", "--color"] if @pretty
62
+
63
+ Dir.chdir(@app_path) do
64
+ Kernel.exec env, *cmd
65
+ end
66
+ end
67
+
68
+ def node_modules_bin_exist?
69
+ File.exist?("#{@node_modules_bin_path}/webpack-dev-server")
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,39 @@
1
+ class Webpacker::Env
2
+ DEFAULT = "production".freeze
3
+
4
+ delegate :config_path, :logger, to: :@webpacker
5
+
6
+ def self.inquire(webpacker)
7
+ new(webpacker).inquire
8
+ end
9
+
10
+ def initialize(webpacker)
11
+ @webpacker = webpacker
12
+ end
13
+
14
+ def inquire
15
+ fallback_env_warning if config_path.exist? && !current
16
+ current || DEFAULT.inquiry
17
+ end
18
+
19
+ private
20
+ def current
21
+ Jets.env.presence_in(available_environments)
22
+ end
23
+
24
+ def fallback_env_warning
25
+ logger.info "JETS_ENV=#{Jets.env} environment is not defined in config/webpacker.yml, falling back to #{DEFAULT} environment"
26
+ end
27
+
28
+ def available_environments
29
+ if config_path.exist?
30
+ YAML.load(config_path.read).keys
31
+ else
32
+ [].freeze
33
+ end
34
+ rescue Psych::SyntaxError => e
35
+ raise "YAML syntax error occurred while parsing #{config_path}. " \
36
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
37
+ "Error: #{e.message}"
38
+ end
39
+ end
@@ -0,0 +1,176 @@
1
+ module Webpacker::Helper
2
+ # Returns the current Webpacker instance.
3
+ # Could be overridden to use multiple Webpacker
4
+ # configurations within the same app (e.g. with engines).
5
+ def current_webpacker_instance
6
+ Webpacker.instance
7
+ end
8
+
9
+ # Computes the relative path for a given Webpacker asset.
10
+ # Returns the relative path using manifest.json and passes it to asset_path helper.
11
+ # This will use asset_path internally, so most of their behaviors will be the same.
12
+ #
13
+ # Example:
14
+ #
15
+ # # When extract_css is false in webpacker.yml and the file is a css:
16
+ # <%= asset_pack_path 'calendar.css' %> # => nil
17
+ #
18
+ # # When extract_css is true in webpacker.yml or the file is not a css:
19
+ # <%= asset_pack_path 'calendar.css' %> # => "/packs/calendar-1016838bab065ae1e122.css"
20
+ def asset_pack_path(name, **options)
21
+ if current_webpacker_instance.config.extract_css? || !stylesheet?(name)
22
+ asset_path(current_webpacker_instance.manifest.lookup!(name), options)
23
+ end
24
+ end
25
+
26
+ # Computes the absolute path for a given Webpacker asset.
27
+ # Returns the absolute path using manifest.json and passes it to asset_url helper.
28
+ # This will use asset_url internally, so most of their behaviors will be the same.
29
+ #
30
+ # Example:
31
+ #
32
+ # # When extract_css is false in webpacker.yml and the file is a css:
33
+ # <%= asset_pack_url 'calendar.css' %> # => nil
34
+ #
35
+ # # When extract_css is true in webpacker.yml or the file is not a css:
36
+ # <%= asset_pack_url 'calendar.css' %> # => "http://example.com/packs/calendar-1016838bab065ae1e122.css"
37
+ def asset_pack_url(name, **options)
38
+ if current_webpacker_instance.config.extract_css? || !stylesheet?(name)
39
+ asset_url(current_webpacker_instance.manifest.lookup!(name), options)
40
+ end
41
+ end
42
+
43
+ # Creates an image tag that references the named pack file.
44
+ #
45
+ # Example:
46
+ #
47
+ # <%= image_pack_tag 'application.png', size: '16x10', alt: 'Edit Entry' %>
48
+ # <img alt='Edit Entry' src='/packs/application-k344a6d59eef8632c9d1.png' width='16' height='10' />
49
+ def image_pack_tag(name, **options)
50
+ image_tag(resolve_path_to_image(name), options)
51
+ end
52
+
53
+ # Creates a link tag for a favicon that references the named pack file.
54
+ #
55
+ # Example:
56
+ #
57
+ # <%= favicon_pack_tag 'mb-icon.png', rel: 'apple-touch-icon', type: 'image/png' %>
58
+ # <link href="/packs/mb-icon-k344a6d59eef8632c9d1.png" rel="apple-touch-icon" type="image/png" />
59
+ def favicon_pack_tag(name, **options)
60
+ favicon_link_tag(resolve_path_to_image(name), options)
61
+ end
62
+
63
+ # Creates a script tag that references the named pack file, as compiled by webpack per the entries list
64
+ # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
65
+ # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
66
+ #
67
+ # Example:
68
+ #
69
+ # <%= javascript_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
70
+ # <script src="/packs/calendar-1016838bab065ae1e314.js" data-turbolinks-track="reload"></script>
71
+ def javascript_pack_tag(*names, **options)
72
+ javascript_include_tag(*sources_from_manifest_entries(names, type: :javascript), **options)
73
+ end
74
+
75
+ # Creates script tags that reference the js chunks from entrypoints when using split chunks API,
76
+ # as compiled by webpack per the entries list in config/webpack/shared.js.
77
+ # By default, this list is auto-generated to match everything in
78
+ # app/javascript/packs/*.js and all the dependent chunks. In production mode, the digested reference is automatically looked up.
79
+ # See: https://webpack.js.org/plugins/split-chunks-plugin/
80
+ # Example:
81
+ #
82
+ # <%= javascript_packs_with_chunks_tag 'calendar', 'map', 'data-turbolinks-track': 'reload' %> # =>
83
+ # <script src="/packs/vendor-16838bab065ae1e314.chunk.js" data-turbolinks-track="reload"></script>
84
+ # <script src="/packs/calendar~runtime-16838bab065ae1e314.chunk.js" data-turbolinks-track="reload"></script>
85
+ # <script src="/packs/calendar-1016838bab065ae1e314.chunk.js" data-turbolinks-track="reload"></script>
86
+ # <script src="/packs/map~runtime-16838bab065ae1e314.chunk.js" data-turbolinks-track="reload"></script>
87
+ # <script src="/packs/map-16838bab065ae1e314.chunk.js" data-turbolinks-track="reload"></script>
88
+ # DO:
89
+ # <%= javascript_packs_with_chunks_tag 'calendar', 'map' %>
90
+ # DON'T:
91
+ # <%= javascript_packs_with_chunks_tag 'calendar' %>
92
+ # <%= javascript_packs_with_chunks_tag 'map' %>
93
+ def javascript_packs_with_chunks_tag(*names, **options)
94
+ javascript_include_tag(*sources_from_manifest_entrypoints(names, type: :javascript), **options)
95
+ end
96
+
97
+ # Creates a link tag, for preloading, that references a given Webpacker asset.
98
+ # In production mode, the digested reference is automatically looked up.
99
+ # See: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
100
+ # Example:
101
+ #
102
+ # <%= preload_pack_asset 'fonts/fa-regular-400.woff2' %> # =>
103
+ # <link rel="preload" href="/packs/fonts/fa-regular-400-944fb546bd7018b07190a32244f67dc9.woff2" as="font" type="font/woff2" crossorigin="anonymous">
104
+ def preload_pack_asset(name, **options)
105
+ if self.class.method_defined?(:preload_link_tag)
106
+ preload_link_tag(current_webpacker_instance.manifest.lookup!(name), options)
107
+ else
108
+ raise "You need Rails >= 5.2 to use this tag."
109
+ end
110
+ end
111
+
112
+ # Creates a link tag that references the named pack file, as compiled by webpack per the entries list
113
+ # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
114
+ # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
115
+ #
116
+ # Note: If the development server is running and hot module replacement is active, this will return nothing.
117
+ # In that setup you need to configure your styles to be inlined in your JavaScript for hot reloading.
118
+ #
119
+ # Examples:
120
+ #
121
+ # # When extract_css is false in webpacker.yml:
122
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
123
+ # nil
124
+ #
125
+ # # When extract_css is true in webpacker.yml:
126
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
127
+ # <link rel="stylesheet" media="screen" href="/packs/calendar-1016838bab065ae1e122.css" data-turbolinks-track="reload" />
128
+ def stylesheet_pack_tag(*names, **options)
129
+ if current_webpacker_instance.config.extract_css?
130
+ stylesheet_link_tag(*sources_from_manifest_entries(names, type: :stylesheet), **options)
131
+ end
132
+ end
133
+
134
+ # Creates link tags that reference the css chunks from entrypoints when using split chunks API,
135
+ # as compiled by webpack per the entries list in config/webpack/shared.js.
136
+ # By default, this list is auto-generated to match everything in
137
+ # app/javascript/packs/*.js and all the dependent chunks. In production mode, the digested reference is automatically looked up.
138
+ # See: https://webpack.js.org/plugins/split-chunks-plugin/
139
+ #
140
+ # Examples:
141
+ #
142
+ # <%= stylesheet_packs_with_chunks_tag 'calendar', 'map' %> # =>
143
+ # <link rel="stylesheet" media="screen" href="/packs/3-8c7ce31a.chunk.css" />
144
+ # <link rel="stylesheet" media="screen" href="/packs/calendar-8c7ce31a.chunk.css" />
145
+ # <link rel="stylesheet" media="screen" href="/packs/map-8c7ce31a.chunk.css" />
146
+ # DO:
147
+ # <%= stylesheet_packs_with_chunks_tag 'calendar', 'map' %>
148
+ # DON'T:
149
+ # <%= stylesheet_packs_with_chunks_tag 'calendar' %>
150
+ # <%= stylesheet_packs_with_chunks_tag 'map' %>
151
+ def stylesheet_packs_with_chunks_tag(*names, **options)
152
+ if current_webpacker_instance.config.extract_css?
153
+ stylesheet_link_tag(*sources_from_manifest_entrypoints(names, type: :stylesheet), **options)
154
+ end
155
+ end
156
+
157
+ private
158
+ def stylesheet?(name)
159
+ File.extname(name) == ".css"
160
+ end
161
+
162
+ def sources_from_manifest_entries(names, type:)
163
+ names.map { |name| current_webpacker_instance.manifest.lookup!(name, type: type) }.flatten
164
+ end
165
+
166
+ def sources_from_manifest_entrypoints(names, type:)
167
+ names.map { |name| current_webpacker_instance.manifest.lookup_pack_with_chunks!(name, type: type) }.flatten.uniq
168
+ end
169
+
170
+ def resolve_path_to_image(name)
171
+ path = name.starts_with?("media/images/") ? name : "media/images/#{name}"
172
+ asset_path(current_webpacker_instance.manifest.lookup!(path))
173
+ rescue
174
+ asset_path(current_webpacker_instance.manifest.lookup!(name))
175
+ end
176
+ end
@@ -0,0 +1,37 @@
1
+ class Webpacker::Instance
2
+ cattr_accessor(:logger) { ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT)) }
3
+
4
+ attr_reader :root_path, :config_path
5
+
6
+ def initialize(root_path: Jets.root, config_path: Jets.root.join("config/webpacker.yml"))
7
+ @root_path, @config_path = root_path, config_path
8
+ end
9
+
10
+ def env
11
+ @env ||= Webpacker::Env.inquire self
12
+ end
13
+
14
+ def config
15
+ @config ||= Webpacker::Configuration.new(
16
+ root_path: root_path,
17
+ config_path: config_path,
18
+ env: env
19
+ )
20
+ end
21
+
22
+ def compiler
23
+ @compiler ||= Webpacker::Compiler.new self
24
+ end
25
+
26
+ def dev_server
27
+ @dev_server ||= Webpacker::DevServer.new config
28
+ end
29
+
30
+ def manifest
31
+ @manifest ||= Webpacker::Manifest.new self
32
+ end
33
+
34
+ def commands
35
+ @commands ||= Webpacker::Commands.new self
36
+ end
37
+ end
@@ -0,0 +1,118 @@
1
+ # Singleton registry for accessing the packs path using a generated manifest.
2
+ # This allows javascript_pack_tag, stylesheet_pack_tag, asset_pack_path to take a reference to,
3
+ # say, "calendar.js" or "calendar.css" and turn it into "/packs/calendar-1016838bab065ae1e314.js" or
4
+ # "/packs/calendar-1016838bab065ae1e314.css".
5
+ #
6
+ # When the configuration is set to on-demand compilation, with the `compile: true` option in
7
+ # the webpacker.yml file, any lookups will be preceded by a compilation if one is needed.
8
+ class Webpacker::Manifest
9
+ class MissingEntryError < StandardError; end
10
+
11
+ delegate :config, :compiler, :dev_server, to: :@webpacker
12
+
13
+ def initialize(webpacker)
14
+ @webpacker = webpacker
15
+ end
16
+
17
+ def refresh
18
+ @data = load
19
+ end
20
+
21
+ def lookup_pack_with_chunks(name, pack_type = {})
22
+ compile if compiling?
23
+
24
+ manifest_pack_type = manifest_type(pack_type[:type])
25
+ manifest_pack_name = manifest_name(name, manifest_pack_type)
26
+ find("entrypoints")[manifest_pack_name][manifest_pack_type]
27
+ rescue NoMethodError
28
+ nil
29
+ end
30
+
31
+ def lookup_pack_with_chunks!(name, pack_type = {})
32
+ lookup_pack_with_chunks(name, pack_type) || handle_missing_entry(name)
33
+ end
34
+
35
+ # Computes the relative path for a given Webpacker asset using manifest.json.
36
+ # If no asset is found, returns nil.
37
+ #
38
+ # Example:
39
+ #
40
+ # Webpacker.manifest.lookup('calendar.js') # => "/packs/calendar-1016838bab065ae1e122.js"
41
+ def lookup(name, pack_type = {})
42
+ compile if compiling?
43
+
44
+ find(full_pack_name(name, pack_type[:type]))
45
+ end
46
+
47
+ # Like lookup, except that if no asset is found, raises a Webpacker::Manifest::MissingEntryError.
48
+ def lookup!(name, pack_type = {})
49
+ lookup(name, pack_type) || handle_missing_entry(name)
50
+ end
51
+
52
+ private
53
+ def compiling?
54
+ config.compile? && !dev_server.running?
55
+ end
56
+
57
+ def compile
58
+ Webpacker.logger.tagged("Webpacker") { compiler.compile }
59
+ end
60
+
61
+ def data
62
+ if config.cache_manifest?
63
+ @data ||= load
64
+ else
65
+ refresh
66
+ end
67
+ end
68
+
69
+ def find(name)
70
+ data[name.to_s].presence
71
+ end
72
+
73
+ def full_pack_name(name, pack_type)
74
+ return name unless File.extname(name.to_s).empty?
75
+ "#{name}.#{manifest_type(pack_type)}"
76
+ end
77
+
78
+ def handle_missing_entry(name)
79
+ raise Webpacker::Manifest::MissingEntryError, missing_file_from_manifest_error(name)
80
+ end
81
+
82
+ def load
83
+ if config.public_manifest_path.exist?
84
+ JSON.parse config.public_manifest_path.read
85
+ else
86
+ {}
87
+ end
88
+ end
89
+
90
+ # The `manifest_name` method strips of the file extension of the name, because in the
91
+ # manifest hash the entrypoints are defined by their pack name without the extension.
92
+ # When the user provides a name with a file extension, we want to try to strip it off.
93
+ def manifest_name(name, pack_type)
94
+ return name if File.extname(name.to_s).empty?
95
+ File.basename(name, pack_type)
96
+ end
97
+
98
+ def manifest_type(pack_type)
99
+ case pack_type
100
+ when :javascript then "js"
101
+ when :stylesheet then "css"
102
+ else pack_type.to_s
103
+ end
104
+ end
105
+
106
+ def missing_file_from_manifest_error(bundle_name)
107
+ <<-MSG
108
+ Webpacker can't find #{bundle_name} in #{config.public_manifest_path}. Possible causes:
109
+ 1. You want to set webpacker.yml value of compile to true for your environment
110
+ unless you are using the `webpack -w` or the webpack-dev-server.
111
+ 2. webpack has not yet re-run to reflect updates.
112
+ 3. You have misconfigured Webpacker's config/webpacker.yml file.
113
+ 4. Your webpack configuration is not creating a manifest.
114
+ Your manifest contains:
115
+ #{JSON.pretty_generate(@data)}
116
+ MSG
117
+ end
118
+ end