qwik icon indicating copy to clipboard operation
qwik copied to clipboard

[🐞] Support Typescript "moduleResolution": "node16" and "bundler"

Open ziimakc opened this issue 2 years ago • 24 comments

Which component is affected?

Qwik Rollup / Vite plugin

Describe the bug

When using esm import .js or .jsx extensions is required. Trying to follow this requirement qwik fails to build with the following error:

Could not resolve "./components/router-head/router-head.jsx" from "src/s_qn6vsz8sp28.js"

error during build:
RollupError: Could not resolve "./components/router-head/router-head.jsx" from "src/s_qn6vsz8sp28.js"
    at error (file:///home/app/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/node-entry.js:2213:30)
    at ModuleLoader.handleInvalidResolvedId (file:///home/app/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/node-entry.js:24219:24)
    at file:///home/app/node_modules/.pnpm/[email protected]/node_modules/rollup/dist/es/shared/node-entry.js:24181:26
// root.tsx
import { RouterHead } from "./components/router-head/router-head.jsx";

Reproduction

  • git clone https://github.com/ZiiMakc/temp
  • npm install
  • npm run build

Steps to reproduce

No response

System Info

System:
    OS: Linux 5.15 Ubuntu 22.04.1 LTS 22.04.1 LTS (Jammy Jellyfish)
    CPU: (8) x64 Intel(R) Core(TM) i5-9300H CPU @ 2.40GHz
    Memory: 5.29 GB / 7.68 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 18.16.1 - /usr/bin/node
    npm: 9.5.1 - /usr/bin/npm

Additional Information

No response

ziimakc avatar Jul 02 '23 12:07 ziimakc

When using esm import .js or .jsx extensions is required

Not sure i understand

manucorporat avatar Jul 02 '23 12:07 manucorporat

Tried and it works, can you provide a full repo that reprodices the issue?

manucorporat avatar Jul 02 '23 13:07 manucorporat

@manucorporat

Here is example:

  • git clone https://github.com/ZiiMakc/temp
  • npm install
  • npm run build

Problem is because of .jsx suffix import { RouterHead } from "./components/router-head/router-head.jsx";

ziimakc avatar Jul 02 '23 14:07 ziimakc

Probably related: https://github.com/rollup/rollup/issues/4917

ziimakc avatar Jul 02 '23 15:07 ziimakc

See also https://github.com/vitejs/vite/issues/8993

ziimakc avatar Jul 05 '23 17:07 ziimakc

Temporary solution:

import { defineConfig } from "vite";
import { qwikVite } from "@builder.io/qwik/optimizer";
import { qwikCity } from "@builder.io/qwik-city/vite";
import pluginTypescript from "@rollup/plugin-typescript";

export default defineConfig(() => {
  return {
    plugins: [qwikCity(), qwikVite()],
    build: {
      rollupOptions: {
        plugins: [pluginTypescript()],
      },
    },
  };
});

Also remove outDir and declaration from tsconfig

ziimakc avatar Jul 05 '23 18:07 ziimakc

I have the same issue. Here's minimal repro on StackBlitz: https://stackblitz.com/edit/qwik-starter-rfjklh?file=src%2Froot.tsx

Just run npm run build in the terminal and you'll get the error.

octet-stream avatar Jan 24 '24 13:01 octet-stream

From what I can tell, it is possible to use .js extensions when importing modules within .ts files. At least this is possible for server-side code. You can see that in src/routes/plugin.ts file: if you remove .js from src/root.tsx, but keep one in src/routes/plugin.tsx then npm run build will build the project successfully. I have tried to import the same file (src/lib/add) in home page module. It shows the error even with npm run dev if I use add function imported from this module in useTask$. On the server this code will be imported and executed without any problem, but then on the client it doesn't work.

octet-stream avatar Jan 24 '24 15:01 octet-stream

̶t̶h̶i̶s̶ ̶s̶e̶e̶m̶s̶ ̶t̶o̶ ̶w̶o̶r̶k̶ ̶n̶o̶w̶ ̶a̶s̶ ̶w̶e̶ ̶a̶r̶e̶ ̶o̶n̶ ̶d̶i̶f̶f̶e̶r̶e̶n̶t̶ ̶T̶y̶p̶e̶S̶c̶r̶i̶p̶t̶ ̶v̶e̶r̶s̶i̶o̶n̶ ̶a̶n̶d̶ ̶n̶o̶d̶e̶ ̶r̶e̶q̶u̶i̶r̶e̶m̶e̶n̶t̶ ̶n̶o̶w̶.̶ ̶p̶l̶e̶a̶s̶e̶ ̶m̶a̶k̶e̶ ̶a̶ ̶n̶e̶w̶ ̶i̶s̶s̶u̶e̶ ̶i̶f̶ ̶t̶h̶e̶r̶e̶ ̶i̶s̶ ̶s̶t̶i̶l̶l̶ ̶a̶n̶ ̶i̶s̶s̶u̶e̶

PatrickJS avatar May 06 '24 18:05 PatrickJS

@PatrickJS is there any estimate date for this fix to be released? Because I still get the same error in 1.5.3, so it's not fixed yet.

octet-stream avatar May 07 '24 10:05 octet-stream

I need a repro repo the one provided is not public and is it only this version of TypeScript or can we use latest version?

PatrickJS avatar May 07 '24 17:05 PatrickJS

Sure, here you go: https://github.com/octet-stream/qwik-typescript-js-extension-issue

octet-stream avatar May 07 '24 19:05 octet-stream

well it's .tsx and you need allowImportingTsExtensions: true in tsconfig

PatrickJS avatar May 07 '24 20:05 PatrickJS

This doesn't solve the issue, I just get different error if I replace .js with .ts/.tsx:

vite v5.2.11 building for production...
✓ 46 modules transformed.
/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:10103
    throw new Error("start < 0");
    ^

Error: start < 0
    at createTextSpan (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:10103:11)
    at createTextSpanFromBounds (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:10111:10)
    at getErrorSpanForNode (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:12660:10)
    at createDiagnosticForNodeFromMessageChain (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:12497:16)
    at resolveExternalModule (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:47034:31)
    at resolveExternalModuleNameWorker (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:46928:61)
    at resolveExternalModuleName (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:46925:12)
    at getSymbolAtLocation (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:82585:18)
    at Object.getSymbolAtLocation (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:43783:21)
    at getReferencedFilesFromImportLiteral (/Users/octetstream/projects/qwik-test/node_modules/.pnpm/[email protected]/node_modules/typescript/lib/tsc.js:120886:28)

Node.js v20.11.1
rendering chunks (19)... ELIFECYCLE  Command failed with exit code 1.
computing gzip size (0)...

 ELIFECYCLE  Command failed

It is important to mention that I need the .js extension, because I might need run parts of my code with ts-node. Case it: Mikro ORM cli support, which is relying on ts-node. TypeScript allows this extension and Node.js requires it for ESM paths. And this is why I set moduleResolution to node16 and not bundler.

octet-stream avatar May 07 '24 20:05 octet-stream

oh yeah I see there were changing in tsconfig. I don't know enough about TypeScript to help with this maybe someone else can

ok it looks like we need to work on updating our "moduleResolution"

this seems like an optimizer issue. maybe @wmertens something with the optimizer to detect or ignore .js https://github.com/PatrickJS/qwik-typescript-js-extension-issue/tree/moduleResolution-bundler

image

PatrickJS avatar May 07 '24 20:05 PatrickJS

yeah the quick fix might be a plugin to remap the .js to the correct files before qwik takes over

PatrickJS avatar May 07 '24 20:05 PatrickJS

For anyone who want to use proper .js extension, install @rollup/plugin-typescript and use following config as example:

tsconfig.json

{
	"extends": "../../other/tsconfig.base.json",
	"compilerOptions": {
		"target": "ES2022",
		"module": "ES2022",
		"lib": ["es2022", "DOM", "WebWorker", "DOM.Iterable"],
		"jsx": "react-jsx",
		"jsxImportSource": "@builder.io/qwik",
		"moduleResolution": "Bundler",
		"esModuleInterop": true,
		"incremental": true,
		"outDir": "dist",
		"noEmit": true
	},
	"include": ["src", "./*.d.ts", "./*.config.ts"]
}

vite.config.ts:

import { qwikCity } from "@builder.io/qwik-city/vite";
import { qwikVite } from "@builder.io/qwik/optimizer";
import pluginTypescript from "@rollup/plugin-typescript";
import { defineConfig, type UserConfig } from "vite";

export default defineConfig(({ command, mode }): UserConfig => {
	const config: UserConfig = {
		plugins: [qwikCity(), qwikVite()],
		build: {
			rollupOptions: {
				plugins: [pluginTypescript()],
			},
		},
	};

	return config;
});

ziimakc avatar Jun 09 '24 08:06 ziimakc

I don't understand, doesn't ts-node look at tsconfig? We recommend using module resolution Bundler.

wmertens avatar Jun 09 '24 10:06 wmertens

@ziimakc is this still happening in 1.8.0?

wmertens avatar Aug 30 '24 14:08 wmertens

I don't understand, doesn't ts-node look at tsconfig? We recommend using module resolution Bundler.

ts-node does not do anything with paths, because TS itself keeps paths untouched. It just keeps them as-is. But in order to ESM to work in Node.js, I need to use the .js specifier (see: https://nodejs.org/api/esm.html#mandatory-file-extensions), which Qwik (or rather Rollup, as far as I see from this conversation) cannot compile when targeting production build. I got the same error, with the same file (router-head).

I just tried 1.9.0 and the issue is still in the effect on a fresh project created via pnpm create qwik@latest.


Also, I encounter a new issue: TypeScript seem to have problems picking up JSX types (see the screenshot) when I use the same tsconfig.json as in the repo I linked above in one of my comments.

Details image

I see the same problem at least in v1.5.3 (which is the same version from the respo I linked above) and above. It seem to cover the whole InristicElements interface. But this probably have to be separated into different issue. Are JSX type from Qwik compatible with node16? I don't have this issue with Remix for example, so types from React are compatible.

octet-stream avatar Oct 03 '24 07:10 octet-stream

Had to mention that as far as I remember, this problem only affects client-side of a bundle. Server-side code runs with .js specifier just fine, so I ended up just keeping moduleResolution set to Bundler and using the specifier only for server code until the issue is resolved (because, as I said, otherwise my code cannot be consumed by Node.js when I run it via ts-node). This is not consistent and I had to remember to use it on the server and keep track on which files will be referenced by Mikro ORM config. When moduleResolution is set to node16 tsc will require .js specifier at every absolute and relative path, so if I forgot one - my code won't compile and VSCode will also show me an error (and suggest .js when I write paths) which is to be expected.

octet-stream avatar Oct 03 '24 07:10 octet-stream

@wmertens a friendly reminder that this one is still relevant too :) I just tested it locally on a fresh project created with pnpm create qwik@latest and changed moduleResolution and module in tsconfig.json to node16 and resolution breaks, but this time on type-level: I am able to build my project now if I remove build.types script. VSCode is also unable to pick up any types from Qwik.

Image

octet-stream avatar Aug 06 '25 08:08 octet-stream

Can also confirm that I am able to build project when I have allowImportingTsExtensions option enabled and use .ts (including .tsx and others) in module specifier. So the issue only remains on type resolution level.

octet-stream avatar Aug 06 '25 08:08 octet-stream

Ok so we need to fix our package so that node16 resolution works for types. Urgh.

wmertens avatar Sep 09 '25 09:09 wmertens