react_on_rails 15.0.0.alpha.1 → 15.0.0.rc.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +479 -81
- data/CONTRIBUTING.md +61 -47
- data/Gemfile.development_dependencies +1 -1
- data/Gemfile.lock +4 -4
- data/KUDOS.md +22 -1
- data/NEWS.md +48 -48
- data/PROJECTS.md +45 -40
- data/README.md +24 -16
- data/SUMMARY.md +62 -52
- data/eslint.config.ts +213 -0
- data/knip.ts +100 -0
- data/lib/generators/USAGE +1 -1
- data/lib/generators/react_on_rails/dev_tests_generator.rb +4 -8
- data/lib/generators/react_on_rails/templates/.eslintrc +1 -1
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +2 -2
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js +1 -1
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +1 -1
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/reducers/helloWorldReducer.js +1 -1
- data/lib/react_on_rails/configuration.rb +81 -12
- data/lib/react_on_rails/controller.rb +4 -2
- data/lib/react_on_rails/engine.rb +1 -3
- data/lib/react_on_rails/helper.rb +184 -56
- data/lib/react_on_rails/locales/base.rb +7 -1
- data/lib/react_on_rails/packer_utils.rb +23 -3
- data/lib/react_on_rails/packs_generator.rb +84 -11
- data/lib/react_on_rails/prerender_error.rb +10 -2
- data/lib/react_on_rails/react_component/render_options.rb +39 -3
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +6 -2
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +4 -2
- data/lib/react_on_rails/utils.rb +67 -23
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +34 -23
- data/lib/tasks/assets.rake +1 -1
- data/react_on_rails.gemspec +2 -2
- data/tsconfig.eslint.json +6 -0
- data/tsconfig.json +10 -6
- metadata +8 -7
data/knip.ts
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
import type { KnipConfig } from 'knip';
|
2
|
+
|
3
|
+
const config: KnipConfig = {
|
4
|
+
// ! at the end means files are used in production
|
5
|
+
workspaces: {
|
6
|
+
'.': {
|
7
|
+
entry: [
|
8
|
+
'node_package/src/ReactOnRails.node.ts!',
|
9
|
+
'node_package/src/ReactOnRailsRSC.ts!',
|
10
|
+
'node_package/src/registerServerComponent/client.tsx!',
|
11
|
+
'node_package/src/registerServerComponent/server.tsx!',
|
12
|
+
'node_package/src/registerServerComponent/server.rsc.ts!',
|
13
|
+
'node_package/src/wrapServerComponentRenderer/server.tsx!',
|
14
|
+
'node_package/src/wrapServerComponentRenderer/server.rsc.tsx!',
|
15
|
+
'node_package/src/RSCRoute.tsx!',
|
16
|
+
'node_package/src/ServerComponentFetchError.ts!',
|
17
|
+
'eslint.config.ts',
|
18
|
+
],
|
19
|
+
project: ['node_package/src/**/*.[jt]s{x,}!', 'node_package/tests/**/*.[jt]s{x,}'],
|
20
|
+
babel: {
|
21
|
+
config: ['node_package/babel.config.js'],
|
22
|
+
},
|
23
|
+
ignore: ['node_package/tests/emptyForTesting.js'],
|
24
|
+
ignoreBinaries: [
|
25
|
+
// Knip fails to detect it's declared in devDependencies
|
26
|
+
'nps',
|
27
|
+
// local scripts
|
28
|
+
'node_package/scripts/.*',
|
29
|
+
],
|
30
|
+
ignoreDependencies: [
|
31
|
+
// Required for TypeScript compilation, but we don't depend on Turbolinks itself.
|
32
|
+
'@types/turbolinks',
|
33
|
+
// The Knip ESLint plugin fails to detect these are transitively required by a config,
|
34
|
+
// though we don't actually use its rules anywhere.
|
35
|
+
'@babel/eslint-parser',
|
36
|
+
'@babel/preset-react',
|
37
|
+
'eslint-config-shakacode',
|
38
|
+
'eslint-import-resolver-alias',
|
39
|
+
'eslint-plugin-import',
|
40
|
+
'eslint-plugin-jsx-a11y',
|
41
|
+
'eslint-plugin-react',
|
42
|
+
'eslint-plugin-react-hooks',
|
43
|
+
// These are used as transitive dependencies and missing from package.json
|
44
|
+
'@eslint/eslintrc',
|
45
|
+
'@eslint/js',
|
46
|
+
// used by Jest
|
47
|
+
'jsdom',
|
48
|
+
],
|
49
|
+
},
|
50
|
+
'spec/dummy': {
|
51
|
+
entry: [
|
52
|
+
'app/assets/config/manifest.js!',
|
53
|
+
'client/app/packs/**/*.js!',
|
54
|
+
// Not sure why this isn't detected as a dependency of client/app/packs/server-bundle.js
|
55
|
+
'client/app/generated/server-bundle-generated.js!',
|
56
|
+
'spec/fixtures/automated_packs_generation/**/*.js{x,}',
|
57
|
+
'config/webpack/{production,development,test}.js',
|
58
|
+
// Declaring this as webpack.config instead doesn't work correctly
|
59
|
+
'config/webpack/webpack.config.js',
|
60
|
+
],
|
61
|
+
ignore: ['**/app-react16/**/*'],
|
62
|
+
project: ['**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}!', 'config/webpack/*.js'],
|
63
|
+
paths: {
|
64
|
+
'Assets/*': ['client/app/assets/*'],
|
65
|
+
},
|
66
|
+
ignoreBinaries: [
|
67
|
+
// Has to be installed globally
|
68
|
+
'yalc',
|
69
|
+
// Local binaries
|
70
|
+
'bin/.*',
|
71
|
+
],
|
72
|
+
ignoreDependencies: [
|
73
|
+
// Knip thinks it can be a devDependency, but it's supposed to be in dependencies.
|
74
|
+
'@babel/runtime',
|
75
|
+
// There's no ReScript plugin for Knip
|
76
|
+
'@rescript/react',
|
77
|
+
// The Babel plugin fails to detect it
|
78
|
+
'babel-plugin-transform-react-remove-prop-types',
|
79
|
+
// This one is weird. It's long-deprecated and shouldn't be necessary.
|
80
|
+
// Probably need to update the Webpack config.
|
81
|
+
'node-libs-browser',
|
82
|
+
// The below dependencies are not detected by the Webpack plugin
|
83
|
+
// due to the config issue.
|
84
|
+
'css-loader',
|
85
|
+
'expose-loader',
|
86
|
+
'file-loader',
|
87
|
+
'imports-loader',
|
88
|
+
'mini-css-extract-plugin',
|
89
|
+
'null-loader',
|
90
|
+
'sass',
|
91
|
+
'sass-loader',
|
92
|
+
'sass-resources-loader',
|
93
|
+
'style-loader',
|
94
|
+
'url-loader',
|
95
|
+
],
|
96
|
+
},
|
97
|
+
},
|
98
|
+
};
|
99
|
+
|
100
|
+
export default config;
|
data/lib/generators/USAGE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Description:
|
2
2
|
|
3
|
-
The react_on_rails:install generator integrates
|
3
|
+
The react_on_rails:install generator integrates Webpack with Rails with ease. You
|
4
4
|
can pass the redux option if you'd like to have redux setup for you automatically.
|
5
5
|
|
6
6
|
* Redux
|
@@ -47,14 +47,10 @@ module ReactOnRails
|
|
47
47
|
|
48
48
|
def add_yarn_relative_install_script_in_package_json
|
49
49
|
package_json = File.join(destination_root, "package.json")
|
50
|
-
contents = File.read(package_json)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
STRING
|
55
|
-
new_client_package_json_contents = contents.gsub(/ {2}"scripts": {/,
|
56
|
-
replacement_value)
|
57
|
-
File.open(package_json, "w+") { |f| f.puts new_client_package_json_contents }
|
50
|
+
contents = JSON.parse(File.read(package_json))
|
51
|
+
contents["scripts"] ||= {}
|
52
|
+
contents["scripts"]["postinstall"] = "yalc link react-on-rails"
|
53
|
+
File.open(package_json, "w+") { |f| f.puts JSON.pretty_generate(contents) }
|
58
54
|
end
|
59
55
|
end
|
60
56
|
end
|
@@ -37,7 +37,7 @@ development:
|
|
37
37
|
# port: 8080
|
38
38
|
compress: true
|
39
39
|
# Note that apps that do not check the host are vulnerable to DNS rebinding attacks
|
40
|
-
allowed_hosts: [
|
40
|
+
allowed_hosts: ['localhost']
|
41
41
|
pretty: true
|
42
42
|
headers:
|
43
43
|
'Access-Control-Allow-Origin': '*'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { combineReducers } from 'redux';
|
2
2
|
import { HELLO_WORLD_NAME_UPDATE } from '../constants/helloWorldConstants';
|
3
3
|
|
4
|
-
const name = (state = '', action) => {
|
4
|
+
const name = (state = '', action = {}) => {
|
5
5
|
switch (action.type) {
|
6
6
|
case HELLO_WORLD_NAME_UPDATE:
|
7
7
|
return action.text;
|
@@ -9,6 +9,9 @@ module ReactOnRails
|
|
9
9
|
end
|
10
10
|
|
11
11
|
DEFAULT_GENERATED_ASSETS_DIR = File.join(%w[public webpack], Rails.env).freeze
|
12
|
+
DEFAULT_REACT_CLIENT_MANIFEST_FILE = "react-client-manifest.json"
|
13
|
+
DEFAULT_REACT_SERVER_CLIENT_MANIFEST_FILE = "react-server-client-manifest.json"
|
14
|
+
DEFAULT_COMPONENT_REGISTRY_TIMEOUT = 5000
|
12
15
|
|
13
16
|
def self.configuration
|
14
17
|
@configuration ||= Configuration.new(
|
@@ -17,6 +20,9 @@ module ReactOnRails
|
|
17
20
|
# generated_assets_dirs is deprecated
|
18
21
|
generated_assets_dir: "",
|
19
22
|
server_bundle_js_file: "",
|
23
|
+
rsc_bundle_js_file: "",
|
24
|
+
react_client_manifest_file: DEFAULT_REACT_CLIENT_MANIFEST_FILE,
|
25
|
+
react_server_client_manifest_file: DEFAULT_REACT_SERVER_CLIENT_MANIFEST_FILE,
|
20
26
|
prerender: false,
|
21
27
|
auto_load_bundle: false,
|
22
28
|
replay_console: true,
|
@@ -39,9 +45,14 @@ module ReactOnRails
|
|
39
45
|
i18n_output_format: nil,
|
40
46
|
components_subdirectory: nil,
|
41
47
|
make_generated_server_bundle_the_entrypoint: false,
|
42
|
-
defer_generated_component_packs:
|
48
|
+
defer_generated_component_packs: false,
|
43
49
|
# forces the loading of React components
|
44
|
-
force_load:
|
50
|
+
force_load: true,
|
51
|
+
# Maximum time in milliseconds to wait for client-side component registration after page load.
|
52
|
+
# If exceeded, an error will be thrown for server-side rendered components not registered on the client.
|
53
|
+
# Set to 0 to disable the timeout and wait indefinitely for component registration.
|
54
|
+
component_registry_timeout: DEFAULT_COMPONENT_REGISTRY_TIMEOUT,
|
55
|
+
generated_component_packs_loading_strategy: nil
|
45
56
|
)
|
46
57
|
end
|
47
58
|
|
@@ -52,26 +63,29 @@ module ReactOnRails
|
|
52
63
|
:generated_assets_dirs, :generated_assets_dir, :components_subdirectory,
|
53
64
|
:webpack_generated_files, :rendering_extension, :build_test_command,
|
54
65
|
:build_production_command, :i18n_dir, :i18n_yml_dir, :i18n_output_format,
|
66
|
+
:i18n_yml_safe_load_options, :defer_generated_component_packs,
|
55
67
|
:server_render_method, :random_dom_id, :auto_load_bundle,
|
56
68
|
:same_bundle_for_client_and_server, :rendering_props_extension,
|
57
69
|
:make_generated_server_bundle_the_entrypoint,
|
58
|
-
:
|
59
|
-
:
|
70
|
+
:generated_component_packs_loading_strategy, :force_load, :rsc_bundle_js_file,
|
71
|
+
:react_client_manifest_file, :react_server_client_manifest_file, :component_registry_timeout
|
60
72
|
|
61
73
|
# rubocop:disable Metrics/AbcSize
|
62
74
|
def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
|
63
75
|
replay_console: nil, make_generated_server_bundle_the_entrypoint: nil,
|
64
|
-
trace: nil, development_mode: nil,
|
76
|
+
trace: nil, development_mode: nil, defer_generated_component_packs: nil,
|
65
77
|
logging_on_server: nil, server_renderer_pool_size: nil,
|
66
78
|
server_renderer_timeout: nil, raise_on_prerender_error: true,
|
67
79
|
skip_display_none: nil, generated_assets_dirs: nil,
|
68
80
|
generated_assets_dir: nil, webpack_generated_files: nil,
|
69
81
|
rendering_extension: nil, build_test_command: nil,
|
70
|
-
build_production_command: nil,
|
82
|
+
build_production_command: nil, generated_component_packs_loading_strategy: nil,
|
71
83
|
same_bundle_for_client_and_server: nil,
|
72
|
-
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
|
84
|
+
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil, i18n_yml_safe_load_options: nil,
|
73
85
|
random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
|
74
|
-
components_subdirectory: nil, auto_load_bundle: nil, force_load: nil
|
86
|
+
components_subdirectory: nil, auto_load_bundle: nil, force_load: nil,
|
87
|
+
rsc_bundle_js_file: nil, react_client_manifest_file: nil, react_server_client_manifest_file: nil,
|
88
|
+
component_registry_timeout: nil)
|
75
89
|
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
|
76
90
|
self.generated_assets_dirs = generated_assets_dirs
|
77
91
|
self.generated_assets_dir = generated_assets_dir
|
@@ -80,6 +94,7 @@ module ReactOnRails
|
|
80
94
|
self.i18n_dir = i18n_dir
|
81
95
|
self.i18n_yml_dir = i18n_yml_dir
|
82
96
|
self.i18n_output_format = i18n_output_format
|
97
|
+
self.i18n_yml_safe_load_options = i18n_yml_safe_load_options
|
83
98
|
|
84
99
|
self.random_dom_id = random_dom_id
|
85
100
|
self.prerender = prerender
|
@@ -94,9 +109,13 @@ module ReactOnRails
|
|
94
109
|
self.raise_on_prerender_error = raise_on_prerender_error
|
95
110
|
self.skip_display_none = skip_display_none
|
96
111
|
self.rendering_props_extension = rendering_props_extension
|
112
|
+
self.component_registry_timeout = component_registry_timeout
|
97
113
|
|
98
114
|
# Server rendering:
|
99
115
|
self.server_bundle_js_file = server_bundle_js_file
|
116
|
+
self.rsc_bundle_js_file = rsc_bundle_js_file
|
117
|
+
self.react_client_manifest_file = react_client_manifest_file
|
118
|
+
self.react_server_client_manifest_file = react_server_client_manifest_file
|
100
119
|
self.same_bundle_for_client_and_server = same_bundle_for_client_and_server
|
101
120
|
self.server_renderer_pool_size = self.development_mode ? 1 : server_renderer_pool_size
|
102
121
|
self.server_renderer_timeout = server_renderer_timeout # seconds
|
@@ -110,6 +129,7 @@ module ReactOnRails
|
|
110
129
|
self.make_generated_server_bundle_the_entrypoint = make_generated_server_bundle_the_entrypoint
|
111
130
|
self.defer_generated_component_packs = defer_generated_component_packs
|
112
131
|
self.force_load = force_load
|
132
|
+
self.generated_component_packs_loading_strategy = generated_component_packs_loading_strategy
|
113
133
|
end
|
114
134
|
# rubocop:enable Metrics/AbcSize
|
115
135
|
|
@@ -124,10 +144,56 @@ module ReactOnRails
|
|
124
144
|
error_if_using_packer_and_generated_assets_dir_not_match_public_output_path
|
125
145
|
# check_deprecated_settings
|
126
146
|
adjust_precompile_task
|
147
|
+
check_component_registry_timeout
|
148
|
+
validate_generated_component_packs_loading_strategy
|
127
149
|
end
|
128
150
|
|
129
151
|
private
|
130
152
|
|
153
|
+
def check_component_registry_timeout
|
154
|
+
self.component_registry_timeout = DEFAULT_COMPONENT_REGISTRY_TIMEOUT if component_registry_timeout.nil?
|
155
|
+
|
156
|
+
return if component_registry_timeout.is_a?(Integer) && component_registry_timeout >= 0
|
157
|
+
|
158
|
+
raise ReactOnRails::Error, "component_registry_timeout must be a positive integer"
|
159
|
+
end
|
160
|
+
|
161
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
162
|
+
def validate_generated_component_packs_loading_strategy
|
163
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
164
|
+
|
165
|
+
if defer_generated_component_packs
|
166
|
+
if %i[async sync].include?(generated_component_packs_loading_strategy)
|
167
|
+
Rails.logger.warn "**WARNING** ReactOnRails: config.defer_generated_component_packs is " \
|
168
|
+
"superseded by config.generated_component_packs_loading_strategy"
|
169
|
+
else
|
170
|
+
Rails.logger.warn "[DEPRECATION] ReactOnRails: Use config." \
|
171
|
+
"generated_component_packs_loading_strategy = :defer rather than " \
|
172
|
+
"defer_generated_component_packs"
|
173
|
+
self.generated_component_packs_loading_strategy ||= :defer
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
msg = <<~MSG
|
178
|
+
ReactOnRails: Your current version of #{ReactOnRails::PackerUtils.packer_type.upcase_first} \
|
179
|
+
does not support async script loading, which may cause performance issues. Please either:
|
180
|
+
1. Use :sync or :defer loading strategy instead of :async
|
181
|
+
2. Upgrade to Shakapacker v8.2.0 or above to enable async script loading
|
182
|
+
MSG
|
183
|
+
if PackerUtils.shakapacker_version_requirement_met?([8, 2, 0])
|
184
|
+
self.generated_component_packs_loading_strategy ||= :async
|
185
|
+
elsif generated_component_packs_loading_strategy.nil?
|
186
|
+
Rails.logger.warn("**WARNING** #{msg}")
|
187
|
+
self.generated_component_packs_loading_strategy = :sync
|
188
|
+
elsif generated_component_packs_loading_strategy == :async
|
189
|
+
raise ReactOnRails::Error, "**ERROR** #{msg}"
|
190
|
+
end
|
191
|
+
|
192
|
+
return if %i[async defer sync].include?(generated_component_packs_loading_strategy)
|
193
|
+
|
194
|
+
raise ReactOnRails::Error, "generated_component_packs_loading_strategy must be either :async, :defer, or :sync"
|
195
|
+
end
|
196
|
+
|
131
197
|
def check_autobundling_requirements
|
132
198
|
raise_missing_components_subdirectory if auto_load_bundle && !components_subdirectory.present?
|
133
199
|
return unless components_subdirectory.present?
|
@@ -239,10 +305,13 @@ module ReactOnRails
|
|
239
305
|
def ensure_webpack_generated_files_exists
|
240
306
|
return unless webpack_generated_files.empty?
|
241
307
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
308
|
+
self.webpack_generated_files = [
|
309
|
+
"manifest.json",
|
310
|
+
server_bundle_js_file,
|
311
|
+
rsc_bundle_js_file,
|
312
|
+
react_client_manifest_file,
|
313
|
+
react_server_client_manifest_file
|
314
|
+
].compact_blank
|
246
315
|
end
|
247
316
|
|
248
317
|
def configure_skip_display_none_deprecation
|
@@ -12,9 +12,11 @@ module ReactOnRails
|
|
12
12
|
#
|
13
13
|
# Be sure to include view helper `redux_store_hydration_data` at the end of your layout or view
|
14
14
|
# or else there will be no client side hydration of your stores.
|
15
|
-
def redux_store(store_name, props: {})
|
15
|
+
def redux_store(store_name, props: {}, force_load: nil)
|
16
|
+
force_load = ReactOnRails.configuration.force_load if force_load.nil?
|
16
17
|
redux_store_data = { store_name: store_name,
|
17
|
-
props: props
|
18
|
+
props: props,
|
19
|
+
force_load: force_load }
|
18
20
|
@registered_stores_defer_render ||= []
|
19
21
|
@registered_stores_defer_render << redux_store_data
|
20
22
|
end
|
@@ -5,9 +5,7 @@ require "rails/railtie"
|
|
5
5
|
module ReactOnRails
|
6
6
|
class Engine < ::Rails::Engine
|
7
7
|
config.to_prepare do
|
8
|
-
|
9
|
-
VersionChecker.build.raise_if_gem_and_node_package_versions_differ
|
10
|
-
end
|
8
|
+
VersionChecker.build.log_if_gem_and_node_package_versions_differ
|
11
9
|
ReactOnRails::ServerRenderingPool.reset_pool
|
12
10
|
end
|
13
11
|
end
|