diff --git a/.eslintrc.js b/.eslintrc.js index 6d493dec553ce..630a8f04f884c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,4 +7,18 @@ module.exports = { env: { jest: true }, + settings: { + 'import/resolver': { + node: { + extensions: [ + '.js', + '.website.js', + '.desktop.js', + '.native.js', + '.ios.js', + '.android.js', + ] + } + } + } }; diff --git a/README.md b/README.md index d5de57d694e9d..5e6b7fb94f333 100644 --- a/README.md +++ b/README.md @@ -92,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.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.website.js` or `index.desktop.js`. + ## Structure of the app These are the main pieces of the application. diff --git a/package.json b/package.json index e06014a9b0ea8..be815949101d1 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,11 @@ "android": "react-native run-android", "ios": "react-native run-ios", "ipad": "react-native run-ios --simulator=\"iPad Pro (12.9-inch) (4th generation)\"", - "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/page/home/sidebar/AppLinks/index.desktop.js b/src/page/home/sidebar/AppLinks/index.desktop.js new file mode 100644 index 0000000000000..2d966d9e149b5 --- /dev/null +++ b/src/page/home/sidebar/AppLinks/index.desktop.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')} + > + 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; diff --git a/src/page/home/sidebar/AppLinks.js b/src/page/home/sidebar/AppLinks/index.website.js similarity index 81% rename from src/page/home/sidebar/AppLinks.js rename to src/page/home/sidebar/AppLinks/index.website.js index 214e6ae63592c..59204dc80c849 100644 --- a/src/page/home/sidebar/AppLinks.js +++ b/src/page/home/sidebar/AppLinks/index.website.js @@ -1,7 +1,8 @@ import React from 'react'; -import styles from '../../../style/StyleSheet'; -import openURLInNewTab from '../../../lib/openURLInNewTab'; -import Text from '../../../components/Text'; + +import styles from '../../../../style/StyleSheet'; +import openURLInNewTab from '../../../../lib/openURLInNewTab'; +import Text from '../../../../components/Text'; const AppLinks = () => ( <> diff --git a/webpack.common.js b/webpack.common.js index 578f7a8e1411a..691a0160fc3aa 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -3,6 +3,12 @@ const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 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 .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(/\.website\.js$/); + module.exports = { entry: { app: './web/index.js', @@ -41,12 +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: /node_modules\/(?!(react-native-render-html|react-native-webview)\/).*|\.native.js$/, + exclude: [ + /node_modules\/(?!(react-native-render-html|react-native-webview)\/).*|\.native\.js$/, + platformExclude + ], }, { test: /\.js$/, loader: 'eslint-loader', - exclude: /node_modules|\.native.js$/, + exclude: [ + /node_modules|\.native\.js$/, + platformExclude + ], options: { cache: false, emitWarning: true, @@ -71,7 +83,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 - extensions: ['.web.js', '.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 .website.js for our own web-specific files... + // Because desktop also relies on "web-specific" module implementations + extensions: ['.web.js', '.js', (platform === 'web') ? '.website.js' : '.desktop.js'], }, };