ts-loader: Definition files are not updated after initial build when using watch mode in Webpack 5.

Expected Behaviour

When using watch mode in Webpack 5 and I’m changing a file, the index.js and index.d.ts bundle files should be updated with the new code/definitions and I should be able to import the code in my app that consumes the code.

Actual Behaviour

Only the index.js file is updated when adding new code. All d.ts files as well as the index.d.ts bundle remains untouched and I get compiler error when importing the new code (in runtime the code actually runs fine). image

Steps to Reproduce the Problem

  1. Run Webpack 5 in watch mode: node node_modules\webpack\bin\webpack.js --config config/webpack.dev.ts --watch
  2. Change any code in the project
  3. Check the dist folder and compare the times between the .js and the d.ts files

Location of a Minimal Repository that Demonstrates the Issue.

(Working on it)

webpack.dev.ts

module: {
    rules: [
        {
            test: /\.ts$/,
            loader: 'ts-loader',
            options: {
                configFile: '../tsconfig.build.json'
            },
            include: [
                projectRootPath('typings')
                rootPath('src'),
                rootPath('typings')
]
        }
    ]
},

tsconfig.build.json

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "rootDir": "./src",
    "declaration": true,
    "declarationMap": true,
    "declarationDir": "./dist",
    "outDir": "./dist"
  },
  "files": [
    "./src/index.ts",
    "./typings/global.d.ts",
    "../../typings/global.d.ts"
  ]
}

tsconfig.json

{
  "compilerOptions": {
    "rootDir": ".",
    "baseUrl": ".",
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noEmitHelpers": true,
    "noEmitOnError": true,
    "importHelpers": true,
    "noImplicitAny": false,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "strictPropertyInitialization": false,
    "pretty": true,
    "sourceMap": true,
    "declaration": false,
    "preserveConstEnums": true,
    "downlevelIteration": true,
    "lib": [
        "dom",
        "es2015",
        "es2017.object",
        "es2016.array.include",
        "es2017.string",
        "es2018.promise",
        "es2019.string"
    ],
    "paths": {
      "@oas/web-lib-core": ["./packages/web-lib-core/dist"],
      "@oas/web-lib-common": ["./packages/web-lib-common/dist"],
      "@oas/web-lib-angular-js": ["./packages/web-lib-angular-js/dist"],
      "@oas/web-lib-angular": ["./packages/web-lib-angular/dist"],
      "@oas/internal-lib-e2e": ["./packages/internal-lib-e2e/dist"]
    }
  },
  "compileOnSave": false,
  "buildOnSave": false
}

I’m open for the possibility that this bug is not an issue for this project. But it is my guess.

About this issue

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

Most upvoted comments

Thanks for looping me in @johnnyreilly. I am intrigued and perhaps also responsible. The section of code here was one I added in https://github.com/TypeStrong/ts-loader/pull/1200 and also https://github.com/TypeStrong/ts-loader/pull/1208.

The changes were to stop adding assets in the afterCompile compiler hook, which is deprecated in webpack5. I could not find a suitable compiler hook so I used the afterProcessAssets compilation hook. I linked to the compilation using loader._compilation.

As others in this thread have found, in watch mode loader._compilation is not persistent. I created a minimal repository to test this and found the same as others. The repo is at:

https://github.com/appzuka/ts-loader-1243

I used the solution proposed by @JonWallsten , to add a compilation hook in the compiler and to add the processAssets hook inside that hook. (Adding a hook inside a hook feels clumsy but I cannot see a better hook to use.)

I also confirmed that the first run needs to be handled separately using loader._compilation. I tried using the compiler-compilation hook at ts-loader’s entry point but this is already too late for the first run. I did confirm that only 1 of these hooks runs for each compilation run. Even if you make multiple changes in watch mode this does not result in multiple hooks running.

I will go ahead and raise a PR for this change. It is possible that in the future the new hooks available in webpack5 can be used differently.

I will review the PR and say how we can better keep compatibility with webpack@4 and webpack@5

Cool - we appreciate your efforts. Don’t worry about what you can do and when, I appreciate everything is best efforts. Myself I’m contending with home schooling right now and so my ability to focus on anything is challenged 😅

Yeah, and with much at work, no time on the weekends anymore and this constant darkness it’s hard to find time/motivation to do work after work! 😅

Cool - we appreciate your efforts. Don’t worry about what you can do and when, I appreciate everything is best efforts. Myself I’m contending with home schooling right now and so my ability to focus on anything is challenged 😅

Do you want to start work on a prospective PR which we can use as a basis for discussion / collaboration?

I’m not sure I have the time required right now. This upgrade to Webpack 5 has been eating so much time from my project due to bug hunting. I did a monkey patch to fix the issue locally for our group for now. But I will happily look at it once I’m ahead again.

Dropping support for webpack before v4.40.0 is possible. It would make it a breaking changes release, but that’s okay.

According to @sokra it should not be a huge deal: https://github.com/TypeStrong/ts-loader/issues/1243#issuecomment-767420333

The only real change here is that the hook now is actually called every build, not just the initial one

I’m somewhat wary of this as the performance impact is likely to be significant.

But isn’t that whats already happening in Webpack 4? And was supposed to happen in Webpack 5, but didn’t just because the hook was never called again? I’m not sure how heavy the process of adding/writing the definition files are. But from what I saw, even the ones not changed was written again (does not happen the initial build). So that might be something to look at. Maybe it’s fixed by itself if we use the new way of adding files.

Let’s start with creating a POC and see what happens. I can try to do that next week or so.