webpacker-react-on-rails 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 (81) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintrc.js +14 -0
  3. data/.gitignore +4 -0
  4. data/.rubocop.yml +124 -0
  5. data/.travis.yml +22 -0
  6. data/CHANGELOG.md +208 -0
  7. data/Gemfile +21 -0
  8. data/Gemfile.lock +137 -0
  9. data/MIT-LICENSE +20 -0
  10. data/README.md +1244 -0
  11. data/Rakefile +12 -0
  12. data/lib/install/angular.rb +18 -0
  13. data/lib/install/bin/webpack-dev-server.tt +71 -0
  14. data/lib/install/bin/webpack.tt +32 -0
  15. data/lib/install/config/.babelrc +18 -0
  16. data/lib/install/config/.postcssrc.yml +3 -0
  17. data/lib/install/config/loaders/core/assets.js +12 -0
  18. data/lib/install/config/loaders/core/babel.js +5 -0
  19. data/lib/install/config/loaders/core/coffee.js +4 -0
  20. data/lib/install/config/loaders/core/erb.js +9 -0
  21. data/lib/install/config/loaders/core/sass.js +18 -0
  22. data/lib/install/config/loaders/installers/angular.js +4 -0
  23. data/lib/install/config/loaders/installers/elm.js +20 -0
  24. data/lib/install/config/loaders/installers/react.js +5 -0
  25. data/lib/install/config/loaders/installers/vue.js +41 -0
  26. data/lib/install/config/webpack/configuration.js +45 -0
  27. data/lib/install/config/webpack/development.js +31 -0
  28. data/lib/install/config/webpack/production.js +35 -0
  29. data/lib/install/config/webpack/shared.js +53 -0
  30. data/lib/install/config/webpack/test.js +6 -0
  31. data/lib/install/config/webpacker.yml +47 -0
  32. data/lib/install/elm.rb +29 -0
  33. data/lib/install/examples/angular/hello_angular.js +7 -0
  34. data/lib/install/examples/angular/hello_angular/app/app.component.ts +9 -0
  35. data/lib/install/examples/angular/hello_angular/app/app.module.ts +16 -0
  36. data/lib/install/examples/angular/hello_angular/index.ts +6 -0
  37. data/lib/install/examples/angular/hello_angular/polyfills.ts +19 -0
  38. data/lib/install/examples/angular/tsconfig.json +19 -0
  39. data/lib/install/examples/elm/Main.elm +54 -0
  40. data/lib/install/examples/elm/hello_elm.js +11 -0
  41. data/lib/install/examples/react/.babelrc +6 -0
  42. data/lib/install/examples/react/hello_react.jsx +26 -0
  43. data/lib/install/examples/vue/app.vue +22 -0
  44. data/lib/install/examples/vue/hello_vue.js +43 -0
  45. data/lib/install/javascript/packs/application.js +10 -0
  46. data/lib/install/react.rb +31 -0
  47. data/lib/install/template.rb +42 -0
  48. data/lib/install/vue.rb +15 -0
  49. data/lib/tasks/installers.rake +22 -0
  50. data/lib/tasks/webpacker.rake +19 -0
  51. data/lib/tasks/webpacker/check_binstubs.rake +12 -0
  52. data/lib/tasks/webpacker/check_node.rake +20 -0
  53. data/lib/tasks/webpacker/check_yarn.rake +15 -0
  54. data/lib/tasks/webpacker/clobber.rake +17 -0
  55. data/lib/tasks/webpacker/compile.rake +38 -0
  56. data/lib/tasks/webpacker/install.rake +12 -0
  57. data/lib/tasks/webpacker/verify_install.rake +16 -0
  58. data/lib/tasks/webpacker/yarn_install.rake +6 -0
  59. data/lib/webpacker.rb +26 -0
  60. data/lib/webpacker/compiler.rb +59 -0
  61. data/lib/webpacker/configuration.rb +83 -0
  62. data/lib/webpacker/dev_server.rb +78 -0
  63. data/lib/webpacker/env.rb +23 -0
  64. data/lib/webpacker/file_loader.rb +47 -0
  65. data/lib/webpacker/helper.rb +69 -0
  66. data/lib/webpacker/manifest.rb +101 -0
  67. data/lib/webpacker/railtie.rb +18 -0
  68. data/lib/webpacker/version.rb +3 -0
  69. data/package.json +31 -0
  70. data/test/compiler_test.rb +25 -0
  71. data/test/configuration_test.rb +36 -0
  72. data/test/dev_server_test.rb +56 -0
  73. data/test/env_test.rb +14 -0
  74. data/test/helper_test.rb +45 -0
  75. data/test/manifest_test.rb +77 -0
  76. data/test/test_app/config/secrets.yml +5 -0
  77. data/test/test_app/public/packs/manifest.json +6 -0
  78. data/test/webpacker_test.rb +20 -0
  79. data/webpacker.gemspec +23 -0
  80. data/yarn.lock +1014 -0
  81. metadata +192 -0
@@ -0,0 +1,47 @@
1
+ # Provides a base singleton-configuration pattern for loading a file, given a path
2
+ class Webpacker::FileLoader
3
+ class NotFoundError < StandardError; end
4
+ class FileLoaderError < StandardError; end
5
+
6
+ class_attribute :instance
7
+ attr_accessor :data, :mtime, :path
8
+
9
+ class << self
10
+ def load_instance(path = file_path)
11
+ # Assume production is 100% cached and don't reload if file's mtime not changed
12
+ cached = self.instance && # if we have a singleton
13
+ (env == "production" || # skip if production bc always cached
14
+ (File.exist?(path) && self.instance.mtime == File.mtime(path))) # skip if mtime not changed
15
+
16
+ return if cached
17
+ self.instance = new(path)
18
+ end
19
+
20
+ def file_path
21
+ raise FileLoaderError.new("Subclass of Webpacker::FileLoader should override this method")
22
+ end
23
+
24
+ def reset
25
+ self.instance = nil
26
+ load_instance
27
+ end
28
+
29
+ private
30
+
31
+ # Prefer the NODE_ENV to the rails env.
32
+ def env
33
+ ENV["NODE_ENV"].presence || Rails.env
34
+ end
35
+ end
36
+
37
+ private
38
+ def initialize(path)
39
+ @path = path
40
+ @mtime = File.exist?(path) ? File.mtime(path) : nil
41
+ @data = load_data
42
+ end
43
+
44
+ def load_data
45
+ {}.freeze
46
+ end
47
+ end
@@ -0,0 +1,69 @@
1
+ module Webpacker::Helper
2
+ # Computes the full path for a given webpacker asset.
3
+ # Return relative path using manifest.json and passes it to asset_url helper
4
+ # This will use asset_path internally, so most of their behaviors will be the same.
5
+ # Examples:
6
+ #
7
+ # In development mode:
8
+ # <%= asset_pack_path 'calendar.js' %> # => "/packs/calendar.js"
9
+ # In production mode:
10
+ # <%= asset_pack_path 'calendar.css' %> # => "/packs/calendar-1016838bab065ae1e122.css"
11
+ def asset_pack_path(name, **options)
12
+ path = Webpacker::Configuration.public_output_path
13
+ file = Webpacker::Manifest.lookup(name)
14
+ full_path = "#{path}/#{file}"
15
+ asset_path(full_path, **options)
16
+ end
17
+
18
+ # Creates a script tag that references the named pack file, as compiled by Webpack per the entries list
19
+ # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
20
+ # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
21
+ #
22
+ # Examples:
23
+ #
24
+ # # In development mode:
25
+ # <%= javascript_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
26
+ # <script src="/packs/calendar.js" data-turbolinks-track="reload"></script>
27
+ #
28
+ # # In production mode:
29
+ # <%= javascript_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
30
+ # <script src="/packs/calendar-1016838bab065ae1e314.js" data-turbolinks-track="reload"></script>
31
+ def javascript_pack_tag(*names, **options)
32
+ javascript_include_tag(*asset_source(names, :javascript), **options)
33
+ end
34
+
35
+ # Creates a link tag that references the named pack file, as compiled by Webpack per the entries list
36
+ # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
37
+ # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
38
+ #
39
+ # Examples:
40
+ #
41
+ # # In development mode:
42
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
43
+ # <link rel="stylesheet" media="screen" href="/packs/calendar.css" data-turbolinks-track="reload" />
44
+ #
45
+ # # In production mode:
46
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
47
+ # <link rel="stylesheet" media="screen" href="/packs/calendar-1016838bab065ae1e122.css" data-turbolinks-track="reload" />
48
+ # # In development mode with hot-reloading
49
+ # <%= stylesheet_pack_tag('main') %> <% # Default is false for enabled_when_hot_loading%>
50
+ # # No output
51
+ #
52
+ # # In development mode with hot-reloading and enabled_when_hot_loading
53
+ # # <%= stylesheet_pack_tag('main', enabled_when_hot_loading: true) %>
54
+ # <link rel="stylesheet" media="screen" href="/public/webpack/development/calendar-1016838bab065ae1e122.css" />
55
+ #
56
+ def stylesheet_pack_tag(*names, **options)
57
+ return "" if Webpacker::DevServer.hot?
58
+ stylesheet_link_tag(*asset_source(names, :stylesheet), **options)
59
+ end
60
+
61
+ private
62
+ def asset_source(names, type)
63
+ output_path_or_url = Webpacker::Configuration.output_path_or_url
64
+ names.map do |name|
65
+ path = Webpacker::Manifest.lookup("#{name}#{compute_asset_extname(name, type: type)}")
66
+ "#{output_path_or_url}/#{path}"
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,101 @@
1
+ # Singleton registry for accessing the packs path using 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.js" or
4
+ # "/packs/calendar.css" in development. In production mode, it returns compiles
5
+ # files, # "/packs/calendar-1016838bab065ae1e314.js" and
6
+ # "/packs/calendar-1016838bab065ae1e314.css" for long-term caching
7
+
8
+ require "webpacker/file_loader"
9
+
10
+ class Webpacker::Manifest < Webpacker::FileLoader
11
+ class << self
12
+ def file_path
13
+ Webpacker::Configuration.manifest_path
14
+ end
15
+
16
+ # Throws an error if the file is not found. If Configuration.compile? then compilation is invoked
17
+ # the file is missing.
18
+ # React on Rails users will need to set Configuration.compile? to false as compilation is configured
19
+ # in the package.json for React on Rails.
20
+ def lookup(name)
21
+ if Webpacker::Configuration.compile?
22
+ compile_and_find!(name)
23
+ else
24
+ find!(name)
25
+ end
26
+ end
27
+
28
+ # Why does this method exist? Testing? It's not in the README
29
+ def lookup_path(name)
30
+ Rails.root.join(File.join(Webpacker::Configuration.output_path, lookup(name)))
31
+ end
32
+
33
+ # Helper method to determine if the manifest file exists. Maybe Webpack needs to run?
34
+ # **Used by React on Rails.**
35
+ def exist?
36
+ path_object = Webpacker::Configuration.manifest_path
37
+ path_object.exist?
38
+ end
39
+
40
+ # Find the real file name from the manifest key. Don't throw an error if the file is simply
41
+ # missing from the manifest. Return nil in that case.
42
+ # If no manifest file exists, then throw an error.
43
+ # **Used by React on Rails.**
44
+ def lookup_no_throw(name)
45
+ instance.confirm_manifest_exists
46
+
47
+ load_instance
48
+ unless instance
49
+ raise Webpacker::FileLoader::FileLoaderError.new("Webpacker::Manifest.load must be called first")
50
+ end
51
+ instance.data[name.to_s]
52
+ end
53
+
54
+ private
55
+ def find!(name)
56
+ unless instance
57
+ raise Webpacker::FileLoader::FileLoaderError.new("Webpacker::Manifest.load must be called first")
58
+ end
59
+ instance.data[name.to_s] || missing_file_from_manifest_error(name)
60
+ end
61
+
62
+ def missing_file_from_manifest_error(bundle_name)
63
+ msg = <<-MSG
64
+ Webpacker can't find #{bundle_name} in your manifest at #{file_path}. Possible causes:
65
+ 1. You are hot reloading.
66
+ 2. You want to set Configuration.compile to true for your environment.
67
+ 3. Webpack has not re-run to reflect updates.
68
+ 4. You have misconfigured Webpacker's config/webpacker.yml file.
69
+ 5. Your Webpack configuration is not creating a manifest.
70
+ MSG
71
+ raise(Webpacker::FileLoader::NotFoundError.new(msg))
72
+ end
73
+
74
+ def missing_manifest_file_error(path_object)
75
+ msg = <<-MSG
76
+ Webpacker can't find the manifest file: #{path_object}
77
+ Possible causes:
78
+ 1. You have not invoked webpack.
79
+ 2. You have misconfigured Webpacker's config/webpacker_.yml file.
80
+ 3. Your Webpack configuration is not creating a manifest.
81
+ MSG
82
+ raise(Webpacker::FileLoader::NotFoundError.new(msg))
83
+ end
84
+
85
+ def compile_and_find!(name)
86
+ Webpacker.compile
87
+ find!(name)
88
+ end
89
+ end
90
+
91
+ def confirm_manifest_exists
92
+ raise missing_manifest_file_error(@path) unless File.exist?(@path)
93
+ end
94
+
95
+ private
96
+
97
+ def load_data
98
+ return super unless File.exist?(@path)
99
+ JSON.parse(File.read(@path))
100
+ end
101
+ end
@@ -0,0 +1,18 @@
1
+ require "rails/railtie"
2
+
3
+ require "webpacker/helper"
4
+
5
+ class Webpacker::Engine < ::Rails::Engine
6
+ initializer :webpacker do |app|
7
+ ActiveSupport.on_load :action_controller do
8
+ ActionController::Base.helper Webpacker::Helper
9
+ end
10
+
11
+ ActiveSupport.on_load :action_view do
12
+ include Webpacker::Helper
13
+ end
14
+
15
+ Webpacker.bootstrap
16
+ Spring.after_fork { Webpacker.bootstrap } if defined?(Spring)
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module Webpacker
2
+ VERSION = "2.0".freeze
3
+ end
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "webpacker",
3
+ "version": "1.0.0",
4
+ "description": "Webpacker makes it easy to use the JavaScript preprocessor and bundler [Webpack](https://webpack.github.io) to manage application-like JavaScript in Rails. It coexists with the asset pipeline, as the purpose is only to use Webpack for app-like JavaScript, not images, css, or even JavaScript Sprinkles (that all continues to live in app/assets).",
5
+ "main": "index.js",
6
+ "engines": {
7
+ "node": ">= 6.4.0"
8
+ },
9
+ "dependencies": {},
10
+ "devDependencies": {
11
+ "eslint": "^3.16.1",
12
+ "eslint-config-airbnb": "^14.1.0",
13
+ "eslint-plugin-import": "^2.2.0",
14
+ "eslint-plugin-jsx-a11y": "^4.0.0",
15
+ "eslint-plugin-react": "^6.10.0"
16
+ },
17
+ "scripts": {
18
+ "test": "echo \"Error: no test specified\" && exit 1",
19
+ "lint": "yarn run eslint lib/"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/rails/webpacker.git"
24
+ },
25
+ "author": "David Heinemeier Hansson <david@basecamp.com>",
26
+ "license": "MIT",
27
+ "bugs": {
28
+ "url": "https://github.com/rails/webpacker/issues"
29
+ },
30
+ "homepage": "https://github.com/rails/webpacker"
31
+ }
@@ -0,0 +1,25 @@
1
+ require "webpacker_test"
2
+
3
+ class CompilerTest < Minitest::Test
4
+ def test_default_watched_paths
5
+ assert_equal Webpacker::Compiler.default_watched_paths, ["app/javascript/**/*", "yarn.lock", "package.json", "config/webpack/**/*"]
6
+ end
7
+
8
+ def test_empty_watched_paths
9
+ assert_equal Webpacker::Compiler.watched_paths, []
10
+ end
11
+
12
+ def test_watched_paths
13
+ Webpacker::Compiler.stub :watched_paths, ["Gemfile"] do
14
+ assert_equal Webpacker::Compiler.watched_paths, ["Gemfile"]
15
+ end
16
+ end
17
+
18
+ def test_cache_dir
19
+ assert_equal Webpacker::Compiler.cache_dir, "tmp/webpacker"
20
+ end
21
+
22
+ def test_compile?
23
+ assert Webpacker::Compiler.compile?
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ require "webpacker_test"
2
+
3
+ class ConfigurationTest < Minitest::Test
4
+ def test_entry_path
5
+ entry_path = File.join(File.dirname(__FILE__), "test_app/app/javascript", "packs").to_s
6
+ assert_equal entry_path, Webpacker::Configuration.entry_path.to_s
7
+ end
8
+
9
+ def test_file_path
10
+ file_path = File.join(File.dirname(__FILE__), "test_app/config", "webpacker.yml").to_s
11
+ assert_equal file_path, Webpacker::Configuration.file_path.to_s
12
+ end
13
+
14
+ def test_manifest_path
15
+ manifest_path = File.join(File.dirname(__FILE__), "test_app/public/packs", "manifest.json").to_s
16
+ assert_equal manifest_path, Webpacker::Configuration.manifest_path.to_s
17
+ end
18
+
19
+ def test_output_path
20
+ output_path = File.join(File.dirname(__FILE__), "test_app/public/packs").to_s
21
+ assert_equal output_path, Webpacker::Configuration.output_path.to_s
22
+ end
23
+
24
+ def test_source
25
+ assert_equal "app/javascript", Webpacker::Configuration.source.to_s
26
+ end
27
+
28
+ def test_source_path
29
+ source_path = File.join(File.dirname(__FILE__), "test_app/app/javascript").to_s
30
+ assert_equal source_path, Webpacker::Configuration.source_path.to_s
31
+ end
32
+
33
+ def test_compile?
34
+ refute Webpacker::Configuration.compile?
35
+ end
36
+ end
@@ -0,0 +1,56 @@
1
+ require "webpacker_test"
2
+
3
+ class DevServerTest < Minitest::Test
4
+ require "webpacker_test"
5
+
6
+ def check_assertion
7
+ stub_value = ActiveSupport::StringInquirer.new("development")
8
+ Webpacker.stub(:env, stub_value) do
9
+ Webpacker::Configuration.reset
10
+ Webpacker::DevServer.reset
11
+ result = yield
12
+ assert_equal(result[0], result[1])
13
+ end
14
+ Webpacker::Configuration.reset
15
+ Webpacker::DevServer.reset
16
+ end
17
+
18
+ def test_dev_server?
19
+ check_assertion { [true, Webpacker::DevServer.dev_server?] }
20
+ end
21
+
22
+ def test_dev_server_host
23
+ check_assertion { ["localhost", Webpacker::DevServer.host] }
24
+ end
25
+
26
+ def test_dev_server_port
27
+ check_assertion { [8080, Webpacker::DevServer.port] }
28
+ end
29
+
30
+ def test_dev_server_hot?
31
+ check_assertion { [false, Webpacker::DevServer.hot?] }
32
+
33
+ ENV.stub(:[], "TRUE") do
34
+ check_assertion { [true, Webpacker::DevServer.hot?] }
35
+ end
36
+
37
+ ENV.stub(:[], "FALSE") do
38
+ check_assertion { [false, Webpacker::DevServer.hot?] }
39
+ end
40
+ ENV.stub(:[], "true") do
41
+ check_assertion { [true, Webpacker::DevServer.hot?] }
42
+ end
43
+ end
44
+
45
+ def test_dev_server_https?
46
+ check_assertion { [false, Webpacker::DevServer.https?] }
47
+ end
48
+
49
+ def test_dev_server_protocol?
50
+ check_assertion { ["http", Webpacker::DevServer.protocol] }
51
+ end
52
+
53
+ def test_base_url?
54
+ check_assertion { ["http://localhost:8080", Webpacker::DevServer.base_url] }
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ require "webpacker_test"
2
+
3
+ class EnvTest < Minitest::Test
4
+ def test_current_env
5
+ assert_equal Webpacker::Env.current, "production"
6
+ assert_equal Webpacker.env, "production"
7
+ assert Webpacker.env.production?
8
+ end
9
+
10
+ def test_file_path
11
+ correct_path = File.join(File.dirname(__FILE__), "test_app/config", "webpacker.yml").to_s
12
+ assert_equal Webpacker::Env.file_path.to_s, correct_path
13
+ end
14
+ end
@@ -0,0 +1,45 @@
1
+ require "webpacker_test"
2
+
3
+ class HelperTest < ActionView::TestCase
4
+ def setup
5
+ @view = ActionView::Base.new
6
+ @view.extend Webpacker::Helper
7
+ end
8
+
9
+ def test_asset_pack_path
10
+ assert_equal "/packs/bootstrap-300631c4f0e0f9c865bc.js", @view.asset_pack_path("bootstrap.js")
11
+ assert_equal "/packs/bootstrap-c38deda30895059837cf.css", @view.asset_pack_path("bootstrap.css")
12
+ end
13
+
14
+ def test_javascript_pack_tag
15
+ script = %(<script src="/packs/bootstrap-300631c4f0e0f9c865bc.js"></script>)
16
+ assert_equal script, @view.javascript_pack_tag("bootstrap.js")
17
+ end
18
+
19
+ def test_javascript_pack_tag_splat
20
+ script = %(<script src="/packs/bootstrap-300631c4f0e0f9c865bc.js" defer="defer"></script>\n) +
21
+ %(<script src="/packs/application-k344a6d59eef8632c9d1.js" defer="defer"></script>)
22
+ assert_equal script, @view.javascript_pack_tag("bootstrap.js", "application.js", defer: true)
23
+ end
24
+
25
+ def test_stylesheet_pack_tag
26
+ style = %(<link rel="stylesheet" media="screen" href="/packs/bootstrap-c38deda30895059837cf.css" />)
27
+ assert_equal style, @view.stylesheet_pack_tag("bootstrap.css")
28
+ end
29
+
30
+ def test_stylesheet_pack_tag_splat
31
+ style = %(<link rel="stylesheet" media="all" href="/packs/bootstrap-c38deda30895059837cf.css" />\n) +
32
+ %(<link rel="stylesheet" media="all" href="/packs/application-dd6b1cd38bfa093df600.css" />)
33
+ assert_equal style, @view.stylesheet_pack_tag("bootstrap.css", "application.css", media: "all")
34
+ end
35
+
36
+ def test_stylesheet_pack_tag_outputs_nothing_for_hot
37
+ Webpacker::DevServer.stub(:hot?, true) do
38
+ # Webpacker::Configuration.reset
39
+ # Webpacker::DevServer.reset
40
+ assert_equal "", @view.stylesheet_pack_tag("bootstrap.css")
41
+ end
42
+ # Webpacker::Configuration.reset
43
+ # Webpacker::DevServer.reset
44
+ end
45
+ end