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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +320 -0
  3. data/.eslintignore +2 -1
  4. data/.eslintrc +30 -2
  5. data/.github/FUNDING.yml +1 -0
  6. data/.gitignore +3 -1
  7. data/.prettierignore +10 -0
  8. data/.prettierrc +23 -0
  9. data/.release-it.json +3 -0
  10. data/.rubocop.yml +37 -11
  11. data/.travis.yml +10 -20
  12. data/CHANGELOG.md +86 -3
  13. data/CONTRIBUTING.md +61 -80
  14. data/Gemfile +3 -5
  15. data/{COMM-LICENSE → REACT-ON-RAILS-PRO-LICENSE} +6 -9
  16. data/README.md +117 -68
  17. data/Rakefile +0 -7
  18. data/SUMMARY.md +12 -12
  19. data/book.json +5 -5
  20. data/docs/additional-reading/asset-pipeline.md +8 -16
  21. data/docs/additional-reading/images.md +1 -1
  22. data/docs/additional-reading/rails_view_rendering_from_inline_javascript.md +2 -1
  23. data/docs/additional-reading/react-helmet.md +30 -10
  24. data/docs/additional-reading/react-router.md +52 -75
  25. data/docs/additional-reading/server-rendering-tips.md +12 -7
  26. data/docs/additional-reading/upgrade-webpacker-v3-to-v4.md +10 -0
  27. data/docs/api/javascript-api.md +3 -3
  28. data/docs/api/redux-store-api.md +4 -2
  29. data/docs/api/view-helpers-api.md +17 -14
  30. data/docs/basics/configuration.md +64 -61
  31. data/docs/basics/deployment.md +1 -2
  32. data/docs/basics/generator-details.md +1 -1
  33. data/docs/basics/i18n.md +44 -22
  34. data/docs/basics/installation-into-an-existing-rails-app.md +2 -2
  35. data/docs/basics/minitest-configuration.md +31 -0
  36. data/docs/basics/react-server-rendering.md +3 -1
  37. data/docs/basics/recommended-project-structure.md +24 -1
  38. data/docs/basics/{generator-functions-and-railscontext.md → render-functions-and-railscontext.md} +59 -21
  39. data/docs/basics/rspec-configuration.md +2 -2
  40. data/docs/basics/upgrading-react-on-rails.md +61 -3
  41. data/docs/basics/webpack-configuration.md +26 -1
  42. data/docs/contributor-info/errors-with-hooks.md +45 -0
  43. data/docs/contributor-info/pull-requests.md +44 -0
  44. data/docs/misc/doctrine.md +1 -1
  45. data/docs/{misc-pending → outdated}/code-splitting.md +13 -9
  46. data/docs/{additional-reading → outdated}/heroku-deployment.md +0 -6
  47. data/docs/{basics → outdated}/how-react-on-rails-works.md +2 -2
  48. data/docs/{misc-pending → outdated}/manual-installation-overview.md +5 -5
  49. data/docs/{additional-reading → outdated}/rails-assets-relative-paths.md +3 -3
  50. data/docs/{misc-pending → outdated}/rails-assets.md +4 -7
  51. data/docs/{misc → outdated}/rails3.md +0 -0
  52. data/docs/testimonials/hvmn.md +25 -0
  53. data/docs/testimonials/resortpass.md +13 -0
  54. data/docs/testimonials/testimonials.md +28 -0
  55. data/docs/tutorial.md +157 -25
  56. data/jest.config.js +4 -0
  57. data/lib/generators/react_on_rails/dev_tests_generator.rb +2 -1
  58. data/lib/generators/react_on_rails/generator_helper.rb +4 -6
  59. data/lib/generators/react_on_rails/install_generator.rb +2 -0
  60. data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +9 -8
  61. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +4 -8
  62. data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js +1 -3
  63. data/lib/react_on_rails.rb +4 -1
  64. data/lib/react_on_rails/configuration.rb +15 -23
  65. data/lib/react_on_rails/error.rb +2 -0
  66. data/lib/react_on_rails/git_utils.rb +2 -0
  67. data/lib/react_on_rails/helper.rb +110 -159
  68. data/lib/react_on_rails/json_output.rb +1 -1
  69. data/lib/react_on_rails/json_parse_error.rb +2 -0
  70. data/lib/react_on_rails/locales/base.rb +142 -0
  71. data/lib/react_on_rails/locales/to_js.rb +37 -0
  72. data/lib/react_on_rails/locales/to_json.rb +27 -0
  73. data/lib/react_on_rails/prerender_error.rb +11 -15
  74. data/lib/react_on_rails/react_component/render_options.rb +4 -0
  75. data/lib/react_on_rails/server_rendering_js_code.rb +42 -0
  76. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +85 -60
  77. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +7 -8
  78. data/lib/react_on_rails/utils.rb +19 -20
  79. data/lib/react_on_rails/version.rb +1 -1
  80. data/lib/react_on_rails/version_checker.rb +5 -1
  81. data/lib/react_on_rails/webpacker_utils.rb +21 -2
  82. data/lib/tasks/assets.rake +5 -45
  83. data/lib/tasks/locale.rake +8 -2
  84. data/package-scripts.yml +49 -0
  85. data/package.json +41 -31
  86. data/rakelib/dummy_apps.rake +1 -9
  87. data/rakelib/example_type.rb +3 -1
  88. data/rakelib/examples.rake +3 -0
  89. data/rakelib/lint.rake +2 -7
  90. data/rakelib/node_package.rake +2 -2
  91. data/rakelib/release.rake +3 -2
  92. data/rakelib/run_rspec.rake +5 -18
  93. data/react_on_rails.gemspec +3 -5
  94. data/tsconfig.json +14 -0
  95. data/webpackConfigLoader.js +5 -4
  96. data/yarn.lock +7042 -2327
  97. metadata +40 -57
  98. data/Gemfile.rails32 +0 -74
  99. data/docs/additional-reading/babel.md +0 -5
  100. data/docs/additional-reading/hot-reloading-rails-development.md +0 -57
  101. data/docs/api/ruby-api-hot-reload-view-helpers.md +0 -44
  102. data/docs/testimonials.md +0 -11
  103. data/lib/react_on_rails/assets_precompile.rb +0 -150
  104. 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