react_on_rails 11.1.7 → 12.0.0.pre.beta.0
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 +30 -2
- data/.github/FUNDING.yml +1 -0
- data/.gitignore +3 -1
- data/.prettierignore +10 -0
- data/.prettierrc +23 -0
- data/.release-it.json +3 -0
- data/.rubocop.yml +37 -11
- data/.travis.yml +10 -20
- data/CHANGELOG.md +86 -3
- data/CONTRIBUTING.md +61 -80
- data/Gemfile +3 -5
- data/{COMM-LICENSE → REACT-ON-RAILS-PRO-LICENSE} +6 -9
- data/README.md +117 -68
- data/Rakefile +0 -7
- data/SUMMARY.md +12 -12
- data/book.json +5 -5
- data/docs/additional-reading/asset-pipeline.md +8 -16
- data/docs/additional-reading/images.md +1 -1
- data/docs/additional-reading/rails_view_rendering_from_inline_javascript.md +2 -1
- 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/additional-reading/upgrade-webpacker-v3-to-v4.md +10 -0
- data/docs/api/javascript-api.md +3 -3
- data/docs/api/redux-store-api.md +4 -2
- data/docs/api/view-helpers-api.md +17 -14
- data/docs/basics/configuration.md +64 -61
- data/docs/basics/deployment.md +1 -2
- data/docs/basics/generator-details.md +1 -1
- data/docs/basics/i18n.md +44 -22
- data/docs/basics/installation-into-an-existing-rails-app.md +2 -2
- data/docs/basics/minitest-configuration.md +31 -0
- data/docs/basics/react-server-rendering.md +3 -1
- data/docs/basics/recommended-project-structure.md +24 -1
- data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
- data/docs/basics/rspec-configuration.md +2 -2
- data/docs/basics/upgrading-react-on-rails.md +61 -3
- data/docs/basics/webpack-configuration.md +26 -1
- 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 +13 -9
- data/docs/{additional-reading → outdated}/heroku-deployment.md +0 -6
- data/docs/{basics → outdated}/how-react-on-rails-works.md +2 -2
- 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 +4 -7
- data/docs/{misc → outdated}/rails3.md +0 -0
- data/docs/testimonials/hvmn.md +25 -0
- data/docs/testimonials/resortpass.md +13 -0
- data/docs/testimonials/testimonials.md +28 -0
- data/docs/tutorial.md +157 -25
- data/jest.config.js +4 -0
- data/lib/generators/react_on_rails/dev_tests_generator.rb +2 -1
- data/lib/generators/react_on_rails/generator_helper.rb +4 -6
- data/lib/generators/react_on_rails/install_generator.rb +2 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +9 -8
- 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 +4 -1
- data/lib/react_on_rails/configuration.rb +15 -23
- data/lib/react_on_rails/error.rb +2 -0
- data/lib/react_on_rails/git_utils.rb +2 -0
- data/lib/react_on_rails/helper.rb +110 -159
- data/lib/react_on_rails/json_output.rb +1 -1
- data/lib/react_on_rails/json_parse_error.rb +2 -0
- data/lib/react_on_rails/locales/base.rb +142 -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/react_component/render_options.rb +4 -0
- data/lib/react_on_rails/server_rendering_js_code.rb +42 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +85 -60
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
- data/lib/react_on_rails/utils.rb +19 -20
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +5 -1
- data/lib/react_on_rails/webpacker_utils.rb +21 -2
- data/lib/tasks/assets.rake +5 -45
- data/lib/tasks/locale.rake +8 -2
- data/package-scripts.yml +49 -0
- data/package.json +41 -31
- 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 +3 -2
- data/rakelib/run_rspec.rake +5 -18
- data/react_on_rails.gemspec +3 -5
- data/tsconfig.json +14 -0
- data/webpackConfigLoader.js +5 -4
- data/yarn.lock +7042 -2327
- metadata +40 -57
- data/Gemfile.rails32 +0 -74
- data/docs/additional-reading/babel.md +0 -5
- data/docs/additional-reading/hot-reloading-rails-development.md +0 -57
- data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
- data/docs/testimonials.md +0 -11
- data/lib/react_on_rails/assets_precompile.rb +0 -150
- data/lib/react_on_rails/locales_to_js.rb +0 -136
@@ -1,150 +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
|
-
manifest_glob = Dir.glob(@assets_path.join(".sprockets-manifest-*.json")) +
|
68
|
-
Dir.glob(@assets_path.join("manifest-*.json")) +
|
69
|
-
Dir.glob(@assets_path.join("manifest.yml"))
|
70
|
-
if manifest_glob.empty?
|
71
|
-
puts "Warning: React On Rails: expected to find .sprockets-manifest-*.json, manifest-*.json "\
|
72
|
-
"or manifest.yml at #{@assets_path}, but found none. Canceling symlinking tasks."
|
73
|
-
return -1
|
74
|
-
end
|
75
|
-
manifest_path = take_most_recent_manifest_path(manifest_glob)
|
76
|
-
manifest_file = File.new(manifest_path)
|
77
|
-
manifest_data = if File.extname(manifest_file) == ".json"
|
78
|
-
manifest_file_data = File.read(manifest_path)
|
79
|
-
JSON.parse(manifest_file_data)["assets"]
|
80
|
-
else
|
81
|
-
YAML.safe_load(manifest_file)
|
82
|
-
end
|
83
|
-
|
84
|
-
# We realize that we're copying other Rails assets that match the regexp, but this just
|
85
|
-
# means that we'd be exposing the original, undigested names.
|
86
|
-
manifest_data.each do |original_filename, rails_digested_filename|
|
87
|
-
# TODO: we should remove any original_filename that is NOT in the webpack deploy folder.
|
88
|
-
next unless original_filename =~ @symlink_non_digested_assets_regex
|
89
|
-
# We're symlinking from the digested filename back to the original filename which has
|
90
|
-
# already been symlinked by Webpack
|
91
|
-
symlink_file(rails_digested_filename, original_filename)
|
92
|
-
|
93
|
-
# We want the gz ones as well if they exist
|
94
|
-
if File.exist?(@assets_path.join("#{rails_digested_filename}.gz"))
|
95
|
-
symlink_file("#{rails_digested_filename}.gz", "#{original_filename}.gz")
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def delete_broken_symlinks
|
101
|
-
Dir.glob(@assets_path.join("*")).each do |filename|
|
102
|
-
next unless File.lstat(filename).symlink?
|
103
|
-
begin
|
104
|
-
target = File.readlink(filename)
|
105
|
-
rescue StandardError
|
106
|
-
puts "React on Rails: Warning: your platform doesn't support File::readlink method." \
|
107
|
-
"Skipping broken link check."
|
108
|
-
break
|
109
|
-
end
|
110
|
-
path = Pathname.new(File.dirname(filename))
|
111
|
-
target_path = path.join(target)
|
112
|
-
unless File.exist?(target_path)
|
113
|
-
puts "React on Rails: Deleting broken link: #{filename}"
|
114
|
-
File.delete(filename)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def clobber
|
120
|
-
dir = Rails.root.join(@generated_assets_dir)
|
121
|
-
if dir.present? && File.directory?(dir)
|
122
|
-
puts "Deleting files in directory #{dir}"
|
123
|
-
FileUtils.rm_r(Dir.glob(Rails.root.join("#{@generated_assets_dir}/*")))
|
124
|
-
else
|
125
|
-
puts "Could not find generated_assets_dir #{dir} defined in react_on_rails initializer: "
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def take_most_recent_manifest_path(manifest_glob)
|
132
|
-
manifest_glob.max_by { |name| File.mtime(name) }
|
133
|
-
end
|
134
|
-
|
135
|
-
def symlink_and_points_to_existing_file?(symlink_path)
|
136
|
-
# File.exist?(symlink_path) will check the file the sym is pointing to is existing
|
137
|
-
# File.lstat(symlink_path).symlink? confirms that this is a symlink
|
138
|
-
File.exist?(symlink_path) && File.lstat(symlink_path).symlink?
|
139
|
-
end
|
140
|
-
|
141
|
-
def file_or_symlink_exists_at_path?(path)
|
142
|
-
# We use lstat and not stat, we we don't want to visit the file that the symlink maybe
|
143
|
-
# pointing to. We can't use File.exist?, as that would check the file pointed at by the symlink.
|
144
|
-
File.lstat(path)
|
145
|
-
true
|
146
|
-
rescue StandardError
|
147
|
-
false
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
@@ -1,136 +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
|
-
@translations, @defaults = generate_translations
|
11
|
-
convert
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def obsolete?
|
17
|
-
return true if exist_js_files.empty?
|
18
|
-
js_files_are_outdated
|
19
|
-
end
|
20
|
-
|
21
|
-
def exist_js_files
|
22
|
-
@exist_js_files ||= js_files.select(&File.method(:exist?))
|
23
|
-
end
|
24
|
-
|
25
|
-
def js_files_are_outdated
|
26
|
-
latest_yml = locale_files.map(&File.method(:mtime)).max
|
27
|
-
earliest_js = exist_js_files.map(&File.method(:mtime)).min
|
28
|
-
latest_yml > earliest_js
|
29
|
-
end
|
30
|
-
|
31
|
-
def js_file_names
|
32
|
-
%w[translations default]
|
33
|
-
end
|
34
|
-
|
35
|
-
def js_files
|
36
|
-
@js_files ||= js_file_names.map { |n| js_file(n) }
|
37
|
-
end
|
38
|
-
|
39
|
-
def js_file(name)
|
40
|
-
"#{i18n_dir}/#{name}.js"
|
41
|
-
end
|
42
|
-
|
43
|
-
def locale_files
|
44
|
-
@locale_files ||= begin
|
45
|
-
if i18n_yml_dir.present?
|
46
|
-
Dir["#{i18n_yml_dir}/**/*.yml"]
|
47
|
-
else
|
48
|
-
ReactOnRails::Utils.truthy_presence(
|
49
|
-
Rails.application && Rails.application.config.i18n.load_path
|
50
|
-
).presence
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def i18n_dir
|
56
|
-
@i18n_dir ||= ReactOnRails.configuration.i18n_dir
|
57
|
-
end
|
58
|
-
|
59
|
-
def i18n_yml_dir
|
60
|
-
@i18n_yml_dir ||= ReactOnRails.configuration.i18n_yml_dir
|
61
|
-
end
|
62
|
-
|
63
|
-
def default_locale
|
64
|
-
@default_locale ||= I18n.default_locale.to_s || "en"
|
65
|
-
end
|
66
|
-
|
67
|
-
def convert
|
68
|
-
js_file_names.each do |name|
|
69
|
-
template = send("template_#{name}")
|
70
|
-
path = js_file(name)
|
71
|
-
generate_js_file(template, path)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def generate_js_file(template, path)
|
76
|
-
result = ERB.new(template).result()
|
77
|
-
File.open(path, "w") do |f|
|
78
|
-
f.write(result)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def generate_translations
|
83
|
-
translations = {}
|
84
|
-
defaults = {}
|
85
|
-
locale_files.each do |f|
|
86
|
-
translation = YAML.safe_load(File.open(f))
|
87
|
-
key = translation.keys[0]
|
88
|
-
val = flatten(translation[key])
|
89
|
-
translations = translations.deep_merge(key => val)
|
90
|
-
defaults = defaults.deep_merge(flatten_defaults(val)) if key == default_locale
|
91
|
-
end
|
92
|
-
[translations.to_json, defaults.to_json]
|
93
|
-
end
|
94
|
-
|
95
|
-
def format(input)
|
96
|
-
input.to_s.tr(".", "_").camelize(:lower).to_sym
|
97
|
-
end
|
98
|
-
|
99
|
-
def flatten_defaults(val)
|
100
|
-
flatten(val).each_with_object({}) do |(k, v), h|
|
101
|
-
key = format(k)
|
102
|
-
h[key] = { id: k, defaultMessage: v }
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def flatten(translations)
|
107
|
-
translations.each_with_object({}) do |(k, v), h|
|
108
|
-
if v.is_a? Hash
|
109
|
-
flatten(v).map { |hk, hv| h["#{k}.#{hk}".to_sym] = hv }
|
110
|
-
elsif v.is_a?(String)
|
111
|
-
h[k] = v.gsub("%{", "{")
|
112
|
-
elsif !v.is_a?(Array)
|
113
|
-
h[k] = v
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def template_translations
|
119
|
-
<<-JS.strip_heredoc
|
120
|
-
export const translations = #{@translations};
|
121
|
-
JS
|
122
|
-
end
|
123
|
-
|
124
|
-
def template_default
|
125
|
-
<<-JS.strip_heredoc
|
126
|
-
import { defineMessages } from 'react-intl';
|
127
|
-
|
128
|
-
const defaultLocale = \'#{default_locale}\';
|
129
|
-
|
130
|
-
const defaultMessages = defineMessages(#{@defaults});
|
131
|
-
|
132
|
-
export { defaultMessages, defaultLocale };
|
133
|
-
JS
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|