frails 0.4.0 → 0.8.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/.autotest +6 -0
- data/.gitignore +8 -1
- data/.rubocop.yml +10 -1
- data/Gemfile +6 -8
- data/Gemfile.lock +64 -109
- data/README.md +21 -29
- data/Rakefile +1 -1
- data/babel.config.js +12 -0
- data/bin/test +5 -3
- data/config.ru +9 -0
- data/frails.gemspec +5 -13
- data/index.js +10 -31
- data/lib/frails.rb +33 -9
- data/lib/frails/component.rb +16 -5
- data/lib/frails/component/{abstract_component.rb → abstract.rb} +11 -9
- data/lib/frails/component/{plain_component.rb → base.rb} +7 -3
- data/lib/frails/component/{react_component.rb → react.rb} +3 -5
- data/lib/frails/component/{react_component_renderer.rb → react_renderer.rb} +22 -16
- data/lib/frails/component/{component_renderer.rb → renderer.rb} +34 -5
- data/lib/frails/component/renderer_concerns.rb +10 -4
- data/lib/frails/component/test_helpers.rb +19 -0
- data/lib/frails/dev_server.rb +2 -2
- data/lib/frails/helper.rb +15 -17
- data/lib/frails/log_subscriber.rb +1 -1
- data/lib/frails/manifest.rb +3 -7
- data/lib/frails/monkey/action_view/abstract_renderer.rb +0 -2
- data/lib/frails/monkey/action_view/partial_renderer.rb +25 -6
- data/lib/frails/monkey/action_view/renderer.rb +6 -7
- data/lib/frails/monkey/action_view/template_renderer.rb +8 -1
- data/lib/frails/railtie.rb +5 -13
- data/lib/frails/side_load_assets.rb +8 -5
- data/lib/frails/utils.rb +22 -0
- data/lib/frails/version.rb +1 -1
- data/lib/tasks/frails.rake +1 -6
- data/package.json +13 -3
- data/package/__snapshots__/config.test.js.snap +10 -0
- data/package/components.js +34 -24
- data/package/config.js +38 -0
- data/package/config.test.js +7 -0
- data/package/side_load.js +7 -5
- data/yarn.lock +4283 -51
- metadata +28 -21
- data/.travis.yml +0 -7
data/lib/frails/helper.rb
CHANGED
@@ -1,34 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Frails::Helper
|
4
|
-
|
4
|
+
# rubocop:disable Metrics/AbcSize
|
5
|
+
def render(options = {}, *locals, &block)
|
6
|
+
sload_assets = respond_to?(:side_load_assets?) ? side_load_assets? : false
|
7
|
+
|
5
8
|
case options
|
6
9
|
when Hash
|
7
|
-
|
8
|
-
|
9
|
-
if block_given?
|
10
|
-
# MONKEY PATCH! simply renders the component with the given block.
|
11
|
-
return view_renderer.render_component(self, options, &block) if options.key?(:component)
|
12
|
-
|
13
|
-
view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
|
14
|
-
else
|
15
|
-
view_renderer.render(self, options)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
else
|
19
|
-
if block_given?
|
20
|
-
# MONKEY PATCH! simply renders the component with the given block.
|
21
|
-
return view_renderer.render_component(self, options, &block) if options.key?(:component)
|
10
|
+
in_rendering_context(options) do
|
11
|
+
return view_renderer.render_component(self, options, &block) if options.key?(:component)
|
22
12
|
|
13
|
+
options[:side_load_assets] = sload_assets
|
14
|
+
if block_given?
|
23
15
|
view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
|
24
16
|
else
|
25
17
|
view_renderer.render(self, options)
|
26
18
|
end
|
27
19
|
end
|
28
20
|
else
|
29
|
-
|
21
|
+
if options.is_a?(Class) && options < Frails::Component::Base
|
22
|
+
return view_renderer.render_component(self, { component: options, locals: locals }, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
view_renderer.render_partial(self, side_load_assets: sload_assets, partial: options,
|
26
|
+
locals: locals.extract_options!, &block)
|
30
27
|
end
|
31
28
|
end
|
29
|
+
# rubocop:enable Metrics/AbcSize
|
32
30
|
|
33
31
|
def javascript_pack_tag(*names, **options)
|
34
32
|
return if Rails.env.test?
|
data/lib/frails/manifest.rb
CHANGED
@@ -62,15 +62,11 @@ class Frails::Manifest
|
|
62
62
|
private
|
63
63
|
|
64
64
|
def read_source(path)
|
65
|
-
unless Frails.dev_server.running?
|
66
|
-
host = ActionController::Base.helpers.compute_asset_host
|
67
|
-
new_path = host && path.start_with?(host) ? path.delete_prefix(host) : path
|
68
|
-
return Rails.public_path.join(new_path.gsub(%r{^\/}, '')).read
|
69
|
-
end
|
65
|
+
return Rails.public_path.join(path.gsub(%r{^\/}, '')).read unless Frails.dev_server.running?
|
70
66
|
|
71
67
|
begin
|
72
|
-
open("http://#{Frails.dev_server.host_with_port}#{path}").read
|
73
|
-
rescue OpenURI::HTTPError
|
68
|
+
URI.open("http://#{Frails.dev_server.host_with_port}#{path}").read
|
69
|
+
rescue OpenURI::HTTPError
|
74
70
|
handle_missing_entry path
|
75
71
|
end
|
76
72
|
end
|
@@ -5,8 +5,6 @@ module Frails
|
|
5
5
|
module ActionView
|
6
6
|
module AbstractRenderer
|
7
7
|
def side_load_assets(view, tpl)
|
8
|
-
return unless view.controller._side_load_assets?
|
9
|
-
|
10
8
|
path = tpl.short_identifier.delete_prefix('app/').delete_suffix('.html.erb')
|
11
9
|
|
12
10
|
instrument :side_loaded_assets, identifier: tpl.identifier, asset_types: [] do |payload|
|
@@ -4,9 +4,22 @@ module Frails
|
|
4
4
|
module Monkey
|
5
5
|
module ActionView
|
6
6
|
module PartialRenderer
|
7
|
+
def render_collection(view, template)
|
8
|
+
# Side load partial assets - if any.
|
9
|
+
@asset_path = @side_load_assets && side_load_assets(view, template)
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
7
14
|
def render_partial(view, template)
|
8
15
|
# Side load partial assets - if any.
|
9
|
-
@asset_path = side_load_assets(view, template)
|
16
|
+
@asset_path = @side_load_assets && side_load_assets(view, template)
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup(context, options, as, block)
|
22
|
+
@side_load_assets = options.key?(:side_load_assets) ? options[:side_load_assets] : false
|
10
23
|
|
11
24
|
super
|
12
25
|
end
|
@@ -20,21 +33,21 @@ module Frails
|
|
20
33
|
doc = Nokogiri::HTML::DocumentFragment.parse(content)
|
21
34
|
|
22
35
|
return content if (modules = doc.css('[css_module]')).empty?
|
36
|
+
return content unless (path = stylesheet_path_for_ident)
|
23
37
|
|
24
38
|
modules.each do |ele|
|
25
|
-
classes = class_name_for_style(ele.delete('css_module'))
|
39
|
+
classes = class_name_for_style(ele.delete('css_module'), path)
|
26
40
|
ele['class'] = (ele['class'].nil? ? classes : classes << ele['class']).join(' ')
|
27
41
|
end
|
28
42
|
|
29
43
|
doc.to_html
|
30
44
|
end
|
31
45
|
|
32
|
-
def class_name_for_style(class_names)
|
33
|
-
class_names.to_s.split.map { |class_name| build_ident class_name }
|
46
|
+
def class_name_for_style(class_names, path)
|
47
|
+
class_names.to_s.split.map { |class_name| build_ident class_name, path }
|
34
48
|
end
|
35
49
|
|
36
|
-
def build_ident(local_name)
|
37
|
-
path = Rails.root.join('app', "#{@asset_path}.css").relative_path_from(Rails.root)
|
50
|
+
def build_ident(local_name, path)
|
38
51
|
hash_digest = Digest::MD5.hexdigest("#{path}+#{local_name}")[0, 6]
|
39
52
|
|
40
53
|
return "#{local_name}-#{hash_digest}" unless Frails.dev_server.running?
|
@@ -44,6 +57,12 @@ module Frails
|
|
44
57
|
ident.prepend("#{path.dirname.to_s.tr('/', '-')}-")
|
45
58
|
ident
|
46
59
|
end
|
60
|
+
|
61
|
+
def stylesheet_path_for_ident
|
62
|
+
return if (globs = Rails.root.glob("app/#{@asset_path}.{css,scss,sass,less}")).empty?
|
63
|
+
|
64
|
+
globs.first.relative_path_from(Rails.root)
|
65
|
+
end
|
47
66
|
end
|
48
67
|
end
|
49
68
|
end
|
@@ -4,7 +4,7 @@ module Frails
|
|
4
4
|
module Monkey
|
5
5
|
module ActionView
|
6
6
|
module Renderer
|
7
|
-
def render_to_object(context, options)
|
7
|
+
def render_to_object(context, options)
|
8
8
|
if options.key?(:partial)
|
9
9
|
render_partial_to_object(context, options)
|
10
10
|
elsif options.key?(:component)
|
@@ -15,19 +15,18 @@ module Frails
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# Direct access to partial rendering.
|
18
|
-
def render_component(context, options, &block)
|
18
|
+
def render_component(context, options, &block)
|
19
19
|
render_component_to_object(context, options, &block).body
|
20
20
|
end
|
21
21
|
|
22
22
|
def render_component_to_object(context, options, &block)
|
23
23
|
component = options[:component].to_s
|
24
24
|
|
25
|
-
result = if
|
26
|
-
Frails::Component::
|
25
|
+
result = if Frails.components_path.join(component, 'index.entry.jsx').exist?
|
26
|
+
Frails::Component::ReactRenderer.new.render(context, options, &block)
|
27
27
|
else
|
28
|
-
|
29
|
-
|
30
|
-
.render(context, options, &block)
|
28
|
+
Frails::Component::Renderer.new(@lookup_context)
|
29
|
+
.render(context, options, &block)
|
31
30
|
end
|
32
31
|
|
33
32
|
::ActionView::AbstractRenderer::RenderedTemplate.new result, nil, nil
|
@@ -4,8 +4,15 @@ module Frails
|
|
4
4
|
module Monkey
|
5
5
|
module ActionView
|
6
6
|
module TemplateRenderer
|
7
|
+
def render(context, options)
|
8
|
+
# See Frails::SideLoadAssets
|
9
|
+
@side_load_assets = options.key?(:side_load_assets) ? options[:side_load_assets] : false
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
7
14
|
def render_template(view, template, layout_name, locals)
|
8
|
-
return super if template.type != :html
|
15
|
+
return super if !@side_load_assets || template.type != :html
|
9
16
|
|
10
17
|
# Side load layout assets - if any.
|
11
18
|
if layout_name
|
data/lib/frails/railtie.rb
CHANGED
@@ -9,7 +9,7 @@ class Frails::Engine < ::Rails::Engine
|
|
9
9
|
app.middleware.insert_before 0, Frails::DevServerProxy, ssl_verify_none: true
|
10
10
|
end
|
11
11
|
|
12
|
-
initializer 'frails
|
12
|
+
initializer 'frails' do
|
13
13
|
ActiveSupport.on_load :action_controller do
|
14
14
|
require 'frails/side_load_assets'
|
15
15
|
|
@@ -28,19 +28,11 @@ class Frails::Engine < ::Rails::Engine
|
|
28
28
|
require 'frails/monkey/action_view/partial_renderer'
|
29
29
|
require 'frails/monkey/action_view/renderer'
|
30
30
|
|
31
|
-
ActionView::AbstractRenderer.
|
32
|
-
ActionView::TemplateRenderer.
|
33
|
-
ActionView::PartialRenderer.
|
34
|
-
ActionView::Renderer.
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
initializer 'frails.helper' do
|
39
|
-
ActiveSupport.on_load :action_controller do
|
40
|
-
ActionController::Base.helper Frails::Helper
|
41
|
-
end
|
31
|
+
ActionView::AbstractRenderer.prepend Frails::Monkey::ActionView::AbstractRenderer
|
32
|
+
ActionView::TemplateRenderer.prepend Frails::Monkey::ActionView::TemplateRenderer
|
33
|
+
ActionView::PartialRenderer.prepend Frails::Monkey::ActionView::PartialRenderer
|
34
|
+
ActionView::Renderer.prepend Frails::Monkey::ActionView::Renderer
|
42
35
|
|
43
|
-
ActiveSupport.on_load :action_view do
|
44
36
|
include Frails::Helper
|
45
37
|
end
|
46
38
|
end
|
@@ -4,12 +4,15 @@ module Frails::SideLoadAssets
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
class_attribute :
|
7
|
+
class_attribute :side_load_assets, default: false
|
8
|
+
helper_method :side_load_assets?
|
8
9
|
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
# Add _side_load_assets flag to the options hash, which will be available in TemplateRenderer,
|
12
|
+
# allowing us control if views/layouts are side loaded.
|
13
|
+
def _normalize_options(options)
|
14
|
+
super
|
15
|
+
options[:side_load_assets] = side_load_assets
|
16
|
+
options
|
14
17
|
end
|
15
18
|
end
|
data/lib/frails/utils.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Frails
|
4
|
+
module Utils
|
5
|
+
def self.camelize(term, first_letter = :upper, convert_slashes: true)
|
6
|
+
# If we are not converting slashes, and `first_letter` is `:lower`, this ensures that the
|
7
|
+
# first letter after a slash is not capitalized.
|
8
|
+
string = if !convert_slashes && first_letter == :lower
|
9
|
+
term.split('/').map { |str| str.camelize :lower }.join('/')
|
10
|
+
else
|
11
|
+
term.camelize first_letter
|
12
|
+
end
|
13
|
+
|
14
|
+
# Reverses the effect of ActiveSupport::Inflector.camelize converting slashes into `::`. If
|
15
|
+
# the keyword argument `convert_slashes:` is false (default: true), we can avoid
|
16
|
+
# converting slashes to `::`.
|
17
|
+
string.gsub!('::', '/') unless convert_slashes
|
18
|
+
|
19
|
+
string
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/frails/version.rb
CHANGED
data/lib/tasks/frails.rake
CHANGED
@@ -16,12 +16,7 @@ namespace :frails do
|
|
16
16
|
puts 'Compiling Webpack...'
|
17
17
|
|
18
18
|
ENV['RAILS_ENV'] ||= 'development'
|
19
|
-
|
20
|
-
'RAILS_ASSET_HOST' => ActionController::Base.helpers.compute_asset_host,
|
21
|
-
'RAILS_RELATIVE_URL_ROOT' => ActionController::Base.relative_url_root
|
22
|
-
}
|
23
|
-
|
24
|
-
stdout, sterr, status = Open3.capture3(env, "yarn webpack --env #{ENV['RAILS_ENV']}")
|
19
|
+
stdout, sterr, status = Open3.capture3({}, "yarn webpack --env #{ENV['RAILS_ENV']}")
|
25
20
|
|
26
21
|
if sterr == '' && status.success?
|
27
22
|
puts 'Frails successfully compiled 🎉'
|
data/package.json
CHANGED
@@ -3,14 +3,24 @@
|
|
3
3
|
"version": "0.3.0",
|
4
4
|
"description": "A Modern [F]ront End on [Rails] and Webpack",
|
5
5
|
"main": "index.js",
|
6
|
-
"files": [
|
7
|
-
"package"
|
8
|
-
],
|
9
6
|
"repository": "git@github.com:joelmoss/frails.git",
|
10
7
|
"author": "Joel Moss <joel@developwithstyle.com>",
|
11
8
|
"license": "MIT",
|
9
|
+
"scripts": {
|
10
|
+
"test": "jest"
|
11
|
+
},
|
12
|
+
"jest": {
|
13
|
+
"clearMocks": true,
|
14
|
+
"testEnvironment": "node"
|
15
|
+
},
|
12
16
|
"dependencies": {
|
13
17
|
"glob": "^7.1.4",
|
14
18
|
"lodash.has": "^4.5.2"
|
19
|
+
},
|
20
|
+
"devDependencies": {
|
21
|
+
"@babel/core": "^7.10.2",
|
22
|
+
"@babel/preset-env": "^7.10.2",
|
23
|
+
"babel-jest": "^26.0.1",
|
24
|
+
"jest": "^26.2.2"
|
15
25
|
}
|
16
26
|
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`config config 1`] = `
|
4
|
+
Object {
|
5
|
+
"absolutePublicPath": "/Users/joelmoss/dev/frails/test/dummy/public/frails",
|
6
|
+
"appPath": "/Users/joelmoss/dev/frails/test/dummy/app",
|
7
|
+
"publicOutputPath": "frails",
|
8
|
+
"rootPath": "/Users/joelmoss/dev/frails/test/dummy",
|
9
|
+
}
|
10
|
+
`;
|
data/package/components.js
CHANGED
@@ -1,47 +1,57 @@
|
|
1
|
-
const glob = require(
|
2
|
-
const path = require(
|
3
|
-
const fs = require(
|
1
|
+
const glob = require("glob");
|
2
|
+
const path = require("path");
|
3
|
+
const fs = require("fs");
|
4
4
|
|
5
|
-
const appPath = path.join(process.cwd(),
|
5
|
+
const appPath = path.join(process.cwd(), "app");
|
6
6
|
|
7
7
|
// Build entry points for HTML based components (components with an index.html.erb and index.css).
|
8
8
|
//
|
9
9
|
// NOTE: Adding new files will require a rebuild!
|
10
10
|
const buildComponents = () => {
|
11
|
-
const result = {}
|
11
|
+
const result = {};
|
12
12
|
|
13
13
|
// Find HTML partials and add its corresponding index.css as an entry point if it exists.
|
14
|
-
glob
|
15
|
-
|
14
|
+
glob
|
15
|
+
.sync(path.join(appPath, "components/**/_index.html.erb"))
|
16
|
+
.forEach(paf => {
|
17
|
+
paf = paf.replace("_index.html.erb", "index.css");
|
16
18
|
|
17
|
-
|
19
|
+
if (!fs.existsSync(paf)) return;
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
const namespace = path.relative(path.join(appPath), path.dirname(paf));
|
22
|
+
const name = path.join(namespace, path.basename(paf, path.extname(paf)));
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
result[name] = paf;
|
25
|
+
});
|
24
26
|
|
25
27
|
// Find components with no JSX and HTML index files, and add its corresponding index.css as an
|
26
28
|
// entry point if it exists. These will be components that render from within the Ruby class
|
27
29
|
// itself.
|
28
|
-
glob.sync(path.join(appPath,
|
29
|
-
css_paf = paf.replace(
|
30
|
-
html_paf = paf.replace(
|
31
|
-
jsx_paf = paf.replace(
|
30
|
+
glob.sync(path.join(appPath, "components/**/*_component.rb")).forEach(paf => {
|
31
|
+
css_paf = paf.replace("_component.rb", "/index.css");
|
32
|
+
html_paf = paf.replace("_component.rb", "/_index.html.erb");
|
33
|
+
jsx_paf = paf.replace("_component.rb", "/index.entry.jsx");
|
32
34
|
|
33
35
|
// Ignore if we have a JSX or HTML file, or no CSS file.
|
34
|
-
if (
|
36
|
+
if (
|
37
|
+
fs.existsSync(jsx_paf) ||
|
38
|
+
fs.existsSync(html_paf) ||
|
39
|
+
!fs.existsSync(css_paf)
|
40
|
+
)
|
41
|
+
return;
|
35
42
|
|
36
|
-
const namespace = path.relative(path.join(appPath), path.dirname(css_paf))
|
37
|
-
const name = path.join(
|
43
|
+
const namespace = path.relative(path.join(appPath), path.dirname(css_paf));
|
44
|
+
const name = path.join(
|
45
|
+
namespace,
|
46
|
+
path.basename(css_paf, path.extname(css_paf))
|
47
|
+
);
|
38
48
|
|
39
|
-
result[name] = css_paf
|
40
|
-
})
|
49
|
+
result[name] = css_paf;
|
50
|
+
});
|
41
51
|
|
42
|
-
return result
|
43
|
-
}
|
52
|
+
return result;
|
53
|
+
};
|
44
54
|
|
45
55
|
module.exports = {
|
46
56
|
entry: { ...buildComponents() }
|
47
|
-
}
|
57
|
+
};
|
data/package/config.js
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
const spawnSync = require("child_process").spawnSync;
|
2
|
+
const path = require("path");
|
3
|
+
|
4
|
+
const isTest = process.env.NODE_ENV === "test";
|
5
|
+
const configFromRails = railsRun("print Frails.config_as_json");
|
6
|
+
const rootPath = isTest
|
7
|
+
? path.join(process.cwd(), "test/dummy")
|
8
|
+
: process.cwd();
|
9
|
+
|
10
|
+
module.exports = {
|
11
|
+
...configFromRails,
|
12
|
+
|
13
|
+
rootPath,
|
14
|
+
appPath: path.join(rootPath, "app"),
|
15
|
+
absolutePublicPath: path.join(
|
16
|
+
rootPath,
|
17
|
+
"public",
|
18
|
+
configFromRails.publicOutputPath
|
19
|
+
),
|
20
|
+
};
|
21
|
+
|
22
|
+
function railsRun(argument) {
|
23
|
+
if (isTest) {
|
24
|
+
return {
|
25
|
+
publicOutputPath: "frails",
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
const result = spawnSync("./bin/rails", ["runner", argument]);
|
30
|
+
|
31
|
+
if (result.status === 0) {
|
32
|
+
return JSON.parse(result.stdout.toString());
|
33
|
+
} else if (result.signal !== null) {
|
34
|
+
throw `Rails runner was terminated with signal: ${result.signal}`;
|
35
|
+
} else {
|
36
|
+
throw `Rails runner failed with '${result.error.toString()}'.`;
|
37
|
+
}
|
38
|
+
}
|