diff --git a/README.md b/README.md index b588811..cb3f216 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,6 @@ $ npm run android

## Folder structure -[Example app](https://github.com/VISI-ONE/create-react-native-web-example) ``` myApp ├── node_modules @@ -96,6 +95,8 @@ myApp └── registerServiceWorker.js ``` +[Example app built with this CLI](https://github.com/VISI-ONE/create-react-native-web-example) + ## Testing ```sh @@ -157,6 +158,8 @@ $ open ./android/app/build/outputs/apk [React native docs for IOS](http://facebook.github.io/react-native/releases/0.49/docs/running-on-device.html#building-your-app-for-production) ## Troubleshooting +Issues with Xcode 10 (newest version) - https://github.com/facebook/react-native/issues/19573 + If you got `Execution failed for task ':app:compileDebugAidl'` when running `yarn android`, try to update Android Gradle plugin to version 3.1.1 and Gradle to version 4.4. Here is how to do that: diff --git a/package.json b/package.json index 2da96d2..ce41337 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "create-react-native-web-app", - "version": "0.1.6", + "version": "0.1.7", "description": "React Native Web CLI", "main": "cli.js", "scripts": { diff --git a/template/.flowconfig b/template/.flowconfig deleted file mode 100644 index 5b1b233..0000000 --- a/template/.flowconfig +++ /dev/null @@ -1,75 +0,0 @@ -[ignore] -; We fork some components by platform -.*/*[.]android.js - -; Ignore templates for 'react-native init' -/node_modules/react-native/local-cli/templates/.* - -; Ignore RN jest -/node_modules/react-native/jest/.* - -; Ignore RNTester -/node_modules/react-native/RNTester/.* - -; Ignore the website subdir -/node_modules/react-native/website/.* - -; Ignore the Dangerfile -/node_modules/react-native/danger/dangerfile.js - -; Ignore Fbemitter -/node_modules/fbemitter/.* - -; Ignore "BUCK" generated dirs -/node_modules/react-native/\.buckd/ - -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore polyfills -/node_modules/react-native/Libraries/polyfills/.* - -; Ignore various node_modules -/node_modules/react-native-gesture-handler/.* -/node_modules/expo/.* -/node_modules/react-navigation/.* -/node_modules/xdl/.* -/node_modules/reqwest/.* -/node_modules/metro-bundler/.* - -[include] - -[libs] -node_modules/react-native/Libraries/react-native/react-native-interface.js -node_modules/react-native/flow/ -node_modules/expo/flow/ - -[options] -emoji=true - -module.system=haste - -module.file_ext=.js -module.file_ext=.jsx -module.file_ext=.json -module.file_ext=.ios.js - -munge_underscores=true - -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FlowFixMeProps -suppress_type=$FlowFixMeState -suppress_type=$FixMe - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native_oss[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy -suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError - -unsafe.enable_getters_and_setters=true - -[version] -^0.56.0 diff --git a/template/.gitignore b/template/.gitignore index a902afa..afa99e4 100644 --- a/template/.gitignore +++ b/template/.gitignore @@ -1,7 +1,16 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. +node_modules/**/* +.expo/* +npm-debug.* +*.jks +*.p12 +*.key +*.mobileprovision +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules +/.pnp +.pnp.js # testing /coverage @@ -19,69 +28,3 @@ npm-debug.log* yarn-debug.log* yarn-error.log* - - -# ========================================== -# OSX -# -.DS_Store - -# Xcode -# -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -project.xcworkspace - -# Android/IntelliJ -# -build/ -.idea -.gradle -local.properties -*.iml - -# node.js -# -node_modules/ -npm-debug.log -npm-debug.log* -yarn-error.log - -# BUCK -buck-out/ -\.buckd/ -*.keystore - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/ - -*/fastlane/report.xml -*/fastlane/Preview.html -*/fastlane/screenshots - -coverage/ -coverageNative/ -build/ -temp.json -android/app/app-release.apk -.vscode -======= -# Bundle artifact -*.jsbundle diff --git a/template/android/app/build.gradle b/template/android/app/build.gradle index 384004a..75cdbb2 100644 --- a/template/android/app/build.gradle +++ b/template/android/app/build.gradle @@ -94,13 +94,13 @@ def enableSeparateBuildPerCPUArchitecture = false def enableProguardInReleaseBuilds = false android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId "com.creaternwapp" - minSdkVersion 16 - targetSdkVersion 22 + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" ndk { @@ -137,9 +137,9 @@ android { } dependencies { - compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" - compile "com.facebook.react:react-native:+" // From node_modules + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" + implementation "com.facebook.react:react-native:+" // From node_modules } // Run this once to be able to run the application with BUCK diff --git a/template/android/app/proguard-rules.pro b/template/android/app/proguard-rules.pro index 6e8516c..a92fa17 100644 --- a/template/android/app/proguard-rules.pro +++ b/template/android/app/proguard-rules.pro @@ -15,56 +15,3 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} - -# Disabling obfuscation is useful if you collect stack traces from production crashes -# (unless you are using a system that supports de-obfuscate the stack traces). --dontobfuscate - -# React Native - -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip --keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters --keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keep @com.facebook.common.internal.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; - @com.facebook.common.internal.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** get*(); -} - --keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } --keep class * extends com.facebook.react.bridge.NativeModule { *; } --keepclassmembers,includedescriptorclasses class * { native ; } --keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } - --dontwarn com.facebook.react.** - -# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. -# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. --dontwarn android.text.StaticLayout - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --dontwarn okhttp3.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** diff --git a/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index cde69bc..a2f5908 100644 Binary files a/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..1b52399 Binary files /dev/null and b/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index c133a0c..ff10afd 100644 Binary files a/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..115a4c7 Binary files /dev/null and b/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index bfa42f0..dcd3cd8 100644 Binary files a/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..459ca60 Binary files /dev/null and b/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 324e72c..8ca12fe 100644 Binary files a/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..8e19b41 Binary files /dev/null and b/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..b824ebd Binary files /dev/null and b/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..4c19a13 Binary files /dev/null and b/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/template/android/app/src/main/res/values/strings.xml b/template/android/app/src/main/res/values/strings.xml index 4142cf4..245225d 100644 --- a/template/android/app/src/main/res/values/strings.xml +++ b/template/android/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - create react native web app + creaternwapp diff --git a/template/android/build.gradle b/template/android/build.gradle index eed9972..85d8f2f 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -1,11 +1,19 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext { + buildToolsVersion = "27.0.3" + minSdkVersion = 16 + compileSdkVersion = 27 + targetSdkVersion = 26 + supportLibVersion = "27.1.1" + } repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.1.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -20,5 +28,12 @@ allprojects { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url "$rootDir/../node_modules/react-native/android" } + google() } } + + +task wrapper(type: Wrapper) { + gradleVersion = '4.4' + distributionUrl = distributionUrl.replace("bin", "all") +} diff --git a/template/android/gradle.properties b/template/android/gradle.properties index 1fd964e..89e0d99 100644 --- a/template/android/gradle.properties +++ b/template/android/gradle.properties @@ -16,5 +16,3 @@ # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true - -android.useDeprecatedNdk=true diff --git a/template/android/gradle/wrapper/gradle-wrapper.jar b/template/android/gradle/wrapper/gradle-wrapper.jar index b5166da..01b8bf6 100644 Binary files a/template/android/gradle/wrapper/gradle-wrapper.jar and b/template/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/template/android/gradle/wrapper/gradle-wrapper.properties b/template/android/gradle/wrapper/gradle-wrapper.properties index dbdc05d..b6517bb 100644 --- a/template/android/gradle/wrapper/gradle-wrapper.properties +++ b/template/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/template/android/gradlew b/template/android/gradlew index 91a7e26..cccdd3d 100755 --- a/template/android/gradlew +++ b/template/android/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/template/android/gradlew.bat b/template/android/gradlew.bat index aec9973..e95643d 100644 --- a/template/android/gradlew.bat +++ b/template/android/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/template/assets/icon.png b/template/assets/icon.png new file mode 100644 index 0000000..3f5bbc0 Binary files /dev/null and b/template/assets/icon.png differ diff --git a/template/assets/splash.png b/template/assets/splash.png new file mode 100644 index 0000000..4f9ade6 Binary files /dev/null and b/template/assets/splash.png differ diff --git a/template/babel.config.js b/template/babel.config.js new file mode 100644 index 0000000..5ee5dfc --- /dev/null +++ b/template/babel.config.js @@ -0,0 +1,14 @@ +module.exports = function(api) { + + api.cache(true); + return { + "plugins": [ + ["module-resolver", { + "alias": { + "^react-native$": "react-native-web" + } + }] + ], + presets: [["react-app"], ['babel-preset-expo']], + }; +}; diff --git a/template/config/env.js b/template/config/env.js index 30a6c7f..b0344c5 100644 --- a/template/config/env.js +++ b/template/config/env.js @@ -42,12 +42,12 @@ dotenvFiles.forEach(dotenvFile => { // We support resolving modules according to `NODE_PATH`. // This lets you use absolute paths in imports inside large monorepos: -// https://github.com/facebookincubator/create-react-app/issues/253. +// 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/facebookincubator/create-react-app/issues/1023#issuecomment-265344421 +// 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 || '') diff --git a/template/config/jest/fileTransform.js b/template/config/jest/fileTransform.js index 9e4047d..07010e3 100644 --- a/template/config/jest/fileTransform.js +++ b/template/config/jest/fileTransform.js @@ -7,6 +7,24 @@ const path = require('path'); module.exports = { process(src, filename) { - return `module.exports = ${JSON.stringify(path.basename(filename))};`; + const assetFilename = JSON.stringify(path.basename(filename)); + + if (filename.match(/\.svg$/)) { + return `module.exports = { + __esModule: true, + default: ${assetFilename}, + ReactComponent: (props) => ({ + $$typeof: Symbol.for('react.element'), + type: 'svg', + ref: null, + key: null, + props: Object.assign({}, props, { + children: ${assetFilename} + }) + }), + };`; + } + + return `module.exports = ${assetFilename};`; }, }; diff --git a/template/config/jest/initTest.js b/template/config/jest/initTest.js deleted file mode 100644 index 37aafae..0000000 --- a/template/config/jest/initTest.js +++ /dev/null @@ -1,10 +0,0 @@ - -if (typeof window !== 'undefined') { - if (typeof HTMLCanvasElement !== 'undefined') { - // taken from https://stackoverflow.com/questions/48828759/jest-and-jsdom-error-with-canvas - HTMLCanvasElement.prototype.getContext = () => { - // return whatever getContext has to return - }; - } - window.matchMedia = () => ({ matches: true }); -} diff --git a/template/config/jest/native.jest.config.js b/template/config/jest/native.jest.config.js deleted file mode 100644 index 839e1f6..0000000 --- a/template/config/jest/native.jest.config.js +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable quote-props, quotes */ - -module.exports = { - coveragePathIgnorePatterns: [ - '/src/index', - ], - coverageDirectory: 'coverageNative', - preset: 'react-native', - rootDir: '../../', - collectCoverageFrom: [ - 'src/**/*.{js,jsx}' - ], - setupFiles: [ - '/config/jest/initTest.js', - '/config/polyfills.js', - ], - testMatch: [ - '/src/**/__tests__/**/*.js?(x)', - '/src/**/?(*.)(spec|test).js?(x)' - ], - browser: false, - testEnvironment: 'node', - transform: { - '^.+\\.(js|jsx)$': 'babel-jest', - '^.+\\.css$': '/config/jest/cssTransform.js', - '^(?!.*\\.(js|jsx|css|json)$)': '/config/jest/fileTransform.js' - }, - transformIgnorePatterns: [], // the array has to be here (no idea why, but it breaks if its gone) ¯\_(ツ)_/¯ - moduleFileExtensions: [ - 'ios.js', - 'android.js', - 'js', - 'json', - 'jsx', - 'node' - ] -}; diff --git a/template/config/jest/web.jest.config.js b/template/config/jest/web.jest.config.js deleted file mode 100644 index 0730f1d..0000000 --- a/template/config/jest/web.jest.config.js +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-disable quote-props, quotes */ - -module.exports = { - coveragePathIgnorePatterns: [ - '/src/index', - ], - collectCoverageFrom: [ - 'src/**/*.{js,jsx}' - ], - preset: 'react-native-web', - rootDir: '../../', - setupFiles: [ - '/config/jest/initTest.js', - '/config/polyfills.js', - ], - testMatch: [ - '/src/**/__tests__/**/*.js?(x)', - '/src/**/?(*.)(spec|test).js?(x)' - ], - testEnvironment: 'jsdom', - browser: true, - testURL: 'http://localhost', - transform: { - '^.+\\.(js|jsx)$': 'babel-jest', - '^.+\\.css$': '/config/jest/cssTransform.js', - '^(?!.*\\.(js|jsx|css|json)$)': '/config/jest/fileTransform.js' - }, - transformIgnorePatterns: [ - ], - moduleNameMapper: { - '^react-native$': 'react-native-web' - }, - moduleFileExtensions: [ - 'web.js', - 'js', - 'json', - 'web.jsx', - 'jsx', - 'node' - ] -}; diff --git a/template/config/paths.js b/template/config/paths.js index 6d16efc..c24b4dd 100644 --- a/template/config/paths.js +++ b/template/config/paths.js @@ -5,20 +5,20 @@ const fs = require('fs'); const url = require('url'); // Make sure any symlinks in the project folder are resolved: -// https://github.com/facebookincubator/create-react-app/issues/637 +// 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(path, needsSlash) { - const hasSlash = path.endsWith('/'); +function ensureSlash(inputPath, needsSlash) { + const hasSlash = inputPath.endsWith('/'); if (hasSlash && !needsSlash) { - return path.substr(path, path.length - 1); + return inputPath.substr(0, inputPath.length - 1); } else if (!hasSlash && needsSlash) { - return `${path}/`; + return `${inputPath}/`; } else { - return path; + return inputPath; } } @@ -38,18 +38,52 @@ function getServedPath(appPackageJson) { return ensureSlash(servedUrl, true); } +const moduleFileExtensions = [ + 'web.mjs', + 'mjs', + 'web.js', + 'js', + 'web.ts', + 'ts', + 'web.tsx', + 'tsx', + 'json', + 'web.jsx', + 'jsx', +]; + +// Resolve file paths in the same order as webpack +const resolveModule = (resolveFn, filePath) => { + const extension = moduleFileExtensions.find(extension => + fs.existsSync(resolveFn(`${filePath}.${extension}`)) + ); + + if (extension) { + return resolveFn(`${filePath}.${extension}`); + } + + return resolveFn(`${filePath}.js`); +}; + // config after eject: we're in ./config/ module.exports = { dotenv: resolveApp('.env'), + appPath: resolveApp('.'), appBuild: resolveApp('build'), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), - appIndexJs: resolveApp('src/index.js'), + appIndexJs: resolveModule(resolveApp, 'src/index'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), + appTsConfig: resolveApp('tsconfig.json'), yarnLockFile: resolveApp('yarn.lock'), - testsSetup: resolveApp('src/setupTests.js'), + testsSetup: resolveModule(resolveApp, 'src/setupTests'), + proxySetup: resolveApp('src/setupProxy.js'), appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), }; + + + +module.exports.moduleFileExtensions = moduleFileExtensions; diff --git a/template/config/polyfills.js b/template/config/polyfills.js deleted file mode 100644 index 66dff0a..0000000 --- a/template/config/polyfills.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -if (typeof Promise === 'undefined') { - // Rejection tracking prevents a common issue where React gets into an - // inconsistent state due to an error, but it gets swallowed by a Promise, - // and the user has no idea what causes React's erratic future behavior. - require('promise/lib/rejection-tracking').enable(); - window.Promise = require('promise/lib/es6-extensions.js'); -} - -// fetch() polyfill for making API calls. -require('whatwg-fetch'); - -// Object.assign() is commonly used with React. -// It will use the native implementation if it's present and isn't buggy. -Object.assign = require('object-assign'); - -// In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet. -// We don't polyfill it in the browser--this is user's responsibility. -if (process.env.NODE_ENV === 'test') { - require('raf').polyfill(global); -} diff --git a/template/config/webpack.config.dev.js b/template/config/webpack.config.dev.js index 0e74b54..068ea3b 100644 --- a/template/config/webpack.config.dev.js +++ b/template/config/webpack.config.dev.js @@ -1,16 +1,23 @@ 'use strict'; -const autoprefixer = require('autoprefixer'); +const fs = require('fs'); const path = require('path'); +const resolve = require('resolve'); const webpack = require('webpack'); +const PnpWebpackPlugin = require('pnp-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); -const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); +const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); const getClientEnvironment = require('./env'); const paths = require('./paths'); +const ManifestPlugin = require('webpack-manifest-plugin'); +const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt'); +const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); + // Webpack uses `publicPath` to determine where the app is being served from. // In development, we always serve from the root. This makes config easier. @@ -22,19 +29,61 @@ const publicUrl = ''; // Get environment variables to inject into our app. const env = getClientEnvironment(publicUrl); +// Check if TypeScript is setup +const useTypeScript = fs.existsSync(paths.appTsConfig); + +// style files regexes +const cssRegex = /\.css$/; +const cssModuleRegex = /\.module\.css$/; +const sassRegex = /\.(scss|sass)$/; +const sassModuleRegex = /\.module\.(scss|sass)$/; + +// common function to get style loaders +const getStyleLoaders = (cssOptions, preProcessor) => { + const loaders = [ + require.resolve('style-loader'), + { + loader: require.resolve('css-loader'), + options: cssOptions, + }, + { + // Options for PostCSS as we reference these options twice + // Adds vendor prefixing based on your specified browser support in + // package.json + loader: require.resolve('postcss-loader'), + options: { + // Necessary for external CSS imports to work + // https://github.com/facebook/create-react-app/issues/2677 + ident: 'postcss', + plugins: () => [ + require('postcss-flexbugs-fixes'), + require('postcss-preset-env')({ + autoprefixer: { + flexbox: 'no-2009', + }, + stage: 3, + }), + ], + }, + }, + ]; + if (preProcessor) { + loaders.push(require.resolve(preProcessor)); + } + return loaders; +}; + // This is the development configuration. // It is focused on developer experience and fast rebuilds. // The production configuration is different and lives in a separate file. module.exports = { + mode: 'development', // You may want 'eval' instead if you prefer to see the compiled output in DevTools. - // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343. + // See the discussion in https://github.com/facebook/create-react-app/issues/343 devtool: 'cheap-module-source-map', // These are the "entry points" to our application. // This means they will be the "root" imports that are included in JS bundle. - // The first two entry points enable "hot" CSS and auto-refreshes for JS. entry: [ - // We ship a few polyfills by default: - require.resolve('./polyfills'), // Include an alternative client for WebpackDevServer. A client's job is to // connect to WebpackDevServer by a socket and get notified about changes. // When you save a file, the client will either apply hot updates (in case @@ -67,29 +116,45 @@ module.exports = { devtoolModuleFilenameTemplate: info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), }, + optimization: { + // Automatically split vendor and commons + // https://twitter.com/wSokra/status/969633336732905474 + // https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 + splitChunks: { + chunks: 'all', + name: false, + }, + // Keep the runtime chunk seperated to enable long term caching + // https://twitter.com/wSokra/status/969679223278505985 + runtimeChunk: true, + }, resolve: { // This allows you to set a fallback for where Webpack should look for modules. // We placed these paths second because we want `node_modules` to "win" // if there are any conflicts. This matches Node resolution mechanism. - // https://github.com/facebookincubator/create-react-app/issues/253 - modules: ['node_modules', paths.appNodeModules].concat( + // https://github.com/facebook/create-react-app/issues/253 + modules: ['node_modules'].concat( // It is guaranteed to exist because we tweak it in `env.js` process.env.NODE_PATH.split(path.delimiter).filter(Boolean) ), // These are the reasonable defaults supported by the Node ecosystem. // We also include JSX as a common component filename extension to support // some tools, although we do not recommend using it, see: - // https://github.com/facebookincubator/create-react-app/issues/290 + // https://github.com/facebook/create-react-app/issues/290 // `web` extension prefixes have been added for better support // for React Native Web. - extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'], + extensions: paths.moduleFileExtensions + .map(ext => `.${ext}`) + .filter(ext => useTypeScript || !ext.includes('ts')), alias: { - // Support React Native Web // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ 'react-native': 'react-native-web', }, plugins: [ + // Adds support for installing with Plug'n'Play, leading to faster installs and adding + // guards against forgotten dependencies and such. + PnpWebpackPlugin, // Prevents users from importing files from outside of src/ (or node_modules/). // This often causes confusion because we only process files within src/ with babel. // To fix this, we prevent you from importing files out of src/ -- if you'd like to, @@ -98,24 +163,30 @@ module.exports = { new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), ], }, + resolveLoader: { + plugins: [ + // Also related to Plug'n'Play, but this time it tells Webpack to load its loaders + // from the current package. + PnpWebpackPlugin.moduleLoader(module), + ], + }, module: { strictExportPresence: true, rules: [ - // TODO: Disable require.ensure as it's not a standard language feature. - // We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176. - // { parser: { requireEnsure: false } }, + // Disable require.ensure as it's not a standard language feature. + { parser: { requireEnsure: false } }, // First, run the linter. // It's important to do this before Babel processes the JS. { - test: /\.(js|jsx|mjs)$/, + test: /\.(js|mjs|jsx)$/, enforce: 'pre', use: [ { options: { - formatter: eslintFormatter, + formatter: require.resolve('react-dev-utils/eslintFormatter'), eslintPath: require.resolve('eslint'), - + }, loader: require.resolve('eslint-loader'), }, @@ -138,21 +209,62 @@ module.exports = { name: 'static/media/[name].[hash:8].[ext]', }, }, - // Process JS with Babel. + // Process application JS with Babel. + // The preset includes JSX, Flow, and some ESnext features. { - test: /\.(js|jsx|mjs)$/, + test: /\.(js|mjs|jsx|ts|tsx)$/, include: paths.appSrc, loader: require.resolve('babel-loader'), options: { - - // The 'react-native' preset is recommended to match React Native's packager - presets: ['react-native'], - // Re-write paths to import only the modules needed by the app - plugins: ['react-native-web'], + customize: require.resolve( + 'babel-preset-react-app/webpack-overrides' + ), + + plugins: [ + [ + require.resolve('babel-plugin-named-asset-import'), + { + loaderMap: { + svg: { + ReactComponent: '@svgr/webpack?-prettier,-svgo![path]', + }, + }, + }, + ], + ], // This is a feature of `babel-loader` for webpack (not Babel itself). // It enables caching results in ./node_modules/.cache/babel-loader/ // directory for faster rebuilds. cacheDirectory: true, + // Don't waste time on Gzipping the cache + cacheCompression: false, + }, + }, + // Process any JS outside of the app with Babel. + // Unlike the application JS, we only compile the standard ES features. + { + test: /\.(js|mjs)$/, + exclude: /@babel(?:\/|\\{1,2})runtime/, + loader: require.resolve('babel-loader'), + options: { + babelrc: false, + configFile: false, + compact: false, + presets: [ + [ + require.resolve('babel-preset-react-app/dependencies'), + { helpers: true }, + ], + ], + cacheDirectory: true, + // Don't waste time on Gzipping the cache + cacheCompression: false, + + // If an error happens in a package, it's possible to be + // because it was compiled. Thus, we don't want the browser + // debugger to show the original code. Instead, the code + // being evaluated would be much more helpful. + sourceMaps: false, }, }, // "postcss" loader applies autoprefixer to our CSS. @@ -160,37 +272,46 @@ module.exports = { // "style" loader turns CSS into JS modules that inject