vue-cli icon indicating copy to clipboard operation
vue-cli copied to clipboard

Can not emit declaration files for TypeScript

Open duduluu opened this issue 7 years ago • 54 comments
trafficstars

Version

3.0.0-beta.6

Reproduction link

https://github.com/HuijiFE/void-ui/tree/0.1

Steps to reproduce

git clone [email protected]:HuijiFE/void-ui.git
cd void-ui
git checkout 0.1
yarn
yarn build:void

What is expected?

Output declaration files after building.

What is actually happening?

There is not any declaration files after building.


I have set "declaration": true, in tsconfig.json, but it doesn't output the typescript declaration files.

And then I use tsc --emitDeclarationOnly, although it output the declaration files but without vue single file component.

duduluu avatar Apr 05 '18 18:04 duduluu

This doesn't seem to be a Vue issue... At least doesn't qualify as a bug report.

yyx990803 avatar Apr 05 '18 18:04 yyx990803

But I actually emit the declaration files all along, using legacy webpack template in branch master of my project.

duduluu avatar Apr 05 '18 19:04 duduluu

I am unable to get the build:void script to run in your example repository without modifying the package.json (it references src/void.ts but the only similarly named file I can see is src/VoidUI.ts). Modifying the script to point to this file gets the build going (not seeing typing files though). Just running yarn tsc --emitDeclarationOnly results in an error in the console. Are you running a globally installed version of tsc? if so, can you specify which version to make sure that is not causing us problems

dhensche avatar May 01 '18 13:05 dhensche

after simplifying the ts file so that typescript stopped complaining on build, I found this issue https://github.com/TypeStrong/ts-loader/issues/711 . Turns out that using the happyPackMode (used when building for production and the parallel flag is set) or setting transpileOnly: true (always the case in the current typescript plugin) in the ts-loader config options will disable the output of declaration files. I'm pretty sure these settings are for build performance reasons so I don't know how the team would like to handle this

dhensche avatar May 01 '18 15:05 dhensche

@dhensche thanks for looking into this!

yyx990803 avatar May 01 '18 17:05 yyx990803

@dhensche Thx, you could checkout https://github.com/HuijiFE/void-ui/tree/alpha-1.0 So... it's a issue for ts-loader.

duduluu avatar May 02 '18 05:05 duduluu

yes, ts-loader related issue. I'm wondering if we need to change the build task for projects with the typescript plugin to change the related options so that we still see the performance gains during development (serve), but build the definitions file during a full build. You could modify your webpack config in your vue.config.js to fix the issue locally by adding

config.module
  .rule('ts')
    .use('ts-loader')
      .loader('ts-loader')
        .tap(opts => {
          opts.transpileOnly = false;
          opts.happyPackMode = false;
          return opts;
        });

to disable the transpileOnly and happyPackMode options.

dhensche avatar May 02 '18 15:05 dhensche

Declaration files are only relevant when generating a library consumable by a package manager. The build time overhead would only happen in this case. We could disable HappyPack in this case only.

I will cook up a quick PR.

elevatebart avatar Jun 01 '18 20:06 elevatebart

@dhensche I've tried your suggestion with vu-cli 3.0. When opts.happyPackMode = false I get the following error during build:

error in ./src/index.ts


Module build failed (from ./node_modules/thread-loader/dist/cjs.js):
Thread Loader (Worker 0)
Cannot read property 'options' of undefined

    at Object.makeServicesHost (C:\...\node_modules\ts-loader\dist\servicesHost.js:18:66)
    at successfulTypeScriptInstance (C:\...\node_modules\ts-loader\dist\instances.js:164:45)
    at Object.getTypeScriptInstance (C:\...\node_modules\ts-loader\dist\instances.js:51:12)
    at Object.loader (C:\...\node_modules\ts-loader\dist\index.js:16:41)

 @ ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js 2:0-24 3:15-18 4:0-22 4:0-22

|  Building for production as library (commonjs + umd)...

(Oddly enough, if I comment out opts.happyPackMode = false; everything is fine).

azampagl avatar Aug 15 '18 12:08 azampagl

exacly the same issue here...

mumrich avatar Sep 12 '18 13:09 mumrich

after some further investigation, it seems that (at least in my case), the issue is related with the 'thread-loader' package that the 'cli-plugin-typescript' is using... if I set parallel: false in the vue.config.js, the typings are correctly emitted, if I override the 'ts-loader'-options as @dhensche suggested!

mumrich avatar Sep 12 '18 15:09 mumrich

This is effecting me at the moment too would be great if there could be specific bit in the documentation detailing what should be done by the dev to enable outputting of declaration files when building as a lib, I appreciate if you are outputting an application you will not care about d.ts files.

grofit avatar Oct 11 '18 13:10 grofit

For some reason the workaround (stopping parallel, removing the happy stuff, add declaration config to tsconfig) behaviour has changed slightly in the new versions. It still outputs the d.ts files but where I used to have to use:

"declarationDir": "." // change from "." to "dist"

This will then go back to putting the d.ts files in the dist folder, for some reason it used to always work relative to the dist folder so "." would indicate to bung the files there, but now it seems to work relative to the root directory for the declaration files.

Not a clue as to why and I dont have the time to go and investigate further but incase anyone has the same issue just change the declaration directory in your tsconfig. I would still ideally want a proper solution to this problem as some of my projects are taking 30 seconds+ to build the library with the workaround in place :(

grofit avatar Nov 13 '18 13:11 grofit

I'm dealing with this issue as well, and when applying the suggested workaround the type definition files are properly generated, but only on the initial build, any additional builds will clear out the dist folder and after it is rebuilt the type files are not regenerated.

khuguet-tfg avatar Nov 29 '18 16:11 khuguet-tfg

@khuguet-tfg you need to delete cache-loader:

chainWebpack: config => {
    config.module.rule("ts").uses.delete("cache-loader");
    config.module.rule("tsx").uses.delete("cache-loader");
}

luotaoyeah avatar Dec 03 '18 00:12 luotaoyeah

Any update on this?

kjleitz avatar Dec 16 '18 04:12 kjleitz

Same here for library :( npx vue-cli-service build --target lib --dest lib ./src/index.ts

I have set "declaration": true, in tsconfig.json, but it doesn't output the typescript declaration files.

wizardnet972 avatar Dec 22 '18 10:12 wizardnet972

Have there been any updates through almost a year?

eakarpov avatar Feb 26 '19 11:02 eakarpov

I just ended up removing vue-cli and using webpack directly :( it was becoming too much of a time sink and faff to build TS related libraries with vue-cli.

If you are going to be doing re-usable ts based components or libraries then I would suggest just skipping vue cli and just building it all yourself with webpack, as its been almost a year now and the workarounds are not great. If you are however just making an "application" for running then vue cli is great (but I would question why you would need declaration files in that scenario).

If it helps anyone, here is an example webpack used to basically do the same stuff vue cli was doing for me (bundling ts, sass, vue files etc).

https://github.com/alchemist/alchemist-core/blob/master/webpack.config.js

grofit avatar Feb 26 '19 11:02 grofit

It does not work for me too :(

HamedFathi avatar Feb 28 '19 14:02 HamedFathi

yes, ts-loader related issue. I'm wondering if we need to change the build task for projects with the typescript plugin to change the related options so that we still see the performance gains during development (serve), but build the definitions file during a full build. You could modify your webpack config in your vue.config.js to fix the issue locally by adding

config.module
  .rule('ts')
    .use('ts-loader')
      .loader('ts-loader')
        .tap(opts => {
          opts.transpileOnly = false;
          opts.happyPackMode = false;
          return opts;
        });

to disable the transpileOnly and happyPackMode options.

@dhensche I want to use your solution but I got an error

I created a vue.config.js file and copied your code but compile failed

 ERROR  Error loading vue.config.js:
 ERROR  ReferenceError: config is not defined
ReferenceError: config is not defined

How to fix it and create .d.ts files?

HamedFathi avatar Feb 28 '19 14:02 HamedFathi

Hello @HamedFathi,

You need to place this code under the chainWebpack property of the exported module.

// vue.config.js

module.exports = {
  chainWebpack: config => {
    // here you can access and tweak the webpack config
  }
}

This is described in the docs here.

have a nice day :)

sybers avatar Mar 12 '19 08:03 sybers

Hello @Gramatiik!

I've already tried to use this config property for modifying webpack configuration.

chainWebpack: config => {
        config.module
            .rule('ts')
            .use('ts-loader')
            .loader('ts-loader')
            .tap(opts => {
                opts.transpileOnly = false;
                opts.happyPackMode = false;
                return opts;
            });
    },

Though, I receive such an error: "Cannot read property 'hooks' of undefined". Do you know, what the cause could be?

eakarpov avatar Mar 12 '19 09:03 eakarpov

@eakarpov This seems to be related to thread-loader,

The workaround proposed in this issue is to simply disable thread-loader.

Because this will slow down the build, you can disable it only for production builds when you want to emit the declaration files.

Please let me know if you find a better solution :)

sybers avatar Mar 12 '19 09:03 sybers

@Gramatiik it seems like the proposal in thread-loader issue does not fix the problem. There are yet no declarations after build.

eakarpov avatar Mar 15 '19 22:03 eakarpov

@eakarpov Hello, here's my current configuration file with which I get the precious .d.ts files !

// vue.config.js

module.exports = {
  configureWebpack: config => {
    if(process.env.NODE_ENV === 'production') {
      config.module.rules.forEach(rule => {
        if (rule.use) {
          let idx = rule.use.findIndex(w => w.loader === 'thread-loader')
          if (idx !== -1) rule.use.splice(idx, 1)
        }
      })
    }
  },
  chainWebpack: config => {
    if(process.env.NODE_ENV === 'production') {
      // disable cache (not sure if this is actually useful...)
      config.module.rule("ts").uses.delete("cache-loader");

      config.module
        .rule('ts')
        .use('ts-loader')
        .loader('ts-loader')
        .tap(opts => {
          opts.transpileOnly = false;
          opts.happyPackMode = false;
          return opts;
        });
    }
  }
}

The only small problem is that it emits empty declarations files for the tests (*.spec.ts, if someone has an idea how to ignore them I am interested) but everything else works well :)

sybers avatar Mar 16 '19 13:03 sybers

@Gramatiik Presumably, this ts-loader option would help:

https://github.com/TypeStrong/ts-loader#onlycompilebundledfiles-boolean-defaultfalse

LinusBorg avatar Mar 16 '19 16:03 LinusBorg

Very interesting, thank you @LinusBorg :)

sybers avatar Mar 17 '19 11:03 sybers

@Gramatiik I copied your config and do not receive .d.ts files after production build :(

eakarpov avatar Mar 21 '19 08:03 eakarpov

configureWebpack: config => {
    if(process.env.NODE_ENV === 'production') {
      config.module.rules.forEach(rule => {
        if (rule.use) {
          let idx = rule.use.findIndex(w => w.loader === 'thread-loader')
          if (idx !== -1) rule.use.splice(idx, 1)
        }
      })
    }
  },
  chainWebpack: config => {
    if(process.env.NODE_ENV === 'production') {
      // disable cache (not sure if this is actually useful...)
      config.module.rule("ts").uses.delete("cache-loader");

      config.module
        .rule('ts')
        .use('ts-loader')
        .loader('ts-loader')
        .tap(opts => {
          opts.transpileOnly = false;
          opts.happyPackMode = false;
          return opts;
        });
    }
  }

I tried that, but seems it doesn't work. My Vue version is: 2.6.10, Vue-cli version:3.11.0

jianwu avatar Oct 21 '19 16:10 jianwu