ts-loader: ts-loader with Typescript 4.5 beta: "Error: TypeScript emitted no output for .../index.mts"

Anyone have luck webpack-5-ing with the new .mts extension? I’m able to output from tsc -p . fine, but through webpack I’m getting “Error: TypeScript emitted no output for …/index.mts”.

Thanks!

    resolve: {
      // Add `.ts` and `.tsx` as a resolvable extension.
      extensions: [".mts", ".ts", ".tsx", ".js"]
    },
    module: {
      rules: [
        {
            test: /(\.mts$)|(\.tsx?$)/,
            use: [
                {
                    loader: 'ts-loader',
                    options: {
                        //transpileOnly: true
                        compilerOptions: {
                            noEmit: false
                        }
                    }
                }
            ]
        }
      ]
    }

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 47 (41 by maintainers)

Most upvoted comments

@alexander-akait I put up a super simple repro showing that .js resolution to .ts doesn’t work, but haven’t had time to start seeing how ts-loader could be involved here. Honestly my expectation was that this would not work; I’m not super familiar with how ts-loader contributes to Webpack’s resolution, but my impression was that this would be a Webpack-level thing, not a ts-loader thing. https://github.com/andrewbranch/nodenext-webpack

@alexander-akait the issue is that in the new TypeScript module resolution modes, users must write import "./foo.js" even though on disk, the colocated file is ./foo.ts. This is because TypeScript expects TS code to be compiled to JS with these import paths unchanged, that way the output JS will resolve correctly at runtime. But this breaks the expectations of bundlers like Webpack, which does module resolution before a 1:1 TS→JS compilation happens. So the correct specifier for Webpack would be import "./foo.ts" but TypeScript doesn’t allow that. The correct specifier for TypeScript is import "./foo.js" but Webpack can’t resolve that by default.

I just want to cross-reference https://github.com/microsoft/TypeScript/issues/37582 which is where I redirected https://github.com/microsoft/TypeScript/issues/46344 to. I would love to hear feedback there from Webpack users about

  • Why do you want/need to use .mts/.cts files?
  • Do you rely on other node12/nodenext module resolution features like export maps?
  • Do you have a mix of ESM and CJS dependencies?
  • Is anyone using Webpack’s resolve.conditionNames and why?
  • Do you want/need to write import paths with complete file extensions? Why?

@fluggo that’s exactly right. Node16/NodeNext were not designed for use in a bundler (hence the name). A mode designed for bundlers is in the works.

I want to add, I’ve been doing a deep dive on this topic, and if all you’re doing is a map of .js to .ts, you’re probably going to have a bad day. Node16/NodeNext module resolution in TypeScript also specifies that you’re importing CommonJS modules from ESM the way Node.js does, which is to say that if you’re asking for import foo from './foo.cjs' in an ESM project, Node.js always gives you the whole module.exports object and never the default export. As far as I can tell, Webpack’s output still operates by the old rules with __esModule interop in place. Please do correct me if I’m wrong.

I do not know the solution to this just yet.

this should be solved by https://github.com/webpack/enhanced-resolve/pull/351


webpack will have a new option for resolve

extensionAlias: {
  ".js": [".ts", ".js"]
}

Good suggestions, thank you @alexander-akait.

@johnnyreilly Yes, no breaking change, now it is just broken and do not work, put console.log and in catch and you will see error always

Thanks, I will look at this

@andrewbranch Feel free to ping me, I some busy today/tomorrow, but will be free on this weekends, and look at this deeply, will be glad to any investigations so we can fix it faster

I’ll give it a try this afternoon.

I think we don’t need a plugin here, webpack already do the same for cjs/mjs, https://github.com/webpack/webpack/blob/main/lib/config/defaults.js#L490, somebody can shortly write problems places with resolving and what is expected and I will show/send a PR with implement

@djcsdy - feels like this might be interesting to you given your work on https://github.com/softwareventures/resolve-typescript-plugin

Yes, I believe it is because of the inclusion of the eventual extension.

import { foo } from "./misc" works as always import { foo } from "./misc.ts" is wrong and gives TS2691: An import path cannot end with a '.ts' extension. Consider importing './misc.js' instead.

but

import { foo } from "./misc.js"; works with tsc but fails only in webpacking with Module not found: Error: Can't resolve './misc.js' in 'C:\example\src' resolve './misc.js'

Does ts-loader need to correct these paths for resolution? Or what?

Haven’t tried this at all - am interested with how this pans out!