From 14bd0808cf5115875a135ae2dc0282556fbaf8ae Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 12:01:26 -0300
Subject: [PATCH 01/14] Display error message when no
config.server_bundle_js_file is provided
---
lib/react_on_rails/helper.rb | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/lib/react_on_rails/helper.rb b/lib/react_on_rails/helper.rb
index 9e638502d..13f25128a 100644
--- a/lib/react_on_rails/helper.rb
+++ b/lib/react_on_rails/helper.rb
@@ -54,6 +54,17 @@ module Helper
# random_dom_id can be set to override the default from the config/initializers. That's only
# used if you have multiple instance of the same component on the Rails view.
def react_component(component_name, options = {})
+ config_server_bundle_js = ReactOnRails.configuration.server_bundle_js_file
+ if options[:prerender] == true && (config_server_bundle_js.nil? || config_server_bundle_js == "")
+ msg = <<~MSG
+ The `prerender` option to allow Server Side Rendering is marked as true but the ReactOnRails configuration
+ for `server_bundle_js_file` is nil or not present in `config/initializers/react_on_rails.rb`.
+ Set `config.server_bundle_js_file` to your javascript bundle to allow server side rendering.
+ Read more at https://www.shakacode.com/react-on-rails/docs/guides/react-server-rendering/
+ MSG
+ raise ReactOnRails::Error, msg
+ end
+
internal_result = internal_react_component(component_name, options)
server_rendered_html = internal_result[:result]["html"]
console_script = internal_result[:result]["consoleReplayScript"]
From a75d7a0a62a95e8566ae9be7324bc1133ad5aa1c Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 12:06:19 -0300
Subject: [PATCH 02/14] Add Webpack configuration files to the template on
generator
---
.../templates/base/base/babel.config.js | 103 +++++++++++++++
.../config/webpack/clientWebpackConfig.js | 15 +++
.../config/webpack/commonWebpackConfig.js | 14 ++
.../base/base/config/webpack/development.js | 40 ++++++
.../base/base/config/webpack/production.js | 11 ++
.../config/webpack/serverWebpackConfig.js | 120 ++++++++++++++++++
.../base/base/config/webpack/test.js | 9 ++
.../base/base/config/webpack/webpackConfig.js | 34 +++++
.../templates/base/base/config/webpacker.yml | 62 +++++++++
9 files changed, 408 insertions(+)
create mode 100644 lib/generators/react_on_rails/templates/base/base/babel.config.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/development.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/production.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/test.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpacker.yml
diff --git a/lib/generators/react_on_rails/templates/base/base/babel.config.js b/lib/generators/react_on_rails/templates/base/base/babel.config.js
new file mode 100644
index 000000000..1515815ce
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/babel.config.js
@@ -0,0 +1,103 @@
+module.exports = function (api) {
+ var validEnv = ['development', 'test', 'production']
+ var currentEnv = api.env()
+ // https://babeljs.io/docs/en/config-files#apienv
+ // api.env is almost the NODE_ENV
+ var isDevelopmentEnv = api.env('development')
+ var isProductionEnv = api.env('production')
+ var isTestEnv = api.env('test')
+
+ if ( !validEnv.includes(currentEnv)) {
+ throw new Error(
+ 'Please specify a valid `NODE_ENV` or ' +
+ '`BABEL_ENV` environment variables. Valid values are "development", ' +
+ '"test", and "production". Instead, received: ' +
+ JSON.stringify(currentEnv) +
+ '.'
+ )
+ }
+
+ return {
+ presets: [
+ isTestEnv && [
+ '@babel/preset-env',
+ {
+ targets: {
+ node: 'current'
+ },
+ modules: 'commonjs'
+ },
+ '@babel/preset-react'
+ ],
+ (isProductionEnv || isDevelopmentEnv) && [
+ '@babel/preset-env',
+ {
+ forceAllTransforms: true,
+ useBuiltIns: 'entry',
+ corejs: 3,
+ modules: false,
+ exclude: ['transform-typeof-symbol']
+ }
+ ],
+ [
+ '@babel/preset-react',
+ {
+ development: isDevelopmentEnv || isTestEnv,
+ useBuiltIns: true
+ }
+ ],
+ ['@babel/preset-typescript', {allExtensions: true, isTSX: true}]
+ ].filter(Boolean),
+ plugins: [
+ 'babel-plugin-macros',
+ '@babel/plugin-syntax-dynamic-import',
+ isTestEnv && 'babel-plugin-dynamic-import-node',
+ '@babel/plugin-transform-destructuring',
+ [
+ '@babel/plugin-proposal-class-properties',
+ {
+ loose: true
+ }
+ ],
+ [
+ '@babel/plugin-proposal-object-rest-spread',
+ {
+ useBuiltIns: true
+ }
+ ],
+ [
+ '@babel/plugin-transform-runtime',
+ {
+ helpers: false,
+ regenerator: true,
+ corejs: false
+ }
+ ],
+ [
+ '@babel/plugin-transform-regenerator',
+ {
+ async: false
+ }
+ ],
+ [
+ "@babel/plugin-proposal-private-property-in-object",
+ {
+ "loose": true
+ }
+ ],
+ [
+ "@babel/plugin-proposal-private-methods",
+ {
+ loose: true
+ }
+ ],
+ process.env.WEBPACK_SERVE && 'react-refresh/babel',
+ isProductionEnv && [
+ 'babel-plugin-transform-react-remove-prop-types',
+ {
+ removeImport: true
+ }
+ ]
+ ].filter(Boolean)
+ }
+}
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js
new file mode 100644
index 000000000..ddc944160
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js
@@ -0,0 +1,15 @@
+const commonWebpackConfig = require('./commonWebpackConfig')
+
+const configureClient = () => {
+ const clientConfig = commonWebpackConfig()
+
+ // server-bundle is special and should ONLY be built by the serverConfig
+ // In case this entry is not deleted, a very strange "window" not found
+ // error shows referring to window["webpackJsonp"]. That is because the
+ // client config is going to try to load chunks.
+ delete clientConfig.entry['server-bundle']
+
+ return clientConfig
+}
+
+module.exports = configureClient
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js
new file mode 100644
index 000000000..e93fa5ba8
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js
@@ -0,0 +1,14 @@
+// Common configuration applying to client and server configuration
+
+const { webpackConfig: baseClientWebpackConfig, merge } = require('@rails/webpacker')
+
+const commonOptions = {
+ resolve: {
+ extensions: ['.css', '.ts', '.tsx']
+ }
+}
+
+// Copy the object using merge b/c the baseClientWebpackConfig and commonOptions are mutable globals
+const commonWebpackConfig = () => (merge({}, baseClientWebpackConfig, commonOptions))
+
+module.exports = commonWebpackConfig
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js
new file mode 100644
index 000000000..cd5bb0eb8
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js
@@ -0,0 +1,40 @@
+process.env.NODE_ENV = process.env.NODE_ENV || 'development'
+
+const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
+const path = require('path')
+const { devServer, inliningCss } = require('@rails/webpacker')
+
+const webpackConfig = require('./webpackConfig')
+
+const developmentEnvOnly = (clientWebpackConfig, serverWebpackConfig) => {
+
+ const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER
+
+ //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.
+ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
+ clientWebpackConfig.plugins.push(
+ new ReactRefreshWebpackPlugin({
+ overlay:{
+ sockPort: devServer.port
+ }
+ })
+ )
+ }
+
+ // To support TypeScript type checker on a separate process uncomment the block below and add tsconfig.json
+ // to the root directory.
+ // As a reference visit https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/development.js
+
+ // clientWebpackConfig.plugins.push(
+ // new ForkTsCheckerWebpackPlugin({
+ // typescript: {
+ // configFile: path.resolve(__dirname, '../../tsconfig.json')
+ // },
+ // async: false
+ // })
+ // )
+}
+module.exports = webpackConfig(developmentEnvOnly)
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js
new file mode 100644
index 000000000..86ee77315
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js
@@ -0,0 +1,11 @@
+process.env.NODE_ENV = process.env.NODE_ENV || 'production'
+
+// Below code should get refactored but the current way that rails/webpacker v5
+// does the globals, it's tricky
+const webpackConfig = require('./webpackConfig')
+
+const productionEnvOnly = (_clientWebpackConfig, _serverWebpackConfig) => {
+ // place any code here that is for production only
+}
+
+module.exports = webpackConfig(productionEnvOnly)
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js
new file mode 100644
index 000000000..4edf3eeac
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js
@@ -0,0 +1,120 @@
+const { merge, config } = require('@rails/webpacker')
+const commonWebpackConfig = require('./commonWebpackConfig')
+
+const webpack = require('webpack')
+
+const configureServer = () => {
+ // We need to use "merge" because the clientConfigObject, EVEN after running
+ // toWebpackConfig() is a mutable GLOBAL. Thus any changes, like modifying the
+ // entry value will result in changing the client config!
+ // Using webpack-merge into an empty object avoids this issue.
+ const serverWebpackConfig = commonWebpackConfig()
+
+ // We just want the single server bundle entry
+ const serverEntry = {
+ 'server-bundle': serverWebpackConfig.entry['server-bundle']
+ }
+
+ if (!serverEntry['server-bundle']) {
+ throw new Error('Create a pack with the file name \'server-bundle.js\' containing all the server rendering files')
+ }
+
+ serverWebpackConfig.entry = serverEntry
+
+ // Remove the mini-css-extract-plugin from the style loaders because
+ // the client build will handle exporting CSS.
+ // replace file-loader with null-loader
+ serverWebpackConfig.module.rules.forEach((loader) => {
+ if (loader.use && loader.use.filter) {
+ loader.use = loader.use.filter(
+ (item) =>
+ !(typeof item === 'string' && item.match(/mini-css-extract-plugin/))
+ )
+ }
+ })
+
+ // No splitting of chunks for a server bundle
+ serverWebpackConfig.optimization = {
+ minimize: false
+ }
+ serverWebpackConfig.plugins.unshift(
+ new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })
+ )
+
+ // Custom output for the server-bundle that matches the config in
+ // config/initializers/react_on_rails.rb
+ 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: config.outputPath,
+ publicPath: config.publicPath,
+ // https://webpack.js.org/configuration/output/#outputglobalobject
+ }
+
+ // Don't hash the server bundle b/c would conflict with the client manifest
+ // And no need for the MiniCssExtractPlugin
+ serverWebpackConfig.plugins = serverWebpackConfig.plugins.filter(
+ (plugin) =>
+ plugin.constructor.name !== 'WebpackAssetsManifest' &&
+ plugin.constructor.name !== 'MiniCssExtractPlugin' &&
+ plugin.constructor.name !== 'ForkTsCheckerWebpackPlugin'
+ )
+
+ // Configure loader rules for SSR
+ // Remove the mini-css-extract-plugin from the style loaders because
+ // the client build will handle exporting CSS.
+ // replace file-loader with null-loader
+ const rules = serverWebpackConfig.module.rules;
+ rules.forEach((rule) => {
+ if (Array.isArray(rule.use)) {
+ // remove the mini-css-extract-plugin and style-loader
+ rule.use = rule.use.filter((item) => {
+ let testValue;
+ if (typeof item === 'string') {
+ testValue = item;
+ } else if (typeof item.loader === 'string') {
+ testValue = item.loader;
+ }
+ return !(testValue.match(/mini-css-extract-plugin/) || testValue === 'style-loader');
+ });
+ const cssLoader = rule.use.find((item) => {
+ let testValue;
+
+ if (typeof item === 'string') {
+ testValue = item;
+ } else if (typeof item.loader === 'string') {
+ testValue = item.loader;
+ }
+
+ return testValue.includes('css-loader');
+ });
+ if (cssLoader && cssLoader.options) {
+ cssLoader.options.modules = { exportOnlyLocals: true };
+ }
+
+ // Skip writing image files during SSR by setting emitFile to false
+ } else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
+ rule.use.options.emitFile = false;
+ }
+ });
+
+ // TODO: DELETE NEXT 2 LINES
+ // Critical due to https://github.com/rails/webpacker/pull/2644
+ // delete serverWebpackConfig.devServer
+
+ // eval works well for the SSR bundle because it's the fastest and shows
+ // lines in the server bundle which is good for debugging SSR
+ // The default of cheap-module-source-map is slow and provides poor info.
+ serverWebpackConfig.devtool = 'eval'
+
+ // If using the default 'web', then libraries like Emotion and loadable-components
+ // break with SSR. The fix is to use a node renderer and change the target.
+ // If using the React on Rails Pro node server renderer, uncomment the next line
+ // serverWebpackConfig.target = 'node'
+
+ return serverWebpackConfig
+}
+
+module.exports = configureServer
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js
new file mode 100644
index 000000000..065efa78c
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js
@@ -0,0 +1,9 @@
+process.env.NODE_ENV = process.env.NODE_ENV || 'development'
+
+const webpackConfig = require('./webpackConfig')
+
+const testOnly = (_clientWebpackConfig, _serverWebpackConfig) => {
+ // place any code here that is for test only
+}
+
+module.exports = webpackConfig(testOnly)
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js
new file mode 100644
index 000000000..5f52597e2
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js
@@ -0,0 +1,34 @@
+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/lib/generators/react_on_rails/templates/base/base/config/webpacker.yml b/lib/generators/react_on_rails/templates/base/base/config/webpacker.yml
new file mode 100644
index 000000000..a3de9872b
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpacker.yml
@@ -0,0 +1,62 @@
+# Note: You must restart bin/webpack-dev-server for changes to take effect
+
+default: &default
+ source_path: app/javascript
+ source_entry_path: packs
+ public_root_path: public
+ public_output_path: packs
+ cache_path: tmp/webpacker
+ webpack_compile_output: true
+
+ # Additional paths webpack should lookup modules
+ # ['app/assets', 'engine/foo/app/assets']
+ additional_paths: []
+
+ # Reload manifest.json on all requests so we reload latest compiled packs
+ cache_manifest: false
+
+development:
+ <<: *default
+ # This is false since we're running `bin/webpack -w` in Procfile.dev-setic
+ compile: false
+
+ # Reference: https://webpack.js.org/configuration/dev-server/
+ dev_server:
+ https: false
+ host: localhost
+ port: 3035
+ # Hot Module Replacement updates modules while the application is running without a full reload
+ hmr: 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"
+ # port: 8080
+ compress: true
+ # Note that apps that do not check the host are vulnerable to DNS rebinding attacks
+ allowed_hosts: [ 'localhost' ]
+ pretty: true
+ headers:
+ 'Access-Control-Allow-Origin': '*'
+ static:
+ watch:
+ ignored: '**/node_modules/**'
+
+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
+
+ # Cache manifest.json for performance
+ cache_manifest: true
From c8dae5fe8ca816a8e82af97dafae3bbc74a46941 Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 12:11:03 -0300
Subject: [PATCH 03/14] Update hello world component files
---
.../bundles/HelloWorld/components/HelloWorld.jsx | 3 ++-
.../bundles/HelloWorld/components/HelloWorld.module.css | 3 +++
.../bundles/HelloWorld/components/HelloWorldServer.js | 5 +++++
.../base/base/app/javascript/packs/server-bundle.js | 8 ++++++++
4 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css
create mode 100644 lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
create mode 100644 lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js
diff --git a/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx b/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
index f7e0487e3..bc60ffebe 100644
--- a/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
+++ b/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { useState } from 'react';
+import style from './HelloWorld.module.css';
const HelloWorld = (props) => {
const [name, setName] = useState(props.name);
@@ -9,7 +10,7 @@ const HelloWorld = (props) => {
Hello, {name}!
+
+
+Setup
+
+ -
+ Create component source: spec/dummy/client/app/components/HelloWorldReason.bs.js
+
+ -
+ Expose the HelloWorld Component: spec/dummy/client/app/startup/clientRegistration.jsx
+
+
+ import HelloWorldReason from '../components/HelloWorldReason';
+ import ReactOnRails from 'react-on-rails';
+ ReactOnRails.register({ HelloWorldReason });
+
+
+ -
+ Place the component on the view: spec/dummy/app/views/pages/client_side_reason_hello_world.html.erb
+
+
+ <%%= react_component("HelloWorldReason", props: @app_props_server_render, prerender: false, trace: true, id: "HelloWorld-reason-react-component-0") %>
+
+
+
diff --git a/spec/dummy/app/views/shared/_header.erb b/spec/dummy/app/views/shared/_header.erb
index 46031488d..bfab95b4f 100644
--- a/spec/dummy/app/views/shared/_header.erb
+++ b/spec/dummy/app/views/shared/_header.erb
@@ -8,6 +8,9 @@
<%= link_to "Hello World Component Client Rendered", client_side_hello_world_path %>
+
+ <%= link_to "Hello World Reason Component Client Rendered", client_side_reason_hello_world_path %>
+
<%= link_to "Hello World Shared Redux Components Client Rendered",
client_side_hello_world_shared_store_path %>
diff --git a/spec/dummy/client/app/components/HelloWorldReason.bs.js b/spec/dummy/client/app/components/HelloWorldReason.bs.js
new file mode 100644
index 000000000..23e405f8d
--- /dev/null
+++ b/spec/dummy/client/app/components/HelloWorldReason.bs.js
@@ -0,0 +1,17 @@
+// Generated by BUCKLESCRIPT VERSION 4.0.5, PLEASE EDIT WITH CARE
+'use strict';
+
+var React = require("react");
+
+function make(title) {
+ return React.createElement("div", {
+ className: "app"
+ }, React.createElement("div", {
+ className: "title"
+ }, title), React.createElement("div", {
+ className: "items"
+ }, "Hello World"));
+}
+
+exports.make = make;
+/* react Not a pure module */
diff --git a/spec/dummy/client/app/components/HelloWorldReason.re b/spec/dummy/client/app/components/HelloWorldReason.re
new file mode 100644
index 000000000..7c43643e7
--- /dev/null
+++ b/spec/dummy/client/app/components/HelloWorldReason.re
@@ -0,0 +1,29 @@
+type state = {name: string};
+
+type action =
+ | UpdateName(string);
+
+let component = ReasonReact.reducerComponent(__MODULE__);
+
+let make = (~name: string, _) => {
+ ...component,
+ initialState: () => {name: name},
+ reducer: (action, _state) =>
+ switch (action) {
+ | UpdateName(name) => ReasonReact.Update({name: name})
+ },
+ render: ({state, send}) =>
+
+
{"Hello, " ++ state.name ++ "!" |> ReasonReact.stringToElement}
+
+
+ ,
+};
diff --git a/spec/dummy/client/app/packs/client-bundle.js b/spec/dummy/client/app/packs/client-bundle.js
index 301e25b27..f91ed5ab1 100644
--- a/spec/dummy/client/app/packs/client-bundle.js
+++ b/spec/dummy/client/app/packs/client-bundle.js
@@ -43,6 +43,7 @@ ReactOnRails.setOptions({
ReactOnRails.register({
BrokenApp,
HelloWorld,
+ HelloWorldReason,
HelloWorldWithLogAndThrow,
HelloWorldES5,
HelloWorldRehydratable,
diff --git a/spec/dummy/client/bsconfig.json b/spec/dummy/client/bsconfig.json
new file mode 100644
index 000000000..20be5effc
--- /dev/null
+++ b/spec/dummy/client/bsconfig.json
@@ -0,0 +1,23 @@
+{
+ "name": "app",
+ "sources": [
+ {
+ "dir": "app/components",
+ "subdirs": true
+ }
+ ],
+ "bs-dependencies": [
+ "reason-react",
+ "bs-react-on-rails"
+ ],
+ "reason": {
+ "react-jsx": 2
+ },
+ "refmt": 3,
+ "bsc-flags": ["-bs-super-errors"],
+ "suffix": ".bs.js",
+ "package-specs": {
+ "module": "commonjs",
+ "in-source": true
+ }
+}
\ No newline at end of file
diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb
index 7c22a7b7b..38aa1154c 100644
--- a/spec/dummy/config/routes.rb
+++ b/spec/dummy/config/routes.rb
@@ -8,6 +8,7 @@
root "pages#index"
get "client_side_hello_world" => "pages#client_side_hello_world"
+ get "client_side_reason_hello_world" => "pages#client_side_reason_hello_world"
get "client_side_hello_world_shared_store" => "pages#client_side_hello_world_shared_store"
get "client_side_hello_world_shared_store_controller" => "pages#client_side_hello_world_shared_store_controller"
get "client_side_hello_world_shared_store_defer" => "pages#client_side_hello_world_shared_store_defer"
From a2f5d2d645a328b03b894f74810e31d0d7ba1956 Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 17:19:31 -0300
Subject: [PATCH 07/14] Add ReScript dependencies and configuration
---
spec/dummy/.gitignore | 5 +++++
spec/dummy/Procfile.dev | 3 +++
spec/dummy/bsconfig.json | 24 ++++++++++++++++++++++++
spec/dummy/client/bsconfig.json | 23 -----------------------
spec/dummy/package.json | 6 +++++-
5 files changed, 37 insertions(+), 24 deletions(-)
create mode 100644 spec/dummy/bsconfig.json
delete mode 100644 spec/dummy/client/bsconfig.json
diff --git a/spec/dummy/.gitignore b/spec/dummy/.gitignore
index c09620ca5..108be19c4 100644
--- a/spec/dummy/.gitignore
+++ b/spec/dummy/.gitignore
@@ -21,3 +21,8 @@
/public/webpack/*
/spec/examples.txt
+
+#Ignore ReScript build files
+/.merlin
+/lib/bs/
+/.bsb.lock
\ No newline at end of file
diff --git a/spec/dummy/Procfile.dev b/spec/dummy/Procfile.dev
index eb99946ae..98d053928 100644
--- a/spec/dummy/Procfile.dev
+++ b/spec/dummy/Procfile.dev
@@ -2,6 +2,9 @@
rails: rails s -p 3000
+# Bundle ReScript .res files
+rescript: yarn re:start
+
# Run the hot reload server for client development
webpack-dev-server: bin/webpack-dev-server
diff --git a/spec/dummy/bsconfig.json b/spec/dummy/bsconfig.json
new file mode 100644
index 000000000..f54413178
--- /dev/null
+++ b/spec/dummy/bsconfig.json
@@ -0,0 +1,24 @@
+{
+ "name": "react_on_rails",
+ "sources": [
+ {
+ "dir": "client/app/components",
+ "subdirs": true
+ }
+ ],
+ "reason": {
+ "react-jsx": 3
+ },
+ "bsc-flags": ["-bs-super-errors"],
+ "suffix": ".bs.js",
+ "namespace": true,
+ "package-specs": [
+ {
+ "module": "commonjs",
+ "in-source": true
+ }
+ ],
+ "bs-dependencies": [
+ "@rescript/react"
+ ]
+}
\ No newline at end of file
diff --git a/spec/dummy/client/bsconfig.json b/spec/dummy/client/bsconfig.json
deleted file mode 100644
index 20be5effc..000000000
--- a/spec/dummy/client/bsconfig.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "app",
- "sources": [
- {
- "dir": "app/components",
- "subdirs": true
- }
- ],
- "bs-dependencies": [
- "reason-react",
- "bs-react-on-rails"
- ],
- "reason": {
- "react-jsx": 2
- },
- "refmt": 3,
- "bsc-flags": ["-bs-super-errors"],
- "suffix": ".bs.js",
- "package-specs": {
- "module": "commonjs",
- "in-source": true
- }
-}
\ No newline at end of file
diff --git a/spec/dummy/package.json b/spec/dummy/package.json
index 57bfeb691..ac97e76c5 100644
--- a/spec/dummy/package.json
+++ b/spec/dummy/package.json
@@ -9,6 +9,7 @@
"dependencies": {
"@babel/preset-react": "^7.10.4",
"@rails/webpacker": "^5.2.1",
+ "@rescript/react": "^0.10.3",
"babel-plugin-module-resolver": "^4.0.0",
"core-js": "3",
"create-react-class": "^15.6.3",
@@ -33,6 +34,7 @@
"react-router-dom": "^5.2.0",
"redux": "^4.0.1",
"redux-thunk": "^2.2.0",
+ "rescript": "^9.1.4",
"resolve-url-loader": "^3.1.1",
"sass-resources-loader": "^2.1.0",
"url-loader": "^4.0.0",
@@ -55,7 +57,9 @@
"build:dev": "rm -rf public/webpack/develoment && RAILS_ENV=development NODE_ENV=development bin/webpack --watch",
"build:dev:server": "rm -rf public/webpack/develoment && RAILS_ENV=development NODE_ENV=development bin/webpack --watch",
"build:dev:watch": "RAILS_ENV=development NODE_ENV=development bin/webpack --watch",
- "build:clean": "rm -rf public/webpack || true"
+ "build:clean": "rm -rf public/webpack || true",
+ "re:build": "rescript build",
+ "re:start": "rescript build -w"
},
"version": "0.0.0"
}
From d2448cf33642e32a2eff650900e2cc55b2a02118 Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 17:24:21 -0300
Subject: [PATCH 08/14] Remove Reason file, Replace Reason occurrences by
ReScript
---
...client_side_rescript_hello_world.html.erb} | 14 ++++-----
spec/dummy/app/views/shared/_header.erb | 2 +-
.../app/components/HelloWorldReason.bs.js | 17 -----------
.../client/app/components/HelloWorldReason.re | 29 -------------------
spec/dummy/config/routes.rb | 2 +-
5 files changed, 9 insertions(+), 55 deletions(-)
rename spec/dummy/app/views/pages/{client_side_reason_hello_world.html.erb => client_side_rescript_hello_world.html.erb} (55%)
delete mode 100644 spec/dummy/client/app/components/HelloWorldReason.bs.js
delete mode 100644 spec/dummy/client/app/components/HelloWorldReason.re
diff --git a/spec/dummy/app/views/pages/client_side_reason_hello_world.html.erb b/spec/dummy/app/views/pages/client_side_rescript_hello_world.html.erb
similarity index 55%
rename from spec/dummy/app/views/pages/client_side_reason_hello_world.html.erb
rename to spec/dummy/app/views/pages/client_side_rescript_hello_world.html.erb
index 554072779..10fcb7964 100644
--- a/spec/dummy/app/views/pages/client_side_reason_hello_world.html.erb
+++ b/spec/dummy/app/views/pages/client_side_rescript_hello_world.html.erb
@@ -1,4 +1,4 @@
-<%= react_component("HelloWorldReason", props: @app_props_server_render, prerender: false, trace: true, id: "HelloWorld-react-component-0") %>
+<%= react_component("HelloWorldReScript", props: @app_props_server_render, prerender: false, trace: true, id: "HelloWorld-rescript-react-component-0") %>
React Rails Client Side Only Rendering
@@ -6,7 +6,7 @@
This example demonstrates client side only rendering.
The source HTML of this page will only show a DIV with an ID matching HelloWorld.
- <%= "" %>
+ <%= "" %>
Compare this to the HTML created for server rendering.
@@ -15,22 +15,22 @@
Setup
-
- Create component source: spec/dummy/client/app/components/HelloWorldReason.bs.js
+ Create component source: spec/dummy/client/app/components/HelloWorldReScript.bs.js
-
Expose the HelloWorld Component: spec/dummy/client/app/startup/clientRegistration.jsx
- import HelloWorldReason from '../components/HelloWorldReason';
+ import HelloWorldReScript from '../components/HelloWorldReScript.bs';
import ReactOnRails from 'react-on-rails';
- ReactOnRails.register({ HelloWorldReason });
+ ReactOnRails.register({ HelloWorldReScript });
-
- Place the component on the view: spec/dummy/app/views/pages/client_side_reason_hello_world.html.erb
+ Place the component on the view: spec/dummy/app/views/pages/client_side_rescript_hello_world.html.erb
- <%%= react_component("HelloWorldReason", props: @app_props_server_render, prerender: false, trace: true, id: "HelloWorld-reason-react-component-0") %>
+ <%%= react_component("HelloWorldReScript", props: @app_props_server_render, prerender: false, trace: true, id: "HelloWorld-rescript-react-component-0") %>
diff --git a/spec/dummy/app/views/shared/_header.erb b/spec/dummy/app/views/shared/_header.erb
index bfab95b4f..d702752a0 100644
--- a/spec/dummy/app/views/shared/_header.erb
+++ b/spec/dummy/app/views/shared/_header.erb
@@ -9,7 +9,7 @@
<%= link_to "Hello World Component Client Rendered", client_side_hello_world_path %>
- <%= link_to "Hello World Reason Component Client Rendered", client_side_reason_hello_world_path %>
+ <%= link_to "Hello World ReScript Component Client Rendered", client_side_rescript_hello_world_path %>
<%= link_to "Hello World Shared Redux Components Client Rendered",
diff --git a/spec/dummy/client/app/components/HelloWorldReason.bs.js b/spec/dummy/client/app/components/HelloWorldReason.bs.js
deleted file mode 100644
index 23e405f8d..000000000
--- a/spec/dummy/client/app/components/HelloWorldReason.bs.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Generated by BUCKLESCRIPT VERSION 4.0.5, PLEASE EDIT WITH CARE
-'use strict';
-
-var React = require("react");
-
-function make(title) {
- return React.createElement("div", {
- className: "app"
- }, React.createElement("div", {
- className: "title"
- }, title), React.createElement("div", {
- className: "items"
- }, "Hello World"));
-}
-
-exports.make = make;
-/* react Not a pure module */
diff --git a/spec/dummy/client/app/components/HelloWorldReason.re b/spec/dummy/client/app/components/HelloWorldReason.re
deleted file mode 100644
index 7c43643e7..000000000
--- a/spec/dummy/client/app/components/HelloWorldReason.re
+++ /dev/null
@@ -1,29 +0,0 @@
-type state = {name: string};
-
-type action =
- | UpdateName(string);
-
-let component = ReasonReact.reducerComponent(__MODULE__);
-
-let make = (~name: string, _) => {
- ...component,
- initialState: () => {name: name},
- reducer: (action, _state) =>
- switch (action) {
- | UpdateName(name) => ReasonReact.Update({name: name})
- },
- render: ({state, send}) =>
-
-
{"Hello, " ++ state.name ++ "!" |> ReasonReact.stringToElement}
-
-
- ,
-};
diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb
index 38aa1154c..a43fabdb9 100644
--- a/spec/dummy/config/routes.rb
+++ b/spec/dummy/config/routes.rb
@@ -8,7 +8,7 @@
root "pages#index"
get "client_side_hello_world" => "pages#client_side_hello_world"
- get "client_side_reason_hello_world" => "pages#client_side_reason_hello_world"
+ get "client_side_rescript_hello_world" => "pages#client_side_rescript_hello_world"
get "client_side_hello_world_shared_store" => "pages#client_side_hello_world_shared_store"
get "client_side_hello_world_shared_store_controller" => "pages#client_side_hello_world_shared_store_controller"
get "client_side_hello_world_shared_store_defer" => "pages#client_side_hello_world_shared_store_defer"
From 5ea3d4377838b77d87e6282f9aecc64c46432b1c Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 17:34:18 -0300
Subject: [PATCH 09/14] Add ReScript component, update yarn.lock at spec/dummy/
---
.../app/components/HelloWorldReScript.bs.js | 29 +++++++++++++++++
.../app/components/HelloWorldReScript.res | 24 ++++++++++++++
spec/dummy/client/app/packs/client-bundle.js | 3 +-
spec/dummy/yarn.lock | 32 ++++++++++++-------
4 files changed, 76 insertions(+), 12 deletions(-)
create mode 100644 spec/dummy/client/app/components/HelloWorldReScript.bs.js
create mode 100644 spec/dummy/client/app/components/HelloWorldReScript.res
diff --git a/spec/dummy/client/app/components/HelloWorldReScript.bs.js b/spec/dummy/client/app/components/HelloWorldReScript.bs.js
new file mode 100644
index 000000000..8092cca72
--- /dev/null
+++ b/spec/dummy/client/app/components/HelloWorldReScript.bs.js
@@ -0,0 +1,29 @@
+// Generated by ReScript, PLEASE EDIT WITH CARE
+'use strict';
+
+var Curry = require("rescript/lib/js/curry.js");
+var React = require("react");
+
+function HelloWorldReScript(Props) {
+ var helloWorldData = Props.helloWorldData;
+ var match = React.useState(function () {
+ return helloWorldData.name;
+ });
+ var setNameState = match[1];
+ var nameState = match[0];
+ return React.createElement("div", undefined, React.createElement("h3", undefined, "Hello, " + nameState + " !"), React.createElement("hr", undefined), React.createElement("form", undefined, React.createElement("label", {
+ htmlFor: "name"
+ }, "Say hello to: ", React.createElement("input", {
+ id: "name",
+ type: "text",
+ value: nameState,
+ onChange: (function (e) {
+ return Curry._1(setNameState, e.currentTarget.value);
+ })
+ }))));
+}
+
+var make = HelloWorldReScript;
+
+exports.make = make;
+/* react Not a pure module */
diff --git a/spec/dummy/client/app/components/HelloWorldReScript.res b/spec/dummy/client/app/components/HelloWorldReScript.res
new file mode 100644
index 000000000..7cc6bfb77
--- /dev/null
+++ b/spec/dummy/client/app/components/HelloWorldReScript.res
@@ -0,0 +1,24 @@
+@react.component
+
+// The compiled JavaScript will always extract your props passed to make from Props, where Props
+// is the same hash passed to react_component method on the view. Log the Props in the compiled JS
+// And make sure the props passed to make match the shape of the prop passed on the view.
+
+let make = (~helloWorldData: {..}) => {
+ let (nameState, setNameState) = React.useState(_ => helloWorldData["name"])
+
+
{("Hello, " ++ nameState ++ " !") -> React.string}
+
+
+
+}
\ No newline at end of file
diff --git a/spec/dummy/client/app/packs/client-bundle.js b/spec/dummy/client/app/packs/client-bundle.js
index f91ed5ab1..5d42d2287 100644
--- a/spec/dummy/client/app/packs/client-bundle.js
+++ b/spec/dummy/client/app/packs/client-bundle.js
@@ -11,6 +11,7 @@ import HelloWorldHooksContext from '../components/HelloWorldHooksContext';
import ContextFunctionReturnInvalidJSX from '../components/ContextFunctionReturnInvalidJSX';
import PureComponentWrappedInFunction from '../components/PureComponentWrappedInFunction';
+import {make as HelloWorldReScript} from '../components/HelloWorldReScript.bs';
import HelloWorldWithLogAndThrow from '../components/HelloWorldWithLogAndThrow';
import HelloWorldES5 from '../components/HelloWorldES5';
import HelloWorldRehydratable from '../components/HelloWorldRehydratable';
@@ -43,7 +44,7 @@ ReactOnRails.setOptions({
ReactOnRails.register({
BrokenApp,
HelloWorld,
- HelloWorldReason,
+ HelloWorldReScript,
HelloWorldWithLogAndThrow,
HelloWorldES5,
HelloWorldRehydratable,
diff --git a/spec/dummy/yarn.lock b/spec/dummy/yarn.lock
index 81f019555..0325d902a 100644
--- a/spec/dummy/yarn.lock
+++ b/spec/dummy/yarn.lock
@@ -1035,12 +1035,12 @@
"@babel/plugin-transform-react-jsx-source" "^7.10.4"
"@babel/plugin-transform-react-pure-annotations" "^7.10.4"
-"@babel/runtime-corejs3@^7.9.6":
- version "7.10.2"
- resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.10.2.tgz#3511797ddf9a3d6f3ce46b99cc835184817eaa4e"
- integrity sha512-+a2M/u7r15o3dV1NEizr9bRi+KUVnrs/qYxF0Z06DAPx/4VCWaz1WA7EcbE+uqGgt39lp5akWGmHsTseIkHkHg==
+"@babel/runtime-corejs3@^7.12.5":
+ version "7.15.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.15.4.tgz#403139af262b9a6e8f9ba04a6fdcebf8de692bf1"
+ integrity sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg==
dependencies:
- core-js-pure "^3.0.0"
+ core-js-pure "^3.16.0"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.1.2":
@@ -1205,6 +1205,11 @@
webpack-cli "^3.3.12"
webpack-sources "^1.4.3"
+"@rescript/react@^0.10.3":
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/@rescript/react/-/react-0.10.3.tgz#a2a8bed6b017940ec26c2154764b350f50348889"
+ integrity sha512-Lf9rzrR3bQPKJjOK3PBRa/B3xrJ7CqQ1HYr9VHPVxJidarIJJFZBhj0Dg1uZURX+Wg/xiP0PHFxXmdj2bK8Vxw==
+
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@@ -2541,10 +2546,10 @@ core-js-compat@^3.6.2:
browserslist "^4.8.5"
semver "7.0.0"
-core-js-pure@^3.0.0:
- version "3.6.5"
- resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
- integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
+core-js-pure@^3.16.0:
+ version "3.18.3"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.18.3.tgz#7eed77dcce1445ab68fd68715856633e2fb3b90c"
+ integrity sha512-qfskyO/KjtbYn09bn1IPkuhHl5PlJ6IzJ9s9sraJ1EqcuGyLGKzhSM1cY0zgyL9hx42eulQLZ6WaeK5ycJCkqw==
core-js@3, core-js@^3.6.5:
version "3.6.5"
@@ -6915,9 +6920,9 @@ react-is@^16.7.0:
integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==
"react-on-rails@file:.yalc/react-on-rails":
- version "12.0.5-beta.0-ea6ccda1"
+ version "12.4.0"
dependencies:
- "@babel/runtime-corejs3" "^7.9.6"
+ "@babel/runtime-corejs3" "^7.12.5"
concurrently "^5.1.0"
react-proptypes@^1.0.0:
@@ -7221,6 +7226,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+rescript@^9.1.4:
+ version "9.1.4"
+ resolved "https://registry.yarnpkg.com/rescript/-/rescript-9.1.4.tgz#1eb126f98d6c16942c0bf0df67c050198e580515"
+ integrity sha512-aXANK4IqecJzdnDpJUsU6pxMViCR5ogAxzuqS0mOr8TloMnzAjJFu63fjD6LCkWrKAhlMkFFzQvVQYaAaVkFXw==
+
reselect@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
From aade9886025b053a06517dfe33e91789caa4a21b Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 17:34:58 -0300
Subject: [PATCH 10/14] Require bundler on rakelib/task_helpers.rb
---
rakelib/task_helpers.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/rakelib/task_helpers.rb b/rakelib/task_helpers.rb
index a95e7722c..975b6ea3e 100644
--- a/rakelib/task_helpers.rb
+++ b/rakelib/task_helpers.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require "bundler"
+
module ReactOnRails
module TaskHelpers
# Returns the root folder of the react_on_rails gem
From 165ee675728bc475227df865a0fc2068adeee5c1 Mon Sep 17 00:00:00 2001
From: Gus
Date: Sat, 23 Oct 2021 17:45:08 -0300
Subject: [PATCH 11/14] Fix RuboCop offence Layout/LineLength
---
lib/generators/react_on_rails/base_generator.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb
index b36d0c8c8..d14702445 100644
--- a/lib/generators/react_on_rails/base_generator.rb
+++ b/lib/generators/react_on_rails/base_generator.rb
@@ -82,7 +82,8 @@ def add_yarn_dependencies
end
puts "Adding React dependencies"
- run "yarn add react react-dom @babel/preset-react prop-types babel-plugin-transform-react-remove-prop-types babel-plugin-macros"
+ run "yarn add react react-dom @babel/preset-react prop-types babel-plugin-macros \
+ babel-plugin-transform-react-remove-prop-types"
puts "Adding TypeScript dependencies"
run "yarn add typescript @babel/preset-typescript @types/react @types/react-dom"
From 086482592cd20e4976445ccee0315107151a61be Mon Sep 17 00:00:00 2001
From: Gus
Date: Tue, 2 Nov 2021 12:43:28 -0300
Subject: [PATCH 12/14] Fix ESLint errors, Add source reference to each config
file
---
.../HelloWorld/components/HelloWorldServer.js | 2 +-
.../app/javascript/packs/server-bundle.js | 2 +-
.../templates/base/base/babel.config.js | 77 ++++++++++---------
.../config/webpack/clientWebpackConfig.js | 3 +
.../config/webpack/commonWebpackConfig.js | 7 +-
.../base/base/config/webpack/development.js | 42 ++++------
.../base/base/config/webpack/production.js | 5 +-
.../config/webpack/serverWebpackConfig.js | 34 ++++----
.../base/base/config/webpack/test.js | 9 ---
.../base/base/config/webpack/webpackConfig.js | 3 +
10 files changed, 83 insertions(+), 101 deletions(-)
delete mode 100644 lib/generators/react_on_rails/templates/base/base/config/webpack/test.js
diff --git a/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js b/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
index 9a22c0b71..aad6e4849 100644
--- a/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
+++ b/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
@@ -2,4 +2,4 @@ import HelloWorld from './HelloWorld';
// This could be specialized for server rendering
// For example, if using React-Router, we'd have the SSR setup here.
-export default HelloWorld;
\ No newline at end of file
+export default HelloWorld;
diff --git a/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js b/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js
index df3e1aa79..2500bef98 100644
--- a/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js
+++ b/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js
@@ -4,5 +4,5 @@ import HelloWorld from '../bundles/HelloWorld/components/HelloWorldServer'
// This is how react_on_rails can see the HelloWorld in the browser.
ReactOnRails.register({
- HelloWorld
+ HelloWorld,
})
diff --git a/lib/generators/react_on_rails/templates/base/base/babel.config.js b/lib/generators/react_on_rails/templates/base/base/babel.config.js
index 1515815ce..cdfa99159 100644
--- a/lib/generators/react_on_rails/templates/base/base/babel.config.js
+++ b/lib/generators/react_on_rails/templates/base/base/babel.config.js
@@ -1,20 +1,21 @@
+// 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/babel.config.js
+
module.exports = function (api) {
- var validEnv = ['development', 'test', 'production']
- var currentEnv = api.env()
+ const validEnv = ['development', 'test', 'production']
+ const currentEnv = api.env()
// https://babeljs.io/docs/en/config-files#apienv
// api.env is almost the NODE_ENV
- var isDevelopmentEnv = api.env('development')
- var isProductionEnv = api.env('production')
- var isTestEnv = api.env('test')
+ const isDevelopmentEnv = api.env('development')
+ const isProductionEnv = api.env('production')
+ const isTestEnv = api.env('test')
- if ( !validEnv.includes(currentEnv)) {
- throw new Error(
- 'Please specify a valid `NODE_ENV` or ' +
+ if (!validEnv.includes(currentEnv)) {
+ throw new Error(`${'Please specify a valid `NODE_ENV` or ' +
'`BABEL_ENV` environment variables. Valid values are "development", ' +
- '"test", and "production". Instead, received: ' +
- JSON.stringify(currentEnv) +
- '.'
- )
+ '"test", and "production". Instead, received: '}${
+ JSON.stringify(currentEnv)
+ }.`)
}
return {
@@ -23,11 +24,11 @@ module.exports = function (api) {
'@babel/preset-env',
{
targets: {
- node: 'current'
+ node: 'current',
},
- modules: 'commonjs'
+ modules: 'commonjs',
},
- '@babel/preset-react'
+ '@babel/preset-react',
],
(isProductionEnv || isDevelopmentEnv) && [
'@babel/preset-env',
@@ -36,17 +37,17 @@ module.exports = function (api) {
useBuiltIns: 'entry',
corejs: 3,
modules: false,
- exclude: ['transform-typeof-symbol']
- }
+ exclude: ['transform-typeof-symbol'],
+ },
],
[
'@babel/preset-react',
{
development: isDevelopmentEnv || isTestEnv,
- useBuiltIns: true
- }
+ useBuiltIns: true,
+ },
],
- ['@babel/preset-typescript', {allExtensions: true, isTSX: true}]
+ ['@babel/preset-typescript', { allExtensions: true, isTSX: true }],
].filter(Boolean),
plugins: [
'babel-plugin-macros',
@@ -56,48 +57,48 @@ module.exports = function (api) {
[
'@babel/plugin-proposal-class-properties',
{
- loose: true
- }
+ loose: true,
+ },
],
[
'@babel/plugin-proposal-object-rest-spread',
{
- useBuiltIns: true
- }
+ useBuiltIns: true,
+ },
],
[
'@babel/plugin-transform-runtime',
{
helpers: false,
regenerator: true,
- corejs: false
- }
+ corejs: false,
+ },
],
[
'@babel/plugin-transform-regenerator',
{
- async: false
- }
+ async: false,
+ },
],
[
- "@babel/plugin-proposal-private-property-in-object",
+ '@babel/plugin-proposal-private-property-in-object',
{
- "loose": true
- }
+ loose: true,
+ },
],
[
- "@babel/plugin-proposal-private-methods",
+ '@babel/plugin-proposal-private-methods',
{
- loose: true
- }
+ loose: true,
+ },
],
process.env.WEBPACK_SERVE && 'react-refresh/babel',
isProductionEnv && [
'babel-plugin-transform-react-remove-prop-types',
{
- removeImport: true
- }
- ]
- ].filter(Boolean)
+ removeImport: true,
+ },
+ ],
+ ].filter(Boolean),
}
}
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js
index ddc944160..cb674b721 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js
@@ -1,3 +1,6 @@
+// The source can be found at:
+// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/clientWebpackConfig.js
+
const commonWebpackConfig = require('./commonWebpackConfig')
const configureClient = () => {
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js
index e93fa5ba8..8cb88e869 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js
@@ -1,11 +1,14 @@
+// The source can be found at:
+// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/commonWebpackConfig.js
+
// Common configuration applying to client and server configuration
const { webpackConfig: baseClientWebpackConfig, merge } = require('@rails/webpacker')
const commonOptions = {
resolve: {
- extensions: ['.css', '.ts', '.tsx']
- }
+ extensions: ['.css', '.ts', '.tsx'],
+ },
}
// Copy the object using merge b/c the baseClientWebpackConfig and commonOptions are mutable globals
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js
index cd5bb0eb8..c3a96e5f5 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js
@@ -1,40 +1,24 @@
+// 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'
-const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
-const path = require('path')
+const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
+
const { devServer, inliningCss } = require('@rails/webpacker')
const webpackConfig = require('./webpackConfig')
-const developmentEnvOnly = (clientWebpackConfig, serverWebpackConfig) => {
-
- const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER
-
- //plugins
- if (inliningCss ) {
+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.
- const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
- clientWebpackConfig.plugins.push(
- new ReactRefreshWebpackPlugin({
- overlay:{
- sockPort: devServer.port
- }
- })
- )
+ clientWebpackConfig.plugins.push(new ReactRefreshWebpackPlugin({
+ overlay: {
+ sockPort: devServer.port,
+ },
+ }))
}
-
- // To support TypeScript type checker on a separate process uncomment the block below and add tsconfig.json
- // to the root directory.
- // As a reference visit https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/development.js
-
- // clientWebpackConfig.plugins.push(
- // new ForkTsCheckerWebpackPlugin({
- // typescript: {
- // configFile: path.resolve(__dirname, '../../tsconfig.json')
- // },
- // async: false
- // })
- // )
}
module.exports = webpackConfig(developmentEnvOnly)
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js
index 86ee77315..7bd119aec 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js
@@ -1,7 +1,8 @@
+// The source can be found at:
+// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/production.js
+
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
-// Below code should get refactored but the current way that rails/webpacker v5
-// does the globals, it's tricky
const webpackConfig = require('./webpackConfig')
const productionEnvOnly = (_clientWebpackConfig, _serverWebpackConfig) => {
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js
index 4edf3eeac..149cd8c2e 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js
@@ -1,3 +1,9 @@
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-param-reassign */
+
+// The source can be found at:
+// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/serverWebpackConfig.js
+
const { merge, config } = require('@rails/webpacker')
const commonWebpackConfig = require('./commonWebpackConfig')
@@ -12,7 +18,7 @@ const configureServer = () => {
// We just want the single server bundle entry
const serverEntry = {
- 'server-bundle': serverWebpackConfig.entry['server-bundle']
+ 'server-bundle': serverWebpackConfig.entry['server-bundle'],
}
if (!serverEntry['server-bundle']) {
@@ -26,20 +32,16 @@ const configureServer = () => {
// replace file-loader with null-loader
serverWebpackConfig.module.rules.forEach((loader) => {
if (loader.use && loader.use.filter) {
- loader.use = loader.use.filter(
- (item) =>
- !(typeof item === 'string' && item.match(/mini-css-extract-plugin/))
- )
+ loader.use = loader.use.filter((item) =>
+ !(typeof item === 'string' && item.match(/mini-css-extract-plugin/)))
}
})
// No splitting of chunks for a server bundle
serverWebpackConfig.optimization = {
- minimize: false
+ minimize: false,
}
- serverWebpackConfig.plugins.unshift(
- new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })
- )
+ serverWebpackConfig.plugins.unshift(new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }))
// Custom output for the server-bundle that matches the config in
// config/initializers/react_on_rails.rb
@@ -55,18 +57,16 @@ const configureServer = () => {
// Don't hash the server bundle b/c would conflict with the client manifest
// And no need for the MiniCssExtractPlugin
- serverWebpackConfig.plugins = serverWebpackConfig.plugins.filter(
- (plugin) =>
- plugin.constructor.name !== 'WebpackAssetsManifest' &&
+ serverWebpackConfig.plugins = serverWebpackConfig.plugins.filter((plugin) =>
+ plugin.constructor.name !== 'WebpackAssetsManifest' &&
plugin.constructor.name !== 'MiniCssExtractPlugin' &&
- plugin.constructor.name !== 'ForkTsCheckerWebpackPlugin'
- )
+ plugin.constructor.name !== 'ForkTsCheckerWebpackPlugin')
// Configure loader rules for SSR
// Remove the mini-css-extract-plugin from the style loaders because
// the client build will handle exporting CSS.
// replace file-loader with null-loader
- const rules = serverWebpackConfig.module.rules;
+ const { rules } = serverWebpackConfig.module;
rules.forEach((rule) => {
if (Array.isArray(rule.use)) {
// remove the mini-css-extract-plugin and style-loader
@@ -100,10 +100,6 @@ const configureServer = () => {
}
});
- // TODO: DELETE NEXT 2 LINES
- // Critical due to https://github.com/rails/webpacker/pull/2644
- // delete serverWebpackConfig.devServer
-
// eval works well for the SSR bundle because it's the fastest and shows
// lines in the server bundle which is good for debugging SSR
// The default of cheap-module-source-map is slow and provides poor info.
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js
deleted file mode 100644
index 065efa78c..000000000
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-process.env.NODE_ENV = process.env.NODE_ENV || 'development'
-
-const webpackConfig = require('./webpackConfig')
-
-const testOnly = (_clientWebpackConfig, _serverWebpackConfig) => {
- // place any code here that is for test only
-}
-
-module.exports = webpackConfig(testOnly)
diff --git a/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js b/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js
index 5f52597e2..e4b075893 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js
+++ b/lib/generators/react_on_rails/templates/base/base/config/webpack/webpackConfig.js
@@ -1,3 +1,6 @@
+// The source can be found at:
+// https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/webpackConfig.js
+
const clientWebpackConfig = require('./clientWebpackConfig')
const serverWebpackConfig = require('./serverWebpackConfig')
From e09e6f9884d57721307ccbaef1b8ac988a90f677 Mon Sep 17 00:00:00 2001
From: Gus
Date: Tue, 2 Nov 2021 20:00:09 -0300
Subject: [PATCH 13/14] Move JavaScript files from base_generator to
react_no_redux_generator
---
lib/generators/react_on_rails/base_generator.rb | 9 ---------
.../react_on_rails/react_no_redux_generator.rb | 5 ++++-
2 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb
index d14702445..0a51ddaaa 100644
--- a/lib/generators/react_on_rails/base_generator.rb
+++ b/lib/generators/react_on_rails/base_generator.rb
@@ -37,14 +37,6 @@ def copy_base_files
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
end
- def copy_js_bundle_files
- base_path = "base/base/"
- base_files = %w[app/javascript/packs/server-bundle.js
- app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
- app/javascript/bundles/HelloWorld/components/HelloWorld.module.css]
- base_files.each { |file| copy_file("#{base_path}#{file}", file) }
- end
-
def copy_webpack_config
puts "Adding Webpack config"
base_path = "base/base/"
@@ -54,7 +46,6 @@ def copy_webpack_config
config/webpack/development.js
config/webpack/production.js
config/webpack/serverWebpackConfig.js
- config/webpack/test.js
config/webpack/webpackConfig.js]
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
end
diff --git a/lib/generators/react_on_rails/react_no_redux_generator.rb b/lib/generators/react_on_rails/react_no_redux_generator.rb
index afc2380aa..aeb82dbdc 100644
--- a/lib/generators/react_on_rails/react_no_redux_generator.rb
+++ b/lib/generators/react_on_rails/react_no_redux_generator.rb
@@ -12,7 +12,10 @@ class ReactNoReduxGenerator < Rails::Generators::Base
def copy_base_files
base_js_path = "base/base"
- base_files = %w[app/javascript/bundles/HelloWorld/components/HelloWorld.jsx]
+ base_files = %w[app/javascript/packs/server-bundle.js
+ app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
+ app/javascript/bundles/HelloWorld/components/HelloWorldServer.js
+ app/javascript/bundles/HelloWorld/components/HelloWorld.module.css]
base_files.each { |file| copy_file("#{base_js_path}/#{file}", file) }
end
From 81008b90dfcecf19f179be2ed4233666a5e742cd Mon Sep 17 00:00:00 2001
From: Gus
Date: Tue, 2 Nov 2021 20:00:39 -0300
Subject: [PATCH 14/14] Remove extra parenthesis
---
spec/react_on_rails/support/generator_spec_helper.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/spec/react_on_rails/support/generator_spec_helper.rb b/spec/react_on_rails/support/generator_spec_helper.rb
index 50fdaca5b..3919616e1 100644
--- a/spec/react_on_rails/support/generator_spec_helper.rb
+++ b/spec/react_on_rails/support/generator_spec_helper.rb
@@ -26,7 +26,7 @@ def simulate_existing_rails_files(options)
simulate_existing_file("Gemfile", "")
simulate_existing_file("config/routes.rb", "Rails.application.routes.draw do\nend\n")
simulate_existing_file("config/application.rb",
- "module Gentest\nclass Application < Rails::Application\nend\nend)")
+ "module Gentest\nclass Application < Rails::Application\nend\nend")
return unless options.fetch(:spec, true)