0

Problem: react-app-rewired start works on App.jsx (and .js too) but not on App.tsx (and .ts too)

Steps

  1. I created a boilerplate app with ionic start my-app blank --type=react --capacitor
  2. on package.json, i replace and reinstall accordingly (remove package.lock.json, npm i)
{
    "name": "my-app",
    "version": "0.0.1",
    "private": true,
    "scripts": {
-       "start": "ionic serve",
+       "start": "react-app-rewired start",
-       "build": "ionic build",
+       "build": "react-app-rewired build",
        "test": "react-scripts test"
    },
    "dependencies": {
        "@capacitor/android": "^2.4.3",
        "@capacitor/core": "2.4.3",
        "@ionic/react": "^5.0.7",
        "@ionic/react-router": "^5.0.7",
        "ionicons": "^5.0.0",
        "react": "^16.13.0",
        "react-dom": "^16.13.0",
        "react-router": "^5.1.2",
        "react-router-dom": "^5.1.2",
+       "babel-plugin-transform-react-pug": "^7.0.1",
+       "customize-cra": "^1.0.0",
+       "react-app-rewired": "^2.1.6",
    },
    "devDependencies": {
        "@capacitor/cli": "2.4.3",
        "@ionic/cli": "6.12.2",
        "@testing-library/jest-dom": "^4.2.4",
        "@testing-library/react": "^9.4.0",
        "@testing-library/user-event": "^8.0.3",
        "@types/jest": "^24.0.25",
        "@types/node": "^12.12.24",
        "@types/react": "^16.9.17",
        "@types/react-dom": "^16.9.4",
        "@types/react-router": "^5.1.4",
        "@types/react-router-dom": "^5.1.3",
        "react-scripts": "3.4.0",
        "typescript": "3.8.3"
    },
    "eslintConfig": {
        "extends": "react-app"
    },
    "browserslist": {
        "production": [
            ">0.2%",
            "not dead",
            "not op_mini all"
        ],
        "development": [
            "last 1 chrome version",
            "last 1 firefox version",
            "last 1 safari version"
        ]
    },
    "description": "An Ionic project"
  1. add config-overrides.js file on the project's root folder
const { override, disableEsLint, addBabelPlugin } = require('customize-cra')

module.exports = override(
    disableEsLint(),
    addBabelPlugin('transform-react-pug'),
)
  1. Replace App.tsx with
import React from 'react'
import {
    IonApp,
    IonContent,
    IonHeader,
    IonTitle,
    IonToolbar,
} from '@ionic/react'

declare const pug: any
const App: React.FC = () => {
    return pug`
        IonApp
            IonHeader
                IonToolbar
                    IonTitle My App
            IonContent.ion-padding Add some content here…
    `
}
export default App

  1. On tsconfig.json set "strict": false
  2. npm start (or react-app-rewired start) on project root folder

There's no error on terminal ('Compiled successfully!'), chrome screen is blank, on chrome console:

Uncaught ReferenceError: React is not defined
    at App (main.chunk.js:33)
    ...

Strangely, the app works fine if I change the App extension with .jsx or .js instead of .tsx or .ts

The pug setup also works when setting up a CRA typescript app instead of a ionic start --type=react --capacitor app

Edit: Here is the github for the working/not working repo https://github.com/calvindio/template-ionic-react-ts-pug

calvindio
  • 347
  • 3
  • 11
  • I guess the problem with the webpack, set strict mode to true, also, the APP() function is not typed, make sure you put the right types to this function – Ahmad Ali Nov 29 '20 at 13:30
  • I tried setting the strict mode to true too, same result. And there's no typescript error. I haven't understand webpack. Because I avoided ejecting the app, I used react-app-rewired, customize-cra, and babel-plugin-transform-react-pug as a workaround – calvindio Nov 29 '20 at 13:33
  • I put `const App: React.FC = () => {...` when in tsx too. Also same error. – calvindio Nov 29 '20 at 13:37
  • 1
    in the package you have 2 start command and 2 builds, delete one of them – Ahmad Ali Nov 29 '20 at 13:45
  • It's a notation I use to indicate I replace `"start": "ionic serve",` with `"start": "react-app-rewired start",` (CMIIW). I only use the 'react-app-rewired' version for both start and build. Thank you for being so attentive. – calvindio Nov 29 '20 at 15:08
  • Can you share your working example repo as well? – tmhao2005 Nov 29 '20 at 15:45
  • Here: https://github.com/calvindio/template-ionic-react-ts-pug. Thank you – calvindio Nov 30 '20 at 03:22

1 Answers1

1

Issue

It looks like the issue is from tsc deleted the unused import which ended up the issue.

For example, this line import React from 'react' won't get included in the compiled code since you didn't return as jsx format.

Likewise, all the import like import { IonApp, ... } from '@ionic/react'; won't be included in the compiled code either. That's why webpack can't map React import correctly.

Solution

From my understanding, I've yet been aware of any option of tsc would still keep the unused imports in the built code. It would be great if you could find that option.

But for now, you could work around by using require keyword which keeps thing sill be imported:

App.tsx

const React = require('react');
const { IonApp, ... } = require('@ionic/react');

// ...
tmhao2005
  • 14,776
  • 2
  • 37
  • 44
  • 1
    Wow, it's solved! Thank you! Your explanation makes sense. I wonder if there's a vscode extension for autoimport using the `require` instead of `import`. Again thank you! – calvindio Nov 30 '20 at 08:56
  • For those reading in the future: you can use a combination of normal auto import extension and the use import-to-require-converter (https://marketplace.visualstudio.com/items?itemName=tlevesque.import-to-require&ssr=false#overview) – calvindio Nov 30 '20 at 09:27
  • 1
    I'm still keen to keep using `esnext` style which means using `import` but then we can configure like allow unused import to deal with kind of situation (it's all about related to `tsc`) – tmhao2005 Nov 30 '20 at 09:30
  • After a day of use, I also really want to use `import`. The amount of manually converting auto `import` to `const require` is a lot. Is it something in the tsconfig? – calvindio Dec 01 '20 at 07:26
  • 1
    Can you try to research about how to keep unused import in Typescript which is available here https://www.typescriptlang.org/docs/handbook/compiler-options.html? Or as long as somehow you could make your import used where you used pug as template, then it would work normally – tmhao2005 Dec 01 '20 at 07:31
  • It's this flag here https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues. I set it to "preserve", but it still can't find React (and other imports too) :(. Seems like the elision of imports is still happening. – calvindio Dec 01 '20 at 11:52