Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack and TypeScript can't resolve declaration file for Vue

I have a project where I introduced Vue for some frontend stuff but I still have a lot of legacy code in TypeScript and jQuery. All the legacy code is in a 'ts' folder and the new Vue single file components and some bootstrapping ts files are in 'src'. It looks all OK in VSCode and even directly calling 'tsc' on the command line works fine but WebPack keeps complaining as soon as I import a declaration/definition (module) from the 'ts' folder.

Project folder structure

+ root
  + php/css/etc
  + ts
    + models
      - LegacyTypeScriptModules.ts
      - PlanDate.ts
    + js-defs
      - tools.d.ts
    - tsconfig.json (to be able to build only legacy code)
  + src
    + components
      - RecentChanged.vue
    + pages
      - Welcome.vue
    - App.vue
    - main.ts
    - tsconfig.json (main configuration)
  - package.json
  - tsconfig.json (only fixing experimentalDecorators issue in VSCode)
  - tslint.json
  - webpack.config.js

Error message npm build

ERROR in ./ts/models/PlanDate.ts Module not found: Error: Can't resolve 'js-defs/tools' in '/Users/username/dev/project-root/ts/models' @ ./ts/models/PlanDate.ts 1:0-45 @ ./node_modules/ts-loader!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/components/RecentChanged.vue @ ./src/components/RecentChanged.vue @ ./node_modules/ts-loader!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/pages/Welcome.vue @ ./src/pages/Welcome.vue @ ./node_modules/ts-loader!./node_modules/vue-loader/lib/selector.js?type=script&index=0!./src/App.vue @ ./src/App.vue @ ./src/main.ts

Main tsconfig.json in 'src' folder

{
    "compilerOptions": {
        "target": "es5",
        "strict": true,
        "module": "es2015",
        "moduleResolution": "node",
        "lib": [
            "dom",
            "es2015",
            "es2015.iterable"
        ],
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "baseUrl": ".",
        "paths": {
            "*": [
                "*",
                "./*",
                "../ts/*"
            ]
        }
      },
      "include": [
          "**/*",
          "../ts/**/*"
      ]
}

webpack.config.js

module.exports = {
  entry: './src/main.ts',
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader",
        exclude: /node_modules|vue\/src/,
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      },
...
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
    },
    extensions: ['.js', '.vue', '.json', '.ts'],
    modules: [
      'node_modules', 
      path.resolve(__dirname, 'src'),
      path.resolve(__dirname, 'ts')
    ],
...

First Vue file importing a legacy ts module

import Vue from 'vue'
import { ChangedItem } from '../../ts/models/ChangedItem'
import { PlanDate } from "../../ts/models/PlanDate"
import { Customer } from "../../ts/models/Customer"
import { Component, Prop } from 'vue-property-decorator'

@Component
export default class RecentChanged extends Vue {
...

Class/module giving the error

import { IDate, IDateSink, IDateSource} from "./interfaces/IDate";
import { addDays, pad } from "js-defs/tools";

export class PlanDate implements IDate {
...

Module which can't be found

import { IMainOptions } from "models/interfaces/IOptions";

export declare function addDays(d: IDate, n: number, keepTime?: boolean): IDate;
export declare function pad(inputString: any, width: number, paddingCharacter?: string): string;

Notice that the first problem already is that I can't seem to get the absolute paths working in Vue SFC so I already had to compromise to an ugly relative path. (maybe already a first sign of a problem?) This absolute path problem in Vue is consistent over VSCode, tsk and WebPack but I have seperate question on this. I also had problems with some absolute paths in the legacy typescript classes but I can imagine this because it only seems to work from the 'ts' folder and deeper but I don't think this is related as WebPack doesn't seem to complain about the import 'IDate'.

As the bare typescript compiler doesn't have a problem with finding the declaration modules and also VSCode language server isn't complaining I assume it is a problem in the configuration file for WebPack but maybe I'm missing/overlooking something.

I tried both absolute and relative paths to the declaration module but both fail. Also tried other legacy classes that don't depend on other legacy modules and they do seem to work. So it looks like the module resolution fails on the declaration file. In webpack.config.js I already tried things like resolve.alias and resolve.modules but they didn't work or I don't know how to define the path.

Update

After the first comments and answers given below I'm pretty sure it has to do with how my own declaration file is defined, how I should import it or how I configure WebPack to properly find it. Can someone tell me how to use declaration files in Vue+WebPack+TypeScript without getting a 'module not found' or a 'no output emitted' error?

like image 822
Huupke Avatar asked Oct 17 '25 16:10

Huupke


1 Answers

When importing .d.ts files make sure you use the type keyword.

import type * as MyTypes from "./types"

like image 97
Peter Hayman Avatar answered Oct 20 '25 07:10

Peter Hayman