webpacker-for-component 1.0.0 → 1.1.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +14 -0
  3. data/.gitignore +6 -0
  4. data/.rubocop.yml +124 -0
  5. data/.travis.yml +22 -0
  6. data/Gemfile +13 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +325 -0
  9. data/Rakefile +12 -0
  10. data/docs/assets.md +106 -0
  11. data/docs/css.md +82 -0
  12. data/docs/deployment.md +39 -0
  13. data/docs/env.md +65 -0
  14. data/docs/es6.md +53 -0
  15. data/docs/folder-structure.md +66 -0
  16. data/docs/misc.md +23 -0
  17. data/docs/props.md +105 -0
  18. data/docs/testing.md +45 -0
  19. data/docs/troubleshooting.md +65 -0
  20. data/docs/typescript.md +116 -0
  21. data/docs/webpack-dev-server.md +32 -0
  22. data/docs/webpack.md +156 -0
  23. data/docs/yarn.md +12 -0
  24. data/lib/install/angular.rb +15 -0
  25. data/lib/install/bin/webpack-dev-server.tt +68 -0
  26. data/lib/install/bin/webpack.tt +30 -0
  27. data/lib/install/config/.babelrc +18 -0
  28. data/lib/install/config/.postcssrc.yml +3 -0
  29. data/lib/install/config/webpack/development.js +3 -0
  30. data/lib/install/config/webpack/environment.js +3 -0
  31. data/lib/install/config/webpack/production.js +3 -0
  32. data/lib/install/config/webpack/test.js +3 -0
  33. data/lib/install/config/webpacker.yml +56 -0
  34. data/lib/install/elm.rb +24 -0
  35. data/lib/install/examples/angular/hello_angular.js +7 -0
  36. data/lib/install/examples/angular/hello_angular/app/app.component.ts +9 -0
  37. data/lib/install/examples/angular/hello_angular/app/app.module.ts +16 -0
  38. data/lib/install/examples/angular/hello_angular/index.ts +8 -0
  39. data/lib/install/examples/angular/hello_angular/polyfills.ts +73 -0
  40. data/lib/install/examples/angular/tsconfig.json +19 -0
  41. data/lib/install/examples/elm/Main.elm +54 -0
  42. data/lib/install/examples/elm/hello_elm.js +11 -0
  43. data/lib/install/examples/react/.babelrc +6 -0
  44. data/lib/install/examples/react/hello_react.jsx +26 -0
  45. data/lib/install/examples/vue/app.vue +22 -0
  46. data/lib/install/examples/vue/hello_vue.js +44 -0
  47. data/lib/install/javascript/packs/application.js +10 -0
  48. data/lib/install/react.rb +28 -0
  49. data/lib/install/template.rb +35 -0
  50. data/lib/install/vue.rb +12 -0
  51. data/lib/tasks/installers.rake +22 -0
  52. data/lib/tasks/webpacker-for-component/check_binstubs.rake +12 -0
  53. data/lib/tasks/webpacker-for-component/check_node.rake +25 -0
  54. data/lib/tasks/webpacker-for-component/check_yarn.rake +24 -0
  55. data/lib/tasks/webpacker-for-component/clobber.rake +16 -0
  56. data/lib/tasks/webpacker-for-component/compile.rake +34 -0
  57. data/lib/tasks/webpacker-for-component/install.rake +13 -0
  58. data/lib/tasks/webpacker-for-component/verify_install.rake +16 -0
  59. data/lib/tasks/webpacker-for-component/yarn_install.rake +6 -0
  60. data/lib/tasks/webpacker.rake +19 -0
  61. data/lib/webpacker-for-component.rb +28 -0
  62. data/lib/webpacker-for-component/commands.rb +23 -0
  63. data/lib/webpacker-for-component/compiler.rb +78 -0
  64. data/lib/webpacker-for-component/configuration.rb +88 -0
  65. data/lib/webpacker-for-component/dev_server.rb +51 -0
  66. data/lib/webpacker-for-component/dev_server_proxy.rb +25 -0
  67. data/lib/webpacker-for-component/helper.rb +65 -0
  68. data/lib/webpacker-for-component/instance.rb +44 -0
  69. data/lib/webpacker-for-component/manifest.rb +79 -0
  70. data/lib/webpacker-for-component/railtie.rb +41 -0
  71. data/lib/webpacker-for-component/version.rb +4 -0
  72. data/package.json +62 -0
  73. data/package/asset_host.js +21 -0
  74. data/package/config.js +8 -0
  75. data/package/environment.js +95 -0
  76. data/package/environments/development.js +46 -0
  77. data/package/environments/production.js +34 -0
  78. data/package/environments/test.js +3 -0
  79. data/package/index.js +16 -0
  80. data/package/loaders/babel.js +11 -0
  81. data/package/loaders/coffee.js +4 -0
  82. data/package/loaders/elm.js +19 -0
  83. data/package/loaders/erb.js +9 -0
  84. data/package/loaders/file.js +15 -0
  85. data/package/loaders/style.js +31 -0
  86. data/package/loaders/typescript.js +4 -0
  87. data/package/loaders/vue.js +12 -0
  88. data/test/command_test.rb +27 -0
  89. data/test/compiler_test.rb +20 -0
  90. data/test/configuration_test.rb +56 -0
  91. data/test/dev_server_test.rb +24 -0
  92. data/test/helper_test.rb +39 -0
  93. data/test/manifest_test.rb +20 -0
  94. data/test/test_app/config/secrets.yml +5 -0
  95. data/test/webpacker_test_helper.rb +40 -0
  96. data/webpacker-for-component.gemspec +23 -0
  97. data/yarn.lock +5162 -0
  98. metadata +111 -7
@@ -0,0 +1,23 @@
1
+ class Webpacker::Commands
2
+ delegate :config, :compiler, :manifest, to: :@webpacker
3
+
4
+ def initialize(webpacker)
5
+ @webpacker = webpacker
6
+ end
7
+
8
+ def clobber
9
+ config.public_output_path.rmtree if config.public_output_path.exist?
10
+ config.cache_path.rmtree if config.cache_path.exist?
11
+ end
12
+
13
+ def bootstrap
14
+ config.refresh
15
+ manifest.refresh
16
+ end
17
+
18
+ def compile
19
+ compiler.compile.tap do |success|
20
+ manifest.refresh if success
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,78 @@
1
+ require "open3"
2
+ require "digest/sha1"
3
+
4
+ class Webpacker::Compiler
5
+ # Additional paths that test compiler needs to watch
6
+ # Webpacker::Compiler.watched_paths << 'bower_components'
7
+ mattr_accessor(:watched_paths) { [] }
8
+
9
+ # Additional environment variables that the compiler is being run with
10
+ # Webpacker::Compiler.env['FRONTEND_API_KEY'] = 'your_secret_key'
11
+ mattr_accessor(:env) { {} }
12
+
13
+ delegate :config, :logger, to: :@webpacker
14
+
15
+ def initialize(webpacker)
16
+ @webpacker = webpacker
17
+ end
18
+
19
+ def compile
20
+ if stale?
21
+ record_compilation_digest
22
+ run_webpack
23
+ else
24
+ true
25
+ end
26
+ end
27
+
28
+ # Returns true if all the compiled packs are up to date with the underlying asset files.
29
+ def fresh?
30
+ watched_files_digest == last_compilation_digest
31
+ end
32
+
33
+ # Returns true if the compiled packs are out of date with the underlying asset files.
34
+ def stale?
35
+ !fresh?
36
+ end
37
+
38
+ private
39
+ def last_compilation_digest
40
+ compilation_digest_path.read if compilation_digest_path.exist? && config.public_manifest_path.exist?
41
+ end
42
+
43
+ def watched_files_digest
44
+ files = Dir[*default_watched_paths, *watched_paths].reject { |f| File.directory?(f) }
45
+ Digest::SHA1.hexdigest(files.map { |f| "#{File.basename(f)}/#{File.mtime(f).utc.to_i}" }.join("/"))
46
+ end
47
+
48
+ def record_compilation_digest
49
+ config.cache_path.mkpath
50
+ compilation_digest_path.write(watched_files_digest)
51
+ end
52
+
53
+ def run_webpack
54
+ logger.info "Compiling…"
55
+
56
+ sterr, stdout, status = Open3.capture3(webpack_env, "#{RbConfig.ruby} ./bin/webpack")
57
+
58
+ if status.success?
59
+ logger.info "Compiled all packs in #{config.public_output_path}"
60
+ else
61
+ logger.error "Compilation failed:\n#{sterr}\n#{stdout}"
62
+ end
63
+
64
+ status.success?
65
+ end
66
+
67
+ def default_watched_paths
68
+ ["#{config.source_path}/**/*", "yarn.lock", "package.json", "config/webpack/**/*"].freeze
69
+ end
70
+
71
+ def compilation_digest_path
72
+ config.cache_path.join(".last-compilation-digest")
73
+ end
74
+
75
+ def webpack_env
76
+ env.merge("NODE_ENV" => @webpacker.env, "ASSET_HOST" => ActionController::Base.helpers.compute_asset_host)
77
+ end
78
+ end
@@ -0,0 +1,88 @@
1
+ class Webpacker::Configuration
2
+ delegate :root_path, :env, to: :@webpacker
3
+
4
+ def initialize(webpacker)
5
+ @webpacker = webpacker
6
+ end
7
+
8
+ def refresh
9
+ @data = load_for_refresh
10
+ end
11
+
12
+ def dev_server
13
+ fetch(:dev_server)
14
+ end
15
+
16
+ def compile?
17
+ fetch(:compile)
18
+ end
19
+
20
+ def source_path
21
+ root_path.join(fetch(:source_path))
22
+ end
23
+
24
+ def source_entry_path
25
+ source_path.join(fetch(:source_entry_path))
26
+ end
27
+
28
+ def public_path
29
+ root_path.join("public")
30
+ end
31
+
32
+ def public_output_path
33
+ public_path.join(fetch(:public_output_path))
34
+ end
35
+
36
+ def public_manifest_path
37
+ public_output_path.join("manifest.json")
38
+ end
39
+
40
+ def cache_manifest?
41
+ fetch(:cache_manifest)
42
+ end
43
+
44
+ def cache_path
45
+ root_path.join(fetch(:cache_path))
46
+ end
47
+
48
+ private
49
+ def fetch(key)
50
+ data.fetch(key, defaults[key])
51
+ end
52
+
53
+ def data
54
+ @data ||= load
55
+ end
56
+
57
+ def load
58
+ YAML.load(root_path.join("config/webpacker.yml").read)[env].deep_symbolize_keys
59
+
60
+ rescue Errno::ENOENT => e
61
+ raise "Webpacker configuration file not found #{root_path.join("config/webpacker.yml")}. " \
62
+ "Please run rails webpacker:install " \
63
+ "Error: #{e.message}"
64
+
65
+ rescue Psych::SyntaxError => e
66
+ raise "YAML syntax error occurred while parsing #{root_path.join("config/webpacker.yml")}. " \
67
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
68
+ "Error: #{e.message}"
69
+ end
70
+
71
+ def load_for_refresh
72
+ YAML.load(root_path.join("components/angular/config/webpacker.yml").read)[env].deep_symbolize_keys
73
+ rescue Errno::ENOENT => e
74
+ raise "Webpacker configuration file not found #{root_path.join("components/angular/config/webpacker.yml")}. " \
75
+ "Please run rails webpacker:install " \
76
+ "Error: #{e.message}"
77
+
78
+ rescue Psych::SyntaxError => e
79
+ raise "YAML syntax error occurred while parsing #{config_path.join("components/angular/config/webpacker.yml")}. " \
80
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
81
+ "Error: #{e.message}"
82
+ end
83
+
84
+ def defaults
85
+ @defaults ||= \
86
+ HashWithIndifferentAccess.new(YAML.load_file(File.expand_path("../../install/config/webpacker.yml", __FILE__))[env])
87
+ end
88
+ end
@@ -0,0 +1,51 @@
1
+ class Webpacker::DevServer
2
+ # Configure dev server connection timeout (in seconds), default: 0.01
3
+ # Webpacker.dev_server.connect_timeout = 1
4
+ mattr_accessor(:connect_timeout) { 0.01 }
5
+
6
+ delegate :config, to: :@webpacker
7
+
8
+ def initialize(webpacker)
9
+ @webpacker = webpacker
10
+ end
11
+
12
+ def running?
13
+ Socket.tcp(host, port, connect_timeout: connect_timeout).close
14
+ true
15
+ rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, NoMethodError
16
+ false
17
+ end
18
+
19
+ def hot_module_replacing?
20
+ fetch(:hmr)
21
+ end
22
+
23
+ def host
24
+ fetch(:host)
25
+ end
26
+
27
+ def port
28
+ fetch(:port)
29
+ end
30
+
31
+ def https?
32
+ fetch(:https)
33
+ end
34
+
35
+ def protocol
36
+ https? ? "https" : "http"
37
+ end
38
+
39
+ def host_with_port
40
+ "#{host}:#{port}"
41
+ end
42
+
43
+ private
44
+ def fetch(key)
45
+ config.dev_server.fetch(key, defaults[key])
46
+ end
47
+
48
+ def defaults
49
+ config.send(:defaults)[:dev_server]
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ require "rack/proxy"
2
+
3
+ class Webpacker::DevServerProxy < Rack::Proxy
4
+ def rewrite_response(response)
5
+ status, headers, body = response
6
+ headers.delete "transfer-encoding"
7
+ headers.delete "content-length" if Webpacker.dev_server.running? && Webpacker.dev_server.https?
8
+ response
9
+ end
10
+
11
+ def perform_request(env)
12
+ if env["PATH_INFO"] =~ /#{public_output_uri_path}/ && Webpacker.dev_server.running?
13
+ env["HTTP_HOST"] = env["HTTP_X_FORWARDED_HOST"] = env["HTTP_X_FORWARDED_SERVER"] = Webpacker.dev_server.host_with_port
14
+
15
+ super(env)
16
+ else
17
+ @app.call(env)
18
+ end
19
+ end
20
+
21
+ private
22
+ def public_output_uri_path
23
+ Webpacker.config.public_output_path.relative_path_from(Webpacker.config.public_path)
24
+ end
25
+ end
@@ -0,0 +1,65 @@
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
+ asset_path(Webpacker.manifest.lookup(name), **options)
13
+ end
14
+ # Creates a script tag that references the named pack file, as compiled by Webpack per the entries list
15
+ # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
16
+ # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
17
+ #
18
+ # Examples:
19
+ #
20
+ # # In development mode:
21
+ # <%= javascript_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
22
+ # <script src="/packs/calendar.js" data-turbolinks-track="reload"></script>
23
+ #
24
+ # # In production mode:
25
+ # <%= javascript_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
26
+ # <script src="/packs/calendar-1016838bab065ae1e314.js" data-turbolinks-track="reload"></script>
27
+ def javascript_pack_tag(*names, **options)
28
+ javascript_include_tag(*sources_from_pack_manifest(names, type: :javascript), **options)
29
+ end
30
+
31
+ # Creates a link tag that references the named pack file, as compiled by Webpack per the entries list
32
+ # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
33
+ # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
34
+ #
35
+ # Note: If the development server is running and hot module replacement is active, this will return nothing.
36
+ # In that setup you need to configure your styles to be inlined in your JavaScript for hot reloading.
37
+ #
38
+ # Examples:
39
+ #
40
+ # # In development mode:
41
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
42
+ # <link rel="stylesheet" media="screen" href="/packs/calendar.css" data-turbolinks-track="reload" />
43
+ #
44
+ # # In development mode with hot module replacement:
45
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
46
+ # nil
47
+ #
48
+ # # In production mode:
49
+ # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # =>
50
+ # <link rel="stylesheet" media="screen" href="/packs/calendar-1016838bab065ae1e122.css" data-turbolinks-track="reload" />
51
+ def stylesheet_pack_tag(*names, **options)
52
+ unless Webpacker.dev_server.running? && Webpacker.dev_server.hot_module_replacing?
53
+ stylesheet_link_tag(*sources_from_pack_manifest(names, type: :stylesheet), **options)
54
+ end
55
+ end
56
+
57
+ private
58
+ def sources_from_pack_manifest(names, type:)
59
+ names.map { |name| Webpacker.manifest.lookup(pack_name_with_extension(name, type: type)) }
60
+ end
61
+
62
+ def pack_name_with_extension(name, type:)
63
+ "#{name}#{compute_asset_extname(name, type: type)}"
64
+ end
65
+ end
@@ -0,0 +1,44 @@
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: Rails.root)
7
+ @root_path = root_path
8
+ end
9
+
10
+ def env
11
+ (ENV["NODE_ENV"].presence_in(available_environments) ||
12
+ Rails.env.presence_in(available_environments) ||
13
+ "production".freeze).inquiry
14
+ end
15
+
16
+ def config
17
+ @config ||= Webpacker::Configuration.new self
18
+ end
19
+
20
+ def compiler
21
+ @compiler ||= Webpacker::Compiler.new self
22
+ end
23
+
24
+ def dev_server
25
+ @dev_server ||= Webpacker::DevServer.new self
26
+ end
27
+
28
+ def manifest
29
+ @manifest ||= Webpacker::Manifest.new self
30
+ end
31
+
32
+ def commands
33
+ @commands ||= Webpacker::Commands.new self
34
+ end
35
+
36
+ private
37
+ def available_environments
38
+ if root_path.join("components/angular/config/webpacker.yml").exist?
39
+ YAML.load(root_path.join("components/angular/config/webpacker.yml").read).keys
40
+ else
41
+ [].freeze
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,79 @@
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.js" or
4
+ # "/packs/calendar.css" in development.
5
+ #
6
+ # In production mode, it returns compiles files, like
7
+ # "/packs/calendar-1016838bab065ae1e314.js" and "/packs/calendar-1016838bab065ae1e314.css",
8
+ # for long-term caching.
9
+ #
10
+ # When the configuration is set to on-demand compilation, with the `compile: true` option in
11
+ # the webpacker.yml file, any lookups will be preceeded by a compilation if one is needed.
12
+ class Webpacker::Manifest
13
+ class MissingEntryError < StandardError; end
14
+
15
+ delegate :config, :compiler, :dev_server, to: :@webpacker
16
+
17
+ def initialize(webpacker)
18
+ @webpacker = webpacker
19
+ end
20
+
21
+ def refresh
22
+ @data = load
23
+ end
24
+
25
+ def lookup(name)
26
+ compile if compiling?
27
+ find name
28
+ end
29
+
30
+ private
31
+ def compiling?
32
+ config.compile? && !dev_server.running?
33
+ end
34
+
35
+ def compile
36
+ Webpacker.logger.tagged("Webpacker") { compiler.compile }
37
+ end
38
+
39
+ def find(name)
40
+ data[name.to_s] || handle_missing_entry(name)
41
+ end
42
+
43
+ def handle_missing_entry(name)
44
+ raise Webpacker::Manifest::MissingEntryError, missing_file_from_manifest_error(name)
45
+ end
46
+
47
+ def missing_file_from_manifest_error(bundle_name)
48
+ msg = <<-MSG
49
+ Webpacker can't find #{bundle_name} in #{config.public_manifest_path}. Possible causes:
50
+ 1. You want to set webpacker.yml value of compile to true for your environment
51
+ unless you are using the `webpack -w` or the webpack-dev-server.
52
+ 2. Webpack has not yet re-run to reflect updates.
53
+ 3. You have misconfigured Webpacker's config/webpacker.yml file.
54
+ 4. Your Webpack configuration is not creating a manifest.
55
+ Your manifest contains:
56
+ #{JSON.pretty_generate(@data)}
57
+ MSG
58
+ 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
+ react_json=JSON.parse Rails.root.join("public/packs/react/manifest.json").read
71
+ vue_json=JSON.parse Rails.root.join("public/packs/vue/manifest.json").read
72
+ angular_json=JSON.parse config.public_manifest_path.read
73
+ angular_react=react_json.merge(angular_json)
74
+ angular_react.merge(vue_json)
75
+ else
76
+ {}
77
+ end
78
+ end
79
+ end