modernweb-dev / web

Guides, tools and libraries for modern web development.
https://modern-web.dev
MIT License
2.2k stars 278 forks source link

[@web/dev-server-esbuild] does not read tsconfig.json #1921

Open pmcelhaney opened 2 years ago

pmcelhaney commented 2 years ago

As far as I can tell, the ESBuild plugin does not look at tsconfig.json.

It uses the ESBuild's Transform API, which would require the plugin to explicitly pass the contents of the tsconfig.json file via the tsconfigRaw option.

So far not reading the tsconfig.json hasn't presented any significant problems for me, but the fact that my changes to that file had no effect on web-dev-server was confusing. I would suggest either documenting the fact that the tsconfig.json file is ignored or adding an option to specify the path to the tsconfig.json file.

If either of those sounds good, or you have some other idea, I'm happy to create a PR.

LarsDenBakker commented 2 years ago

Adding an option to specify the path would be a good idea.

kobleistvan commented 2 years ago

I agree. We would need this to work, because we're using this within a monorepo, and specifying path aliases would be very useful. Thanks

pmcelhaney commented 2 years ago

@kobleistvan Would it be helpful if there was an option to automatically find the tsconfig file for each .ts file (using the same algorithm as TypeScript itself)?

That's my ultimate goal. I started with specifying the path to a single tsconfig.json because I didn't want to do too much in one PR (and there are cases when I want to point to a specific config).

kobleistvan commented 2 years ago

@pmcelhaney In our application, we have a 'base' tsconfig in the monorepo root, and some packages have their own tsconfig file which extends the one from the root. So it would be great if perhaps the wtr command itself could take as an additional argument the path to a specific tsconfig file (and take into consideration the internal 'extends' key's value).

kobleistvan commented 2 years ago

@pmcelhaney FYI, I worked around my issue via: `import { fromRollup } from '@web/dev-server-rollup'; import tsConfigPaths from 'rollup-plugin-tsconfig-paths';

const tsPaths = fromRollup(tsConfigPaths.default);

// ...

plugins: [ tsPaths({}), esbuildPlugin({ ts: true }), ], `

So basically there's a rollup plugin to overcome the path issues, and the fromRollup makes it so that I can use it here. Would be nice if there would be native support though (i.e. for other tsConfig configs)

Cheers

lucaelin commented 2 years ago

So far not reading the tsconfig.json hasn't presented any significant problems for me

One example for this being useful is the importsNotUsedAsValues compilerOption. This option is supposed to fix the need for duplicate import statements when importing a module with both a type export and side-effects, like defining a custom-element. Without this option, typescript strips all import statements, that only import types. This also gets rid off any side-effects that would happen during the import, see https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues .

Starting in v14, esbuild now aligns with behavior of tsc, see https://github.com/evanw/esbuild/releases/tag/v0.14.0 , so by default import-statements in typescript file often have to be listed twice, once for the type and once as a bare import to cause side-effects.

Passing the tsconfig with this option set to preserve would fix the duplication.

lucaelin commented 2 years ago

I saw the MR for this being merged, but no new release for this plugin. Is there an estimate on when the next release is gonna happen?

muratcorlu commented 2 years ago

This problem causes inconsistencies for some Typescript features (like decorators) in tests. I had a problem (explained in #1963) and returning back to v0.2.16 fixed the issue. I hope v0.3.1 will arrive soon with a fix for this.

Does anyone know what is the procedure for releases?

jrencz commented 1 year ago

I just found this issue after a of of investigation of some problem I experienced in my project.

I'm happy that tsconfig can be specified since https://github.com/modernweb-dev/web/pull/1922 and specifying it resolved the problem I had, but I think that when ts is set to true, then @web/dev-server-esbuild should try to find a tsconfig.json. I'm not creating a new issue, because name of this one exactly describes what I wanted to write. Maybe but for "does not automatically read" part :)

Problem I had was that @web/dev-server-esbuild compiles to esnext if

In my case it caused property decorated with a Lit decorator @query,

@query('.something')
foo;

which in compiled code becomes:

__decorateClass([
  query(".something")
], MyClass.prototype, "foo", 2);

being shadowed with an empty initializer:

foo;

(I'm aware it's a thin ice to use esbuild when Lit recommends using decorators in TS ina certain way)

Once pointed path to my tsconfig, problem went away: the field initializer is not longer emitted.

pmcelhaney commented 1 year ago

@jrencz I agree. I figured adding a config option would be easier to "sell" to the maintainers and is probably necessary in some cases anyway. All that remains now is default that option to the location of the automatically found tsconfig.json file (if one exists).

Per the TypeScript docs:

... the compiler searches for the tsconfig.json file starting in the current directory and continuing up the parent directory chain.

I don't have the bandwidth right now so I'll leave it open for anyone else who wants to create a pull request.

Stradivario commented 1 year ago

Hello there guys!

Any solution to namespace problem with esbuild and testing library ?

I have a component called flights.component.ts

I have a test which just imports the lit html web component import './flights.component

My test looks as follows

import './flights.component';

it('Should create admin-flights element', () => {
  document.createElement('admin-flights');
});

I have the following configuration inside web-test-runner.config.mjs

import { esbuildPlugin } from '@web/dev-server-esbuild';
import { legacyPlugin } from '@web/dev-server-legacy';
import { fileURLToPath } from 'url';

export default {
  files: ['src/**/*.spec.ts'],
  nodeResolve: true,
  watch: true,
  concurrency: 10,
  plugins: [
    esbuildPlugin({ ts: true, tsconfig: fileURLToPath(new URL('./tsconfig.json', import.meta.url)), target: 'auto' }),
    // make sure this plugin is always last
    legacyPlugin({
      polyfills: {
        webcomponents: true,
        // Inject lit's polyfill-support module into test files, which is required
        // for interfacing with the webcomponents polyfills
        custom: [
          {
            name: 'lit-polyfill-support',
            path: 'node_modules/lit/polyfill-support.js',
            test: "!('attachShadow' in Element.prototype)",
            module: false,
          },
        ],
      },
    }),
  ],
};

When i run the tests i got an error that it cannot resolve import @core/services

❌ Could not import your test module. Check the browser logs or open the browser in debug mode for more information. 

Error while transforming src/app/portals/admin/flights/flights.component.ts: Could not resolve import "@core/services".
  10 |   return result;
  11 | };
> 12 | import { Api } from "@core/services";
     |                     ^
  13 | import { Component } from "@rhtml/component";
  14 | import { FlexLayout } from "@rhtml/modifiers";
  15 | import { Container } from "@rxdi/core";

Chrome: |██████████████████████████████| 1/1 test files | 0 passed, 0 failed

Finished running tests, watching for file changes...

In my tsconfig i have the following paths specified


    "paths": {
      "@shared/*": [
        "app/shared/*"
      ],
      "@introspection/*": [
        "app/@introspection/*"
      ],
      "@core/*": [
        "app/core/*"
      ],
      "@assets/*": [
        "assets/*"
      ],
      "~/*": [
        "app/*"
      ]
    }

I was assuming that since i have defined tsconfig property and import the configuration inside esbuild plugin it will automatically resolve my paths but unfortunate this does not happen.

Any idea how i can manage to add my paths from tsconfig to esbuild ?

For my regular starting the application i am using babel to convert these paths to appropriate imports but inside web testing runner i cannot make it to work...

jrencz commented 1 year ago

@Stradivario take a look at rollup-plugin-typescript-paths

I use it and it does the job

venikx commented 1 year ago

@kobleistvan and possibly @pmcelhaney is the test case I added here what you were referring to?

electrovir commented 1 year ago

@jrencz how does one use rollup-plugin-typescript-paths in wtr? I added typescriptPaths to plugins but it just throws tons of Could not resolve import errors.

Edit:

Figured it out. I needed the following configuration:

import {fromRollup} from '@web/dev-server-rollup';
import {typescriptPaths} from 'rollup-plugin-typescript-paths';
import {esbuildPlugin} from '@web/dev-server-esbuild';

export default {
    plugins: [
        fromRollup(typescriptPaths)({
            preserveExtensions: true,
            absolute: false,
            transform(path) {
                return '/' + path;
            },
        }),
        esbuildPlugin({ts: true}),
    ],
}

All of the typescriptPaths options provided above were necessary (for me at least).

jrencz commented 1 year ago

@electrovir you need to pass the tsconfig part next to ts:true in esbuild

difosfor commented 1 year ago

Ah, thanks! I was able to get this working by specifying the tsconfig option to esbuildPlugin as now documented:

import { fileURLToPath } from 'url';

esbuildPlugin({
  ts: true,
  tsconfig: fileURLToPath(new URL('./tsconfig.json', import.meta.url)),
});

-- https://modern-web.dev/docs/dev-server/plugins/esbuild/

I also had to add "useDefineForClassFields": false below "experimentalDecorators": true in my tsconfig.json file as now documented by lit: https://lit.dev/docs/components/decorators/#decorators-typescript