diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb index b36d0c8c8..74aeab622 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-transform-react-remove-prop-types + babel-plugin-macros" puts "Adding TypeScript dependencies" run "yarn add typescript @babel/preset-typescript @types/react @types/react-dom" 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..7d764f113 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 @@ -1,8 +1,8 @@ -import ReactOnRails from 'react-on-rails' +import ReactOnRails from 'react-on-rails'; -import HelloWorld from '../bundles/HelloWorld/components/HelloWorldServer' +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..1e18cc711 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( + 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) + - '.' - ) + '`BABEL_ENV` environment variables. Valid values are "development", ' + + '"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..a9d9eb4c1 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,15 +1,18 @@ -const commonWebpackConfig = require('./commonWebpackConfig') +// 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 = () => { - const clientConfig = commonWebpackConfig() + 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'] + delete clientConfig.entry['server-bundle']; - return clientConfig -} + return clientConfig; +}; -module.exports = configureClient +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 index e93fa5ba8..044eab0b7 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,14 +1,17 @@ +// 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 { 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 -const commonWebpackConfig = () => (merge({}, baseClientWebpackConfig, commonOptions)) +const commonWebpackConfig = () => merge({}, baseClientWebpackConfig, commonOptions); -module.exports = commonWebpackConfig +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 index cd5bb0eb8..88e609360 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,28 @@ -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_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/development.js -const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin') -const path = require('path') -const { devServer, inliningCss } = require('@rails/webpacker') +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; -const webpackConfig = require('./webpackConfig') +const { devServer, inliningCss } = require('@rails/webpacker'); -const developmentEnvOnly = (clientWebpackConfig, serverWebpackConfig) => { +const webpackConfig = require('./webpackConfig'); - const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER +const developmentEnvOnly = (clientWebpackConfig, _serverWebpackConfig) => { + // eslint-disable-next-line no-unused-vars + const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER; - //plugins - if (inliningCss ) { + // 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) + // eslint-disable-next-line global-require + const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); + clientWebpackConfig.plugins.push(new ReactRefreshWebpackPlugin({ + overlay: { + sockPort: devServer.port, + }, + })); + } +}; +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..49553b41f 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,11 +1,12 @@ -process.env.NODE_ENV = process.env.NODE_ENV || 'production' +// 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 -// Below code should get refactored but the current way that rails/webpacker v5 -// does the globals, it's tricky -const webpackConfig = require('./webpackConfig') +process.env.NODE_ENV = process.env.NODE_ENV || 'production'; + +const webpackConfig = require('./webpackConfig'); const productionEnvOnly = (_clientWebpackConfig, _serverWebpackConfig) => { // place any code here that is for production only -} +}; -module.exports = webpackConfig(productionEnvOnly) +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 index 4edf3eeac..ca8b48e6c 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,45 +1,45 @@ -const { merge, config } = require('@rails/webpacker') -const commonWebpackConfig = require('./commonWebpackConfig') +// 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 webpack = require('webpack') +// eslint-disable-next-line no-unused-vars +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() + const serverWebpackConfig = commonWebpackConfig(); // 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']) { - throw new Error('Create a pack with the file name \'server-bundle.js\' containing all the server rendering files') + throw new Error("Create a pack with the file name 'server-bundle.js' containing all the server rendering files"); } - serverWebpackConfig.entry = serverEntry + 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/)) - ) + // eslint-disable-next-line no-param-reassign + 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 }) - ) + 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 @@ -51,25 +51,24 @@ const configureServer = () => { 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' && + 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 + // eslint-disable-next-line no-param-reassign rule.use = rule.use.filter((item) => { let testValue; if (typeof item === 'string') { @@ -96,25 +95,22 @@ const configureServer = () => { // 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')) { + // eslint-disable-next-line no-param-reassign 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' + 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 -} + return serverWebpackConfig; +}; -module.exports = configureServer +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 index 065efa78c..dc95d6d12 100644 --- 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 @@ -1,9 +1,9 @@ -process.env.NODE_ENV = process.env.NODE_ENV || 'development' +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; -const webpackConfig = require('./webpackConfig') +const webpackConfig = require('./webpackConfig'); const testOnly = (_clientWebpackConfig, _serverWebpackConfig) => { // place any code here that is for test only -} +}; -module.exports = webpackConfig(testOnly) +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..8e6df9b4d 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,34 +1,37 @@ -const clientWebpackConfig = require('./clientWebpackConfig') -const serverWebpackConfig = require('./serverWebpackConfig') +// 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'); const webpackConfig = (envSpecific) => { - const clientConfig = clientWebpackConfig() - const serverConfig = serverWebpackConfig() + const clientConfig = clientWebpackConfig(); + const serverConfig = serverWebpackConfig(); if (envSpecific) { - envSpecific(clientConfig, serverConfig) + envSpecific(clientConfig, serverConfig); } - let result + 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 + 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 + 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] + 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 -} + return result; +}; -module.exports = webpackConfig +module.exports = webpackConfig;