From f359b1dc296e510335d613be57e1c264a408d1d6 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Fri, 11 Sep 2020 12:18:17 -0700 Subject: [PATCH 01/14] make download links cross-platform --- src/page/home/sidebar/AppLinks.js | 29 ------------- src/page/home/sidebar/AppLinks/index.js | 41 +++++++++++++++++++ .../home/sidebar/AppLinks/index.native.js | 17 ++++++++ 3 files changed, 58 insertions(+), 29 deletions(-) delete mode 100644 src/page/home/sidebar/AppLinks.js create mode 100644 src/page/home/sidebar/AppLinks/index.js create mode 100644 src/page/home/sidebar/AppLinks/index.native.js diff --git a/src/page/home/sidebar/AppLinks.js b/src/page/home/sidebar/AppLinks.js deleted file mode 100644 index 214e6ae63592c..0000000000000 --- a/src/page/home/sidebar/AppLinks.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import styles from '../../../style/StyleSheet'; -import openURLInNewTab from '../../../lib/openURLInNewTab'; -import Text from '../../../components/Text'; - -const AppLinks = () => ( - <> - openURLInNewTab('https://chat.expensify.com/Chat.dmg')} - > - Desktop - - openURLInNewTab('https://testflight.apple.com/join/ucuXr4g5')} - > - iOS - - openURLInNewTab('https://play.google.com/apps/internaltest/4700657970395613233')} - > - Android - - -); - -export default AppLinks; diff --git a/src/page/home/sidebar/AppLinks/index.js b/src/page/home/sidebar/AppLinks/index.js new file mode 100644 index 0000000000000..5d50a0c5e748d --- /dev/null +++ b/src/page/home/sidebar/AppLinks/index.js @@ -0,0 +1,41 @@ +import React from 'react'; +import {Platform} from 'react-native'; + +import styles from '../../../../style/StyleSheet'; +import openURLInNewTab from '../../../../lib/openURLInNewTab'; +import Text from '../../../../components/Text'; + +const AppLinks = () => ( + <> + {Platform.OS === 'web' && ( + openURLInNewTab('https://chat.expensify.com/Chat.dmg')} + > + Desktop + + )} + {Platform.OS !== 'web' && ( + openURLInNewTab('https://chat.expensify.com')} + > + Web + + )} + openURLInNewTab('https://testflight.apple.com/join/ucuXr4g5')} + > + iOS + + openURLInNewTab('https://play.google.com/apps/internaltest/4700657970395613233')} + > + Android + + +); + +export default AppLinks; diff --git a/src/page/home/sidebar/AppLinks/index.native.js b/src/page/home/sidebar/AppLinks/index.native.js new file mode 100644 index 0000000000000..7488b7905b4aa --- /dev/null +++ b/src/page/home/sidebar/AppLinks/index.native.js @@ -0,0 +1,17 @@ +import React from 'react'; +import styles from '../../../../style/StyleSheet'; +import openURLInNewTab from '../../../../lib/openURLInNewTab'; +import Text from '../../../../components/Text'; + +const AppLinks = () => ( + <> + openURLInNewTab('https://chat.expensify.com/')} + > + View on web + + +); + +export default AppLinks; From 72d65e16c6c6632389713be98519cde4dc39bcd3 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Fri, 11 Sep 2020 12:24:36 -0700 Subject: [PATCH 02/14] fix js style --- src/page/home/sidebar/AppLinks/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/page/home/sidebar/AppLinks/index.js b/src/page/home/sidebar/AppLinks/index.js index 5d50a0c5e748d..2dc33db92377e 100644 --- a/src/page/home/sidebar/AppLinks/index.js +++ b/src/page/home/sidebar/AppLinks/index.js @@ -17,7 +17,7 @@ const AppLinks = () => ( )} {Platform.OS !== 'web' && ( openURLInNewTab('https://chat.expensify.com')} > Web From bcb5bb7cd01f7a268d8b269a5bf0da7f14d00733 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 10:40:42 -0700 Subject: [PATCH 03/14] enable .desktop.js files --- package.json | 4 +-- src/components/TestComponent/index.desktop.js | 0 src/components/TestComponent/index.webify.js | 7 +++++ src/lib/RegexUtils.js | 12 +++++++++ webpack.common.js | 27 ++++++++++++++++--- 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/components/TestComponent/index.desktop.js create mode 100644 src/components/TestComponent/index.webify.js create mode 100644 src/lib/RegexUtils.js diff --git a/package.json b/package.json index c857d66b74641..04ceb2e466768 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", - "desktop": "webpack --config webpack.dev.js && electron main.js", + "desktop": "webpack --config webpack.dev.js --platform desktop && electron main.js", "start": "react-native start", "web": "webpack-dev-server --open --config webpack.dev.js", "build": "webpack --config webpack.prod.js", - "desktop-build": "webpack --config webpack.prod.js && electron-builder --config desktop/electron.config.js --publish always", + "desktop-build": "webpack --config webpack.prod.js --platform desktop && electron-builder --config desktop/electron.config.js --publish always", "ios-build": "fastlane ios build", "android-build": "fastlane android build", "test": "jest", diff --git a/src/components/TestComponent/index.desktop.js b/src/components/TestComponent/index.desktop.js new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/components/TestComponent/index.webify.js b/src/components/TestComponent/index.webify.js new file mode 100644 index 0000000000000..d0589b43f40a1 --- /dev/null +++ b/src/components/TestComponent/index.webify.js @@ -0,0 +1,7 @@ +import React from 'react'; +import {View} from 'react-native'; +import Text from '../Text'; + +const TestComponent = () => The platform is Web!; + +export default TestComponent; diff --git a/src/lib/RegexUtils.js b/src/lib/RegexUtils.js new file mode 100644 index 0000000000000..094746655665d --- /dev/null +++ b/src/lib/RegexUtils.js @@ -0,0 +1,12 @@ +/** + * Take the logical union of an arbitrary number of regexes + * @param {...RegExp} regexes + * @returns {RegExp} + */ +function union(...regexes) { + return new RegExp(regexes.map(regex => regex.source).join('|')); +} + +export default { + union, +}; diff --git a/webpack.common.js b/webpack.common.js index 979dcb1c50d04..9f5452e5fb868 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -3,6 +3,21 @@ const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); +/** + * Take the logical union of an arbitrary number of regexes + * (duplicated from RegexUtils because we can't use ES6 modules here) + * + * @param {...RegExp} regexes + * @returns {RegExp} + */ +function regexUnion(...regexes) { + return new RegExp(regexes.map(regex => regex.source).join('|')); +} + +const platformIndex = process.argv.findIndex(arg => arg === '--platform'); +const platform = (platformIndex > 0) ? process.argv[platformIndex + 1] : 'web'; +const platformExclude = platform === 'web' ? new RegExp(/\.desktop\.js$/) : new RegExp(/\.webify\.js$/); + module.exports = { entry: { app: './web/index.js', @@ -41,12 +56,18 @@ module.exports = { * You can remove something from this list if it doesn't use "react-native" as an import and it doesn't * use JSX/JS that needs to be transformed by babel. */ - exclude: /node_modules\/(?!(react-native-render-html|react-native-webview)\/).*|\.native.js$/, + exclude: regexUnion( + /node_modules\/(?!(react-native-render-html|react-native-webview)\/).*|\.native\.js$/, + platformExclude + ), }, { test: /\.js$/, loader: 'eslint-loader', - exclude: /node_modules|\.native.js$/, + exclude: regexUnion( + /node_modules|\.native\.js$/, + platformExclude + ), options: { cache: true, emitWarning: true, @@ -72,6 +93,6 @@ module.exports = { // React Native libraries may have web-specific module implementations that appear with the extension `.web.js` // without this, web will try to use native implementations and break in not very obvious ways - extensions: ['.web.js', '.js'], + extensions: ['.web.js', '.js', (platform === 'web') ? '.webify.js' : '.desktop.js'], }, }; From 1e40b31142c4836aa3ccaca1138d702a79a57f82 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 10:45:12 -0700 Subject: [PATCH 04/14] move platform-specific links to their own file --- src/components/TestComponent/index.desktop.js | 0 src/components/TestComponent/index.webify.js | 7 ----- .../AppLinks/{index.js => index.desktop.js} | 22 ++++---------- .../home/sidebar/AppLinks/index.webify.js | 30 +++++++++++++++++++ 4 files changed, 36 insertions(+), 23 deletions(-) delete mode 100644 src/components/TestComponent/index.desktop.js delete mode 100644 src/components/TestComponent/index.webify.js rename src/page/home/sidebar/AppLinks/{index.js => index.desktop.js} (57%) create mode 100644 src/page/home/sidebar/AppLinks/index.webify.js diff --git a/src/components/TestComponent/index.desktop.js b/src/components/TestComponent/index.desktop.js deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/components/TestComponent/index.webify.js b/src/components/TestComponent/index.webify.js deleted file mode 100644 index d0589b43f40a1..0000000000000 --- a/src/components/TestComponent/index.webify.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; -import {View} from 'react-native'; -import Text from '../Text'; - -const TestComponent = () => The platform is Web!; - -export default TestComponent; diff --git a/src/page/home/sidebar/AppLinks/index.js b/src/page/home/sidebar/AppLinks/index.desktop.js similarity index 57% rename from src/page/home/sidebar/AppLinks/index.js rename to src/page/home/sidebar/AppLinks/index.desktop.js index 2dc33db92377e..84688d46f5d5c 100644 --- a/src/page/home/sidebar/AppLinks/index.js +++ b/src/page/home/sidebar/AppLinks/index.desktop.js @@ -7,22 +7,12 @@ import Text from '../../../../components/Text'; const AppLinks = () => ( <> - {Platform.OS === 'web' && ( - openURLInNewTab('https://chat.expensify.com/Chat.dmg')} - > - Desktop - - )} - {Platform.OS !== 'web' && ( - openURLInNewTab('https://chat.expensify.com')} - > - Web - - )} + openURLInNewTab('https://chat.expensify.com')} + > + Web + openURLInNewTab('https://testflight.apple.com/join/ucuXr4g5')} diff --git a/src/page/home/sidebar/AppLinks/index.webify.js b/src/page/home/sidebar/AppLinks/index.webify.js new file mode 100644 index 0000000000000..59204dc80c849 --- /dev/null +++ b/src/page/home/sidebar/AppLinks/index.webify.js @@ -0,0 +1,30 @@ +import React from 'react'; + +import styles from '../../../../style/StyleSheet'; +import openURLInNewTab from '../../../../lib/openURLInNewTab'; +import Text from '../../../../components/Text'; + +const AppLinks = () => ( + <> + openURLInNewTab('https://chat.expensify.com/Chat.dmg')} + > + Desktop + + openURLInNewTab('https://testflight.apple.com/join/ucuXr4g5')} + > + iOS + + openURLInNewTab('https://play.google.com/apps/internaltest/4700657970395613233')} + > + Android + + +); + +export default AppLinks; From a48443ccfb3fc942433f9c4a40bf81af947ff035 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 10:54:16 -0700 Subject: [PATCH 05/14] update README --- README.md | 5 +++++ webpack.common.js | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6462d5ae68d66..db4fb9c2c6a67 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ This application is built with the following principles. 1. If the reason you can't write cross platform code is because there is a bug in ReactNative that is preventing it from working, the correct action is to fix RN and submit a PR upstream -- not to hack around RN bugs with platform-specific code paths. 1. If there is a feature that simply doesn't exist on all platforms and thus doesn't exist in RN, rather than doing if (platform=iOS) { }, instead write a "shim" library that is implemented with NOOPs on the other platforms. For example, rather than injecting platform-specific multi-tab code (which can only work on browsers, because it's the only platform with multiple tabs), write a TabManager class that just is NOOP for non-browser platforms. This encapsulates the platform-specific code into a platform library, rather than sprinkling through the business logic. 1. Put all platform specific code in dedicated files and folders, like /platform, and reject any PR that attempts to put platform-specific code anywhere else. This maintains a strict separation between business logic and platform code. + 1. Within a module, the following file extensions can be used to separate platform-specific code, when necessary: + - Mobile => `.native.js` + - iOS/Android => `.ios.js`/`.android.js` + - Web => `.webify.js` + - Desktop => `.desktop.js` # Local development ## Getting started diff --git a/webpack.common.js b/webpack.common.js index 9f5452e5fb868..80ac955213929 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -92,7 +92,9 @@ module.exports = { }, // React Native libraries may have web-specific module implementations that appear with the extension `.web.js` - // without this, web will try to use native implementations and break in not very obvious ways + // without this, web will try to use native implementations and break in not very obvious ways. + // This is also why we have to use .webify.js for our own web-specific files... + // Because desktop also relies on "web-specific" module implementations extensions: ['.web.js', '.js', (platform === 'web') ? '.webify.js' : '.desktop.js'], }, }; From 868317d9d368442d9f4166635ec3340727761c1c Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 11:19:43 -0700 Subject: [PATCH 06/14] fix style and linter --- .eslintrc.js | 14 ++++++++++++++ src/page/home/sidebar/AppLinks/index.desktop.js | 1 - 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 6d493dec553ce..67e7d95fe17d9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,4 +7,18 @@ module.exports = { env: { jest: true }, + settings: { + 'import/resolver': { + node: { + extensions: [ + '.js', + '.webify.js', + '.desktop.js', + '.native.js', + '.ios.js', + '.android.js', + ] + } + } + } }; diff --git a/src/page/home/sidebar/AppLinks/index.desktop.js b/src/page/home/sidebar/AppLinks/index.desktop.js index 84688d46f5d5c..2d966d9e149b5 100644 --- a/src/page/home/sidebar/AppLinks/index.desktop.js +++ b/src/page/home/sidebar/AppLinks/index.desktop.js @@ -1,5 +1,4 @@ import React from 'react'; -import {Platform} from 'react-native'; import styles from '../../../../style/StyleSheet'; import openURLInNewTab from '../../../../lib/openURLInNewTab'; From ee240ced970fa9692d9417debc95f9168e932b16 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 11:29:44 -0700 Subject: [PATCH 07/14] remove incorrect comma from README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0f8ab6cf52b5..3f9491f22c3cb 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This application is built with the following principles. 1. If the reason you can't write cross platform code is because there is a bug in ReactNative that is preventing it from working, the correct action is to fix RN and submit a PR upstream -- not to hack around RN bugs with platform-specific code paths. 1. If there is a feature that simply doesn't exist on all platforms and thus doesn't exist in RN, rather than doing if (platform=iOS) { }, instead write a "shim" library that is implemented with NOOPs on the other platforms. For example, rather than injecting platform-specific multi-tab code (which can only work on browsers, because it's the only platform with multiple tabs), write a TabManager class that just is NOOP for non-browser platforms. This encapsulates the platform-specific code into a platform library, rather than sprinkling through the business logic. 1. Put all platform specific code in dedicated files and folders, like /platform, and reject any PR that attempts to put platform-specific code anywhere else. This maintains a strict separation between business logic and platform code. - 1. Within a module, the following file extensions can be used to separate platform-specific code, when necessary: + 1. Within a module, the following file extensions can be used to separate platform-specific code when necessary: - Mobile => `.native.js` - iOS/Android => `.ios.js`/`.android.js` - Web => `.webify.js` From 42937c29d53295d09148d5bdddd2167d222d76f5 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 11:54:58 -0700 Subject: [PATCH 08/14] make RegexUtils a commonJS module --- src/lib/RegexUtils.js | 4 +--- webpack.common.js | 16 +++------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/lib/RegexUtils.js b/src/lib/RegexUtils.js index 094746655665d..cea37c79cc2bd 100644 --- a/src/lib/RegexUtils.js +++ b/src/lib/RegexUtils.js @@ -7,6 +7,4 @@ function union(...regexes) { return new RegExp(regexes.map(regex => regex.source).join('|')); } -export default { - union, -}; +module.exports = {union}; diff --git a/webpack.common.js b/webpack.common.js index 7d71e0d4997da..3889afbb9f44c 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -2,17 +2,7 @@ const path = require('path'); const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); - -/** - * Take the logical union of an arbitrary number of regexes - * (duplicated from RegexUtils because we can't use ES6 modules here) - * - * @param {...RegExp} regexes - * @returns {RegExp} - */ -function regexUnion(...regexes) { - return new RegExp(regexes.map(regex => regex.source).join('|')); -} +const RegexUtils = require('./src/lib/RegexUtils'); const platformIndex = process.argv.findIndex(arg => arg === '--platform'); const platform = (platformIndex > 0) ? process.argv[platformIndex + 1] : 'web'; @@ -56,7 +46,7 @@ module.exports = { * You can remove something from this list if it doesn't use "react-native" as an import and it doesn't * use JSX/JS that needs to be transformed by babel. */ - exclude: regexUnion( + exclude: RegexUtils.union( /node_modules\/(?!(react-native-render-html|react-native-webview)\/).*|\.native\.js$/, platformExclude ), @@ -64,7 +54,7 @@ module.exports = { { test: /\.js$/, loader: 'eslint-loader', - exclude: regexUnion( + exclude: RegexUtils.union( /node_modules|\.native\.js$/, platformExclude ), From d178df1656a872e544394eed1cec967a937ca72d Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 12:17:04 -0700 Subject: [PATCH 09/14] update README and use index.browser.js instead of index.webify.js --- .eslintrc.js | 2 +- README.md | 10 +++++----- .../AppLinks/{index.webify.js => index.browser.js} | 0 webpack.common.js | 8 +++++--- 4 files changed, 11 insertions(+), 9 deletions(-) rename src/page/home/sidebar/AppLinks/{index.webify.js => index.browser.js} (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 67e7d95fe17d9..897691e2a6366 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,7 +12,7 @@ module.exports = { node: { extensions: [ '.js', - '.webify.js', + '.browser.js', '.desktop.js', '.native.js', '.ios.js', diff --git a/README.md b/README.md index 3f9491f22c3cb..640ff592b6e37 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,11 @@ This application is built with the following principles. 1. If the reason you can't write cross platform code is because there is a bug in ReactNative that is preventing it from working, the correct action is to fix RN and submit a PR upstream -- not to hack around RN bugs with platform-specific code paths. 1. If there is a feature that simply doesn't exist on all platforms and thus doesn't exist in RN, rather than doing if (platform=iOS) { }, instead write a "shim" library that is implemented with NOOPs on the other platforms. For example, rather than injecting platform-specific multi-tab code (which can only work on browsers, because it's the only platform with multiple tabs), write a TabManager class that just is NOOP for non-browser platforms. This encapsulates the platform-specific code into a platform library, rather than sprinkling through the business logic. 1. Put all platform specific code in dedicated files and folders, like /platform, and reject any PR that attempts to put platform-specific code anywhere else. This maintains a strict separation between business logic and platform code. - 1. Within a module, the following file extensions can be used to separate platform-specific code when necessary: - - Mobile => `.native.js` - - iOS/Android => `.ios.js`/`.android.js` - - Web => `.webify.js` - - Desktop => `.desktop.js` + 1. Within a module, the following files can be used to export platform-specific code _only when necessary_: + - Mobile => `index.native.js` + - iOS/Android => `index.ios.js`/`index.android.js` + - Web => `index.browser.js` + - Desktop => `index.desktop.js` # Local development ## Getting started diff --git a/src/page/home/sidebar/AppLinks/index.webify.js b/src/page/home/sidebar/AppLinks/index.browser.js similarity index 100% rename from src/page/home/sidebar/AppLinks/index.webify.js rename to src/page/home/sidebar/AppLinks/index.browser.js diff --git a/webpack.common.js b/webpack.common.js index 3889afbb9f44c..743a048340249 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -4,9 +4,11 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); const RegexUtils = require('./src/lib/RegexUtils'); +// Check for a --platform command line argument. +// If it is 'web', we want to ignore .desktop.js files, and if it is 'desktop', we want to ignore .browser.js files. const platformIndex = process.argv.findIndex(arg => arg === '--platform'); const platform = (platformIndex > 0) ? process.argv[platformIndex + 1] : 'web'; -const platformExclude = platform === 'web' ? new RegExp(/\.desktop\.js$/) : new RegExp(/\.webify\.js$/); +const platformExclude = platform === 'web' ? new RegExp(/\.desktop\.js$/) : new RegExp(/\.browser\.js$/); module.exports = { entry: { @@ -83,8 +85,8 @@ module.exports = { // React Native libraries may have web-specific module implementations that appear with the extension `.web.js` // without this, web will try to use native implementations and break in not very obvious ways. - // This is also why we have to use .webify.js for our own web-specific files... + // This is also why we have to use .browser.js for our own web-specific files... // Because desktop also relies on "web-specific" module implementations - extensions: ['.web.js', '.js', (platform === 'web') ? '.webify.js' : '.desktop.js'], + extensions: ['.web.js', '.js', (platform === 'web') ? '.browser.js' : '.desktop.js'], }, }; From 32adfe4bbda9cd3227f93ee0436801e282904344 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 12:18:16 -0700 Subject: [PATCH 10/14] update comment to say default is web --- webpack.common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.common.js b/webpack.common.js index 743a048340249..e9a5c4286add6 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -4,7 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); const RegexUtils = require('./src/lib/RegexUtils'); -// Check for a --platform command line argument. +// Check for a --platform command line argument (default to 'web') // If it is 'web', we want to ignore .desktop.js files, and if it is 'desktop', we want to ignore .browser.js files. const platformIndex = process.argv.findIndex(arg => arg === '--platform'); const platform = (platformIndex > 0) ? process.argv[platformIndex + 1] : 'web'; From 4fc33595903d354d63f20c5907b5097be8f02cf1 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 12:44:50 -0700 Subject: [PATCH 11/14] update README again, created separate section for Platform-Specific file extensions --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 640ff592b6e37..289a84a178be9 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,6 @@ This application is built with the following principles. 1. If the reason you can't write cross platform code is because there is a bug in ReactNative that is preventing it from working, the correct action is to fix RN and submit a PR upstream -- not to hack around RN bugs with platform-specific code paths. 1. If there is a feature that simply doesn't exist on all platforms and thus doesn't exist in RN, rather than doing if (platform=iOS) { }, instead write a "shim" library that is implemented with NOOPs on the other platforms. For example, rather than injecting platform-specific multi-tab code (which can only work on browsers, because it's the only platform with multiple tabs), write a TabManager class that just is NOOP for non-browser platforms. This encapsulates the platform-specific code into a platform library, rather than sprinkling through the business logic. 1. Put all platform specific code in dedicated files and folders, like /platform, and reject any PR that attempts to put platform-specific code anywhere else. This maintains a strict separation between business logic and platform code. - 1. Within a module, the following files can be used to export platform-specific code _only when necessary_: - - Mobile => `index.native.js` - - iOS/Android => `index.ios.js`/`index.android.js` - - Web => `index.browser.js` - - Desktop => `index.desktop.js` # Local development ## Getting started @@ -97,6 +92,15 @@ You can use any IDE or code editing tool for developing on any platform. Use you 1. The application uses [React-Router](https://reactrouter.com/native/guides/quick-start) for navigating between parts of the app. 1. [Higher Order Components](https://reactjs.org/docs/higher-order-components.html) are used to connect React components to persistent storage via Ion. +## Platform-Specific File Extensions +In most cases, the code written for this repo should be platform-independent. In such cases, each module should have a single file, `index.js`, which defines the module's exports. There are, however, some cases in which a feature is intrinsically tied to the underlying platform. In such cases, the following file extensions can be used to export platform-specific code from a module: +- Mobile => `index.native.js` +- iOS/Android => `index.ios.js`/`index.android.js` +- Web => `index.browser.js` +- Desktop => `index.desktop.js` + +Note that `index.js` should be the default. i.e: If you have mobile-specific implementation in `index.native.js`, then the desktop/web implementation can be contained in a shared `index.js`. Furthermore, `index.native.js` should not be included in the same module as `index.ios.js` or `index.android.js`, nor should `index.js` be included in the same module as `index.browser.js` or `index.desktop.js`. + ## Structure of the app These are the main pieces of the application. From aace2364a6883d509b8d3716bf6cd5619b131327 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 12:51:52 -0700 Subject: [PATCH 12/14] nix RegexUtils from webpack file --- src/lib/RegexUtils.js | 4 +++- webpack.common.js | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/RegexUtils.js b/src/lib/RegexUtils.js index cea37c79cc2bd..094746655665d 100644 --- a/src/lib/RegexUtils.js +++ b/src/lib/RegexUtils.js @@ -7,4 +7,6 @@ function union(...regexes) { return new RegExp(regexes.map(regex => regex.source).join('|')); } -module.exports = {union}; +export default { + union, +}; diff --git a/webpack.common.js b/webpack.common.js index e9a5c4286add6..d68b5c3984a17 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -2,7 +2,6 @@ const path = require('path'); const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); -const RegexUtils = require('./src/lib/RegexUtils'); // Check for a --platform command line argument (default to 'web') // If it is 'web', we want to ignore .desktop.js files, and if it is 'desktop', we want to ignore .browser.js files. @@ -48,18 +47,18 @@ module.exports = { * You can remove something from this list if it doesn't use "react-native" as an import and it doesn't * use JSX/JS that needs to be transformed by babel. */ - exclude: RegexUtils.union( + exclude: [ /node_modules\/(?!(react-native-render-html|react-native-webview)\/).*|\.native\.js$/, platformExclude - ), + ], }, { test: /\.js$/, loader: 'eslint-loader', - exclude: RegexUtils.union( + exclude: [ /node_modules|\.native\.js$/, platformExclude - ), + ], options: { cache: false, emitWarning: true, From 727506f44815da77f21b091f48714d74c2a8a01c Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 12:59:47 -0700 Subject: [PATCH 13/14] use website instead of browser --- .eslintrc.js | 2 +- README.md | 4 ++-- .../AppLinks/{index.browser.js => index.website.js} | 0 webpack.common.js | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) rename src/page/home/sidebar/AppLinks/{index.browser.js => index.website.js} (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 897691e2a6366..630a8f04f884c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,7 +12,7 @@ module.exports = { node: { extensions: [ '.js', - '.browser.js', + '.website.js', '.desktop.js', '.native.js', '.ios.js', diff --git a/README.md b/README.md index 289a84a178be9..5e6b7fb94f333 100644 --- a/README.md +++ b/README.md @@ -96,10 +96,10 @@ You can use any IDE or code editing tool for developing on any platform. Use you In most cases, the code written for this repo should be platform-independent. In such cases, each module should have a single file, `index.js`, which defines the module's exports. There are, however, some cases in which a feature is intrinsically tied to the underlying platform. In such cases, the following file extensions can be used to export platform-specific code from a module: - Mobile => `index.native.js` - iOS/Android => `index.ios.js`/`index.android.js` -- Web => `index.browser.js` +- Web => `index.website.js` - Desktop => `index.desktop.js` -Note that `index.js` should be the default. i.e: If you have mobile-specific implementation in `index.native.js`, then the desktop/web implementation can be contained in a shared `index.js`. Furthermore, `index.native.js` should not be included in the same module as `index.ios.js` or `index.android.js`, nor should `index.js` be included in the same module as `index.browser.js` or `index.desktop.js`. +Note that `index.js` should be the default. i.e: If you have mobile-specific implementation in `index.native.js`, then the desktop/web implementation can be contained in a shared `index.js`. Furthermore, `index.native.js` should not be included in the same module as `index.ios.js` or `index.android.js`, nor should `index.js` be included in the same module as `index.website.js` or `index.desktop.js`. ## Structure of the app These are the main pieces of the application. diff --git a/src/page/home/sidebar/AppLinks/index.browser.js b/src/page/home/sidebar/AppLinks/index.website.js similarity index 100% rename from src/page/home/sidebar/AppLinks/index.browser.js rename to src/page/home/sidebar/AppLinks/index.website.js diff --git a/webpack.common.js b/webpack.common.js index d68b5c3984a17..691a0160fc3aa 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -4,10 +4,10 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); // Check for a --platform command line argument (default to 'web') -// If it is 'web', we want to ignore .desktop.js files, and if it is 'desktop', we want to ignore .browser.js files. +// If it is 'web', we want to ignore .desktop.js files, and if it is 'desktop', we want to ignore .website.js files. const platformIndex = process.argv.findIndex(arg => arg === '--platform'); const platform = (platformIndex > 0) ? process.argv[platformIndex + 1] : 'web'; -const platformExclude = platform === 'web' ? new RegExp(/\.desktop\.js$/) : new RegExp(/\.browser\.js$/); +const platformExclude = platform === 'web' ? new RegExp(/\.desktop\.js$/) : new RegExp(/\.website\.js$/); module.exports = { entry: { @@ -84,8 +84,8 @@ module.exports = { // React Native libraries may have web-specific module implementations that appear with the extension `.web.js` // without this, web will try to use native implementations and break in not very obvious ways. - // This is also why we have to use .browser.js for our own web-specific files... + // This is also why we have to use .website.js for our own web-specific files... // Because desktop also relies on "web-specific" module implementations - extensions: ['.web.js', '.js', (platform === 'web') ? '.browser.js' : '.desktop.js'], + extensions: ['.web.js', '.js', (platform === 'web') ? '.website.js' : '.desktop.js'], }, }; From 1089626ea22f2503c8e57ee00c34c10d97472e87 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 23 Sep 2020 13:13:50 -0700 Subject: [PATCH 14/14] delete RegexUtils --- src/lib/RegexUtils.js | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/lib/RegexUtils.js diff --git a/src/lib/RegexUtils.js b/src/lib/RegexUtils.js deleted file mode 100644 index 094746655665d..0000000000000 --- a/src/lib/RegexUtils.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Take the logical union of an arbitrary number of regexes - * @param {...RegExp} regexes - * @returns {RegExp} - */ -function union(...regexes) { - return new RegExp(regexes.map(regex => regex.source).join('|')); -} - -export default { - union, -};