diff --git a/Gemfile b/Gemfile index 77b86575..a4879f2e 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby "3.3.4" gem "react_on_rails", "16.1.1" -gem "shakapacker", "8.2.0" +gem "shakapacker", "8.4.0" # Bundle edge Rails instead: gem "rails", github: "rails/rails" gem "listen" diff --git a/Gemfile.lock b/Gemfile.lock index b0cddd1d..a55f29f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -390,7 +390,7 @@ GEM websocket (~> 1.0) semantic_range (3.1.0) sexp_processor (4.17.1) - shakapacker (8.2.0) + shakapacker (8.4.0) activesupport (>= 5.2) package_json rack-proxy (>= 0.6.1) @@ -499,7 +499,7 @@ DEPENDENCIES scss_lint sdoc selenium-webdriver (~> 4) - shakapacker (= 8.2.0) + shakapacker (= 8.4.0) spring spring-commands-rspec stimulus-rails (~> 1.3) diff --git a/Procfile.dev b/Procfile.dev index 20453bbe..650af5e4 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,7 +1,5 @@ # Procfile for development using HMR # You can run these commands in separate shells -rescript: yarn res:dev -redis: redis-server rails: bundle exec rails s -p 3000 -wp-client: HMR=true RAILS_ENV=development NODE_ENV=development bin/shakapacker-dev-server -wp-server: bundle exec rake react_on_rails:locale && HMR=true SERVER_BUNDLE_ONLY=yes bin/shakapacker --watch +wp-client: WEBPACK_SERVE=true bin/shakapacker-dev-server +wp-server: SERVER_BUNDLE_ONLY=yes bin/shakapacker --watch diff --git a/Procfile.dev-prod-assets b/Procfile.dev-prod-assets index 096efc60..5e970472 100644 --- a/Procfile.dev-prod-assets +++ b/Procfile.dev-prod-assets @@ -1,10 +1,8 @@ -# You can run these commands in separate shells -web: bin/rails s -p 3001 -redis: redis-server +# Procfile for development with production assets +# Uses production-optimized, precompiled assets with development environment +# Uncomment additional processes as needed for your app -# Next line runs a watch process with webpack to compile the changed files. -# When making frequent changes to client side assets, you will prefer building webpack assets -# upon saving rather than when you refresh your browser page. -# Note, if using React on Rails localization you will need to run -# `bundle exec rake react_on_rails:locale` before you run bin/shakapacker -webpack: sh -c 'bundle exec rake react_on_rails:locale && rm -rf public/packs/* || true && bin/shakapacker -w' +rails: bundle exec rails s -p 3001 +# sidekiq: bundle exec sidekiq -C config/sidekiq.yml +# redis: redis-server +# mailcatcher: mailcatcher --foreground diff --git a/Procfile.dev-static-assets b/Procfile.dev-static-assets index 4561761a..75152f0e 100644 --- a/Procfile.dev-static-assets +++ b/Procfile.dev-static-assets @@ -1,10 +1,2 @@ -# You can run these commands in separate shells -web: bin/rails s -p 3000 -redis: redis-server - -# Next line runs a watch process with webpack to compile the changed files. -# When making frequent changes to client side assets, you will prefer building webpack assets -# upon saving rather than when you refresh your browser page. -# Note, if using React on Rails localization you will need to run -# `bundle exec rake react_on_rails:locale` before you run bin/shakapacker -webpack: sh -c 'bundle exec rake react_on_rails:locale && rm -rf public/packs/* || true && bin/shakapacker -w' +web: bin/rails server -p 3000 +js: bin/shakapacker --watch diff --git a/app/controllers/hello_world_controller.rb b/app/controllers/hello_world_controller.rb new file mode 100644 index 00000000..ad09c5ef --- /dev/null +++ b/app/controllers/hello_world_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class HelloWorldController < ApplicationController + layout "hello_world" + + def index + @hello_world_props = { name: "Stranger" } + end +end diff --git a/app/javascript/generated b/app/javascript/generated new file mode 120000 index 00000000..ec645461 --- /dev/null +++ b/app/javascript/generated @@ -0,0 +1 @@ +../../client/app/generated \ No newline at end of file diff --git a/app/javascript/packs/generated b/app/javascript/packs/generated new file mode 120000 index 00000000..64ef33c0 --- /dev/null +++ b/app/javascript/packs/generated @@ -0,0 +1 @@ +../../../client/app/packs/generated \ No newline at end of file diff --git a/app/javascript/packs/server-bundle.js b/app/javascript/packs/server-bundle.js new file mode 100644 index 00000000..28a58fd4 --- /dev/null +++ b/app/javascript/packs/server-bundle.js @@ -0,0 +1,3 @@ +// import statement added by react_on_rails:generate_packs rake task +import "./../generated/server-bundle-generated.js" +// Placeholder comment - auto-generated imports will be prepended here by react_on_rails:generate_packs diff --git a/app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css b/app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css new file mode 100644 index 00000000..1983caaa --- /dev/null +++ b/app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css @@ -0,0 +1,4 @@ +.bright { + color: green; + font-weight: bold; +} diff --git a/app/views/layouts/hello_world.html.erb b/app/views/layouts/hello_world.html.erb new file mode 100644 index 00000000..59a52bad --- /dev/null +++ b/app/views/layouts/hello_world.html.erb @@ -0,0 +1,15 @@ + + + + ReactOnRailsWithShakapacker + <%= csrf_meta_tags %> + + + <%= stylesheet_pack_tag %> + <%= javascript_pack_tag %> + + + + <%= yield %> + + diff --git a/babel.config.js b/babel.config.js index 6e2c3800..9953e2a5 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,32 +1,36 @@ +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/babel.config.js + module.exports = function (api) { - const defaultConfigFunc = require('shakapacker/package/babel/preset.js'); - const resultConfig = defaultConfigFunc(api); - const isProductionEnv = api.env('production'); + const defaultConfigFunc = require('shakapacker/package/babel/preset.js') + const resultConfig = defaultConfigFunc(api) + const isProductionEnv = api.env('production') const changesOnDefault = { presets: [ [ '@babel/preset-react', { - runtime: 'automatic', development: !isProductionEnv, useBuiltIns: true, - }, - ], + runtime: 'automatic' + } + ] ].filter(Boolean), plugins: [ - process.env.WEBPACK_SERVE && 'react-refresh/babel', - isProductionEnv && [ - 'babel-plugin-transform-react-remove-prop-types', + // Enable React Refresh (Fast Refresh) only when webpack-dev-server is running (HMR mode) + // This prevents React Refresh from trying to connect when using static compilation + !isProductionEnv && process.env.WEBPACK_SERVE && 'react-refresh/babel', + isProductionEnv && ['babel-plugin-transform-react-remove-prop-types', { - removeImport: true, - }, - ], + removeImport: true + } + ] ].filter(Boolean), - }; + } - resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]; - resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins]; + resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets] + resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ] - return resultConfig; -}; + return resultConfig +} diff --git a/config/initializers/react_on_rails.rb b/config/initializers/react_on_rails.rb index 2a1faceb..f1b1a866 100644 --- a/config/initializers/react_on_rails.rb +++ b/config/initializers/react_on_rails.rb @@ -1,90 +1,67 @@ # frozen_string_literal: true -# Shown below are the defaults for configuration -ReactOnRails.configure do |config| - # Auto-registration configuration for v16 - config.components_subdirectory = "ror_components" - config.auto_load_bundle = true - - config.build_test_command = "RAILS_ENV=test bin/shakapacker" - config.build_production_command = "RAILS_ENV=production NODE_ENV=production bin/shakapacker" +# See https://github.com/shakacode/react_on_rails/blob/master/docs/guides/configuration.md +# for many more options. - # This is the file used for server rendering of React when using `(prerender: true)` - # If you are never using server rendering, you may set this to "". - # If you are using the same file for client and server rendering, having this set probably does - # not affect performance. - config.server_bundle_js_file = "server-bundle.js" +ReactOnRails.configure do |config| + # This configures the script to run to build the production assets by webpack. Set this to nil + # if you don't want react_on_rails building this file for you. + # If nil, then the standard shakacode/shakapacker assets:precompile will run + # config.build_production_command = nil - # Server bundle output path for private SSR bundles (React on Rails 16+) - # This keeps server bundles separate from public assets for security - # Using the default from React on Rails docs - config.server_bundle_output_path = "ssr-generated" + ################################################################################ + ################################################################################ + # TEST CONFIGURATION OPTIONS + # Below options are used with the use of this test helper: + # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) + ################################################################################ - # React on Rails 16 compatibility: Workaround for removed error handling + # If you are using this in your spec_helper.rb (or rails_helper.rb): # - # BREAKING CHANGE in v16: React on Rails 14.2.1 had robust error handling that would - # fallback to the Shakapacker output path when bundle lookup failed. This was removed - # in v16.0.1.rc.2, causing it to look in the wrong directory during tests. + # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) # - # This configuration tells React on Rails where to find bundles in test environment. - # Without this, it defaults to public/webpack/test/ instead of public/packs/ - config.generated_assets_dir = Rails.public_path.join("packs").to_s if Rails.env.test? + # with rspec then this controls what npm command is run + # to automatically refresh your webpack assets on every test run. + # + # Alternately, you can remove the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets` + # and set the config/shakapacker.yml option for test to true. + config.build_test_command = "RAILS_ENV=test bin/shakapacker" ################################################################################ - # CLIENT RENDERING OPTIONS - # Below options can be overriden by passing options to the react_on_rails - # `render_component` view helper method. - ################################################################################ - - # Default is false. Can be overriden at the component level. - # Set to false for debugging issues before turning on to true. - config.prerender = true - - # default is true for development, off otherwise - config.trace = Rails.env.development? - ################################################################################ # SERVER RENDERING OPTIONS - # Applicable options can be overriden by passing options to the react_on_rails - # `render_component` view helper method. ################################################################################ + # This is the file used for server rendering of React when using `(prerender: true)` + # If you are never using server rendering, you should set this to "". + # Note, there is only one server bundle, unlike JavaScript where you want to minimize the size + # of the JS sent to the client. For the server rendering, React on Rails creates a pool of + # JavaScript execution instances which should handle any component requested. + # + # While you may configure this to be the same as your client bundle file, this file is typically + # different. You should have ONE server bundle which can create all of your server rendered + # React components. + # + config.server_bundle_js_file = "server-bundle.js" - # If set to true, this forces Rails to reload the server bundle if it is modified - config.development_mode = Rails.env.development? - - # For server rendering. This can be set to false so that server side messages are discarded. - # Default is true. Be cautious about turning this off. - config.replay_console = true - - # Default is true. Logs server rendering messages to Rails.logger.info - config.logging_on_server = true - - # Change to true to raise exception on server if the JS code throws. Let's do this only if not - # in production, as the JS code might still work on the client and we don't want to blow up the - # whole Rails page. - config.raise_on_prerender_error = !Rails.env.production? + # Configure where server bundles are output. Defaults to "ssr-generated". + # This should match your webpack configuration for server bundles. + config.server_bundle_output_path = "ssr-generated" - # Server rendering only (not for render_component helper) - # You can configure your pool of JS virtual machines and specify where it should load code: - # On MRI, use `therubyracer` for the best performance - # (see [discussion](https://github.com/reactjs/react-rails/pull/290)) - # On MRI, you'll get a deadlock with `pool_size` > 1 - # If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering. - config.server_renderer_pool_size = 1 # increase if you're on JRuby - config.server_renderer_timeout = 20 # seconds + # Enforce that server bundles are only loaded from private (non-public) directories. + # When true, server bundles will only be loaded from the configured server_bundle_output_path. + # This is recommended for production to prevent server-side code from being exposed. + config.enforce_private_server_bundles = true ################################################################################ - # I18N OPTIONS - ################################################################################ - # Replace the following line to the location where you keep translation.js & default.js. - config.i18n_dir = Rails.root.join("client/app/libs/i18n") - ################################################################################ - # MISCELLANEOUS OPTIONS + # FILE SYSTEM BASED COMPONENT REGISTRY ################################################################################ - - # This allows you to add additional values to the Rails Context. Implement one static method - # called `custom_context(view_context)` and return a Hash. - config.rendering_extension = nil - config.i18n_output_format = "js" + # `components_subdirectory` is the name of the matching directories that contain automatically registered components + # for use in the Rails views. The default is nil, you can enable the feature by updating it in the next line. + config.components_subdirectory = "ror_components" + # + # For automated component registry, `render_component` view helper method tries to load bundle for component from + # generated directory. default is false, you can pass option at the time of individual usage or update the default + # in the following line + config.auto_load_bundle = true end diff --git a/config/routes.rb b/config/routes.rb index 1d8c7b7a..946aff4c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true Rails.application.routes.draw do + get 'hello_world', to: 'hello_world#index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html # Serve websocket cable requests in-process diff --git a/config/shakapacker.yml b/config/shakapacker.yml index ebc5e4c5..61c81837 100644 --- a/config/shakapacker.yml +++ b/config/shakapacker.yml @@ -1,47 +1,109 @@ # Note: You must restart bin/shakapacker-dev-server for changes to take effect +# This file contains the defaults used by shakapacker. default: &default source_path: client/app + + # You can have a subdirectory of the source_path, like 'packs' (recommended). + # Alternatively, you can use '/' to use the whole source_path directory. + # Notice that this is a relative path to source_path source_entry_path: packs + + # If nested_entries is true, then we'll pick up subdirectories within the source_entry_path. + # You cannot set this option to true if you set source_entry_path to '/' + nested_entries: true + + # While using a File-System-based automated bundle generation feature, miscellaneous warnings suggesting css order + # conflicts may arise due to the mini-css-extract-plugin. For projects where css ordering has been mitigated through + # consistent use of scoping or naming conventions, the css order warnings can be disabled by setting + # css_extract_ignore_order_warnings to true + css_extract_ignore_order_warnings: false + public_root_path: public public_output_path: packs cache_path: tmp/shakapacker webpack_compile_output: true - nested_entries: true + # See https://github.com/shakacode/shakapacker#deployment + shakapacker_precompile: true + + # Location for manifest.json, defaults to {public_output_path}/manifest.json if unset + # manifest_path: public/packs/manifest.json - # Additional paths webpack should lookup modules + # Additional paths webpack should look up modules # ['app/assets', 'engine/foo/app/assets'] additional_paths: [] # Reload manifest.json on all requests so we reload latest compiled packs cache_manifest: false - - # Use the config.build_production_command in config/initializers/react_on_rails.rb - shakapacker_precompile: false + + # Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild' + webpack_loader: 'babel' + + # Raises an error if there is a mismatch in the shakapacker gem and npm package being used + ensure_consistent_versioning: true + + # Select whether the compiler will use SHA digest ('digest' option) or most recent modified timestamp ('mtime') to determine freshness + compiler_strategy: digest + + # Select whether the compiler will always use a content hash and not just in production + # Don't use contentHash except for production for performance + # https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling + useContentHash: false + + # Setting the asset host here will override Rails.application.config.asset_host. + # Here, you can set different asset_host per environment. Note that + # SHAKAPACKER_ASSET_HOST will override both configurations. + # asset_host: custom-path + + # Utilizing webpack-subresource-integrity plugin, will generate integrity hashes for all entries in manifest.json + # https://github.com/waysact/webpack-subresource-integrity/tree/main/webpack-subresource-integrity + integrity: + enabled: false + # Which cryptographic function(s) to use, for generating the integrity hash(es). Default sha-384. Other possible values sha256, sha512 + hash_functions: ["sha384"] + # Default "anonymous". Other possible value "use-credentials" + # https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#cross-origin_resource_sharing_and_subresource_integrity + cross_origin: "anonymous" development: <<: *default - # This is false since we're running `bin/shakapacker -w` in Procfile.dev-setic - compile: false + compile: true + compiler_strategy: mtime # Reference: https://webpack.js.org/configuration/dev-server/ + # Keys not described there are documented inline and in https://github.com/shakacode/shakapacker/ dev_server: - https: false + # For running dev server with https, set `server: https`. + # server: https + host: localhost port: 3035 # Hot Module Replacement updates modules while the application is running without a full reload + # Used instead of the `hot` key in https://webpack.js.org/configuration/dev-server/#devserverhot hmr: true + # If HMR is on, CSS will be inlined by delivering it as part of the script payload via style-loader. Be sure + # that you add style-loader to your project dependencies. + # + # If you want to instead deliver CSS via with the mini-css-extract-plugin, set inline_css to false. + # In that case, style-loader is not needed as a dependency. + # + # mini-css-extract-plugin is a required dependency in both cases. + inline_css: true + # Defaults to the inverse of hmr. Uncomment to manually set this. + # live_reload: true client: # Should we show a full-screen overlay in the browser when there are compiler errors or warnings? overlay: true # May also be a string # webSocketURL: - # hostname: "0.0.0.0" - # pathname: "/ws" + # hostname: '0.0.0.0' + # pathname: '/ws' # port: 8080 + # Should we use gzip compression? compress: true # Note that apps that do not check the host are vulnerable to DNS rebinding attacks - allowed_hosts: [ 'localhost' ] + allowed_hosts: 'auto' + # Shows progress and colorizes output of bin/shakapacker[-dev-server] pretty: true headers: 'Access-Control-Allow-Origin': '*' @@ -53,11 +115,17 @@ test: <<: *default compile: true + # Compile test packs to a separate directory + public_output_path: packs-test + production: <<: *default # Production depends on precompilation of packs prior to booting for performance. compile: false + # Use content hash for naming assets. Cannot be overridden in production. + useContentHash: true + # Cache manifest.json for performance cache_manifest: true diff --git a/config/webpack/alias.js b/config/webpack/alias.js index 5645c184..8d904c85 100644 --- a/config/webpack/alias.js +++ b/config/webpack/alias.js @@ -4,6 +4,7 @@ module.exports = { resolve: { alias: { Assets: resolve(__dirname, '..', '..', 'client', 'app', 'assets'), + libs: resolve(__dirname, '..', '..', 'client', 'app', 'libs'), }, }, }; diff --git a/config/webpack/clientWebpackConfig.js b/config/webpack/clientWebpackConfig.js index d1e29def..ad6b4383 100644 --- a/config/webpack/clientWebpackConfig.js +++ b/config/webpack/clientWebpackConfig.js @@ -1,5 +1,5 @@ -// The source code including full typescript support is available at: -// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/clientWebpackConfig.js +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/clientWebpackConfig.js const webpack = require('webpack'); const commonWebpackConfig = require('./commonWebpackConfig'); @@ -25,4 +25,3 @@ const configureClient = () => { }; module.exports = configureClient; - diff --git a/config/webpack/commonWebpackConfig.js b/config/webpack/commonWebpackConfig.js index b1d64ca2..58f33ef3 100644 --- a/config/webpack/commonWebpackConfig.js +++ b/config/webpack/commonWebpackConfig.js @@ -1,10 +1,12 @@ -// The source code including full typescript support is available at: -// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/commonWebpackConfig.js +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/commonWebpackConfig.js // Common configuration applying to client and server configuration const { generateWebpackConfig, merge } = require('shakapacker'); +const aliasConfig = require('./alias'); const baseClientWebpackConfig = generateWebpackConfig(); + const commonOptions = { resolve: { extensions: ['.css', '.ts', '.tsx'], @@ -57,7 +59,6 @@ if (sassLoaderIndex !== -1) { baseClientWebpackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig); // Copy the object using merge b/c the baseClientWebpackConfig and commonOptions are mutable globals -const commonWebpackConfig = () => merge({}, baseClientWebpackConfig, commonOptions, ignoreWarningsConfig); - -module.exports = commonWebpackConfig; +const commonWebpackConfig = () => merge({}, baseClientWebpackConfig, commonOptions, aliasConfig, ignoreWarningsConfig); +module.exports = commonWebpackConfig; \ No newline at end of file diff --git a/config/webpack/development.js b/config/webpack/development.js index 6b6b7609..99e63775 100644 --- a/config/webpack/development.js +++ b/config/webpack/development.js @@ -1,29 +1,22 @@ -// The source code including full typescript support is available at: -// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/development.js - -process.env.NODE_ENV = process.env.NODE_ENV || 'development'; +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/development.js const { devServer, inliningCss } = require('shakapacker'); -const webpackConfig = require('./webpackConfig'); +const generateWebpackConfigs = require('./generateWebpackConfigs'); const developmentEnvOnly = (clientWebpackConfig, _serverWebpackConfig) => { - // plugins - if (inliningCss) { - // Note, when this is run, we're building the server and client bundles in separate processes. - // Thus, this plugin is not applied to the server bundle. - + // React Refresh (Fast Refresh) setup - only when webpack-dev-server is running (HMR mode) + // This matches the condition in generateWebpackConfigs.js and babel.config.js + if (process.env.WEBPACK_SERVE) { // eslint-disable-next-line global-require const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); clientWebpackConfig.plugins.push( new ReactRefreshWebpackPlugin({ - overlay: { - sockPort: devServer.port, - }, + // Use default overlay configuration for better compatibility }), ); } }; -module.exports = webpackConfig(developmentEnvOnly); - +module.exports = generateWebpackConfigs(developmentEnvOnly); diff --git a/config/webpack/generateWebpackConfigs.js b/config/webpack/generateWebpackConfigs.js new file mode 100644 index 00000000..08e5f376 --- /dev/null +++ b/config/webpack/generateWebpackConfigs.js @@ -0,0 +1,37 @@ +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/webpackConfig.js + +const clientWebpackConfig = require('./clientWebpackConfig'); +const serverWebpackConfig = require('./serverWebpackConfig'); + +const webpackConfig = (envSpecific) => { + const clientConfig = clientWebpackConfig(); + const serverConfig = serverWebpackConfig(); + + if (envSpecific) { + envSpecific(clientConfig, serverConfig); + } + + let result; + // For HMR, need to separate the the client and server webpack configurations + if (process.env.WEBPACK_SERVE || process.env.CLIENT_BUNDLE_ONLY) { + // eslint-disable-next-line no-console + console.log('[React on Rails] Creating only the client bundles.'); + result = clientConfig; + } else if (process.env.SERVER_BUNDLE_ONLY) { + // eslint-disable-next-line no-console + console.log('[React on Rails] Creating only the server bundle.'); + result = serverConfig; + } else { + // default is the standard client and server build + // eslint-disable-next-line no-console + console.log('[React on Rails] Creating both client and server bundles.'); + result = [clientConfig, serverConfig]; + } + + // To debug, uncomment next line and inspect "result" + // debugger + return result; +}; + +module.exports = webpackConfig; diff --git a/config/webpack/production.js b/config/webpack/production.js index 9faa5179..dce3586b 100644 --- a/config/webpack/production.js +++ b/config/webpack/production.js @@ -1,12 +1,10 @@ -// The source code including full typescript support is available at: -// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/production.js +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/production.js -process.env.NODE_ENV = process.env.NODE_ENV || 'production'; - -const webpackConfig = require('./webpackConfig'); +const generateWebpackConfigs = require('./generateWebpackConfigs'); const productionEnvOnly = (_clientWebpackConfig, _serverWebpackConfig) => { // place any code here that is for production only }; -module.exports = webpackConfig(productionEnvOnly); +module.exports = generateWebpackConfigs(productionEnvOnly); diff --git a/config/webpack/serverWebpackConfig.js b/config/webpack/serverWebpackConfig.js index a6e9631d..26147c66 100644 --- a/config/webpack/serverWebpackConfig.js +++ b/config/webpack/serverWebpackConfig.js @@ -1,8 +1,7 @@ -// The source code including full typescript support is available at: -// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/serverWebpackConfig.js +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/serverWebpackConfig.js -const path = require('path'); -const { config } = require('shakapacker'); +const { merge, config } = require('shakapacker'); const commonWebpackConfig = require('./commonWebpackConfig'); const webpack = require('webpack'); @@ -46,15 +45,14 @@ const configureServer = () => { // Custom output for the server-bundle that matches the config in // config/initializers/react_on_rails.rb - // Output to a private directory for SSR bundles (not in public/) - // Using the default React on Rails path: ssr-generated + // Server bundles are output to a private directory (not public) for security serverWebpackConfig.output = { filename: 'server-bundle.js', globalObject: 'this', // If using the React on Rails Pro node server renderer, uncomment the next line // libraryTarget: 'commonjs2', - path: path.resolve(__dirname, '../../ssr-generated'), - publicPath: config.publicPath, + path: require('path').resolve(__dirname, '../../ssr-generated'), + // No publicPath needed since server bundles are not served via web // https://webpack.js.org/configuration/output/#outputglobalobject }; diff --git a/config/webpack/test.js b/config/webpack/test.js index 8c378b39..eb449326 100644 --- a/config/webpack/test.js +++ b/config/webpack/test.js @@ -1,7 +1,10 @@ -const webpackConfig = require('./webpackConfig'); +// The source code including full typescript support is available at: +// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/test.js + +const generateWebpackConfigs = require('./generateWebpackConfigs') const testOnly = (_clientWebpackConfig, _serverWebpackConfig) => { // place any code here that is for test only -}; +} -module.exports = webpackConfig(testOnly); +module.exports = generateWebpackConfigs(testOnly) diff --git a/package.json b/package.json index afa73247..ebb99b62 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "sass": "^1.58.3", "sass-loader": "^13.3.2", "sass-resources-loader": "^2.2.5", - "shakapacker": "8.2.0", + "shakapacker": "8.4.0", "stimulus": "^3.0.1", "style-loader": "^3.3.1", "tailwindcss": "^3.3.3", diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 21f7a611..27a7fcc9 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -38,6 +38,11 @@ Rails.root.glob("spec/support/**/*.rb").sort.each { |f| require f } RSpec.configure do |config| + # Ensure that if we are running js tests, we are using latest webpack assets + # This will use the defaults of :js and :server_rendering meta tags + ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) +end + config.include FactoryBot::Syntax::Methods # Ensure that if we are running js tests, we are using latest webpack assets # This will use the defaults of :js and :server_rendering meta tags diff --git a/yarn.lock b/yarn.lock index 0189edd8..62a91c94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2905,9 +2905,9 @@ balanced-match@^1.0.0: integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== baseline-browser-mapping@^2.8.3: - version "2.8.8" - resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.8.tgz#ca0de7b23bf9c49d72e21dcbfba26f2bb223ea2e" - integrity sha512-be0PUaPsQX/gPWWgFsdD+GFzaoig5PXaUC1xLkQiYdDnANU8sMnHoQd8JhbJQuvTWrWLyeFN9Imb5Qtfvr4RrQ== + version "2.8.9" + resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.9.tgz#fd0b8543c4f172595131e94965335536b3101b75" + integrity sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA== batch@0.6.1: version "0.6.1" @@ -3888,9 +3888,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.5.218: - version "1.5.226" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.226.tgz#2f9f795829dc5c5d1c5387f4c2648ca180cc933d" - integrity sha512-0tS/r72Ze0WUBiDwnqw4X43TxA7gEuZg0kFwLthoCzkshIbNQFjkf6D8xEzBe6tY6Y65fUhZIuNedTugw+11Lw== + version "1.5.227" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.227.tgz#c81b6af045b0d6098faed261f0bd611dc282d3a7" + integrity sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA== emittery@^0.13.1: version "0.13.1" @@ -8263,10 +8263,10 @@ setprototypeof@1.2.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -shakapacker@8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-8.2.0.tgz#c7bed87b8be2ae565cfe616f68552be545c77e14" - integrity sha512-Ct7BFqJVnKbxdqCzG+ja7Q6LPt/PlB7sSVBfG5jsAvmVCADM05cuoNwEgYNjFGKbDzHAxUqy5XgoI9Y030+JKQ== +shakapacker@8.4.0: + version "8.4.0" + resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-8.4.0.tgz#be37a2adba5a090f581811b8c0c1a00f2e227580" + integrity sha512-ZfuxfHxy5tdjv7tCdRZHJKJQLDFwvFXOVBVUj150zgNuRKUlOAyXzOBp9/G5hUhu4MLzuPAif/fuKOdjnZeVtw== dependencies: js-yaml "^4.1.0" path-complete-extname "^1.0.0"