/
packs_generator.rb
182 lines (138 loc) · 5.73 KB
/
packs_generator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# frozen_string_literal: true
require "fileutils"
module ReactOnRails
class PacksGenerator
ENDS_WITH_CLIENT_OR_SERVER_REGEX = /\.server$|\.client$/.freeze
def self.generate
return unless components_directory.present?
return unless ReactOnRails::WebpackerUtils.using_webpacker?
clean_generated_packs_directory
generate_packs
end
def self.generate_packs
client_component_to_path.each_value { |component_path| create_pack component_path }
create_server_pack if ReactOnRails.configuration.server_bundle_js_file.present?
end
def self.create_pack(file_path)
output_path = generated_pack_path file_path
content = pack_file_contents file_path
f = File.new(output_path, "w")
f.puts content
f.close
puts(Rainbow("Generated Packs: #{output_path}").yellow)
end
def self.pack_file_contents(file_path)
registered_component_name = component_name file_path
<<~FILE_CONTENT
/* eslint-disable */
import ReactOnRails from 'react-on-rails';
import #{registered_component_name} from '#{relative_component_path_from_generated_pack file_path}';
ReactOnRails.register({#{registered_component_name}});
/* eslint-enable */
FILE_CONTENT
end
def self.create_server_pack
f = File.new(generated_server_bundle_file_path, "w")
f.puts generated_server_pack_file_content
f.close
add_generated_pack_to_server_bundle
puts(Rainbow("Generated Server Bundle: #{generated_server_bundle_file_path}").orange)
end
def self.generated_server_pack_file_content
server_component_imports = server_component_to_path.map do |name, component_path|
"import #{name} from '#{relative_path(generated_server_bundle_file_path, component_path)}';"
end
components_to_register = server_component_to_path.keys
<<~FILE_CONTENT
/* eslint-disable */
import ReactOnRails from 'react-on-rails';
#{server_component_imports.join("\n")}
ReactOnRails.register({#{components_to_register.join(",\n")}});
/* eslint-enable */
FILE_CONTENT
end
def self.add_generated_pack_to_server_bundle
relative_path_to_generated_server_bundle = relative_path(defined_server_bundle_file_path,
generated_server_bundle_file_path)
content = <<~FILE_CONTENT
// eslint-disable-next-line import/extensions
import "./#{relative_path_to_generated_server_bundle}"\n
FILE_CONTENT
prepend_to_file_if_not_present(defined_server_bundle_file_path, content)
end
def self.generated_server_bundle_file_path
generated_server_bundle_file_name = component_name defined_server_bundle_file_path.sub(".js", "-generated.js")
"#{source_entry_path}/#{generated_server_bundle_file_name}.js"
end
def self.clean_generated_packs_directory
FileUtils.rm_rf generated_packs_directory_path
FileUtils.mkdir_p generated_packs_directory_path
end
def self.defined_server_bundle_file_path
server_bundle_file_name = ReactOnRails.configuration.server_bundle_js_file
Dir.glob("#{source_entry_path}/**/#{server_bundle_file_name}").first
end
def self.generated_packs_directory_path
"#{source_entry_path}/generated"
end
def self.source_entry_path
ReactOnRails::WebpackerUtils.webpacker_source_entry_path
end
def self.relative_component_path_from_generated_pack(ror_component_path)
component_file_path = Pathname.new ror_component_path
generated_pack_path = Pathname.new generated_pack_path ror_component_path
relative_path(generated_pack_path, component_file_path)
end
def self.relative_path(from, to)
from_path = Pathname.new from
to_path = Pathname.new to
# TODO: Debug Relative Path always has extra '../'
relative_path = to_path.relative_path_from from_path
relative_path.sub("../", "")
end
def self.generated_pack_path(file_path)
"#{generated_packs_directory_path}/#{component_name file_path}.jsx"
end
def self.component_name(file_path)
basename = File.basename(file_path, File.extname(file_path))
basename.sub(ENDS_WITH_CLIENT_OR_SERVER_REGEX, "")
end
def self.component_name_to_path(paths)
paths.to_h { |path| [component_name(path), path] }
end
def self.common_component_to_path
common_components_paths = Dir.glob("#{components_search_path}/*").reject do |f|
f.include?(".client.") || f.include?(".server.")
end
component_name_to_path(common_components_paths)
end
def self.client_component_to_path
client_render_components_paths = Dir.glob("#{components_search_path}/*.client.*")
client_specific_components = component_name_to_path(client_render_components_paths)
common_component_to_path.merge(client_specific_components)
end
def self.server_component_to_path
server_render_components_paths = Dir.glob("#{components_search_path}/*.server.*")
server_specific_components = component_name_to_path(server_render_components_paths)
common_component_to_path.merge(server_specific_components)
end
def self.components_search_path
source_path = ReactOnRails::WebpackerUtils.webpacker_source_path
"#{source_path}/**/#{components_directory}"
end
def self.components_directory
ReactOnRails.configuration.components_directory
end
def self.prepend_to_file_if_not_present(file, str)
content = ""
File.open(file, "r") do |fd|
contents = fd.read
content += contents
end
return if content.start_with? str
File.open(file, "w") do |fd|
fd.write str + content
end
end
end
end