react_on_rails 11.3.0 → 12.0.0.pre.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +320 -0
- data/.eslintignore +2 -1
- data/.eslintrc +23 -1
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +3 -1
- data/.prettierignore +10 -1
- data/.prettierrc +3 -0
- data/.rubocop.yml +37 -11
- data/.travis.yml +9 -22
- data/CHANGELOG.md +65 -6
- data/CONTRIBUTING.md +60 -71
- data/Gemfile +3 -4
- data/{COMM-LICENSE → REACT-ON-RAILS-PRO-LICENSE} +6 -9
- data/README.md +129 -92
- data/Rakefile +0 -7
- data/SUMMARY.md +7 -11
- data/book.json +5 -5
- data/docs/additional-reading/asset-pipeline.md +8 -16
- data/docs/additional-reading/react-helmet.md +30 -10
- data/docs/additional-reading/react-router.md +52 -75
- data/docs/additional-reading/server-rendering-tips.md +12 -7
- data/docs/api/javascript-api.md +3 -3
- data/docs/api/redux-store-api.md +4 -2
- data/docs/api/view-helpers-api.md +6 -7
- data/docs/basics/configuration.md +83 -69
- data/docs/basics/deployment.md +2 -4
- data/docs/basics/heroku-deployment.md +24 -0
- data/docs/basics/hmr-and-hot-reloading-with-the-webpack-dev-server.md +49 -0
- data/docs/basics/i18n.md +45 -23
- data/docs/basics/installation-into-an-existing-rails-app.md +4 -9
- data/docs/basics/react-server-rendering.md +1 -1
- data/docs/basics/recommended-project-structure.md +5 -22
- data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
- data/docs/basics/rspec-configuration.md +27 -16
- data/docs/basics/upgrading-react-on-rails.md +58 -2
- data/docs/basics/webpack-configuration.md +18 -8
- data/docs/contributor-info/errors-with-hooks.md +45 -0
- data/docs/contributor-info/pull-requests.md +44 -0
- data/docs/misc/doctrine.md +1 -1
- data/docs/{misc-pending → outdated}/code-splitting.md +12 -8
- data/docs/{basics → outdated}/how-react-on-rails-works.md +8 -4
- data/docs/{misc-pending → outdated}/manual-installation-overview.md +5 -5
- data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
- data/docs/{misc-pending → outdated}/rails-assets.md +2 -12
- data/docs/{misc → outdated}/rails3.md +0 -0
- data/docs/tutorial.md +94 -68
- data/jest.config.js +4 -0
- data/lib/generators/react_on_rails/base_generator.rb +2 -2
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
- data/lib/generators/react_on_rails/generator_helper.rb +4 -6
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -1
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-hmr +26 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +20 -40
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +4 -1
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
- data/lib/react_on_rails.rb +3 -1
- data/lib/react_on_rails/configuration.rb +58 -28
- data/lib/react_on_rails/error.rb +2 -0
- data/lib/react_on_rails/helper.rb +41 -91
- data/lib/react_on_rails/json_parse_error.rb +2 -0
- data/lib/react_on_rails/locales/base.rb +150 -0
- data/lib/react_on_rails/locales/to_js.rb +37 -0
- data/lib/react_on_rails/locales/to_json.rb +27 -0
- data/lib/react_on_rails/prerender_error.rb +11 -15
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +41 -46
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +17 -0
- data/lib/react_on_rails/utils.rb +14 -19
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +1 -0
- data/lib/react_on_rails/webpacker_utils.rb +19 -2
- data/lib/tasks/assets.rake +33 -46
- data/lib/tasks/locale.rake +4 -2
- data/package-scripts.yml +11 -8
- data/package.json +29 -28
- data/rakelib/dummy_apps.rake +1 -9
- data/rakelib/example_type.rb +3 -1
- data/rakelib/examples.rake +3 -0
- data/rakelib/lint.rake +2 -7
- data/rakelib/node_package.rake +2 -2
- data/rakelib/release.rake +0 -6
- data/rakelib/run_rspec.rake +5 -18
- data/react_on_rails.gemspec +4 -5
- data/tsconfig.json +14 -0
- data/webpackConfigLoader.js +3 -2
- data/yarn.lock +4333 -2209
- metadata +46 -57
- data/Gemfile.rails32 +0 -73
- data/docs/additional-reading/babel.md +0 -5
- data/docs/additional-reading/heroku-deployment.md +0 -92
- data/docs/additional-reading/hot-reloading-rails-development-asset-pipeline.md +0 -47
- data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-server +0 -12
- data/lib/react_on_rails/assets_precompile.rb +0 -153
- data/lib/react_on_rails/locales_to_js.rb +0 -138
@@ -1,44 +0,0 @@
|
|
1
|
-
## NOTE: These helpers are NOT needed if using webpacker
|
2
|
-
|
3
|
-
## Hot Reloading View Helpers
|
4
|
-
The `env_javascript_include_tag` and `env_stylesheet_link_tag` support the usage of a webpack dev server for providing the JS and CSS assets during development mode. See the [shakacode/react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/) for a working example.
|
5
|
-
|
6
|
-
The key options are `static` and `hot` which specify what you want for static vs. hot. Both of these params are optional, and support either a single value, or an array.
|
7
|
-
|
8
|
-
static vs. hot is picked based on whether `ENV["REACT_ON_RAILS_ENV"] == "HOT"`
|
9
|
-
|
10
|
-
```erb
|
11
|
-
<%= env_stylesheet_link_tag(static: 'application_static',
|
12
|
-
hot: 'application_non_webpack',
|
13
|
-
media: 'all',
|
14
|
-
'data-turbolinks-track' => true) %>
|
15
|
-
|
16
|
-
<!-- These do not use turbolinks, so no data-turbolinks-track -->
|
17
|
-
<!-- This is to load the hot assets. -->
|
18
|
-
|
19
|
-
<!-- Note, you can have multiple files here. It's an array. -->
|
20
|
-
<%= env_javascript_include_tag(hot: ['http://localhost:3500/hello-world-bundle.js]') %>
|
21
|
-
|
22
|
-
<!-- These do use turbolinks -->
|
23
|
-
<%= env_javascript_include_tag(static: 'application_static',
|
24
|
-
hot: 'application_non_webpack',
|
25
|
-
'data-turbolinks-track' => true) %>
|
26
|
-
```
|
27
|
-
|
28
|
-
See application.html.erb for usage example and [application.html.erb](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/app%2Fviews%2Flayouts%2Fapplication.html.erb)
|
29
|
-
|
30
|
-
Helper to set CSS and JS assets depending on if we want static or "hot", which means from the Webpack dev server.
|
31
|
-
|
32
|
-
In this example, `application_non_webpack` is simply a CSS asset pipeline file which includes styles not placed in the webpack build. The same can be said for `application_non_webpack` for JS files. Note, the suffix is not used in the helper calls.
|
33
|
-
|
34
|
-
We don't need styles from the webpack build, as those will come via the JavaScript include tags.
|
35
|
-
|
36
|
-
The key options are `static` and `hot` which specify what you want for static vs. hot. Both of
|
37
|
-
these params are optional, and support either a single value, or an array.
|
38
|
-
|
39
|
-
```erb
|
40
|
-
<%= env_stylesheet_link_tag(static: 'application_static',
|
41
|
-
hot: 'application_non_webpack',
|
42
|
-
media: 'all',
|
43
|
-
'data-turbolinks-track' => true) %>
|
44
|
-
```
|
@@ -1,12 +0,0 @@
|
|
1
|
-
# You can run these commands in separate shells instead of using foreman
|
2
|
-
web: rails s -p 3000
|
3
|
-
|
4
|
-
# Next line runs the webpack-dev-server
|
5
|
-
# You can edit config/webpacker.yml to set HMR to true to see hot reloading.
|
6
|
-
# Note, hot and live reloading don't work with the default generator setup on top of
|
7
|
-
# the rails/webpacker Webpack config with server rendering.
|
8
|
-
# If you have server rendering enabled, modify the call to bin/webpack-dev-server line
|
9
|
-
# so you add `--inline=false` and then CSS is not inlined.
|
10
|
-
# Otherwise, you will have an error. If you want HMR and Server Rendering, see
|
11
|
-
# the example in the https://github.com/shakacode/react-webpack-rails-tutorial
|
12
|
-
client: sh -c 'rm -rf public/packs/* || true && bundle exec rake react_on_rails:locale && bin/webpack-dev-server'
|
@@ -1,153 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ReactOnRails
|
4
|
-
class AssetsPrecompile
|
5
|
-
class SymlinkTargetDoesNotExistException < StandardError
|
6
|
-
end
|
7
|
-
|
8
|
-
# Used by the rake task
|
9
|
-
def default_asset_path
|
10
|
-
dir = File.join(Rails.configuration.paths["public"].first,
|
11
|
-
Rails.configuration.assets.prefix)
|
12
|
-
Pathname.new(dir)
|
13
|
-
end
|
14
|
-
|
15
|
-
# assets_path should be a Pathname object
|
16
|
-
def initialize(assets_path: nil,
|
17
|
-
symlink_non_digested_assets_regex: nil,
|
18
|
-
generated_assets_dir: nil)
|
19
|
-
@assets_path = ReactOnRails::Utils.truthy_presence(assets_path) || default_asset_path
|
20
|
-
@symlink_non_digested_assets_regex =
|
21
|
-
ReactOnRails::Utils.truthy_presence(symlink_non_digested_assets_regex) ||
|
22
|
-
ReactOnRails.configuration.symlink_non_digested_assets_regex
|
23
|
-
@generated_assets_dir = ReactOnRails::Utils.truthy_presence(generated_assets_dir) ||
|
24
|
-
ReactOnRails.configuration.generated_assets_dir
|
25
|
-
end
|
26
|
-
|
27
|
-
# target and symlink are relative to the assets directory
|
28
|
-
def symlink_file(target, symlink)
|
29
|
-
target_path = @assets_path.join(target)
|
30
|
-
symlink_path = @assets_path.join(symlink)
|
31
|
-
|
32
|
-
target_exists = File.exist?(target_path)
|
33
|
-
raise SymlinkTargetDoesNotExistException, "Target Path was: #{target_path}" unless target_exists
|
34
|
-
|
35
|
-
if symlink_and_points_to_existing_file?(symlink_path)
|
36
|
-
puts "React On Rails: Digested version of #{symlink} already exists indicating #{target} did not change."
|
37
|
-
return
|
38
|
-
end
|
39
|
-
|
40
|
-
if file_or_symlink_exists_at_path?(symlink_path)
|
41
|
-
puts "React On Rails: Removing existing invalid symlink or file #{symlink_path}"
|
42
|
-
FileUtils.remove_file(symlink_path, true)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Might be like:
|
46
|
-
# "images/5cf5db49df178f9357603f945752a1ef.png":
|
47
|
-
# "images/5cf5db49df178f9357603f945752a1ef-033650e1d6193b70d59bb60e773f47b6d9aefdd56abc7cc.png"
|
48
|
-
# need to cd to directory and then symlink
|
49
|
-
target_sub_path, _divider, target_filename = target.rpartition("/")
|
50
|
-
_symlink_sub_path, _divider, symlink_filename = symlink.rpartition("/")
|
51
|
-
dest_path = File.join(@assets_path, target_sub_path)
|
52
|
-
|
53
|
-
puts "React On Rails: Symlinking \"#{target}\" to \"#{symlink}\""
|
54
|
-
FileUtils.chdir(dest_path) do
|
55
|
-
File.symlink(target_filename, symlink_filename)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def symlink_non_digested_assets
|
60
|
-
# digest ==> means that the file has a unique sha so the browser will load a new copy.
|
61
|
-
# Webpack's CSS extract-text-plugin copies digested asset files over to directory where we put
|
62
|
-
# we deploy the webpack compiled JS file. Since Rails will deploy the image files in this
|
63
|
-
# directory with a digest, then the files are essentially "double-digested" and the CSS
|
64
|
-
# references from webpack's CSS would be invalid. The fix is to symlink the double-digested
|
65
|
-
# file back to the original digested name, and make a similar symlink for the gz version.
|
66
|
-
return unless @symlink_non_digested_assets_regex
|
67
|
-
|
68
|
-
manifest_glob = Dir.glob(@assets_path.join(".sprockets-manifest-*.json")) +
|
69
|
-
Dir.glob(@assets_path.join("manifest-*.json")) +
|
70
|
-
Dir.glob(@assets_path.join("manifest.yml"))
|
71
|
-
if manifest_glob.empty?
|
72
|
-
puts "Warning: React On Rails: expected to find .sprockets-manifest-*.json, manifest-*.json "\
|
73
|
-
"or manifest.yml at #{@assets_path}, but found none. Canceling symlinking tasks."
|
74
|
-
return -1
|
75
|
-
end
|
76
|
-
manifest_path = take_most_recent_manifest_path(manifest_glob)
|
77
|
-
manifest_file = File.new(manifest_path)
|
78
|
-
manifest_data = if File.extname(manifest_file) == ".json"
|
79
|
-
manifest_file_data = File.read(manifest_path)
|
80
|
-
JSON.parse(manifest_file_data)["assets"]
|
81
|
-
else
|
82
|
-
YAML.safe_load(manifest_file)
|
83
|
-
end
|
84
|
-
|
85
|
-
# We realize that we're copying other Rails assets that match the regexp, but this just
|
86
|
-
# means that we'd be exposing the original, undigested names.
|
87
|
-
manifest_data.each do |original_filename, rails_digested_filename|
|
88
|
-
# TODO: we should remove any original_filename that is NOT in the webpack deploy folder.
|
89
|
-
next unless original_filename =~ @symlink_non_digested_assets_regex
|
90
|
-
|
91
|
-
# We're symlinking from the digested filename back to the original filename which has
|
92
|
-
# already been symlinked by Webpack
|
93
|
-
symlink_file(rails_digested_filename, original_filename)
|
94
|
-
|
95
|
-
# We want the gz ones as well if they exist
|
96
|
-
if File.exist?(@assets_path.join("#{rails_digested_filename}.gz"))
|
97
|
-
symlink_file("#{rails_digested_filename}.gz", "#{original_filename}.gz")
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def delete_broken_symlinks
|
103
|
-
Dir.glob(@assets_path.join("*")).each do |filename|
|
104
|
-
next unless File.lstat(filename).symlink?
|
105
|
-
|
106
|
-
begin
|
107
|
-
target = File.readlink(filename)
|
108
|
-
rescue StandardError
|
109
|
-
puts "React on Rails: Warning: your platform doesn't support File::readlink method." \
|
110
|
-
"Skipping broken link check."
|
111
|
-
break
|
112
|
-
end
|
113
|
-
path = Pathname.new(File.dirname(filename))
|
114
|
-
target_path = path.join(target)
|
115
|
-
unless File.exist?(target_path)
|
116
|
-
puts "React on Rails: Deleting broken link: #{filename}"
|
117
|
-
File.delete(filename)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def clobber
|
123
|
-
dir = Rails.root.join(@generated_assets_dir)
|
124
|
-
if dir.present? && File.directory?(dir)
|
125
|
-
puts "Deleting files in directory #{dir}"
|
126
|
-
FileUtils.rm_r(Dir.glob(Rails.root.join("#{@generated_assets_dir}/*")))
|
127
|
-
else
|
128
|
-
puts "Could not find generated_assets_dir #{dir} defined in react_on_rails initializer: "
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
def take_most_recent_manifest_path(manifest_glob)
|
135
|
-
manifest_glob.max_by { |name| File.mtime(name) }
|
136
|
-
end
|
137
|
-
|
138
|
-
def symlink_and_points_to_existing_file?(symlink_path)
|
139
|
-
# File.exist?(symlink_path) will check the file the sym is pointing to is existing
|
140
|
-
# File.lstat(symlink_path).symlink? confirms that this is a symlink
|
141
|
-
File.exist?(symlink_path) && File.lstat(symlink_path).symlink?
|
142
|
-
end
|
143
|
-
|
144
|
-
def file_or_symlink_exists_at_path?(path)
|
145
|
-
# We use lstat and not stat, we we don't want to visit the file that the symlink maybe
|
146
|
-
# pointing to. We can't use File.exist?, as that would check the file pointed at by the symlink.
|
147
|
-
File.lstat(path)
|
148
|
-
true
|
149
|
-
rescue StandardError
|
150
|
-
false
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
@@ -1,138 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "erb"
|
4
|
-
|
5
|
-
module ReactOnRails
|
6
|
-
class LocalesToJs
|
7
|
-
def initialize
|
8
|
-
return if i18n_dir.nil?
|
9
|
-
return unless obsolete?
|
10
|
-
|
11
|
-
@translations, @defaults = generate_translations
|
12
|
-
convert
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def obsolete?
|
18
|
-
return true if exist_js_files.empty?
|
19
|
-
|
20
|
-
js_files_are_outdated
|
21
|
-
end
|
22
|
-
|
23
|
-
def exist_js_files
|
24
|
-
@exist_js_files ||= js_files.select(&File.method(:exist?))
|
25
|
-
end
|
26
|
-
|
27
|
-
def js_files_are_outdated
|
28
|
-
latest_yml = locale_files.map(&File.method(:mtime)).max
|
29
|
-
earliest_js = exist_js_files.map(&File.method(:mtime)).min
|
30
|
-
latest_yml > earliest_js
|
31
|
-
end
|
32
|
-
|
33
|
-
def js_file_names
|
34
|
-
%w[translations default]
|
35
|
-
end
|
36
|
-
|
37
|
-
def js_files
|
38
|
-
@js_files ||= js_file_names.map { |n| js_file(n) }
|
39
|
-
end
|
40
|
-
|
41
|
-
def js_file(name)
|
42
|
-
"#{i18n_dir}/#{name}.js"
|
43
|
-
end
|
44
|
-
|
45
|
-
def locale_files
|
46
|
-
@locale_files ||= begin
|
47
|
-
if i18n_yml_dir.present?
|
48
|
-
Dir["#{i18n_yml_dir}/**/*.yml"]
|
49
|
-
else
|
50
|
-
ReactOnRails::Utils.truthy_presence(
|
51
|
-
Rails.application && Rails.application.config.i18n.load_path
|
52
|
-
).presence
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def i18n_dir
|
58
|
-
@i18n_dir ||= ReactOnRails.configuration.i18n_dir
|
59
|
-
end
|
60
|
-
|
61
|
-
def i18n_yml_dir
|
62
|
-
@i18n_yml_dir ||= ReactOnRails.configuration.i18n_yml_dir
|
63
|
-
end
|
64
|
-
|
65
|
-
def default_locale
|
66
|
-
@default_locale ||= I18n.default_locale.to_s || "en"
|
67
|
-
end
|
68
|
-
|
69
|
-
def convert
|
70
|
-
js_file_names.each do |name|
|
71
|
-
template = send("template_#{name}")
|
72
|
-
path = js_file(name)
|
73
|
-
generate_js_file(template, path)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def generate_js_file(template, path)
|
78
|
-
result = ERB.new(template).result()
|
79
|
-
File.open(path, "w") do |f|
|
80
|
-
f.write(result)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def generate_translations
|
85
|
-
translations = {}
|
86
|
-
defaults = {}
|
87
|
-
locale_files.each do |f|
|
88
|
-
translation = YAML.safe_load(File.open(f))
|
89
|
-
key = translation.keys[0]
|
90
|
-
val = flatten(translation[key])
|
91
|
-
translations = translations.deep_merge(key => val)
|
92
|
-
defaults = defaults.deep_merge(flatten_defaults(val)) if key == default_locale
|
93
|
-
end
|
94
|
-
[translations.to_json, defaults.to_json]
|
95
|
-
end
|
96
|
-
|
97
|
-
def format(input)
|
98
|
-
input.to_s.tr(".", "_").camelize(:lower).to_sym
|
99
|
-
end
|
100
|
-
|
101
|
-
def flatten_defaults(val)
|
102
|
-
flatten(val).each_with_object({}) do |(k, v), h|
|
103
|
-
key = format(k)
|
104
|
-
h[key] = { id: k, defaultMessage: v }
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def flatten(translations)
|
109
|
-
translations.each_with_object({}) do |(k, v), h|
|
110
|
-
if v.is_a? Hash
|
111
|
-
flatten(v).map { |hk, hv| h["#{k}.#{hk}".to_sym] = hv }
|
112
|
-
elsif v.is_a?(String)
|
113
|
-
h[k] = v.gsub("%{", "{")
|
114
|
-
elsif !v.is_a?(Array)
|
115
|
-
h[k] = v
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def template_translations
|
121
|
-
<<-JS.strip_heredoc
|
122
|
-
export const translations = #{@translations};
|
123
|
-
JS
|
124
|
-
end
|
125
|
-
|
126
|
-
def template_default
|
127
|
-
<<-JS.strip_heredoc
|
128
|
-
import { defineMessages } from 'react-intl';
|
129
|
-
|
130
|
-
const defaultLocale = \'#{default_locale}\';
|
131
|
-
|
132
|
-
const defaultMessages = defineMessages(#{@defaults});
|
133
|
-
|
134
|
-
export { defaultMessages, defaultLocale };
|
135
|
-
JS
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|