remix: Remix updates tsconfig and doesn't care about extends key

What version of Remix are you using?

1.9.0

Steps to Reproduce

  1. Create tsconfig-base.json to extends
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Default",
  "compilerOptions": {
    "target": "ES2019",
    "composite": false,
    "declaration": true,
    "declarationMap": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "inlineSources": false,
    "isolatedModules": true,
    "moduleResolution": "node",
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noImplicitAny": false,
    "preserveWatchOutput": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "resolveJsonModule": true
  }
}
  1. Create tsconfig-react.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "React Application",
  "extends": "./tsconfig-base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["DOM", "DOM.Iterable", "ES2019"],
    "module": "ESNext"
  },
  "include": ["src"]
}
  1. Create tsconfig-remix.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Remix Application",
  "extends": "./tsconfig-react.json",
  "compilerOptions": {
    "allowJs": true,
    "resolveJsonModule": true
  }
}
  1. Update tsconfig.json
{
  "extends": "./tsconfig-remix.json",
  "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["./app/*"]
    }
  }
}
  1. Run npm run dev And you’ll see: The following suggested values were added to your “tsconfig.json”. These values can be changed to fit your project’s needs:

     - compilerOptions.forceConsistentCasingInFileNames was set to 'true'
     - compilerOptions.lib was set to 'DOM,DOM.Iterable,ES2019'
     - compilerOptions.strict was set to 'true'
     - compilerOptions.target was set to 'ES2019'
    

The following mandatory changes were made to your tsconfig.json:

    - compilerOptions.esModuleInterop was set to 'true'
    - compilerOptions.isolatedModules was set to 'true'
    - compilerOptions.jsx was set to 'react-jsx'
    - compilerOptions.noEmit was set to 'true'
    - compilerOptions.moduleResolution was set to 'node'

And tsconfig.json will be updated. So Remix doesn’t care about extends and update config to

{
  "extends": "@packages/ts-configs/remix",
  "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["./app/*"]
    },
    // everything that above added by remix after npm run dev
    "allowJs": true,
    "forceConsistentCasingInFileNames": true,
    "lib": ["DOM", "DOM.Iterable", "ES2019"],
    "strict": true,
    "target": "ES2019",
    "esModuleInterop": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "noEmit": true,
    "resolveJsonModule": true,
    "moduleResolution": "node"
  }
}

As you see this props already exists in extended config, but why remix updates it?

If I run tsc --showConfig before npm run dev and config will be updated, I got this:

> tsc --showConfig

{
    "compilerOptions": {
        "target": "es2019",
        "composite": false,
        "declaration": true,
        "declarationMap": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "inlineSources": false,
        "isolatedModules": true,
        "moduleResolution": "node",
        "noUnusedLocals": false,
        "noUnusedParameters": false,
        "noImplicitAny": false,
        "preserveWatchOutput": true,
        "skipLibCheck": true,
        "strict": true,
        "noEmit": true,
        "resolveJsonModule": true,
        "jsx": "react-jsx",
        "lib": [
            "dom",
            "dom.iterable",
            "es2019"
        ],
        "module": "esnext",
        "allowJs": true,
        "baseUrl": "./",
        "paths": {
            "@app/*": [
                "./app/*"
            ]
        }
    },
    "files": [
        "./remix.env.d.ts",
        "./app/entry.client.tsx",
        "./app/entry.server.tsx",
        "./app/root.tsx",
        "./app/routes/index.tsx"
    ],
    "include": [
        "remix.env.d.ts",
        "**/*.ts",
        "**/*.tsx"
    ]
}

As you see, ts tracks extended configs and merged it.

Expected Behavior

Remix will track extends from tsconfig.json and will not update it

Actual Behavior

Remix doesn’t care about tsconfig extends props.

If I log console.log(fullConfig); from node_modules/@remix-run/dev/dist/compiler/utils/tsconfig/write-config-defaults.js It returns

{
  extends: '@packages/ts-configs/remix',
  include: [ 'remix.env.d.ts', '**/*.ts', '**/*.tsx' ],
  compilerOptions: {
    baseUrl: '.',
    paths: { '@app/*': [Array] },
    allowJs: true,
    resolveJsonModule: true
  }
}

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 18 (2 by maintainers)

Most upvoted comments

@mcansh This needs to be reopened.

agreed - gonna look into a barebones typescript project with yarn berry (and npm) and tsconfig-paths

@mcansh Thank you for verifying! It’s definitely a problem with yarn v2+ as well as I mentioned. 👍🏻

definitely a valid bug, we use tsconfig-paths to handle tsconfig loading and it seems that it’s returning the incorrect path when hitting extends in a npm workspace

{ 
  extendedConfig: '@packages/ts-configs/remix',
  extendedConfigPath: '/Users/logan/remix-npm-monorepo-tsconfig/my-remix-app/@packages/ts-configs/remix.json'
}

where @packages/ts-configs/remix.json is actually located at /Users/logan/remix-npm-monorepo-tsconfig/my-remix-app/packages/tsconfig/remix.json

…Then it’s all good. However, if/when we decide to rely on an external package instead, then I think we’d probably run into the same thing?

{
  "extends": "../node_modules/@packages/ts-configs/remix.json"
}

interesting, we should be merging based on extends (https://github.com/remix-run/remix/blob/main/integration/tsconfig-test.ts#L94) - i’ll take a look 😃