diff --git a/.gitignore b/.gitignore index a24971e612b..ffd6dbf69bc 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,10 @@ android/app/src/main/java/com/expensify/chat/generated/ node_modules/ npm-debug.log yarn-error.log + +# Bundled code dist/ +desktop-build/ # BUCK buck-out/ diff --git a/config/electronBuilder/electronBuilder.config.js b/config/electronBuilder/electronBuilder.config.js new file mode 100644 index 00000000000..f2455ad0428 --- /dev/null +++ b/config/electronBuilder/electronBuilder.config.js @@ -0,0 +1,44 @@ +const {version} = require('../../package.json'); + +const isStaging = process.env.ELECTRON_ENV === 'staging'; +const isPublishing = process.argv.includes('--publish'); + +/** + * The configuration for the production and staging Electron builds. + * It can be used to create local builds of the same, by omitting the `--publish` flag + */ +module.exports = { + appId: 'com.expensifyreactnative.chat', + productName: 'New Expensify', + extraMetadata: { + version, + }, + mac: { + category: 'public.app-category.finance', + target: [ + {target: 'dmg', arch: ['x64', 'arm64', 'universal']}, + ], + icon: isStaging ? './desktop/icon-stg.png' : './desktop/icon.png', + hardenedRuntime: true, + entitlements: 'desktop/entitlements.mac.plist', + entitlementsInherit: 'desktop/entitlements.mac.plist', + type: 'distribution', + }, + dmg: { + internetEnabled: true, + }, + publish: [{ + provider: 's3', + bucket: isStaging ? 'staging-expensify-cash' : 'expensify-cash', + channel: 'latest', + }], + afterSign: isPublishing ? './desktop/notarize.js' : undefined, + files: [ + 'dist', + '!dist/www/{.well-known,favicon*}', + ], + directories: { + app: 'desktop', + output: 'desktop-build', + }, +}; diff --git a/config/electronBuilder/electronBuilder.ghactions.config.js b/config/electronBuilder/electronBuilder.ghactions.config.js deleted file mode 100644 index c2ed9bcd379..00000000000 --- a/config/electronBuilder/electronBuilder.ghactions.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const baseElectronBuilderConfig = require('./electronBuilder.local.config'); - -module.exports = { - ...baseElectronBuilderConfig, - publish: [{ - provider: 's3', - bucket: process.env.ELECTRON_ENV === 'staging' ? 'staging-expensify-cash' : 'expensify-cash', - channel: 'latest', - }], - afterSign: './desktop/notarize.js', -}; diff --git a/config/electronBuilder/electronBuilder.local.config.js b/config/electronBuilder/electronBuilder.local.config.js deleted file mode 100644 index 611851614f2..00000000000 --- a/config/electronBuilder/electronBuilder.local.config.js +++ /dev/null @@ -1,37 +0,0 @@ -const ENVIRONMENT = require('../../src/CONST/ENVIRONMENT'); - -const isStaging = process.env.ELECTRON_ENV === 'staging'; - -/** - * The basic app configurations for the production and staging Electron builds, - * without the pieces that require code signing, notarizing, and publishing. - * - * This has been separated from main electronBuilder.ghactions.config.js file to make it easier to run local production or staging builds. - */ -module.exports = { - appId: 'com.expensifyreactnative.chat', - productName: 'New Expensify', - extraMetadata: { - main: './desktop/main.js', - electronEnvironment: isStaging ? ENVIRONMENT.STAGING : ENVIRONMENT.PRODUCTION, - }, - mac: { - category: 'public.app-category.finance', - icon: isStaging ? './desktop/icon-stg.png' : './desktop/icon.png', - hardenedRuntime: true, - entitlements: 'desktop/entitlements.mac.plist', - entitlementsInherit: 'desktop/entitlements.mac.plist', - type: 'distribution', - }, - dmg: { - title: 'New Expensify', - artifactName: 'NewExpensify.dmg', - internetEnabled: true, - }, - files: [ - './dist/**/*', - './desktop/*.js', - './src/libs/checkForUpdates.js', - './src/CONST/ENVIRONMENT.js', - ], -}; diff --git a/config/webpack/productionConfig.js b/config/webpack/productionConfig.js deleted file mode 100644 index 594d616ac42..00000000000 --- a/config/webpack/productionConfig.js +++ /dev/null @@ -1,29 +0,0 @@ -const webpack = require('webpack'); -const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); - -/** - * Get the production webpack configuration, given an environment object. - * - * @param {Object} env - * @returns {Object} - */ -function getProductionConfig(env) { - return ({ - mode: 'production', - devtool: 'source-map', - plugins: [ - // This allows us to interactively inspect JS bundle contents - ...(process.env.ANALYZE_BUNDLE === 'true' ? [new BundleAnalyzerPlugin()] : []), - new webpack.DefinePlugin({ - __REACT_WEB_CONFIG__: JSON.stringify(env), - - // React Native JavaScript environment requires the global __DEV__ variable to be accessible. - // react-native-render-html uses variable to log exclusively during development. - // See https://reactnative.dev/docs/javascript-environment - __DEV__: false, - }), - ], - }); -} - -module.exports = getProductionConfig; diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 7493a4c7602..1b856a3039c 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -1,17 +1,12 @@ -const _ = require('underscore'); const path = require('path'); -const {IgnorePlugin} = require('webpack'); +const {IgnorePlugin, DefinePlugin} = require('webpack'); const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); +const dotenv = require('dotenv'); +const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); const CustomVersionFilePlugin = require('./CustomVersionFilePlugin'); -// 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 = _.findIndex(process.argv, arg => arg === '--platform'); -const platform = (platformIndex > 0) ? process.argv[platformIndex + 1] : 'web'; -const platformExclude = platform === 'web' ? new RegExp(/\.desktop\.js$/) : new RegExp(/\.website\.js$/); - const includeModules = [ 'react-native-animatable', 'react-native-reanimated', @@ -26,7 +21,16 @@ const includeModules = [ 'react-native-google-places-autocomplete', ].join('|'); -const webpackConfig = { +/** + * Get a production grade config for web or desktop + * @param {Object} env + * @param {String} env.envFile path to the env file to be used + * @param {'web'|'desktop'} env.platform + * @returns {Configuration} + */ +const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({ + mode: 'production', + devtool: 'source-map', entry: { app: './index.js', }, @@ -60,7 +64,20 @@ const webpackConfig = { ], }), new IgnorePlugin(/^\.\/locale$/, /moment$/), - new CustomVersionFilePlugin(), + ...(platform === 'web' ? [new CustomVersionFilePlugin()] : []), + new DefinePlugin({ + __REACT_WEB_CONFIG__: JSON.stringify( + dotenv.config({path: envFile}).parsed, + ), + + // React Native JavaScript environment requires the global __DEV__ variable to be accessible. + // react-native-render-html uses variable to log exclusively during development. + // See https://reactnative.dev/docs/javascript-environment + __DEV__: /staging|prod/.test(envFile) === false, + }), + + // This allows us to interactively inspect JS bundle contents + ...(process.env.ANALYZE_BUNDLE === 'true' ? [new BundleAnalyzerPlugin()] : []), ], module: { rules: [ @@ -79,7 +96,6 @@ const webpackConfig = { */ exclude: [ new RegExp(`node_modules/(?!(${includeModules})/).*|.native.js$`), - platformExclude, ], }, { @@ -87,7 +103,6 @@ const webpackConfig = { loader: 'eslint-loader', exclude: [ /node_modules|\.native\.js$/, - platformExclude, ], options: { cache: false, @@ -143,8 +158,9 @@ const webpackConfig = { // 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 + // This also skips packing web only dependencies to desktop and vice versa extensions: ['.web.js', (platform === 'web') ? '.website.js' : '.desktop.js', '.js', '.jsx'], }, -}; +}); module.exports = webpackConfig; diff --git a/config/webpack/webpack.desktop.js b/config/webpack/webpack.desktop.js new file mode 100644 index 00000000000..298741eed49 --- /dev/null +++ b/config/webpack/webpack.desktop.js @@ -0,0 +1,56 @@ +const path = require('path'); +const webpack = require('webpack'); +const _ = require('underscore'); + +const desktopDependencies = require('../../desktop/package.json').dependencies; +const getCommonConfig = require('./webpack.common'); + +/** + * Desktop creates 2 configurations in parallel + * 1. electron-main - the core that serves the app content + * 2. web - the app content that would be rendered in electron + * Everything is placed in desktop/dist and ready for packaging + * @param {Object} env + * @returns {webpack.Configuration[]} + */ +module.exports = (env) => { + const rendererConfig = getCommonConfig({...env, platform: 'desktop'}); + const outputPath = path.resolve(__dirname, '../../desktop/dist'); + + rendererConfig.name = 'renderer'; + rendererConfig.output.path = path.join(outputPath, 'www'); + + // Expose react-native-config to desktop-main + const definePlugin = _.find(rendererConfig.plugins, plugin => plugin.constructor === webpack.DefinePlugin); + + const mainProcessConfig = { + mode: 'production', + name: 'desktop-main', + target: 'electron-main', + entry: { + main: './desktop/main.js', + contextBridge: './desktop/contextBridge.js', + }, + output: { + filename: '[name].js', + path: outputPath, + libraryTarget: 'commonjs2', + }, + resolve: rendererConfig.resolve, + plugins: [definePlugin], + externals: [ + ..._.keys(desktopDependencies), + 'fsevents', + ], + node: { + /** + * Disables webpack processing of __dirname and __filename, so it works like in node + * https://github.com/webpack/webpack/issues/2010 + */ + __dirname: false, + __filename: false, + }, + }; + + return [mainProcessConfig, rendererConfig]; +}; diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index e32304af8aa..0c46975435c 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -1,12 +1,13 @@ const path = require('path'); -const webpack = require('webpack'); const {merge} = require('webpack-merge'); -const dotenv = require('dotenv'); -const common = require('./webpack.common'); +const getCommonConfig = require('./webpack.common'); -const env = dotenv.config({path: path.resolve(__dirname, '../../.env')}).parsed; - -module.exports = () => { +/** + * Configuration for the local dev server + * @param {Object} env + * @returns {Configuration} + */ +module.exports = (env = {}) => { // Check if the USE_WEB_PROXY variable has been provided // and rewrite any requests to the local proxy server const proxySettings = process.env.USE_WEB_PROXY === 'false' @@ -18,7 +19,9 @@ module.exports = () => { }, }; - return merge(common, { + const baseConfig = getCommonConfig(env); + + return merge(baseConfig, { mode: 'development', devtool: 'inline-source-map', devServer: { @@ -27,15 +30,5 @@ module.exports = () => { ...proxySettings, historyApiFallback: true, }, - plugins: [ - new webpack.DefinePlugin({ - __REACT_WEB_CONFIG__: JSON.stringify(env), - - // React Native JavaScript environment requires the global __DEV__ variable to be accessible. - // react-native-render-html uses variable to log exclusively during development. - // See https://reactnative.dev/docs/javascript-environment - __DEV__: true, - }), - ], }); }; diff --git a/config/webpack/webpack.prod.js b/config/webpack/webpack.prod.js deleted file mode 100644 index dfd7c852ab9..00000000000 --- a/config/webpack/webpack.prod.js +++ /dev/null @@ -1,9 +0,0 @@ -const path = require('path'); -const {merge} = require('webpack-merge'); -const dotenv = require('dotenv'); -const common = require('./webpack.common'); -const getProductionConfig = require('./productionConfig'); - -const env = dotenv.config({path: path.resolve(__dirname, '../../.env.production')}).parsed; - -module.exports = merge(common, getProductionConfig(env)); diff --git a/config/webpack/webpack.staging.js b/config/webpack/webpack.staging.js deleted file mode 100644 index 24f706d9073..00000000000 --- a/config/webpack/webpack.staging.js +++ /dev/null @@ -1,9 +0,0 @@ -const path = require('path'); -const {merge} = require('webpack-merge'); -const dotenv = require('dotenv'); -const common = require('./webpack.common'); -const getProductionConfig = require('./productionConfig'); - -const env = dotenv.config({path: path.resolve(__dirname, '../../.env.staging')}).parsed; - -module.exports = merge(common, getProductionConfig(env)); diff --git a/desktop/ELECTRON_ENVIRONMENT.js b/desktop/ELECTRON_ENVIRONMENT.js deleted file mode 100644 index f2de42121a5..00000000000 --- a/desktop/ELECTRON_ENVIRONMENT.js +++ /dev/null @@ -1,30 +0,0 @@ -// This variable is injected into package.json by electron-builder via the extraMetadata field (specified in electronBuilder.ghactions.config.js) -// It will be `PROD` on production, `STG` on staging, and `undefined` on dev (because dev doesn't use electron-builder) -const {electronEnvironment} = require('../package.json'); -const ENVIRONMENT = require('../src/CONST/ENVIRONMENT'); - -/** - * @returns {String} – One of ['PROD', 'STG', 'DEV'] - */ -function getEnvironment() { - // If we are on dev, then the ELECTRON_ENVIRONMENT environment variable will be present (set in package.json desktop script `npm run desktop`) - if (process.env.ELECTRON_ENV === ENVIRONMENT.DEV) { - return ENVIRONMENT.DEV; - } - - // Otherwise, use the environment injected into package.json by electron-builder - return electronEnvironment; -} - -function isDev() { - return getEnvironment() === ENVIRONMENT.DEV; -} - -function isProd() { - return getEnvironment() === ENVIRONMENT.PRODUCTION; -} - -module.exports = { - isDev, - isProd, -}; diff --git a/desktop/README.md b/desktop/README.md index 3980972d3d9..87ca4dc36b2 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -23,6 +23,7 @@ * [Architecture](#architecture) * [Testing Electron Auto-Update](#testing-electron-auto-update) +* [Packaging](#packaging) # Architecture The New Expensify desktop app is built using [Electron.js](https://www.electronjs.org/). We try our best to maintain Electron best practices, particularly when it comes to [security](https://www.electronjs.org/docs/latest/tutorial/security). @@ -87,7 +88,7 @@ mc policy set public electron-builder/electron-builder Once you have Min.IO setup and running, the next step is to temporarily revert some changes from https://github.com/Expensify/App/commit/b640b3010fd7a40783d1c04faf4489836e98038d, specifically 1. Update the `desktop-build` command in package.json to add `--publish always` at the end -2. Update electronBuilder.ghactions.config.js to replace the `publish` value with the following: +2. Update electronBuilder.config.js to replace the `publish` value with the following: ``` publish: [{ provider: 's3', @@ -121,3 +122,20 @@ AWS_ACCESS_KEY_ID=RootUserKey AWS_SECRET_ACCESS_KEY=RootPassKey APPLE_ID=YOUR_AP This command will create a build, notarize it, and push your build to the server. Note that it can take around 10 minutes for the command to complete. Once the command finishes, revert the version update in `package.json`, remove `--publish always` from the `desktop-build` command, and again run the `npm run desktop-build` command above **including the args**. After the build is done, you'll find `NewExpensify.dmg` in the `dist/` folder in the root of the project. Open the `.dmg` and install the app. Your app will attempt to auto-update in the background. + +# Packaging +To avoid bundling unnecessary `node_modules` we use a [2 package structure](https://www.electron.build/tutorials/two-package-structure) +The root [package.json](../package.json) serves for `devDependencies` and shared (renderer) `dependencies` +The [desktop/package.json](./package.json) serves for desktop (electron-main) specific dependencies +We use Webpack with a [desktop specific config](../config/webpack/webpack.desktop.js) to bundle our js code +Half of the config takes care of packaging root package dependencies - everything related to rendering App in the Electron window. Packaged under `dist/www` +The other half is about bundling the `main.js` script which initializes Electron and renders `www` + +## See what is getting packaged in the app +If you suspect unnecessary items might be getting packaged you can inspect the package content in `desktop-build/` +The app content (`dist/www`) is archived under `/New\ Expensify.app/Contents/Resources/app.asar` +To see the actual `app.asar` content run the following script +```shell +npx asar extract desktop-build/mac/New\ Expensify.app/Contents/Resources/app.asar ./unpacked-asar +``` +The expected size of `app.asar` = `desktop/dist/www/` + `desktop/node_modules/`; diff --git a/desktop/main.js b/desktop/main.js index 01075edd303..fc1bd8ff10e 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -11,9 +11,9 @@ const serve = require('electron-serve'); const contextMenu = require('electron-context-menu'); const {autoUpdater} = require('electron-updater'); const log = require('electron-log'); -const ELECTRON_ENVIRONMENT = require('./ELECTRON_ENVIRONMENT'); const ELECTRON_EVENTS = require('./ELECTRON_EVENTS'); const checkForUpdates = require('../src/libs/checkForUpdates'); +const CONFIG = require('../src/CONFIG').default; const port = process.env.PORT || 8080; @@ -40,17 +40,6 @@ autoUpdater.logger.transports.file.level = 'info'; // See https://www.npmjs.com/package/electron-log _.assign(console, log.functions); -// setup Hot reload -if (ELECTRON_ENVIRONMENT.isDev()) { - try { - require('electron-reloader')(module, { - watchRenderer: false, - ignore: [/^(desktop)/], - }); - // eslint-disable-next-line no-empty - } catch {} -} - // This sets up the command line arguments used to manage the update. When // the --expected-update-version flag is set, the app will open pre-hidden // until it detects that it has been upgraded to the correct version. @@ -124,13 +113,14 @@ const electronUpdater = browserWindow => ({ }); const mainWindow = (() => { - const loadURL = ELECTRON_ENVIRONMENT.isDev() + const loadURL = __DEV__ ? win => win.loadURL(`http://localhost:${port}`) - : serve({directory: `${__dirname}/../dist`}); + : serve({directory: `${__dirname}/www`}); // Prod and staging set the icon in the electron-builder config, so only update it here for dev - if (ELECTRON_ENVIRONMENT.isDev()) { - app.dock.setIcon(`${__dirname}/icon-dev.png`); + if (__DEV__) { + console.debug('CONFIG: ', CONFIG); + app.dock.setIcon(`${__dirname}/../icon-dev.png`); app.setName('New Expensify'); } @@ -157,40 +147,32 @@ const mainWindow = (() => { * 1. Modify headers on any outgoing requests to match the origin of our corresponding web environment (not necessary in case of web proxy, because it already does that) * 2. Modify the Access-Control-Allow-Origin header of the response to match the "real" origin of our Electron app. */ + const webRequest = browserWindow.webContents.session.webRequest; const validDestinationFilters = {urls: ['https://*.expensify.com/*']}; - if (!ELECTRON_ENVIRONMENT.isDev()) { - const newDotURL = ELECTRON_ENVIRONMENT.isProd() ? 'https://new.expensify.com' : 'https://staging.new.expensify.com'; - + /* eslint-disable no-param-reassign */ + if (!__DEV__) { // Modify the origin and referer for requests sent to our API - browserWindow.webContents.session.webRequest.onBeforeSendHeaders(validDestinationFilters, (details, callback) => { - // eslint-disable-next-line no-param-reassign - details.requestHeaders.origin = newDotURL; - // eslint-disable-next-line no-param-reassign - details.requestHeaders.referer = newDotURL; + webRequest.onBeforeSendHeaders(validDestinationFilters, (details, callback) => { + details.requestHeaders.origin = CONFIG.EXPENSIFY.URL_EXPENSIFY_CASH; + details.requestHeaders.referer = CONFIG.EXPENSIFY.URL_EXPENSIFY_CASH; callback({requestHeaders: details.requestHeaders}); }); // Modify access-control-allow-origin header for the response - browserWindow.webContents.session.webRequest.onHeadersReceived(validDestinationFilters, (details, callback) => { - // eslint-disable-next-line no-param-reassign + webRequest.onHeadersReceived(validDestinationFilters, (details, callback) => { details.responseHeaders['access-control-allow-origin'] = ['app://-']; callback({responseHeaders: details.responseHeaders}); }); + } else { + webRequest.onHeadersReceived(validDestinationFilters, (details, callback) => { + details.responseHeaders['access-control-allow-origin'] = [`http://localhost:${process.env.PORT}`]; + callback({responseHeaders: details.responseHeaders}); + }); } - - if (ELECTRON_ENVIRONMENT.isDev()) { - require('dotenv').config(); - if (process.env.USE_WEB_PROXY !== 'false') { - browserWindow.webContents.session.webRequest.onHeadersReceived(validDestinationFilters, (details, callback) => { - // eslint-disable-next-line no-param-reassign - details.responseHeaders['access-control-allow-origin'] = ['http://localhost:8080']; - callback({responseHeaders: details.responseHeaders}); - }); - } - } + /* eslint-enable */ // Prod and staging overwrite the app name in the electron-builder config, so only update it here for dev - if (ELECTRON_ENVIRONMENT.isDev()) { + if (__DEV__) { browserWindow.setTitle('New Expensify'); } @@ -328,7 +310,7 @@ const mainWindow = (() => { // Start checking for JS updates .then((browserWindow) => { - if (ELECTRON_ENVIRONMENT.isDev()) { + if (__DEV__) { return; } diff --git a/desktop/notarize.js b/desktop/notarize.js index fd4be01f35d..70ee4a89335 100644 --- a/desktop/notarize.js +++ b/desktop/notarize.js @@ -1,5 +1,5 @@ const {notarize} = require('electron-notarize'); -const electron = require('../config/electronBuilder/electronBuilder.ghactions.config'); +const electron = require('../config/electronBuilder/electronBuilder.config'); exports.default = function notarizing(context) { const {electronPlatformName, appOutDir} = context; diff --git a/desktop/package-lock.json b/desktop/package-lock.json new file mode 100644 index 00000000000..99cc9074ef1 --- /dev/null +++ b/desktop/package-lock.json @@ -0,0 +1,320 @@ +{ + "name": "new.expensify.desktop", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@types/semver": { + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", + "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "builder-util-runtime": { + "version": "8.9.2", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.9.2.tgz", + "integrity": "sha512-rhuKm5vh7E0aAmT6i8aoSfEjxzdYEFX7zDApK+eNgOhjofnWb74d9SRJv0H/8nsgOkos0TZ4zxW0P8J4N7xQ2A==", + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "electron-context-menu": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-2.5.2.tgz", + "integrity": "sha512-1cEQR6fA9ktFsRBc+eXPwvrOgAPytUD7rUV4iBAA5zTrLAPKokJ23xeMjcK2fjrDPrlFRBxcLz0KP+GUhMrSCQ==", + "requires": { + "cli-truncate": "^2.1.0", + "electron-dl": "^3.1.0", + "electron-is-dev": "^1.2.0" + } + }, + "electron-dl": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-3.3.0.tgz", + "integrity": "sha512-Zwaz/OMGPIfBLV2SQH4sTsdDOs/U4y5AOHfremMBXEpjIxX+SiTx845DZAvJJwgb5hfowyWOBLiJhd/emBNLLQ==", + "requires": { + "ext-name": "^5.0.0", + "pupa": "^2.0.1", + "unused-filename": "^2.1.0" + } + }, + "electron-is-dev": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz", + "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==" + }, + "electron-log": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.6.tgz", + "integrity": "sha512-nirYgRdY+F+vclr8ijdwy2vW03IzFpDHTaKNWu76dEN21Y76+smcES5knS7cgHUUB0qNLOi8vZO36taakjbSXA==" + }, + "electron-serve": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/electron-serve/-/electron-serve-1.1.0.tgz", + "integrity": "sha512-tQJBCbXKoKCfkBC143QCqnEtT1s8dNE2V+b/82NF6lxnGO/2Q3a3GSLHtKl3iEDQgdzTf9pH7p418xq2rXbz1Q==" + }, + "electron-updater": { + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.6.5.tgz", + "integrity": "sha512-kdTly8O9mSZfm9fslc1mnCY+mYOeaYRy7ERa2Fed240u01BKll3aiupzkd07qKw69KvhBSzuHroIW3mF0D8DWA==", + "requires": { + "@types/semver": "^7.3.6", + "builder-util-runtime": "8.9.2", + "fs-extra": "^10.0.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "^7.3.5" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==" + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "modify-filename": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-1.1.0.tgz", + "integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "requires": { + "sort-keys": "^1.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unused-filename": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-2.1.0.tgz", + "integrity": "sha512-BMiNwJbuWmqCpAM1FqxCTD7lXF97AvfQC8Kr/DIeA6VtvhJaMDupZ82+inbjl5yVP44PcxOuCSxye1QMS0wZyg==", + "requires": { + "modify-filename": "^1.1.0", + "path-exists": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/desktop/package.json b/desktop/package.json new file mode 100644 index 00000000000..926e39b5ce9 --- /dev/null +++ b/desktop/package.json @@ -0,0 +1,15 @@ +{ + "name": "new.expensify.desktop", + "description": "Desktop package native dependencies", + "main": "dist/main.js", + "scripts": {}, + "dependencies": { + "electron-context-menu": "^2.3.0", + "electron-log": "^4.3.5", + "electron-serve": "^1.0.0", + "electron-updater": "^4.3.4" + }, + "author": "Expensify, Inc.", + "license": "MIT", + "private": true +} diff --git a/desktop/start.js b/desktop/start.js index e09ee8a2d03..d3d26d4de08 100644 --- a/desktop/start.js +++ b/desktop/start.js @@ -1,23 +1,30 @@ #!/usr/bin/env node const portfinder = require('portfinder'); const concurrently = require('concurrently'); +require('dotenv').config(); const basePort = 8080; portfinder.getPortPromise({ port: basePort, }).then((port) => { + const devServer = `webpack-dev-server --config config/webpack/webpack.dev.js --port ${port} --env.platform desktop`; + const buildMain = 'webpack --config config/webpack/webpack.desktop.js --config-name desktop-main --mode=development'; + const processes = [ { - command: `webpack-dev-server --config config/webpack/webpack.dev.js --port ${port} --platform desktop`, + command: devServer, name: 'Renderer', prefixColor: 'red.dim', - }, { - command: `wait-port localhost:${port} && export PORT=${port} && electron desktop/main.js`, + command: `${buildMain} && wait-port localhost:${port} && electron desktop/dist/main.js`, name: 'Main', prefixColor: 'cyan.dim', + env: { + PORT: port, + NODE_ENV: 'development', + }, }, ]; concurrently(processes, { diff --git a/package-lock.json b/package-lock.json index ae2230e61dc..fda48d0e403 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15283,11 +15283,6 @@ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "dev": true }, - "@types/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==" - }, "@types/source-list-map": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", @@ -16947,11 +16942,6 @@ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", "dev": true }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" - }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", @@ -16985,7 +16975,8 @@ "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true }, "atob": { "version": "2.1.2", @@ -18687,15 +18678,6 @@ } } }, - "builder-util-runtime": { - "version": "8.7.2", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz", - "integrity": "sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==", - "requires": { - "debug": "^4.1.1", - "sax": "^1.2.4" - } - }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -19346,15 +19328,6 @@ "string-width": "^4.2.0" } }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - } - }, "cli-width": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", @@ -21928,35 +21901,11 @@ } } }, - "electron-context-menu": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-2.3.0.tgz", - "integrity": "sha512-XYsYkNY+jvX4C5o09qMuZoKL6e9frnQzBFehZSIiKp6zK0u3XYowJYDyK3vDKKZxYsOIGiE/Gbx40jERC03Ctw==", - "requires": { - "cli-truncate": "^2.0.0", - "electron-dl": "^3.0.0", - "electron-is-dev": "^1.0.1" - } - }, - "electron-dl": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-3.0.2.tgz", - "integrity": "sha512-pRgE9Jbhoo5z6Vk3qi+vIrfpMDlCp2oB1UeR96SMnsfz073jj0AZGQwp69EdIcEvlUlwBSGyJK8Jt6OB6JLn+g==", - "requires": { - "ext-name": "^5.0.0", - "pupa": "^2.0.1", - "unused-filename": "^2.1.0" - } - }, "electron-is-dev": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz", - "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==" - }, - "electron-log": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.3.5.tgz", - "integrity": "sha512-J5Ew3axdk7W4jzzxKLSAi1sqbcAoo9CzHuBVsG0tT47j256xKulNrWFf3lZmHJ1KDXOQUcuwOngQF0jjmpEdpw==" + "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==", + "dev": true }, "electron-notarize": { "version": "1.0.0", @@ -22216,31 +22165,12 @@ } } }, - "electron-serve": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/electron-serve/-/electron-serve-1.0.0.tgz", - "integrity": "sha512-Rsm4tjj1eK7NUWKgGw6NjHkjfB+bIXZh0ztybUYzqmwCm1wzb7zv95LERbwricDZfCsKHB0V57NgVvHdi2OOAQ==" - }, "electron-to-chromium": { "version": "1.3.820", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.820.tgz", "integrity": "sha512-5cFwDmo2yzEA9hn55KZ9+cX/b6DSFvpKz8Hb2fiDmriXWB+DBoXKXmncQwNRFBBTlUdsvPHCoy594OoMLAO0Tg==", "dev": true }, - "electron-updater": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.5.tgz", - "integrity": "sha512-5jjN7ebvfj1cLI0VZMdCnJk6aC4bP+dy7ryBf21vArR0JzpRVk0OZHA2QBD+H5rm6ZSeDYHOY6+8PrMEqJ4wlQ==", - "requires": { - "@types/semver": "^7.3.1", - "builder-util-runtime": "8.7.2", - "fs-extra": "^9.0.1", - "js-yaml": "^3.14.0", - "lazy-val": "^1.0.4", - "lodash.isequal": "^4.5.0", - "semver": "^7.3.2" - } - }, "element-resize-detector": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz", @@ -22538,7 +22468,8 @@ "escape-goat": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true }, "escape-html": { "version": "1.0.3", @@ -24255,23 +24186,6 @@ } } }, - "ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "requires": { - "mime-db": "^1.28.0" - } - }, - "ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "requires": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -25076,6 +24990,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -26891,11 +26806,6 @@ "path-is-inside": "^1.0.2" } }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -30757,6 +30667,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^1.0.0" @@ -30872,7 +30783,8 @@ "lazy-val": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", - "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==" + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", + "dev": true }, "lcid": { "version": "1.0.0", @@ -33793,11 +33705,6 @@ "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.5.tgz", "integrity": "sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==" }, - "modify-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-1.1.0.tgz", - "integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=" - }, "moment": { "version": "2.29.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", @@ -36039,14 +35946,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "pupa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", - "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", - "requires": { - "escape-goat": "^2.0.0" - } - }, "pusher-js": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-7.0.0.tgz", @@ -39304,16 +39203,6 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -39523,22 +39412,6 @@ } } }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", - "requires": { - "sort-keys": "^1.0.0" - } - }, "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -41764,7 +41637,8 @@ "universalify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true }, "unpipe": { "version": "1.0.0", @@ -41813,15 +41687,6 @@ } } }, - "unused-filename": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-2.1.0.tgz", - "integrity": "sha512-BMiNwJbuWmqCpAM1FqxCTD7lXF97AvfQC8Kr/DIeA6VtvhJaMDupZ82+inbjl5yVP44PcxOuCSxye1QMS0wZyg==", - "requires": { - "modify-filename": "^1.1.0", - "path-exists": "^4.0.0" - } - }, "upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", diff --git a/package.json b/package.json index 59011c60f4d..c9d6f62da4f 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "private": true, "scripts": { - "postinstall": "./build/react-native-web.sh", + "postinstall": "scripts/react-native-web.sh && cd desktop npm install", "clean": "react-native clean-project-auto", "android": "npm run check-metro-bundler-port && react-native run-android", "ios": "npm run check-metro-bundler-port && react-native run-ios", @@ -15,13 +15,11 @@ "ipad-sm": "npm run check-metro-bundler-port && react-native run-ios --simulator=\"iPad Pro (9.7-inch)\"", "start": "react-native start", "web": "node web/proxy.js & webpack-dev-server --open --config config/webpack/webpack.dev.js", - "build": "webpack --config config/webpack/webpack.prod.js", - "build-staging": "webpack --config config/webpack/webpack.staging.js", - "desktop": "export ELECTRON_ENV=development && node desktop/start.js", - "desktop-build": "export ELECTRON_ENV=production && webpack --config config/webpack/webpack.prod.js --platform desktop && electron-builder --config config/electronBuilder/electronBuilder.ghactions.config.js", - "desktop-build-staging": "export ELECTRON_ENV=staging && webpack --config config/webpack/webpack.staging.js --platform desktop && electron-builder --config config/electronBuilder/electronBuilder.ghactions.config.js", - "desktop-build-local": "export ELECTRON_ENV=production && webpack --config config/webpack/webpack.prod.js --platform desktop && electron-builder --config config/electronBuilder/electronBuilder.local.config.js", - "desktop-build-staging-local": "export ELECTRON_ENV=staging && webpack --config config/webpack/webpack.staging.js --platform desktop && electron-builder --config config/electronBuilder/electronBuilder.local.config.js", + "build": "webpack --config config/webpack/webpack.common.js --env.envFile=.env.production", + "build-staging": "webpack --config config/webpack/webpack.common.js --env.envFile=.env.staging", + "desktop": "node desktop/start.js", + "desktop-build": "scripts/build-desktop.sh production", + "desktop-build-staging": "scripts/build-desktop.sh staging", "ios-build": "fastlane ios build", "android-build": "fastlane android build", "test": "jest", @@ -63,10 +61,6 @@ "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", "dotenv": "^8.2.0", - "electron-context-menu": "^2.3.0", - "electron-log": "^4.3.5", - "electron-serve": "^1.0.0", - "electron-updater": "^4.3.4", "expensify-common": "git+https://github.com/Expensify/expensify-common.git#f77bb4710c13d01153716df7fb087b637ba3b8bd", "fbjs": "^3.0.2", "file-loader": "^6.0.0", diff --git a/scripts/build-desktop.sh b/scripts/build-desktop.sh new file mode 100755 index 00000000000..caacef99302 --- /dev/null +++ b/scripts/build-desktop.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -e + +ELECTRON_ENV=${1:-development} + +if [[ "$ELECTRON_ENV" == "staging" ]]; then + ENV_FILE=".env.staging" +elif [[ "$ELECTRON_ENV" == "production" ]]; then + ENV_FILE=".env.production" +else + ENV_FILE=".env" +fi + +SCRIPTS_DIR=$(dirname "${BASH_SOURCE[0]}") +LOCAL_PACKAGES=$(npm bin) +source "$SCRIPTS_DIR/shellUtils.sh"; + +title "Bundling Desktop js Bundle Using Webpack" +info " • ELECTRON_ENV: $ELECTRON_ENV" +info " • ENV file: $ENV_FILE" +info "" +"$LOCAL_PACKAGES/webpack" --config config/webpack/webpack.desktop.js --env.envFile=$ENV_FILE + +title "Building Desktop App Archive Using Electron" +info "" +shift 1 +"$LOCAL_PACKAGES/electron-builder" --config config/electronBuilder/electronBuilder.config.js "$@" diff --git a/build/react-native-web.sh b/scripts/react-native-web.sh similarity index 100% rename from build/react-native-web.sh rename to scripts/react-native-web.sh diff --git a/tests/utils/shellUtils.sh b/scripts/shellUtils.sh similarity index 100% rename from tests/utils/shellUtils.sh rename to scripts/shellUtils.sh diff --git a/src/CONST/index.js b/src/CONST.js similarity index 99% rename from src/CONST/index.js rename to src/CONST.js index de65811922c..d169485906e 100755 --- a/src/CONST/index.js +++ b/src/CONST.js @@ -1,7 +1,6 @@ import lodashGet from 'lodash/get'; import Config from 'react-native-config'; -import ENVIRONMENT from './ENVIRONMENT'; -import * as Url from '../libs/Url'; +import * as Url from './libs/Url'; const CLOUDFRONT_URL = 'https://d2k5nsl2zxldvw.cloudfront.net'; const USE_EXPENSIFY_URL = 'https://use.expensify.com'; @@ -397,6 +396,12 @@ const CONST = { ADMIN: 'admin@expensify.com', }, + ENVIRONMENT: { + DEV: 'development', + STAGING: 'staging', + PRODUCTION: 'production', + }, + // Used to delay the initial fetching of reportActions when the app first inits or reconnects (e.g. returning // from backgound). The times are based on how long it generally seems to take for the app to become interactive // in each scenario. @@ -616,6 +621,4 @@ const CONST = { }, }; -CONST.ENVIRONMENT = ENVIRONMENT; - export default CONST; diff --git a/src/CONST/ENVIRONMENT.js b/src/CONST/ENVIRONMENT.js deleted file mode 100644 index d18744fffbe..00000000000 --- a/src/CONST/ENVIRONMENT.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - DEV: 'development', - STAGING: 'staging', - PRODUCTION: 'production', -}; diff --git a/tests/unit/getPullRequestsMergedBetweenTest.sh b/tests/unit/getPullRequestsMergedBetweenTest.sh index 6a30429c58a..47e0e9d9c35 100755 --- a/tests/unit/getPullRequestsMergedBetweenTest.sh +++ b/tests/unit/getPullRequestsMergedBetweenTest.sh @@ -4,10 +4,11 @@ set -e TEST_DIR=$(dirname "$(dirname "$(cd "$(dirname "$0")" || exit 1;pwd)/$(basename "$0")")") +SCRIPTS_DIR="$TEST_DIR/../scripts" DUMMY_DIR="$HOME/DumDumRepo" getPullRequestsMergedBetween="$TEST_DIR/utils/getPullRequestsMergedBetween.js" -source "$TEST_DIR/utils/shellUtils.sh" +source "$SCRIPTS_DIR/shellUtils.sh" function print_version { < package.json jq -r .version