Description
I have a RN project set up with typescript. In general it works, but in some cases we make changes to the .ts/.tsx files which are NOT reflected in a debugged app (ios simulator). We've tried doing a clean build, clearing caches, forcing the tsc task, restarting the laptop and simulator, removing the app from the simulator, just about everything, but can't seem to get the debug build to recognise edits again. On previous occasions it has resolved itself eventually but I haven't managed to tie down what made the difference, and I've wasted precious development hours trying.
Changes to screens ARE sometimes reflected immediately via fast refresh but NOT changes to underlying services (in general called via redux action creators), but other times not. Production builds reflect the latest changes but even doing this doesn't affect the dev build if we do one afterwards. All very strange. It's as if only certain parts of the app are re-bundled for development on a change, perhaps there is some caching is involved?
If I examine the source in chrome dev tools, it shows the changed tsx files but that's not what's running on the simulated device. Is there anywhere I can see the transpiled javascript that is bundled?
React Native version:
System:
OS: macOS Mojave 10.14.6
CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
Memory: 116.66 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 12.12.0 - /usr/local/bin/node
Yarn: 1.19.1 - ~/.yarn/bin/yarn
npm: 6.11.3 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
Android SDK:
API Levels: 28
Build Tools: 23.0.1, 23.0.2, 25.0.0, 25.0.1, 25.0.2, 26.0.2, 26.0.3, 27.0.0, 27.0.3, 28.0.2, 28.0.3
System Images: android-16 | Google APIs Intel x86 Atom, android-18 | Google APIs Intel x86 Atom, android-19 | Google APIs Intel x86 Atom, android-21 | Google APIs Intel x86 Atom, android-22 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom_64
IDEs:
Android Studio: 3.4 AI-183.6156.11.34.5522156
Xcode: 11.2.1/11B53 - /usr/bin/xcodebuild
npmPackages:
react: 16.9.0 => 16.9.0
react-native: 0.61.4 => 0.61.4
npmGlobalPackages:
create-react-native-typescript-app: 1.2.0
react-native-cli: 2.0.1
Steps To Reproduce
tsconfig.json
{
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"allowJs": false,
"sourceMap": true,
"noEmit": true,
"removeComments": true,
"strict": true,
"noImplicitAny": false,
"strictFunctionTypes": false, // https://github.com/reactjs/redux/issues/2709
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"allowSyntheticDefaultImports": true,
"preserveConstEnums": true,
"experimentalDecorators": false,
"resolveJsonModule": true,
"skipLibCheck": true, // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/24573
"inlineSources": true, // https://docs.sentry.io/platforms/javascript/#typescript
"target": "esnext",
"baseUrl": ".",
"jsx": "react",
"esModuleInterop": true,
"isolatedModules": true,
"lib": ["es6"],
"paths": {
"*": ["src/*"],
},
},
"include": [
"typings/index.d.ts",
"src/**/*.ts",
"src/**/*.tsx"
],
"types": [
"react",
"react-native",
"jest"
],
"exclude": [
"android",
"ios",
"build",
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js"
],
"compileOnSave": false
}
package.json:
{
"name": "ccf",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start",
"cleanstart": "npm start -- --reset-cache",
"test": "jest",
"tsc": "tsc",
"w": "npm run tsc -- --watch",
"clean": "rimraf build",
"build": "npm run clean && npm run tsc --",
"tf": "./build-android.sh t && ./build-ios.sh t",
"lint": "tslint src/**/*.ts",
"ipad": "react-native run-ios --simulator \"iPad Pro (12.9-inch) (3rd generation)\"",
"iphone": "react-native run-ios --device",
"ios-prod": "react-native run-ios --configuration Release",
"galaxy": "nohup emulator -avd Galaxy_S8_API_28 &",
"android": "react-native run-android",
"android-prod": "react-native run-android --variant=release",
"debug": "open \"rndebugger://set-debugger-loc?host=localhost&port=8081\"",
"pod": "cd ios && pod install && cd ..",
"podupdate": "cd ios && pod update && cd ..",
"ver": "react-native --version"
},
"dependencies": {
"@ptomasroos/react-native-multi-slider": "^1.0.0",
"@react-native-community/async-storage": "^1.6.2",
"@react-native-community/netinfo": "^4.6.0",
"@react-native-firebase/analytics": "^6.0.4",
"@react-native-firebase/app": "^6.0.4",
"@sentry/react-native": "^1.0.9",
"axios": "^0.19.0",
"dot-prop-immutable": "^1.5.0",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"native-base": "^2.13.8",
"papaparse": "^5.1.0",
"react": "16.9.0",
"react-native": "0.61.4",
"react-native-animatable": "^1.3.3",
"react-native-app-link": "^1.0.0",
"react-native-audio-recorder-player": "^2.4.3",
"react-native-circular-progress": "^1.3.4",
"react-native-color-picker": "^0.4.2",
"react-native-config": "^0.11.7",
"react-native-device-info": "^5.2.1",
"react-native-document-picker": "^3.2.4",
"react-native-event-listeners": "^1.0.3",
"react-native-extended-stylesheet": "^0.12.0",
"react-native-fast-image": "^7.0.2",
"react-native-file-viewer": "^2.0.0",
"react-native-fs": "^2.16.1",
"react-native-gesture-handler": "^1.5.0",
"react-native-i18n": "^2.0.15",
"react-native-image-picker": "^1.1.0",
"react-native-input-scroll-view": "^1.9.5",
"react-native-iphone-x-helper": "^1.2.1",
"react-native-keyboard-listener": "^1.1.0",
"react-native-keyboard-manager": "^4.0.13-15",
"react-native-keyboard-spacer": "^0.4.1",
"react-native-materialui-textfield": "^0.13.2",
"react-native-modal": "^11.5.1",
"react-native-modal-datetime-picker": "^7.6.0",
"react-native-offline": "^5.2.0",
"react-native-orientation-locker": "^1.1.7",
"react-native-path": "0.0.5",
"react-native-permissions": "^2.0.3",
"react-native-progress-circle": "^2.1.0",
"react-native-radio-buttons": "^1.0.0",
"react-native-reanimated": "^1.4.0",
"react-native-screens": "^1.0.0-alpha.23",
"react-native-simple-radio-button": "^2.7.4",
"react-native-slider": "^0.11.0",
"react-native-sortable-listview": "^0.2.9",
"react-native-spinkit": "^1.5.0",
"react-native-splash-screen": "^3.2.0",
"react-native-store-version": "^1.2.1",
"react-native-svg": "9.13.3",
"react-native-swipe-gestures": "^1.0.4",
"react-native-video": "^5.0.2",
"react-native-view-pdf": "^0.10.1",
"react-native-voice": "^0.3.0",
"react-native-webview": "^6.11.1",
"react-navigation": "^4.0.10",
"react-navigation-drawer": "^2.3.3",
"react-navigation-slide-from-right-transition": "^1.0.4",
"react-navigation-stack": "^1.10.3",
"react-navigation-tabs": "^2.5.6",
"react-redux": "^7.1.3",
"redux": "^4.0.4",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"redux-persist-transform-filter": "0.0.20",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"showdown": "^1.9.1",
"string-hash-64": "^1.0.3"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/runtime": "^7.6.2",
"@bam.tech/react-native-make": "^1.0.3",
"@types/jest": "^24.0.22",
"@types/lodash": "^4.14.144",
"@types/react": "^16.9.11",
"@types/react-native": "^0.60.22",
"@types/react-test-renderer": "^16.9.1",
"@types/redux-testkit": "^1.0.3",
"babel-jest": "^24.9.0",
"babel-plugin-module-resolver": "^3.2.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"jest": "^24.9.0",
"jest-mock-axios": "^3.1.2",
"jetifier": "^1.6.4",
"metro-react-native-babel-preset": "^0.57.0",
"react-native-mock-render": "^0.1.7",
"react-test-renderer": "16.9.0",
"redux-testkit": "^1.0.6",
"replace": "^1.1.1",
"rimraf": "^3.0.0",
"ts-jest": "^24.1.0",
"tslint": "^5.20.1",
"tslint-no-circular-imports": "^0.7.0",
"tslint-react": "^4.1.0",
"typescript": "^3.7.2"
},
"jest": {
"preset": "react-native",
"testEnvironment": "node",
"transformIgnorePatterns": [
"node_modules/(?!native-base-shoutem-theme|native-base|react-native|@react-navigation|react-navigation|react-native-fs|react-native-gesture-handler|react-native-keyboard-aware-scroll-view|victory-*|react-native-cookies|@sentry/react-native)"
],
"transform": {
"^.+\\.jsx?$": "<rootDir>/node_modules/babel-jest",
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(tsx?)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"globals": {
"ts-jest": {
"babelConfig": true
}
},
"setupFiles": [
"<rootDir>/jest/setup.js",
"./node_modules/react-native-gesture-handler/jestSetup.js"
],
"verbose": true,
"automock": false,
"browser": false,
"collectCoverage": true,
"collectCoverageFrom": [
"**/*.ts",
"!**/node_modules/**",
"!**/build/**"
],
"coveragePathIgnorePatterns": [
"/node_modules/",
"/build/"
],
"coverageDirectory": "jest/coverage",
"coverageReporters": [
"json",
"lcov",
"text-summary"
]
}
}
npm run ipad
Note: this project started off by using https://github.com/huestack/create-react-native-typescript-app, then we adopted https://github.com/ds300/react-native-typescript-transformer, then finally we migrated it to using the approach advocated by RN itself (https://facebook.github.io/react-native/docs/typescript) - so we may have made some mistakes during these migrations.