webpacker_helpers 3.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2016 David Heinemeier Hansson, Basecamp, and
2
+ 2017 Justin Gordon, ShakaCode
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # Webpacker Helpers
2
+ ![Gem Version](https://badge.fury.io/rb/webpacker_helpers.svg)
3
+
4
+ **VERSION 8 of [React on Rails](https://github.com/shakacode/react_on_rails) is super close!!!** [VERSION 8.0.0-beta.3](https://rubygems.org/gems/react_on_rails/versions/8.0.0.beta.3) has shipped with [webpacker_helpers](https://github.com/shakacode/webpacker_helpers) support! Please try [the 8.0.0-beta.3 beta](https://rubygems.org/gems/react_on_rails/versions/8.0.0.beta.3) and please report issues! We're **SUPER** close as we've also upgraded the [shakacode/react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial) with [PR #395](https://github.com/shakacode/react-webpack-rails-tutorial/pull/395). That PR shows the changes needed to go to Webpacker Helpers.
5
+
6
+
7
+ *A slimmer version of Webpacker*
8
+
9
+ Webpacker Helpers provides similar webpack enabled view helpers from [Webpacker](https://github.com/rails/webpacker).
10
+ [React on Rails](https://github.com/shakacode/react_on_rails) version 8 and greater defaults to using Webpacker Helpers.
11
+
12
+ For example, these view helpers allow your application's layout to easily reference JavaScript and CSS files created by your Webpack setup, taking into account differences in the Rails environments. With these helpers, there is no reason for Webpack created assets to run through the [Asset Pipeline](http://guides.rubyonrails.org/asset_pipeline.html), as was done in React on Rails 7.x and earlier.
13
+
14
+ If you like this project, show your support by giving us a star!
15
+
16
+ # Why Fork?
17
+
18
+ > Everything should be made as simple as possible, but not simpler.
19
+
20
+ [Albert Einstein on Wikiquote](https://en.wikiquote.org/wiki/Albert_Einstein)
21
+
22
+ Why did [ShakaCode](http://www.shakacode.com) fork [rails/webpacker](https://github.com/rails/webpacker)? For [react_on_rails](https://github.com/shakacode/react_on_rails), we wanted a simpler configuration to get the core functionality needed. You configure 2 things:
23
+
24
+ 1. Name of the manifest file.
25
+ 2. The directory within `/public` where Webpack will create the manifest and output file.
26
+
27
+ Then you need to configure your Webpack to generate a simple manifest that maps the base output names to the possibly fingerprinted versions. Note, unlike Webpacker, Webpacker Helpers wants your manifest to **NOT** contain any host information.
28
+
29
+ Optionally, you can configure the name of the server and port for hot reloading, and if hot reloading is the default for a given Rails.env.
30
+
31
+ For more details on how this project differs from Webpacker and why we forked, please see [Webpacker Helpers: Why Did We Fork Webpacker?](https://medium.com/@railsonmaui/webpacker-lite-why-did-we-fork-webpacker-ee3305688d66)
32
+
33
+ # NEWS
34
+
35
+ * 2017-05-03: React on Rails 8.0.0 beta defaults to using webpacker_helpers.
36
+
37
+ ## Installation
38
+
39
+ The best way to see the installation of webpacker_helpers is to use the generator for React on Rails 8.0.0 or greater. Otherwise, add the gem and create the configuration file described below.
40
+
41
+ ## Overview
42
+
43
+ 1. Configure the `config/webpacker_helpers.yml` file, as described below. You will specify the name of the manifest file and the output directory used by step 2.
44
+ 2. Use the [webpack-manifest-plugin](https://www.npmjs.com/package/webpack-manifest-plugin) to generate a manifest
45
+ in the output directory (`webpack_public_output_dir`) that you configured in your `/config/webpacker_helpers.yml` file.
46
+ 3. Use the view helpers on your layouts to provide the webpack generated files. Note, these are the same names used by [rails/webpacker](https://github.com/rails/webpacker).
47
+ These `output` names are **NOT** the actual file names, as the file name may have a [fingerprint](http://guides.rubyonrails.org/asset_pipeline.html#what-is-fingerprinting-and-why-should-i-care-questionmark).
48
+ ```erb
49
+ <%# app/views/layouts/application.html.erb %>
50
+ <%= javascript_pack_tag('main') %>
51
+ <%= stylesheet_pack_tag('main') %>
52
+ ```
53
+ 4. When hot-reloading, the extract-text-plugin (extracted CSS from being inlined in the JavaScript)is not supported. Therefore, all your hot-reloaded Webpack-compiled CSS will be inlined and we will skip the CSS file by default. If you're not worried about hot-reloading for your CSS, use the `enabled_when_hot_loading: true` option.
54
+
55
+ ```erb
56
+ <%= stylesheet_pack_tag('main', enabled_when_hot_loading: true) %> <% # Default is false %>
57
+ ```
58
+
59
+ For more details on the helper documentation, see the Ruby comments in [lib/webpacker_helpers/helper.rb](lib/webpacker_helpers/helper.rb) and please submit PRs here to help us improve the docs!
60
+
61
+ ## Configuration
62
+ Webpacker Helpers takes one configuration file: `config/webpacker_helpers.yml` used to configure two required values and a couple optional values. Note, this file is configured like `config/database.yml` in that you place the values beneath the name of the Rails.env.
63
+
64
+ ### Mandatory Configuration within `config/webpacker_helpers.yml`
65
+
66
+ 1. `manifest`: The manifest file name
67
+ 1. `webpack_public_output_dir`: The output directory of both the manifest and the webpack static generated files within the `/public` directory.
68
+
69
+ Note, placing output files within the Rails `/public` directory is not configurable.
70
+
71
+ ### Optional Configuration within `config/webpacker_helpers.yml`
72
+ 1. `hot_reloading_host`: The name of the hot reloading `webpack-dev-server` including the port
73
+ 2. `hot_reloading_enabled_by_default`: If hot reloading should default to true
74
+
75
+ ### Hot Reloading Notes
76
+
77
+ Do not put the output server in your `manifest.json` file. The rails view helpers will automatically prepend the hot_reloading_host to the asset path.
78
+
79
+ ### Example Configuration `/config/webpacker_helpers.yml`
80
+
81
+ This example config shows how we use different output directories for the webpack generated assets per the type of environment. This is extremely convenient when you want to log redux messages in development but not in your tests.
82
+
83
+ ```yaml
84
+ # /config/webpacker_helpers.yml
85
+ # Note: Base output directory of /public is assumed for static files
86
+ default: &default
87
+ manifest: manifest.json
88
+ # Used in your webpack configuration. Must be created in the
89
+ # webpack_public_output_dir folder.
90
+
91
+ development:
92
+ <<: *default
93
+ # generated files for development, in /public/webpack/development
94
+ webpack_public_output_dir: webpack/development
95
+
96
+ # Default is localhost:3500. You can specify the protocol if needed. Defaults to http://.
97
+ hot_reloading_host: localhost:3500
98
+
99
+ # Developer note: considering removing this option so it can ONLY be turned by using an ENV value.
100
+ # Default is false, ENV 'HOT_RELOADING' will always override
101
+ hot_reloading_enabled_by_default: false
102
+
103
+ test:
104
+ <<: *default
105
+ # generated files for tests, in /public/webpack/test
106
+ webpack_public_output_dir: webpack/test
107
+
108
+ production:
109
+ <<: *default
110
+ # generated files for tests, in /public/webpack/production
111
+ webpack_public_output_dir: webpack/production
112
+ ```
113
+
114
+ ## Example for Development vs Hot Reloading vs Production Mode
115
+
116
+ **erb file**
117
+
118
+ ```erb
119
+ <% # app/views/layouts/application.html.erb %>
120
+ <%= javascript_pack_tag('main') %>
121
+ <%= stylesheet_pack_tag('main') %>
122
+ ```
123
+
124
+ **html file**
125
+
126
+ ```html
127
+ <!-- In test mode -->
128
+ <script src="/webpack/test/main.js"></script>
129
+ <link rel="stylesheet" media="screen" href="/webpack/test/main-0bd141f6d9360cf4a7f5.js">
130
+
131
+ <!-- In development mode -->
132
+ <script src="/webpack/development/main.js"></script>
133
+ <link rel="stylesheet" media="screen" href="/webpack/development/main-0bd141f6d9360cf4a7f5.js">
134
+
135
+ <!-- In development mode with hot reloading, using the webpack-dev-server -->
136
+ <script src="http://localhost:8080/webpack/development/main.js"></script>
137
+ <!-- Note, there's no stylesheet tag by default, as your CSS should be inlined in your JS. -->
138
+
139
+ <!-- In production mode -->
140
+ <script src="/webpack/production/main-0bd141f6d9360cf4a7f5.js"></script>
141
+ <link rel="stylesheet" media="screen" href="/webpack/production/main-dc02976b5f94b507e3b6.css">
142
+ ```
143
+
144
+ ## Other Helpers: Getting the asset path
145
+
146
+ The `asset_pack_path` helper provides the path of any given asset that's been compiled by webpack.
147
+ Note, the real file path is the subdirectory of the public.
148
+
149
+ For example, if you want to create a `<link rel="prefetch">` or `<img />`
150
+ for an asset used in your pack code you can reference them like this in your view,
151
+
152
+ ```erb
153
+ <img src="<%= asset_pack_path 'calendar.png' %>" />
154
+ <% # => <img src="/webpack/calendar.png" /> %>
155
+ <% # real file path "public/webpack/calendar.png" /> %>
156
+ ```
157
+
158
+ ## Webpack Helper
159
+ You may use the [React on Rails NPM Package](https://www.npmjs.com/package/react-on-rails), [react-on-rails/webpackConfigLoader](https://github.com/shakacode/react_on_rails/blob/master/webpackConfigLoader.js) to provide your Webpack config with easy access to the YAML settings. Even if you don't use the NPM package, you can use that file to inspire your Webpack configuration.
160
+
161
+ ## Rake Tasks
162
+
163
+ ### Examples
164
+
165
+ To see available webpacker_helpers rake tasks:
166
+
167
+ ```
168
+ rake webpacker_helpers
169
+ ```
170
+
171
+ If you are using different directories for the output paths per RAILS_ENV, this is how you'd delete the files created for tests:
172
+ ```
173
+ RAILS_ENV=test rake webpacker_helpers:clobber
174
+ ```
175
+
176
+ ## Differences from Webpacker
177
+
178
+ 1. Configuration setup of an optional single file `/config/webpacker_helpers.yml`
179
+ 2. Webpacker helpers expect the manifest to contain the server URL when hot reloading. Webpacker Helpers expects the manifest to never contain any host information.
180
+
181
+ ## Hot Reloading
182
+
183
+ 1. Tell Rails and Webpacker Helpers that you're hot reloading by setting the ENV value of `HOT_RELOADING=YES` if you are not hot reloading by default by setting the `hot_reloading_enabled_by_default` key in your config file.
184
+ 1. By default, the `stylesheet_pack_tag` helper will not create a tag when hot reloading is enabled. Per the note above, when hot-reloading, the extract-text-plugin (extracted CSS from being inlined in the JavaScript)is not supported. Therefore, all your hot-reloaded Webpack-compiled CSS will be inlined and we will skip the CSS file by default.
185
+
186
+ ```erb
187
+ <%= stylesheet_pack_tag('main', enabled_when_hot_loading: true) %> <% # Default is false %>
188
+ ```
189
+
190
+
191
+
192
+ ## Prerequisites
193
+ * Ruby 2+
194
+ * Rails 4.2+
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ # Executes a string or an array of strings in a shell in the given directory
6
+ def sh_in_dir(dir, shell_commands)
7
+ shell_commands = [shell_commands] if shell_commands.is_a?(String)
8
+ shell_commands.each { |shell_command| sh %(cd #{dir} && #{shell_command.strip}) }
9
+ end
10
+
11
+ def gem_root
12
+ File.expand_path("../.", __FILE__)
13
+ end
14
+
15
+ Rake::TestTask.new(:test) do |t|
16
+ t.libs << "test"
17
+ t.libs << "lib"
18
+ t.test_files = FileList["test/**/*_test.rb"]
19
+ t.verbose = true
20
+ end
21
+
22
+ desc "Run Rubocop as shell"
23
+ task :rubocop do
24
+ sh_in_dir(gem_root, "bundle exec rubocop .")
25
+ end
26
+
27
+ task default: [:test, :rubocop]
@@ -0,0 +1,12 @@
1
+ tasks = {
2
+ "webpacker_helpers:clobber" => "Remove the webpack compiled output directory as defined in config/webpack/paths.yml",
3
+ "webpacker_helpers:check_node" => "Verifies if Node.js is installed",
4
+ "webpacker_helpers:check_yarn" => "Verifies if yarn is installed",
5
+ "webpacker_helpers:verify_install" => "Verifies if webpacker is installed"
6
+ }.freeze
7
+
8
+ desc "Lists all available tasks in webpacker_helpers"
9
+ task :webpacker_helpers do
10
+ puts "Available webpacker_helpers tasks are:"
11
+ tasks.each { |task, message| puts task.ljust(30) + message }
12
+ end
@@ -0,0 +1,19 @@
1
+ namespace :webpacker_helpers do
2
+ desc "Verifies if Node.js is installed"
3
+ task :check_node do
4
+ begin
5
+ node_version = `node -v`
6
+ required_node_version = "6.4"
7
+
8
+ raise Errno::ENOENT if node_version.blank?
9
+ if Gem::Version.new(node_version.strip.tr("v", "")) < Gem::Version.new(required_node_version)
10
+ puts "WebpackerHelpers requires Node.js >= v#{required_node_version} and you are using #{node_version}"
11
+ puts "Please upgrade Node.js https://nodejs.org/en/download/"
12
+ puts "Exiting!" && exit!
13
+ end
14
+ rescue Errno::ENOENT
15
+ puts "Node.js not installed. Please download and install Node.js https://nodejs.org/en/download/"
16
+ puts "Exiting!" && exit!
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ namespace :webpacker_helpers do
2
+ desc "Verifies if yarn is installed"
3
+ task :check_yarn do
4
+ begin
5
+ version = `yarn --version`
6
+ raise Errno::ENOENT if version.blank?
7
+ rescue Errno::ENOENT
8
+ puts "WebpackerHelpers requires yarn. Please download and install Yarn https://yarnpkg.com/lang/en/docs/install/"
9
+ puts "Exiting!" && exit!
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ require "webpacker_helpers/configuration"
2
+
3
+ namespace :webpacker_helpers do
4
+ desc "Remove the webpack compiled output directory as defined in config/webpack/paths.yml"
5
+ task clobber: ["webpacker_helpers:verify_install", :environment] do
6
+ output_path = WebpackerHelpers::Configuration.webpack_public_output_dir
7
+ FileUtils.rm_r(output_path) if File.exist?(output_path)
8
+ puts "Removed webpack output path directory #{output_path}"
9
+ end
10
+ end
11
+
12
+ # Run clobber if the assets:clobber is run
13
+ if Rake::Task.task_defined?("assets:clobber")
14
+ Rake::Task["assets:clobber"].enhance do
15
+ Rake::Task["webpacker_helpers:clobber"].invoke
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require "webpacker_helpers/configuration"
2
+
3
+ namespace :webpacker_helpers do
4
+ desc "Verifies if webpacker_helpers is installed"
5
+ task verify_install: [:check_node, :check_yarn] do
6
+ if File.exist?(WebpackerHelpers::Env.file_path)
7
+ puts "WebpackerHelpers is installed 🎉 🍰"
8
+ puts "Using #{WebpackerHelpers::Env.file_path} file for setting up webpack paths"
9
+ else
10
+ puts "Configuration config/webpack/paths.yml file not found. \n"\
11
+ "Make sure webpacker_helpers:install is run successfully before " \
12
+ "running dependent tasks"
13
+ exit!
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module WebpackerHelpers
2
+ def self.bootstrap
3
+ WebpackerHelpers::Env.load_instance
4
+ WebpackerHelpers::Configuration.load_instance
5
+ WebpackerHelpers::Manifest.load_instance
6
+ end
7
+
8
+ def env
9
+ WebpackerHelpers::Env.current.inquiry
10
+ end
11
+ end
12
+
13
+ require "webpacker_helpers/railtie" if defined?(Rails)
@@ -0,0 +1,56 @@
1
+ # Loads webpacker configuration from config/webpack/paths.yml
2
+ require "webpacker_helpers/file_loader"
3
+ require "webpacker_helpers/env"
4
+
5
+ class WebpackerHelpers::Configuration < WebpackerHelpers::FileLoader
6
+ RAILS_WEB_PUBLIC = "public"
7
+
8
+ class << self
9
+ def manifest_path
10
+ Rails.root.join(webpack_public_output_dir,
11
+ configuration.fetch(:manifest, "manifest.json"))
12
+ end
13
+
14
+ def webpack_public_output_dir
15
+ Rails.root.join(RAILS_WEB_PUBLIC, configuration.fetch(:webpack_public_output_dir, "webpack"))
16
+ end
17
+
18
+ def base_path
19
+ "/#{configuration.fetch(:webpack_public_output_dir, "webpack")}"
20
+ end
21
+
22
+ # Uses the hot_reloading_host if appropriate
23
+ def base_url
24
+ if WebpackerHelpers::Env.hot_loading?
25
+ host = configuration[:hot_reloading_host]
26
+ if host.blank?
27
+ raise "WebpackerHelpers's /config/webpacker_helpers.yml needs a configuration value for the "\
28
+ "`hot_reloading_host` for environment #{Rails.env}."
29
+ end
30
+ if host.starts_with?("http")
31
+ host
32
+ else
33
+ "http://#{host}"
34
+ end
35
+ else
36
+ base_path
37
+ end
38
+ end
39
+
40
+ def configuration
41
+ load_instance
42
+ raise WebpackerHelpers::FileLoader::FileLoaderError.new("WebpackerHelpers::Configuration.load_instance must be called first") unless instance
43
+ instance.data
44
+ end
45
+
46
+ def file_path
47
+ Rails.root.join("config", "webpacker_helpers.yml")
48
+ end
49
+ end
50
+
51
+ private
52
+ def load_data
53
+ return super unless File.exist?(@path)
54
+ HashWithIndifferentAccess.new(YAML.load(File.read(@path))[WebpackerHelpers::Env.current])
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ # Singleton registry for determining NODE_ENV from config/webpacker_helpers.yml
2
+ require "webpacker_helpers/file_loader"
3
+
4
+ class WebpackerHelpers::Env < WebpackerHelpers::FileLoader
5
+ class << self
6
+ def current
7
+ raise WebpackerHelpers::FileLoader::FileLoaderError.new("WebpackerHelpers::Env.load must be called first") unless instance
8
+ instance.data
9
+ end
10
+
11
+ def hot_loading?
12
+ (ENV["HOT_RELOADING"].present? && (
13
+ ENV["HOT_RELOADING"].upcase == "YES" ||
14
+ ENV["HOT_RELOADING"].upcase == "TRUE")) ||
15
+ current["hot_reloading_enabled_by_default"]
16
+ end
17
+
18
+ def file_path
19
+ Rails.root.join("config", "webpacker_helpers.yml")
20
+ end
21
+ end
22
+
23
+ private
24
+ def load_data
25
+ environments = File.exist?(@path) ? YAML.load(File.read(@path)).keys : [].freeze
26
+ return ENV["NODE_ENV"] if environments.include?(ENV["NODE_ENV"])
27
+ return Rails.env if environments.include?(Rails.env)
28
+ "production"
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ # Provides a base singleton-configuration pattern for loading a JSON or YAML file, given a path
2
+ class WebpackerHelpers::FileLoader
3
+ class NotFoundError < StandardError; end
4
+ class FileLoaderError < StandardError; end
5
+
6
+ class_attribute :instance
7
+ attr_accessor :data, :mtime
8
+
9
+ class << self
10
+ def load_instance(path = file_path)
11
+ # Assume production is 100% cached
12
+ return if 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
+ self.instance = new(path)
17
+ end
18
+
19
+ def file_path
20
+ raise FileLoaderError.new("Subclass of WebpackerHelpers::FileLoader should override this method")
21
+ end
22
+
23
+ private
24
+
25
+ # Prefer the NODE_ENV to the rails env.
26
+ def env
27
+ ENV["NODE_ENV"].presence || Rails.env
28
+ end
29
+ end
30
+
31
+ private
32
+ def initialize(path)
33
+ @path = path
34
+ @mtime = File.exist?(path) ? File.mtime(path) : nil
35
+ @data = load_data
36
+ end
37
+
38
+ def load_data
39
+ {}.freeze
40
+ end
41
+ end