vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
66.33k stars 5.93k forks source link

Typescript imports with ".js" file extension are failing. #6671

Closed dashavoo closed 2 years ago

dashavoo commented 2 years ago

Describe the bug

Importing from a Typescript file by referencing it with a ".js" file extension is failing with the error below. It is my understanding that it should work (based on looking at #5510).

To reproduce, clone the repository provided, run pnpm install and pnpm run dev.

This is a VueJS project, but after sitting in front of this bug report for a long time and agonising over the question, I think it is probably a Vite bug and not a vuejs/core bug. That, or I am making an elementary mistake (sorry).

22:36:26 [vite] Internal server error: Failed to resolve import "../constructors.js" from "src/components/Example.vue". Does the file exist?
  Plugin: vite:import-analysis
  File: /home/redacted/redacted/vite-bug-report/vite-bug-report/src/components/Example.vue
  1  |  import { defineComponent as _defineComponent } from "vue";
  2  |  import { makeProfile } from "../constructors.js";
     |                               ^
  3  |  const _sfc_main = /* @__PURE__ */ _defineComponent({
  4  |    setup(__props, { expose }) {
      at formatError (/home/redacted/redacted/vite-bug-report/vite-bug-report/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:36769:46)
      at TransformContext.error (/home/redacted/redacted/vite-bug-report/vite-bug-report/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:36765:19)
      at normalizeUrl (/home/redacted/redacted/vite-bug-report/vite-bug-report/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:73703:26)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async TransformContext.transform (/home/redacted/redacted/vite-bug-report/vite-bug-report/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:73843:57)
      at async Object.transform (/home/redacted/redacted/vite-bug-report/vite-bug-report/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:36985:30)
      at async doTransform (/home/redacted/redacted/vite-bug-report/vite-bug-report/node_modules/.pnpm/vite@2.7.13/node_modules/vite/dist/node/chunks/dep-f5552faa.js:52060:29) (x2)

Reproduction

https://github.com/dashavoo/vite-bug-report

System Info

System:
    OS: Linux 5.10 Debian GNU/Linux 11 (bullseye) 11 (bullseye)
    CPU: (8) x64 Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
    Memory: 10.53 GB / 12.29 GB
    Container: Yes
    Shell: 5.1.4 - /bin/bash
  Binaries:
    Node: 16.13.1 - ~/.nvm/versions/node/v16.13.1/bin/node
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.1/bin/npm
  npmPackages:
    @vitejs/plugin-vue: 2 => 2.1.0
    vite: ^2.7.13 => 2.7.13

Used Package Manager

pnpm

Logs

No response

Validations

zheeeng commented 2 years ago

As the report says, Does the file exist?

You could choose one of the solutions here:

  1. Importing ../constructors or ../constructors.ts instead
  2. Make sure running a tsc watch mode for compiling ../constructors.ts to ../constructors.js
dashavoo commented 2 years ago

@zheeeng I feel like I might be missing something here but: no, it doesn't exist, and if I understand the PR I linked above correctly (and also the corresponding issue #3040) it shouldn't need to.

Interestingly, if I remove the import of the constructors file but keep the other import, it works fine. Maybe because it is just Types and Interfaces so it gets stripped altogether by that point?

darthtrevino commented 2 years ago

So here's the reason: it's all about ESM support.

ESM imports need to end with a file extension. To support this in TypeScript, you can import other TS files using the .js extension in the import and TypeScript is smart enough to know that you really mean the .ts file. When it builds the output, all the imports have .js extensions and the files themselves are JS at that point.

common patterns look like:

import mod from './my-typescript-module.js' // source is .ts
import mod from './my-explicitly-commonjs-typescript-module.cjs' //source is .cts
import mod from './my-explicitly-esm-typescirpt-module.mjs' // source is .mts

Edit: it looks like this was all covered in #3040 - I look forward to more official support!

darthtrevino commented 2 years ago

This comment seems to indicate that support for this feature has been shipped? I'm using v2.8.3 and this issue is still present.

https://github.com/vitejs/vite/issues/5539#issuecomment-960271520

bluwy commented 2 years ago

The issue is because #5510 handles cases where the importer is a TS file only, then it resolves the .js/.ts import check. In this case, because the importer is a Vue file (not a TS file), Vite incorrectly skips the import check, hence the error. To fix this, we need to provide a hint somewhere so that Vite knows the Vue file is written in TS, and do the extra import checks.

wight554 commented 2 years ago

The issue is because #5510 handles cases where the importer is a TS file only, then it resolves the .js/.ts import check. In this case, because the importer is a Vue file (not a TS file), Vite incorrectly skips the import check, hence the error. To fix this, we need to provide a hint somewhere so that Vite knows the Vue file is written in TS, and do the extra import checks.

it's also broken when used with typescript alias: tsconfig, vite config Error:

Error: [vite]: Rollup failed to resolve import "@src/components/App/index.js" from "src/main.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`

Project for reference: https://github.com/wight554/blog-template/ (doesn't contain nodenext changes)

I have to do smth like this to make it work:

  resolve: {
    alias: [{ find: /^(@?src\/.*)\.js$/, replacement: '$1.ts' }],
  },