Troubleshooting: Unable to locate .vue.d.ts file during declaration generation with Vue, webpack, and TypeScript

Currently, I am developing a library using Typescript and VueJS with webpack for handling the build process.

One of the challenges I'm facing is related to the generation of TypeScript declaration files (.d.ts).

In my source code, I have Typescript files along with Vue components. Each Vue component consists of two files: a .vue file and a .ts file.

For example:

Consider the following code snippet:

// index.ts
export { default } from './components/Foobar.vue';

// components/Foobar.vue
<template><p>Hello!</p></template>
<script lang="ts" src="./Foobar.ts"></script>

// components/Foobar.ts
@Component
export default class Foobar extends Vue {

}

After the build process, the output will look something like this:

lib/
dist/
    index.js // my lib
    index.d.ts // aggregated .d.ts with dts-bundle
    lib/ // all my .d.ts are here !
        index.d.ts
        components/
            Foobar.d.ts

The issue arises because dts-bundle fails to generate dist/index.d.ts due to invalid declarations (dist/lib/**/*.d.ts) created by ts-loader.

If we examine the content of dist/lib/index.d.ts, we see the following:

// dist/lib/index.d.ts
export { default } from './components/Foobar.vue'

The problem lies in the fact that /dist/lib/components/Foobar.vue does not exist. The correct definition for this component should be Foobar.d.ts, not Foobar.vue.d.ts.

During bundling, dts-bundle encounters difficulty finding /dist/lib/components/Foobar.vue.d.ts.

To resolve this issue, I simply need to replace the existing line:

// dist/lib/index.d.ts
export { default } from './components/Foobar.vue'

with:

// dist/lib/index.d.ts
export { default } from './components/Foobar'

This seems to be a common error, possibly originating from misconfiguration in my webpack setup. Here's a glimpse at my webpack configuration:

{
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',

  entry: 'path/to/index.ts',

  output: { /* ... */}

  resolve: {
    symlinks: true,
    extensions: [
      '.ts',
      '.vue',
      '.js',
      '.json',
    ],
    modules: [
      'node_modules',
    ]
  },

  module: {
    noParse: /^(vue|vuex)$/,
    rules: [
      {
        test: /\.vue$/,
        use: [
          {
            loader: 'cache-loader',
            options: {
              cacheDirectory: // cache path
            }
          },
          {
            loader: 'vue-loader',
            options: {
              cacheDirectory: // cache path
            }
          },
        ]
      },
      {
        test: /\.ts$/,
        use: [
          {
            loader: 'cache-loader',
            options: {
              cacheDirectory: // cache path
            }
          },
          {
            loader: 'babel-loader'
          },
          {
            loader: 'ts-loader',
            options: {
              appendTsSuffixTo: [
                /\.vue$/
              ],
            }
          }
        ]
      }
      // ...
  }

  plugins: [
    new ProgressPlugin(),
    new FriendlyErrorsWebpackPlugin({
      clearConsole: false
    }),
    new VueLoaderPlugin(),
    new ForkTsCheckerWebpackPlugin({
      vue: true,
      tslint: 'custom path to my file',
      formatter: 'codeframe',
    }),
    new CopyWebpackPlugin(
      [
        {
          from: 'assets',
          to: 'dist',
          ignore: [
            '.gitkeep',
            '.DS_Store'
          ]
        }
      ]
    ),      
    new DtsBundlePlugin({
      name: `MyModule`,
      main: path.join(LIB_PATH, entry.output.path, 'lib', 'index.d.ts'),
      out: path.join(LIB_PATH, entry.output.path, 'index.d.ts'),
      verbose,
    })
  ],
}

I am currently working on creating a minimal reproduction repository for this issue, which I will update as needed.

In the meantime, please let me know if additional information is required.

Thank you for your assistance.

Answer №1

Finally, after some trial and error, I was able to figure it out.

The role of vue-loader is to separate vue monofiles into various webpack assets. The intention is for webpack to apply different loaders to each section of a vue monofile (script, style, and template).

In my scenario, I didn't have a traditional vue monofile because the typescript portion was in a separate file from the .vue file. I referenced it using

<script lang="ts" src="./MyComponent.ts"></script>
.

This setup caused issues with declaration generation due to how ts-loader and vue-loader function.

To resolve this, I had to switch to using standard monofile components. However, since I needed to keep my ts code separate from my .vue file (due to a known bug in typescript), I had to import my ts module explicitly instead of referencing the file directly:

<script lang="ts">
    export { default } from './MyComponent.ts';
</script>

I hope that explanation clarifies things.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a specific type in typescript that represents every iterable object?

We have a unique function shown below: export const transformUndefinedToNull = (obj) => { const convert = (o) => { Object.keys(o).forEach((key) => { const value = o[key]; if (value === undefined) { o[key] = null; } ...

Getting the content of a textarea within a v-for loop collection

Exploring this particular situation In a .vue file within the template <div v-for="(tweet, index) in tweets"> <div class="each_tweet"> <textarea v-on:keyup="typing(index)" placeholder="Share your thoughts">{{ tweet.c ...

Ways to define an interface that can accommodate various interfaces with a specific structure

I am in need of a function that can accept a parameter with interfaces having a specific structure. The parameter should be either a string hash or a string hash along with an attribute string hash, as shown below: { anotherHash: { a: 'a', ...

What is the best way to retrieve a property from a conditional type using generics?

The code snippet above presents an issue in TypeScript: const exampleFn = function<AttributeName extends 'attributeA' | 'attributeB'>( whatToProcess: AttributeName extends 'attributeA' ? {attributeA: string} : {attri ...

Ways to access a nested property within an array

I'm having an issue when trying to access a sub property of an array. Here's the snippet in question: ngOnInit() { this.menus = this.navService.defaultMenu; console.log(this.getMenusItem()); this.registerChangeInProjects(); } T ...

When switching tabs, Ion-select should not reload the selected name

Whenever I switch tabs and then return to the previous tab in Ionic, the select field that was previously set becomes null, even though the page is still loading and the variable is populated. <ion-header color="primary"> <ion-navbar> &l ...

Error: The options object provided for the Copy Plugin is invalid and does not conform to the API schema

After addressing vulnerabilities in my package.json by updating some packages, I encountered an error while running npm. The Copy Plugin package was updated as part of fixing vulnerabilities. I attempted to revert to older commits by copying the package.j ...

Adjusting the width of row items in Angular by modifying the CSS styles

I am envisioning a horizontal bar with items that are all the same width and evenly spaced apart. They can expand vertically as needed. Check out the updated version here on StackBlitz Issue: I am struggling to automatically set the width of the row elem ...

Tips for integrating a vue plugin into your nuxt project

I've come across a plugin called vue-chat-scroll and I'm interested in utilizing it within nuxt. As a beginner, I'm not fully grasping how to go about this. I am curious if it's feasible to integrate this Vue plugin into nuxt as a plugi ...

Display notification if the request exceeds the expected duration

Is there a way to display a message when a request is taking too long? For instance, if the request exceeds 10 seconds in duration, I want to show a message asking the user to wait until it finishes. fetchData(url, requestParams) { return this.restServic ...

Learn how to integrate ES6 features into your nodejs/expressjs application using either Gulp or Webpack

I am looking to incorporate ES6 features into my nodejs/expressjs application. Currently, I am using Gulp for JavaScript compilation and setting up live reload. What steps do I need to take in order to compile the es6 code to standard js within my exis ...

Could you explain the contrast among "yarn serve," "yarn start," and "yarn build"?

Although both "yarn serve" and "yarn start" can launch my Vue project, I'm unsure of the differences between them. I've heard that "yarn build" is for packaging, but why don't I use it at work? Usually, I just upload my code to git and let ...

Transform JSON into a TypeScript interface with a specialized Date method

Within my Angular 7 project, there is a Post Model defined as follows: export interface PostModel { id: number; created: Date; published: boolean; title: string; } I have implemented an Angular service method aimed at retrieving posts: public g ...

What is the proper way to utilize queries in BlitzJS?

I am attempting to extract data from a table by filtering based on the relationship with the Blitzjs framework. However, I am facing difficulties using queries as it seems to be the only option available. Every time I try to call the quer ...

What is the best way to combine individual function declarations in TypeScript?

In my project, I am currently developing a TypeScript version of the async library, specifically focusing on creating an *-as-promised version. To achieve this, I am utilizing the types provided by @types/async. One issue I have encountered is that in the ...

Encountering an Invalid JSON error on the Developer console

I'm in the process of building a React application and aiming to establish a connection with my Back4App database. Within the Back4App dashboard, there exists a Person class containing data that needs to be retrieved. It appears that the call is being ...

What is the process of invoking a function from a different component in Vue 3?

I attempted to use the $on method and this.$root.$refs.compname_component = this;, but encountered some errors. Please see my code below: formComponent.vue <template> <div v-if="showForm"> create Form </div> </templa ...

Tips on displaying a spinner only when data is retrieved from an Http service

How can I ensure that a spinner is only shown during an HTTP service call and dismissed when my component receives data? To address this issue, I implemented a cache service to store data fetched from the HTTP service for future use. However, I want to sh ...

Determine whether there is only one array in the object that contains values

At the moment, I am attempting to examine an array in order to determine if only one of its elements contains data. Consider this sample array: playersByGender = { mens: [], womens: [], other: [] }; Any combination of these elements may contain dat ...

Converting handlebars templates to vue 2.0 when using @last condition

I am in the process of transitioning from Backbone + Handlebars to Vue, but I'm encountering difficulties with Handlebars templates. Here's an example snippet from one of my templates: {{#each tHeads}} {{#if @last}} {{#each th}} {{# ...