react_on_rails 6.0.5 → 6.1.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +2 -3
  3. data/.gitignore +1 -1
  4. data/.travis.yml +15 -13
  5. data/CHANGELOG.md +27 -15
  6. data/{docs/contributor-info/contributing.md → CONTRIBUTING.md} +24 -1
  7. data/Gemfile +1 -1
  8. data/KUDOS.md +3 -0
  9. data/NEWS.md +3 -0
  10. data/PROJECTS.md +1 -1
  11. data/README.md +143 -202
  12. data/app/helpers/react_on_rails_helper.rb +29 -17
  13. data/docs/additional-reading/node-server-rendering.md +127 -7
  14. data/docs/additional-reading/rails-assets.md +74 -10
  15. data/docs/additional-reading/react-router.md +1 -1
  16. data/docs/additional-reading/server-rendering-tips.md +3 -0
  17. data/docs/api/javascript-api.md +23 -0
  18. data/docs/contributor-info/releasing.md +1 -1
  19. data/docs/misc/doctrine.md +6 -6
  20. data/docs/tutorial.md +74 -93
  21. data/lib/generators/USAGE +5 -1
  22. data/lib/generators/react_on_rails/base_generator.rb +2 -2
  23. data/lib/generators/react_on_rails/install_generator.rb +8 -0
  24. data/lib/generators/react_on_rails/node_generator.rb +22 -0
  25. data/lib/generators/react_on_rails/templates/base/base/client/REACT_ON_RAILS_CLIENT_README.md +1 -1
  26. data/lib/generators/react_on_rails/templates/base/base/client/webpack.config.js +3 -2
  27. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +7 -3
  28. data/lib/generators/react_on_rails/templates/node/base/client/node/package.json +10 -0
  29. data/lib/generators/react_on_rails/templates/node/base/client/node/server.js +87 -0
  30. data/lib/react_on_rails/assets_precompile.rb +112 -0
  31. data/lib/react_on_rails/configuration.rb +1 -1
  32. data/lib/react_on_rails/server_rendering_pool.rb +1 -0
  33. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +1 -1
  34. data/lib/react_on_rails/utils.rb +1 -0
  35. data/lib/react_on_rails/version.rb +1 -1
  36. data/lib/react_on_rails/version_checker.rb +3 -2
  37. data/lib/tasks/assets.rake +10 -73
  38. data/package.json +9 -7
  39. metadata +7 -5
  40. data/Dockerfile_tests +0 -12
  41. data/docker-compose.yml +0 -11
@@ -9,6 +9,10 @@ can pass the redux option if you'd like to have redux setup for you automaticall
9
9
  to integrate the Redux state container framework. The necessary node modules
10
10
  will be automatically included for you.
11
11
 
12
+ * Node
13
+
14
+ Passing the --node generator option sets up the necessary files for node to render the react_components.
15
+
12
16
  *******************************************************************************
13
17
 
14
18
  After running the generator, you will want to:
@@ -21,4 +25,4 @@ Then you may run
21
25
 
22
26
  More Details:
23
27
 
24
- `https://github.com/shakacode/react_on_rails#generator`
28
+ `https://github.com/shakacode/react_on_rails/blob/master/docs/basics/generator.md`
@@ -23,7 +23,7 @@ module ReactOnRails
23
23
  def update_git_ignore
24
24
  data = <<-DATA.strip_heredoc
25
25
  # React on Rails
26
- npm-debug.log
26
+ npm-debug.log*
27
27
  node_modules
28
28
 
29
29
  # Generated js bundles
@@ -82,7 +82,7 @@ module ReactOnRails
82
82
  end
83
83
 
84
84
  def add_base_gems_to_gemfile
85
- append_to_file("Gemfile", "\ngem 'therubyracer', platforms: :ruby\n")
85
+ append_to_file("Gemfile", "\ngem 'mini_racer', platforms: :ruby\n")
86
86
  end
87
87
 
88
88
  ASSETS_RB_APPEND = <<-DATA.strip_heredoc
@@ -17,6 +17,13 @@ module ReactOnRails
17
17
  desc: "Install Redux gems and Redux version of Hello World Example. Default: false",
18
18
  aliases: "-R"
19
19
 
20
+ # --redux
21
+ class_option :node,
22
+ type: :boolean,
23
+ default: false,
24
+ desc: "Sets up node as a server rendering option. Default: false",
25
+ aliases: "-N"
26
+
20
27
  # --ignore-warnings
21
28
  class_option :ignore_warnings,
22
29
  type: :boolean,
@@ -46,6 +53,7 @@ module ReactOnRails
46
53
  invoke "react_on_rails:base"
47
54
  invoke "react_on_rails:react_no_redux" unless options.redux?
48
55
  invoke "react_on_rails:react_with_redux" if options.redux?
56
+ invoke "react_on_rails:node" if options.node?
49
57
  end
50
58
 
51
59
  # NOTE: other requirements for existing files such as .gitignore or application.
@@ -0,0 +1,22 @@
1
+ require "rails/generators"
2
+
3
+ module ReactOnRails
4
+ module Generators
5
+ class NodeGenerator < Rails::Generators::Base
6
+ Rails::Generators.hide_namespace(namespace)
7
+ source_root(File.expand_path("../templates", __FILE__))
8
+
9
+ def create_node_directory
10
+ empty_directory("client/node")
11
+ end
12
+
13
+ def copy_base_redux_files
14
+ base_path = "node/base/"
15
+ %w(client/node/server.js
16
+ client/node/package.json).each do |file|
17
+ copy_file(base_path + file, file)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -5,5 +5,5 @@ See documentation [at github.com/shakacode/react_on_rails](https://github.com/sh
5
5
  If you need additional help, please consider:
6
6
 
7
7
  * [Our ShakaCode Forum for React on Rails](https://forum.shakacode.com/c/rails/reactonrails).
8
- * Joining our Slack discussion room by [email us a bit about you and your project](mailto:contact@shakacode.com).
8
+ * Joining our Slack discussion room by [emailing us a bit about you and your project](mailto:contact@shakacode.com).
9
9
  * [Hiring us](https://forum.shakacode.com/c/rails/reactonrails) for coaching and custom web application development for your project.
@@ -4,7 +4,7 @@ const path = require('path');
4
4
  const devBuild = process.env.NODE_ENV !== 'production';
5
5
  const nodeEnv = devBuild ? 'development' : 'production';
6
6
 
7
- config = {
7
+ const config = {
8
8
  entry: [
9
9
  'es5-shim/es5-shim',
10
10
  'es5-shim/es5-sham',
@@ -38,7 +38,8 @@ config = {
38
38
  loader: 'imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham',
39
39
  },
40
40
  {
41
- test: /\.jsx?$/, loader: 'babel-loader',
41
+ test: /\.jsx?$/,
42
+ loader: 'babel-loader',
42
43
  exclude: /node_modules/,
43
44
  },
44
45
  ],
@@ -52,7 +52,7 @@ ReactOnRails.configure do |config|
52
52
 
53
53
  # Server rendering only (not for render_component helper)
54
54
  # You can configure your pool of JS virtual machines and specify where it should load code:
55
- # On MRI, use `therubyracer` for the best performance
55
+ # On MRI, use `mini_racer` for the best performance
56
56
  # (see [discussion](https://github.com/reactjs/react-rails/pull/290))
57
57
  # On MRI, you'll get a deadlock with `pool_size` > 1
58
58
  # If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
@@ -67,11 +67,15 @@ ReactOnRails.configure do |config|
67
67
  config.skip_display_none = false
68
68
 
69
69
  # The server render method - either ExecJS or NodeJS
70
+ <%- if options.node? -%>
71
+ config.server_render_method = "NodeJS"
72
+ <%- else -%>
70
73
  config.server_render_method = "ExecJS"
74
+ <%- end -%>
71
75
 
72
76
  # Client js uses assets not digested by rails.
73
- # For any asset matching this regex, non-digested symlink will be created
77
+ # For any asset matching this regex, non-digested symlink will be created (what webpack's css wants)
74
78
  # To disable symlinks set this parameter to nil.
75
- config.symlink_non_digested_assets_regex = /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/
79
+ config.symlink_non_digested_assets_regex = /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg|map)/
76
80
 
77
81
  end
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "react_on_rails_node",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "start": "node ./server.js -s webpack-bundle.js"
7
+ },
8
+ "dependencies": {
9
+ }
10
+ }
@@ -0,0 +1,87 @@
1
+ const net = require('net');
2
+ const fs = require('fs');
3
+
4
+ const bundlePath = '../../app/assets/webpack/';
5
+ let bundleFileName = 'webpack-bundle.js';
6
+
7
+ let currentArg;
8
+
9
+ function Handler() {
10
+ this.queue = [];
11
+ this.initialized = false;
12
+ }
13
+
14
+ Handler.prototype.handle = (connection) => {
15
+ const callback = () => {
16
+ connection.setEncoding('utf8');
17
+ connection.on('data', (data) => {
18
+ console.log(`Processing request: ${data}`);
19
+
20
+ // eslint-disable-next-line no-eval
21
+ const result = eval(data);
22
+ connection.write(result);
23
+ });
24
+ };
25
+
26
+ if (this.initialized) {
27
+ callback();
28
+ } else {
29
+ this.queue.push(callback);
30
+ }
31
+ };
32
+
33
+ Handler.prototype.initialize = () => {
34
+ console.log(`Processing ${this.queue.length} pending requests`);
35
+ let callback;
36
+
37
+ // eslint-disable-next-line no-cond-assign
38
+ while (callback = this.queue.pop()) {
39
+ callback();
40
+ }
41
+
42
+ this.initialized = true;
43
+ };
44
+
45
+ const handler = new Handler();
46
+
47
+ process.argv.forEach((val) => {
48
+ if (val[0] === '-') {
49
+ currentArg = val.slice(1);
50
+ return;
51
+ }
52
+
53
+ if (currentArg === 's') {
54
+ bundleFileName = val;
55
+ }
56
+ });
57
+
58
+ try {
59
+ fs.mkdirSync(bundlePath);
60
+ } catch (e) {
61
+ if (e.code !== 'EEXIST') throw e;
62
+ }
63
+
64
+ fs.watchFile(bundlePath + bundleFileName, (curr) => {
65
+ if (curr && curr.blocks && curr.blocks > 0) {
66
+ if (handler.initialized) {
67
+ console.log('Reloading server bundle must be implemented by restarting the node process!');
68
+ return;
69
+ }
70
+
71
+ // eslint-disable-next-line global-require
72
+ require(bundlePath + bundleFileName);
73
+ console.log(`Loaded server bundle: ${bundlePath + bundleFileName}`);
74
+ handler.initialize();
75
+ }
76
+ });
77
+
78
+ const unixServer = net.createServer((connection) => {
79
+ handler.handle(connection);
80
+ });
81
+
82
+ unixServer.listen('node.sock');
83
+
84
+ process.on('SIGINT', () => {
85
+ unixServer.close();
86
+ process.exit();
87
+ });
@@ -0,0 +1,112 @@
1
+ module ReactOnRails
2
+ class AssetsPrecompile
3
+ # Used by the rake task
4
+ def default_asset_path
5
+ dir = File.join(Rails.configuration.paths["public"].first,
6
+ Rails.configuration.assets.prefix)
7
+ Pathname.new(dir)
8
+ end
9
+
10
+ def initialize(assets_path: nil,
11
+ symlink_non_digested_assets_regex: nil,
12
+ generated_assets_dir: nil)
13
+ @assets_path = assets_path.presence || default_asset_path
14
+ @symlink_non_digested_assets_regex = symlink_non_digested_assets_regex.presence ||
15
+ ReactOnRails.configuration.symlink_non_digested_assets_regex
16
+ @generated_assets_dir = generated_assets_dir.presence || ReactOnRails.configuration.generated_assets_dir
17
+ end
18
+
19
+ # target and symlink are relative to the assets directory
20
+ def symlink_file(target, symlink)
21
+ target_path = @assets_path.join(target)
22
+ symlink_path = @assets_path.join(symlink)
23
+ target_exists = File.exist?(target_path)
24
+
25
+ # File.exist?(symlink_path) will check the file the sym is pointing to is existing
26
+ # File.lstat(symlink_path).symlink? confirms that this is a symlink
27
+ symlink_already_there_and_valid = File.exist?(symlink_path) &&
28
+ File.lstat(symlink_path).symlink?
29
+ if symlink_already_there_and_valid
30
+ puts "React On Rails: Digested #{symlink} already exists indicating #{target} did not change."
31
+ elsif target_exists
32
+ if File.exist?(symlink_path) && File.lstat(symlink_path).symlink?
33
+ puts "React On Rails: Removing invalid symlink #{symlink_path}"
34
+ `cd #{@assets_path} && rm #{symlink}`
35
+ end
36
+ # Might be like:
37
+ # "images/5cf5db49df178f9357603f945752a1ef.png":
38
+ # "images/5cf5db49df178f9357603f945752a1ef-033650e1d6193b70d59bb60e773f47b6d9aefdd56abc7cc.png"
39
+ # need to cd to directory and then symlink
40
+ target_sub_path, _divider, target_filename = target.rpartition("/")
41
+ _symlink_sub_path, _divider, symlink_filename = symlink.rpartition("/")
42
+ puts "React On Rails: Symlinking \"#{target}\" to \"#{symlink}\""
43
+ dest_path = File.join(@assets_path, target_sub_path)
44
+ FileUtils.chdir(dest_path) do
45
+ File.symlink(target_filename, symlink_filename)
46
+ end
47
+ end
48
+ end
49
+
50
+ def symlink_non_digested_assets
51
+ # digest ==> means that the file has a unique sha so the browser will load a new copy.
52
+ # Webpack's CSS extract-text-plugin copies digested asset files over to directory where we put
53
+ # we deploy the webpack compiled JS file. Since Rails will deploy the image files in this
54
+ # directory with a digest, then the files are essentially "double-digested" and the CSS
55
+ # references from webpack's CSS would be invalid. The fix is to symlink the double-digested
56
+ # file back to the original digested name, and make a similar symlink for the gz version.
57
+ if @symlink_non_digested_assets_regex
58
+ manifest_glob = Dir.glob(@assets_path.join(".sprockets-manifest-*.json")) +
59
+ Dir.glob(@assets_path.join("manifest-*.json"))
60
+ if manifest_glob.empty?
61
+ puts "Warning: React On Rails: expected to find .sprockets-manifest-*.json or manifest-*.json "\
62
+ "at #{@assets_path}, but found none. Canceling symlinking tasks."
63
+ return -1
64
+ end
65
+ manifest_path = manifest_glob.first
66
+ manifest_data = JSON.load(File.new(manifest_path))
67
+
68
+ # We realize that we're copying other Rails assets that match the regexp, but this just
69
+ # means that we'd be exposing the original, undigested names.
70
+ manifest_data["assets"].each do |original_filename, rails_digested_filename|
71
+ # TODO: we should remove any original_filename that is NOT in the webpack deploy folder.
72
+ next unless original_filename =~ @symlink_non_digested_assets_regex
73
+ # We're symlinking from the digested filename back to the original filename which has
74
+ # already been symlinked by Webpack
75
+ symlink_file(rails_digested_filename, original_filename)
76
+
77
+ # We want the gz ones as well
78
+ symlink_file("#{rails_digested_filename}.gz", "#{original_filename}.gz")
79
+ end
80
+ end
81
+ end
82
+
83
+ def delete_broken_symlinks
84
+ Dir.glob(@assets_path.join("*")).each do |filename|
85
+ next unless File.lstat(filename).symlink?
86
+ begin
87
+ target = File.readlink(filename)
88
+ rescue
89
+ puts "React on Rails: Warning: your platform doesn't support File::readlink method." /
90
+ "Skipping broken link check."
91
+ break
92
+ end
93
+ path = Pathname.new(File.dirname(filename))
94
+ target_path = path.join(target)
95
+ unless File.exist?(target_path)
96
+ puts "React on Rails: Deleting broken link: #{filename}"
97
+ File.delete(filename)
98
+ end
99
+ end
100
+ end
101
+
102
+ def clobber
103
+ dir = Rails.root.join(@generated_assets_dir)
104
+ if dir.present? && File.directory?(dir)
105
+ puts "Deleting files in directory #{dir}"
106
+ FileUtils.rm_r(Dir.glob(Rails.root.join("#{@generated_assets_dir}/*")))
107
+ else
108
+ puts "Could not find generated_assets_dir #{dir} defined in react_on_rails initializer: "
109
+ end
110
+ end
111
+ end
112
+ end
@@ -57,7 +57,7 @@ module ReactOnRails
57
57
  webpack_generated_files: [],
58
58
  rendering_extension: nil,
59
59
  server_render_method: "",
60
- symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/,
60
+ symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg|map)/,
61
61
  npm_build_test_command: "",
62
62
  npm_build_production_command: ""
63
63
  )
@@ -16,6 +16,7 @@ module ReactOnRails
16
16
  end
17
17
  end
18
18
 
19
+ # rubocop:disable Style/MethodMissing
19
20
  def method_missing(sym, *args, &block)
20
21
  pool.send sym, *args, &block
21
22
  end
@@ -45,7 +45,7 @@ Detected are the following stale generated files:
45
45
  #{stale_files.join("\n")}
46
46
 
47
47
  React on Rails will ensure your JavaScript generated files are up to date, using your
48
- /client level package.json `build:test` command.
48
+ /client level package.json `#{ReactOnRails.configuration.npm_build_test_command}` command.
49
49
 
50
50
  MSG
51
51
  end
@@ -11,6 +11,7 @@ module ReactOnRails
11
11
  end
12
12
 
13
13
  def self.last_process_completed_successfully?
14
+ # rubocop:disable Style/NumericPredicate
14
15
  $CHILD_STATUS.exitstatus == 0
15
16
  end
16
17
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ReactOnRails
3
- VERSION = "6.0.5".freeze
3
+ VERSION = "6.1.0".freeze
4
4
  end
@@ -3,6 +3,7 @@ module ReactOnRails
3
3
  # against each otherat runtime.
4
4
  class VersionChecker
5
5
  attr_reader :node_package_version, :logger
6
+ MAJOR_VERSION_REGEX = /(\d+)\.?/
6
7
 
7
8
  def self.build
8
9
  new(NodePackageVersion.build, Rails.logger)
@@ -38,7 +39,7 @@ module ReactOnRails
38
39
  end
39
40
 
40
41
  def gem_major_version
41
- gem_version.match(/(\d+)\./)[1]
42
+ gem_version.match(MAJOR_VERSION_REGEX)[1]
42
43
  end
43
44
 
44
45
  class NodePackageVersion
@@ -66,7 +67,7 @@ module ReactOnRails
66
67
 
67
68
  def major
68
69
  return if relative_path?
69
- raw.match(/(\d+)\./)[1]
70
+ raw.match(MAJOR_VERSION_REGEX)[1]
70
71
  end
71
72
 
72
73
  private
@@ -1,72 +1,15 @@
1
- module ReactOnRails
2
- class << self
3
- def assets_path
4
- dir = File.join(Rails.configuration.paths['public'].first,
5
- Rails.configuration.assets.prefix)
6
- Pathname.new(dir)
7
- end
8
-
9
- def symlink_file(target, symlink)
10
- target_path = ReactOnRails::assets_path.join(target)
11
- symlink_path = ReactOnRails::assets_path.join(symlink)
12
- if not File.exist?(symlink_path) or File.lstat(symlink_path).symlink?
13
- if File.exist?(target_path)
14
- puts "React On Rails: Symlinking #{target_path} to #{symlink_path}"
15
- `cd #{ReactOnRails::assets_path} && ln -s #{target} #{symlink}`
16
- end
17
- else
18
- puts "React On Rails: File #{symlink_path} already exists. Failed to symlink #{target_path}"
19
- end
20
- end
21
- end
22
- end
1
+ require "react_on_rails/assets_precompile"
23
2
 
24
3
  namespace :react_on_rails do
25
4
  namespace :assets do
26
5
  desc "Creates non-digested symlinks for the assets in the public asset dir"
27
6
  task symlink_non_digested_assets: :"assets:environment" do
28
- if ReactOnRails.configuration.symlink_non_digested_assets_regex
29
- manifest_glob = Dir.glob(ReactOnRails::assets_path.join(".sprockets-manifest-*.json")) +
30
- Dir.glob(ReactOnRails::assets_path.join("manifest-*.json"))
31
- if manifest_glob.empty?
32
- puts "Warning: React On Rails: expected to find .sprockets-manifest-*.json or manifest-*.json "\
33
- "at #{ReactOnRails::assets_path}, but found none. Canceling symlinking tasks."
34
- next
35
- end
36
- manifest_path = manifest_glob.first
37
- manifest_data = JSON.load(File.new(manifest_path))
38
-
39
- manifest_data["assets"].each do |logical_path, digested_path|
40
- regex = ReactOnRails.configuration.symlink_non_digested_assets_regex
41
- if logical_path =~ regex
42
- digested_gz_path = "#{digested_path}.gz"
43
- logical_gz_path = "#{logical_path}.gz"
44
- ReactOnRails::symlink_file(digested_path, logical_path)
45
- ReactOnRails::symlink_file(digested_gz_path, logical_gz_path)
46
- end
47
- end
48
- end
7
+ ReactOnRails::AssetsPrecompile.new.symlink_non_digested_assets
49
8
  end
50
9
 
51
10
  desc "Cleans all broken symlinks for the assets in the public asset dir"
52
11
  task delete_broken_symlinks: :"assets:environment" do
53
- Dir.glob(ReactOnRails::assets_path.join("*")).each do |filename|
54
- if File.lstat(filename).symlink?
55
- begin
56
- target = File.readlink(filename)
57
- rescue
58
- puts "React on Rails: Warning: your platform doesn't support File::readlink method."/
59
- "Skipping broken link check."
60
- return
61
- end
62
- path = Pathname.new(File.dirname(filename))
63
- target_path = path.join(target)
64
- unless File.exist?(target_path)
65
- puts "React on Rails: Deleting broken link: #{filename}"
66
- File.delete(filename)
67
- end
68
- end
69
- end
12
+ ReactOnRails::AssetsPrecompile.new.delete_broken_symlinks
70
13
  end
71
14
 
72
15
  # In this task, set prerequisites for the assets:precompile task
@@ -93,13 +36,7 @@ sh "cd client && `ReactOnRails.configuration.npm_build_production_command`"
93
36
 
94
37
  desc "Delete assets created with webpack, in the generated assetst directory (/app/assets/webpack)"
95
38
  task clobber: :environment do
96
- dir = Rails.root.join(ReactOnRails.configuration.generated_assets_dir)
97
- if dir.present? && File.directory?(dir)
98
- puts "Deleting files in directory #{dir}"
99
- rm_r Dir.glob(Rails.root.join("#{ReactOnRails.configuration.generated_assets_dir}/*"))
100
- else
101
- puts "Could not find dir #{dir}"
102
- end
39
+ ReactOnRails::AssetsPrecompile.new.clobber
103
40
  end
104
41
  end
105
42
  end
@@ -107,10 +44,10 @@ end
107
44
  # These tasks run as pre-requisites of assets:precompile.
108
45
  # Note, it's not possible to refer to ReactOnRails configuration values at this point.
109
46
  Rake::Task["assets:precompile"]
110
- .clear_prerequisites
111
- .enhance([:environment, "react_on_rails:assets:compile_environment"])
112
- .enhance do
113
- Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke
114
- Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke
115
- end
47
+ .clear_prerequisites
48
+ .enhance([:environment, "react_on_rails:assets:compile_environment"])
49
+ .enhance do
50
+ Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke
51
+ Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke
52
+ end
116
53