Skip to content

Commit

Permalink
Support React Native (#37)
Browse files Browse the repository at this point in the history
* Update build system to support a React Native bundle

* Add initial implementation for React Native (requires e2e testing)

* Fix CJS builds and rename 'WebViewController' to 'ReactNativeWebViewController'

* Remove unnecessary return statement

* Fix React dependency regex in Webpack config

* Update CircleCI config

* Re-organize '/core' tests to reflect additional view controllers

* Organizational comments

* Remove superfluous comment

* Add first draft CHANGELOG entry for React Native feature

* Update 'isViewReady' condition

* Package 'react-native-webview' and 'whatwg-url' in the RN bundle

* Add .vscode to git ignores

* Add /dist to eslint ignores

* Clean up Webpack config

* Externalize 'react-native-webview' & fix event listener bug in 'PayloadTransport'

* React native unit tests (#49)

* Add constructor test for MagicSDKReactNative

* Add 'magic.link' as homepage in 'package.json'

* Update 'tsconfig.jsx' to 'react-native'

* Revert change to tsconfig

* Fix test preprocessing to support React/React Native

* Fix typo

* Fix 'PayloadTransport.post' tests

* Cleanup test files & improve core SDK coverage after RN changes

* Add unit tests for 'PayloadTransport.handleReactNativeWebViewMessage'

* Update architectural overview with React Native-specific info

* Add unit tests for 'ReactNativeWebViewController' methods (WIP)

* Add coverage ignore comment

* Add 'utils/url' tests

* Add some testing cleanups
  • Loading branch information
smithki committed Apr 22, 2020
1 parent a3c261d commit 24228c3
Show file tree
Hide file tree
Showing 93 changed files with 3,945 additions and 1,279 deletions.
5 changes: 2 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ aliases: [
# List of build output paths that should be persisted to the
# CircleCI workspace.
&build-output-paths [
"dist",
"build"
"dist"
],

# NPM lockfile cache key (update "vN" => "vN+1" to cache-bust).
&dependency-cache-key "v1-dependency-cache-{{ checksum \"yarn.lock\" }}",
&dependency-cache-key "v2-dependency-cache-{{ checksum \"yarn.lock\" }}",

&workspace-root "/home/circleci/project",

Expand Down
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/node_modules
/dist
react-native.js
react-native.d.ts
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"@typescript-eslint/await-thenable": 0,
"no-useless-constructor": 0,
"@typescript-eslint/no-useless-constructor": 0,
"@typescript-eslint/no-empty-function": 0
"@typescript-eslint/no-empty-function": 0,
"import/no-extraneous-dependencies": [1, {"devDependencies": true}]
},
"settings": {
"import/resolver": {
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies

/node_modules
/.vscode
/.idea
.DS_Store
/dist
Expand Down
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@

#### Added

- ...
- Support for React Native:

```tsx
// Import the React Native bundle
// (Don't worry, the API is exactly the same!)
import { Magic } from 'magic-sdk/react-native';

const magic = new Magic('API_KEY');

function App() {
return (<div>
{/* Just render the `Modal` component to connect Magic SDK! 🚀 */}
<magic.Modal />
</div>);
}
```

## `1.0.3` - 04/21/2020

Expand Down
30 changes: 30 additions & 0 deletions config/tsconfig.base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"compilerOptions": {
"lib": ["es2018", "dom"],
"module": "commonjs",
"moduleResolution": "node",
"target": "es5",
"strict": true,
"jsx": "react",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"esModuleInterop": true,
"downlevelIteration": true,
"resolveJsonModule": true,
"allowJs": true,
"sourceMap": true,
"declaration": true,
},
"include": [
"../src/**/*.ts",
"../src/**/*.tsx",
"../test/**/*.ts",
"../webpack/**/*.ts"
],
"exclude": [
"../node_modules",
"../dist"
]
}
12 changes: 12 additions & 0 deletions config/tsconfig.cdn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "../src",
"outDir": "../dist",
"declaration": false
},
"include": [
"../src/**/*.ts",
"../src/**/*.tsx"
]
}
11 changes: 11 additions & 0 deletions config/tsconfig.cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "../src",
"outDir": "../dist/cjs"
},
"include": [
"../src/**/*.ts",
"../src/**/*.tsx"
]
}
11 changes: 11 additions & 0 deletions config/tsconfig.react-native.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "../src",
"outDir": "../dist/react-native"
},
"include": [
"../src/**/*.ts",
"../src/**/*.tsx"
]
}
9 changes: 9 additions & 0 deletions config/tsconfig.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"target": "es6",
"strict": false,
"noImplicitAny": false
},
"include": ["../test/**/*.ts"]
}
4 changes: 4 additions & 0 deletions config/tsconfig.webpack.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.base.json",
"include": ["../webpack/**/*.ts"]
}
21 changes: 16 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"type": "git",
"url": "https://github.com/fortmatic/magic-js"
},
"homepage": "https://www.fortmatic.com",
"main": "dist/cjs/magic.js",
"types": "dist/cjs/src/index.d.ts",
"homepage": "https://magic.link",
"main": "dist/cjs/index.js",
"types": "dist/cjs/index.cjs.d.ts",
"scripts": {
"start": "yarn run clean:build && ./scripts/start.sh",
"build": "yarn run clean:build && ./scripts/build.sh",
Expand All @@ -21,15 +21,22 @@
"clean:build": "rimraf dist",
"clean_node_modules": "rimraf node_modules"
},
"dependencies": {},
"dependencies": {
"react-native-webview": "^8.1.2",
"whatwg-url": "^8.0.0"
},
"devDependencies": {
"@ikscodes/browser-env": "~0.3.1",
"@ikscodes/eslint-config": "~6.2.0",
"@ikscodes/prettier-config": "^0.1.0",
"@istanbuljs/nyc-config-typescript": "~0.1.3",
"@types/jsdom": "~12.2.4",
"@types/mockery": "^1.4.29",
"@types/react": "^16.9.34",
"@types/react-native": "^0.62.2",
"@types/sinon": "~7.5.0",
"@types/webpack": "~4.41.0",
"@types/whatwg-url": "^6.4.0",
"@typescript-eslint/eslint-plugin": "~2.17.0",
"ava": "2.2.0",
"cli-glob": "^0.1.0",
Expand All @@ -42,9 +49,12 @@
"eslint-plugin-react-hooks": "~1.7.0",
"husky": "^4.2.3",
"lint-staged": "^10.0.7",
"mockery": "^2.1.0",
"npm-run-all": "~4.1.5",
"nyc": "13.1.0",
"prettier": "~1.19.1",
"react": "^16.13.1",
"react-native": "^0.62.2",
"rimraf": "~3.0.0",
"sinon": "7.1.1",
"ts-loader": "~6.2.1",
Expand All @@ -64,7 +74,8 @@
},
"ava": {
"require": [
"ts-node/register"
"ts-node/register",
"./test/setup.ts"
],
"files": [
"test/**/*.spec.ts"
Expand Down
1 change: 1 addition & 0 deletions react-native.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './dist/react-native/index.react-native.d.ts';
1 change: 1 addition & 0 deletions react-native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/react-native/index.js');
10 changes: 8 additions & 2 deletions scripts/build.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#!/usr/bin/env bash

export NODE_ENV=production
export MAGIC_URL=https://auth.magic.link
export MAGIC_URL=https://auth.magic.link/
export MGBOX_URL=https://mgbox.io/
export SDK_NAME=$(node -pe "require('./package.json')['name']")
export SDK_VERSION=$(node -pe "require('./package.json')['version']")

# Increase memory limit for Node
export NODE_OPTIONS=--max_old_space_size=4096

echo
echo "Building Magic SDK for production, pointing to $MAGIC_URL"
echo "Building Magic SDK for production, pointing to:"
echo
echo " auth: $MAGIC_URL"
echo " mgbox: $MGBOX_URL"
echo

export TS_NODE_PROJECT="webpack/tsconfig.json"
Expand Down
13 changes: 11 additions & 2 deletions scripts/start.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
#!/usr/bin/env bash

LOCAL_MAGIC_PORT=3014
LOCAL_MGBOX_PORT=3016

export NODE_ENV=development
export MAGIC_URL=https://auth.magic.link
export MAGIC_URL=https://auth.magic.link/
export MGBOX_URL=https://mgbox.io/
export SDK_NAME=$(node -pe "require('./package.json')['name']")
export SDK_VERSION=$(node -pe "require('./package.json')['version']")

# Increase memory limit for Node
export NODE_OPTIONS=--max_old_space_size=4096

echo
echo "Building Magic SDK for development, pointing to $MAGIC_URL"
echo "Building Magic SDK for production, pointing to:"
echo
echo " auth: $MAGIC_URL"
echo " mgbox: $MGBOX_URL"
echo

export TS_NODE_PROJECT="webpack/tsconfig.json"
Expand Down
4 changes: 4 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ echo
echo "Running unit tests..."
echo

export NODE_ENV=test
export SDK_NAME=$(node -pe "require('./package.json')['name']")
export SDK_VERSION=$(node -pe "require('./package.json')['version']")

if [ -n "$1" ]; then
input=$(echo $(npx glob $1))
fi
Expand Down
10 changes: 10 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,13 @@ web3.eth.sendTransaction(...);

RPCProviderModule.sendAsync -> PayloadTransport.post -> Window.postMessage -> iframe
```

## React Native

We support web and React Native implementations from the same SDK. This introduces a few notable _gotchas:_

1. Do not reference any React dependencies at the top-level! Only use these dependencies within a closure (such as the body of a class method or function), and assume they could be `undefined`. We completely remove these dependencies from CJS and CDN bundles, so referencing these imports will raise a `TypeError`.

2. You can use the `IS_REACT_NATIVE` environment constant to gate browser-specific or React Native-specific APIs. Do not assume that all `window` functionality is available in a React Native context! It may be helpful to familiarize yourself with the [differences between React.js and React Native](https://medium.com/@alexmngn/from-reactjs-to-react-native-what-are-the-main-differences-between-both-d6e8e88ebf24).

3. See [`./noop-module.ts`](./noop-module.ts)? It's purposefully empty! Any dependencies that need removal from a specific environment's bundle is replaced with this module. Please don't change or remove this file!
4 changes: 4 additions & 0 deletions src/constants/config.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export const MAGIC_URL = process.env.MAGIC_URL || 'https://auth.magic.link/';
export const MGBOX_URL = process.env.MGBOX_URL || 'https://mgbox.io/';
export const IS_REACT_NATIVE = Boolean(process.env.IS_REACT_NATIVE);
export const SDK_NAME = process.env.SDK_NAME!;
export const SDK_VERSION = process.env.SDK_VERSION!;
Loading

0 comments on commit 24228c3

Please sign in to comment.