diff --git a/README.md b/README.md
index 4be2332c..b19a429b 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,42 @@
# Async Storage
-A collection of persistent data storages, unified into a single API.
+A collection of persistent data storages, targeting different platforms, unified within a single API.
## Work in progress
Async Storage v2 is under development.
-If you're looking for published and operational Async Storage version, please check out [`LEGACY`](https://github.com/react-native-community/async-storage/tree/LEGACY) branch.
+If you're looking for published and operational Async Storage version, please check out [`LEGACY`](https://github.com/react-native-community/async-storage/tree/LEGACY) branch.
## Features
-- Unified API to consume any supported storage
-- Different type of storage for different purpose, see [available storages](#available-storages)
-- Extensible functionality, to leverage full storage potential
-- Support for Mobile, Web and more
+- One, unified API to support different storages
+- [Extensible functionality](./packages/core/docs/API.md#extensions)
+- Targets Mobile, Web and more
+
## Getting started
### Install
-1. Get required core
+1. Install Core dependency
```bash
yarn add @react-native-community/async-storage@next
```
-2. Pick desired [storage for your platform.](#available-storages)
+2. Select a [storage for your platform.](#available-storages)
### Usage
-Example usage can [be found here.](./packages/core/docs/Usage.md)
+See usage can [be found here.](./packages/core/docs/Usage.md)
## Available storages
-- [Legacy](./packages/storage-legacy/README.md) - for React Native
-- [Web](./packages/storage-web/README.md) - for Web applications
+- [Legacy](./packages/storage-legacy/README.md) - for React Native apps
+- [Web](./packages/storage-web/README.md) - for Web apps
## Documentation
diff --git a/examples/mobile/README.md b/examples/mobile/README.md
index d1e3155b..18b15de5 100644
--- a/examples/mobile/README.md
+++ b/examples/mobile/README.md
@@ -1,14 +1,16 @@
-# Async Storage mobile examples
+# Async Storage - Mobile example
-## Running the example
+Example React Native app presenting features of [`async-storage-backend-legacy`](https://github.com/react-native-community/async-storage/tree/master/packages/storage-legacy).
-1. Get dependencies
+## Running the app
+
+1. Install dependencies
```bash
$ yarn install
```
-2. Install the app
+2. Run the app on either platform
```bash
# Android
@@ -18,17 +20,10 @@ $ yarn start:android
$ yarn start:ios
```
-3. Run packager
-
-```bash
-$ yarn start
-```
-
## Feedback
-Let me know about any issue found or feedback you have at [Async-Storage issue page](https://github.com/react-native-community/async-storage/issues).
-Please mark it as `examples` label.
+All feedback is welcome at [Async-Storage issue page](https://github.com/react-native-community/async-storage/issues).
## License
-MIT
+MIT.
diff --git a/examples/mobile/ios/Podfile.lock b/examples/mobile/ios/Podfile.lock
index 5a56362e..f51bea0c 100644
--- a/examples/mobile/ios/Podfile.lock
+++ b/examples/mobile/ios/Podfile.lock
@@ -111,7 +111,7 @@ DEPENDENCIES:
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
- https://github.com/cocoapods/specs.git:
+ https://github.com/CocoaPods/Specs.git:
- boost-for-react-native
EXTERNAL SOURCES:
@@ -190,4 +190,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 4e647e55207a6e7a83f354d0cfc8a32c14b6e9ae
-COCOAPODS: 1.7.1
+COCOAPODS: 1.8.4
diff --git a/examples/mobile/package.json b/examples/mobile/package.json
index 2a6f5133..994666ca 100644
--- a/examples/mobile/package.json
+++ b/examples/mobile/package.json
@@ -1,11 +1,11 @@
{
- "name": "asyncstorageexample",
+ "name": "AsyncStorageMobileExample",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
- "start:android": "react-native run-android",
- "start:ios": "react-native run-ios",
+ "android": "react-native run-android",
+ "ios": "react-native run-ios",
"test": "jest",
"lint": "eslint ."
},
@@ -17,11 +17,10 @@
"devDependencies": {
"@babel/core": "7.5.4",
"@babel/runtime": "7.5.4",
- "@react-native-community/eslint-config": "0.0.3",
+ "@react-native-community/eslint-config": "0.0.5",
"babel-jest": "24.8.0",
"babel-plugin-module-resolver": "^3.2.0",
"eslint": "5.16.0",
- "get-yarn-workspaces": "^1.0.2",
"jest": "24.8.0",
"metro-react-native-babel-preset": "0.55.0",
"react-test-renderer": "16.8.6"
diff --git a/examples/mobile/src/legacy/storage.js b/examples/mobile/src/legacy/storage.js
index e7a46d2f..8227be15 100644
--- a/examples/mobile/src/legacy/storage.js
+++ b/examples/mobile/src/legacy/storage.js
@@ -1,9 +1,8 @@
import LegacyStorage from '@react-native-community/async-storage-backend-legacy';
import AsyncStorageFactory from '@react-native-community/async-storage';
-
const legacy = new LegacyStorage();
-const storage = AsyncStorageFactory.create(legacy, {});
+const storage = AsyncStorageFactory.create(legacy);
export default storage;
diff --git a/examples/mobile/yarn.lock b/examples/mobile/yarn.lock
index 14e39e8e..64e5093c 100644
--- a/examples/mobile/yarn.lock
+++ b/examples/mobile/yarn.lock
@@ -910,11 +910,13 @@
shell-quote "1.6.1"
ws "^1.1.0"
-"@react-native-community/eslint-config@0.0.3":
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/@react-native-community/eslint-config/-/eslint-config-0.0.3.tgz#bf9be8434caa18f85b570cf4e28366f2a7f1ea91"
- integrity sha512-YmCiqoiqgSW8YpWYWLwG4WYwVIwvkhfH97COxbin71CuCr5muZPlmhHOFwo2gIQzUvt1ewFb1shtUi1X8TAVhA==
+"@react-native-community/eslint-config@0.0.5":
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/@react-native-community/eslint-config/-/eslint-config-0.0.5.tgz#584f6493258202a57efc22e7be66966e43832795"
+ integrity sha512-jwO2tnKaTPTLX5XYXMHGEnFdf543SU7jz98/OF5mDH3b7lP+BOaCD+jVfqqHoDRkcqyPlYiR1CgwVGWpi0vMWg==
dependencies:
+ "@typescript-eslint/eslint-plugin" "^1.5.0"
+ "@typescript-eslint/parser" "^1.5.0"
babel-eslint "10.0.1"
eslint-plugin-eslint-comments "^3.1.1"
eslint-plugin-flowtype "2.50.3"
@@ -958,6 +960,11 @@
dependencies:
"@babel/types" "^7.3.0"
+"@types/eslint-visitor-keys@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
+ integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
+
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@@ -978,6 +985,11 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
+"@types/json-schema@^7.0.3":
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
+ integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
+
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
@@ -988,6 +1000,44 @@
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916"
integrity sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==
+"@typescript-eslint/eslint-plugin@^1.5.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz#22fed9b16ddfeb402fd7bcde56307820f6ebc49f"
+ integrity sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==
+ dependencies:
+ "@typescript-eslint/experimental-utils" "1.13.0"
+ eslint-utils "^1.3.1"
+ functional-red-black-tree "^1.0.1"
+ regexpp "^2.0.1"
+ tsutils "^3.7.0"
+
+"@typescript-eslint/experimental-utils@1.13.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz#b08c60d780c0067de2fb44b04b432f540138301e"
+ integrity sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==
+ dependencies:
+ "@types/json-schema" "^7.0.3"
+ "@typescript-eslint/typescript-estree" "1.13.0"
+ eslint-scope "^4.0.0"
+
+"@typescript-eslint/parser@^1.5.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.13.0.tgz#61ac7811ea52791c47dc9fd4dd4a184fae9ac355"
+ integrity sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==
+ dependencies:
+ "@types/eslint-visitor-keys" "^1.0.0"
+ "@typescript-eslint/experimental-utils" "1.13.0"
+ "@typescript-eslint/typescript-estree" "1.13.0"
+ eslint-visitor-keys "^1.0.0"
+
+"@typescript-eslint/typescript-estree@1.13.0":
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz#8140f17d0f60c03619798f1d628b8434913dc32e"
+ integrity sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==
+ dependencies:
+ lodash.unescape "4.0.1"
+ semver "5.5.0"
+
abab@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f"
@@ -2172,7 +2222,7 @@ eslint-scope@3.7.1:
esrecurse "^4.1.0"
estraverse "^4.1.1"
-eslint-scope@^4.0.3:
+eslint-scope@^4.0.0, eslint-scope@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
@@ -2559,11 +2609,6 @@ find-cache-dir@^2.0.0:
make-dir "^2.0.0"
pkg-dir "^3.0.0"
-find-root@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
- integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
-
find-up@^2.0.0, find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@@ -2592,11 +2637,6 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
-flatten@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
- integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
-
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -2712,15 +2752,6 @@ get-value@^2.0.3, get-value@^2.0.6:
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
-get-yarn-workspaces@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/get-yarn-workspaces/-/get-yarn-workspaces-1.0.2.tgz#81591bdb392f1c6bac09cdc8491a6d275781aa44"
- integrity sha512-Auel048Uclfgr74oNXKZWH30UgKDZXQdfUfgD9iWXdoUGJpeWg9lSuX/FZkQ6RB3KnBfAaf70xQXfwOjiE9rPw==
- dependencies:
- find-root "^1.1.0"
- flatten "^1.0.2"
- glob "^7.1.2"
-
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@@ -3881,6 +3912,11 @@ lodash.throttle@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
+lodash.unescape@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
+ integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=
+
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.6.1:
version "4.17.14"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
@@ -5526,6 +5562,11 @@ scheduler@^0.13.6:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+semver@5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
+ integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
+
semver@^6.0.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db"
@@ -6052,11 +6093,18 @@ trim-right@^1.0.1:
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
-tslib@^1.9.0:
+tslib@^1.8.1, tslib@^1.9.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+tsutils@^3.7.0:
+ version "3.17.1"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
+ integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
+ dependencies:
+ tslib "^1.8.1"
+
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
diff --git a/examples/web/.gitignore b/examples/web/.gitignore
new file mode 100644
index 00000000..4d29575d
--- /dev/null
+++ b/examples/web/.gitignore
@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/examples/web/README.md b/examples/web/README.md
new file mode 100644
index 00000000..1366d835
--- /dev/null
+++ b/examples/web/README.md
@@ -0,0 +1,25 @@
+# Async Storage - Web example
+
+Example React app presenting features of [`async-storage-backend-web`](https://github.com/react-native-community/async-storage/tree/master/packages/storage-web).
+
+## Running the app
+
+1. Install dependencies
+
+```bash
+$ yarn install
+```
+
+2. Run the app
+
+```bash
+$ yarn start
+```
+
+## Feedback
+
+All feedback is welcome at [Async-Storage issue page](https://github.com/react-native-community/async-storage/issues).
+
+## License
+
+MIT.
diff --git a/examples/web/config/env.js b/examples/web/config/env.js
new file mode 100644
index 00000000..211711b2
--- /dev/null
+++ b/examples/web/config/env.js
@@ -0,0 +1,93 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const paths = require('./paths');
+
+// Make sure that including paths.js after env.js will read .env variables.
+delete require.cache[require.resolve('./paths')];
+
+const NODE_ENV = process.env.NODE_ENV;
+if (!NODE_ENV) {
+ throw new Error(
+ 'The NODE_ENV environment variable is required but was not specified.'
+ );
+}
+
+// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
+const dotenvFiles = [
+ `${paths.dotenv}.${NODE_ENV}.local`,
+ `${paths.dotenv}.${NODE_ENV}`,
+ // Don't include `.env.local` for `test` environment
+ // since normally you expect tests to produce the same
+ // results for everyone
+ NODE_ENV !== 'test' && `${paths.dotenv}.local`,
+ paths.dotenv,
+].filter(Boolean);
+
+// Load environment variables from .env* files. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set. Variable expansion is supported in .env files.
+// https://github.com/motdotla/dotenv
+// https://github.com/motdotla/dotenv-expand
+dotenvFiles.forEach(dotenvFile => {
+ if (fs.existsSync(dotenvFile)) {
+ require('dotenv-expand')(
+ require('dotenv').config({
+ path: dotenvFile,
+ })
+ );
+ }
+});
+
+// We support resolving modules according to `NODE_PATH`.
+// This lets you use absolute paths in imports inside large monorepos:
+// https://github.com/facebook/create-react-app/issues/253.
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
+// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
+// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
+// We also resolve them to make sure all tools using them work consistently.
+const appDirectory = fs.realpathSync(process.cwd());
+process.env.NODE_PATH = (process.env.NODE_PATH || '')
+ .split(path.delimiter)
+ .filter(folder => folder && !path.isAbsolute(folder))
+ .map(folder => path.resolve(appDirectory, folder))
+ .join(path.delimiter);
+
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in Webpack configuration.
+const REACT_APP = /^REACT_APP_/i;
+
+function getClientEnvironment(publicUrl) {
+ const raw = Object.keys(process.env)
+ .filter(key => REACT_APP.test(key))
+ .reduce(
+ (env, key) => {
+ env[key] = process.env[key];
+ return env;
+ },
+ {
+ // Useful for determining whether we’re running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ NODE_ENV: process.env.NODE_ENV || 'development',
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example,
.
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ PUBLIC_URL: publicUrl,
+ }
+ );
+ // Stringify all values so we can feed into Webpack DefinePlugin
+ const stringified = {
+ 'process.env': Object.keys(raw).reduce((env, key) => {
+ env[key] = JSON.stringify(raw[key]);
+ return env;
+ }, {}),
+ };
+
+ return { raw, stringified };
+}
+
+module.exports = getClientEnvironment;
diff --git a/examples/web/config/modules.js b/examples/web/config/modules.js
new file mode 100644
index 00000000..c8efd0dd
--- /dev/null
+++ b/examples/web/config/modules.js
@@ -0,0 +1,141 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const paths = require('./paths');
+const chalk = require('react-dev-utils/chalk');
+const resolve = require('resolve');
+
+/**
+ * Get additional module paths based on the baseUrl of a compilerOptions object.
+ *
+ * @param {Object} options
+ */
+function getAdditionalModulePaths(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ // We need to explicitly check for null and undefined (and not a falsy value) because
+ // TypeScript treats an empty string as `.`.
+ if (baseUrl == null) {
+ // If there's no baseUrl set we respect NODE_PATH
+ // Note that NODE_PATH is deprecated and will be removed
+ // in the next major release of create-react-app.
+
+ const nodePath = process.env.NODE_PATH || '';
+ return nodePath.split(path.delimiter).filter(Boolean);
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
+ // the default behavior.
+ if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Allow the user set the `baseUrl` to `appSrc`.
+ if (path.relative(paths.appSrc, baseUrlResolved) === '') {
+ return [paths.appSrc];
+ }
+
+ // If the path is equal to the root directory we ignore it here.
+ // We don't want to allow importing from the root directly as source files are
+ // not transpiled outside of `src`. We do allow importing them with the
+ // absolute path (e.g. `src/Components/Button.js`) but we set that up with
+ // an alias.
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Otherwise, throw an error.
+ throw new Error(
+ chalk.red.bold(
+ "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
+ ' Create React App does not support other values at this time.'
+ )
+ );
+}
+
+/**
+ * Get webpack aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getWebpackAliases(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ src: paths.appSrc,
+ };
+ }
+}
+
+/**
+ * Get jest aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getJestAliases(options = {}) {
+ const baseUrl = options.baseUrl;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ '^src/(.*)$': '/src/$1',
+ };
+ }
+}
+
+function getModules() {
+ // Check if TypeScript is setup
+ const hasTsConfig = fs.existsSync(paths.appTsConfig);
+ const hasJsConfig = fs.existsSync(paths.appJsConfig);
+
+ if (hasTsConfig && hasJsConfig) {
+ throw new Error(
+ 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
+ );
+ }
+
+ let config;
+
+ // If there's a tsconfig.json we assume it's a
+ // TypeScript project and set up the config
+ // based on tsconfig.json
+ if (hasTsConfig) {
+ const ts = require(resolve.sync('typescript', {
+ basedir: paths.appNodeModules,
+ }));
+ config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
+ // Otherwise we'll check if there is jsconfig.json
+ // for non TS projects.
+ } else if (hasJsConfig) {
+ config = require(paths.appJsConfig);
+ }
+
+ config = config || {};
+ const options = config.compilerOptions || {};
+
+ const additionalModulePaths = getAdditionalModulePaths(options);
+
+ return {
+ additionalModulePaths: additionalModulePaths,
+ webpackAliases: getWebpackAliases(options),
+ jestAliases: getJestAliases(options),
+ hasTsConfig,
+ };
+}
+
+module.exports = getModules();
diff --git a/examples/web/config/paths.js b/examples/web/config/paths.js
new file mode 100644
index 00000000..8cea8399
--- /dev/null
+++ b/examples/web/config/paths.js
@@ -0,0 +1,88 @@
+'use strict';
+
+const path = require('path');
+const fs = require('fs');
+const url = require('url');
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebook/create-react-app/issues/637
+const appDirectory = fs.realpathSync(process.cwd());
+const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
+
+const envPublicUrl = process.env.PUBLIC_URL;
+
+function ensureSlash(inputPath, needsSlash) {
+ const hasSlash = inputPath.endsWith('/');
+ if (hasSlash && !needsSlash) {
+ return inputPath.substr(0, inputPath.length - 1);
+ } else if (!hasSlash && needsSlash) {
+ return `${inputPath}/`;
+ } else {
+ return inputPath;
+ }
+}
+
+const getPublicUrl = appPackageJson =>
+ envPublicUrl || require(appPackageJson).homepage;
+
+// We use `PUBLIC_URL` environment variable or "homepage" field to infer
+// "public path" at which the app is served.
+// Webpack needs to know it to put the right