Vue + webpack + TS:生成声明

时间:2018-06-07 10:11:40

标签: typescript webpack vue.js

我正在使用Typescript编写的库并使用VueJS。我也在使用webpack作为建筑部件。

我遇到了生成TypeScript声明文件(.d.ts)的问题。

首先,我们来谈谈我的源代码。我有Typescript文件(显然)和Vue组件。每个Vue组件由2个文件组成:.vue文件和.ts文件。

我们举一个例子。

我有以下代码:

// 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 {

}

构建的输出将是这样的:

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

问题是dts-bundle无法输出dist / index.d.ts,因为生成的声明(dist/lib/**/*.d.ts)无效。它们由ts-loader生成。

如果我们查看dist / lib / index.d.ts,我们会发现以下内容:

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

问题当然是: /dist/lib/components/Foobar.vue 存在。此组件的定义为Foobar.d.ts,而非Foobar.vue.d.ts

将每个声明捆绑在一起时,dts-bundle失败,因为它找不到/dist/lib/components/Foobar.vue.d.ts

我该如何解决?

我只需要替换这个

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

由此

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

我认为这是一个非常常见的错误,我只是对我的webpack配置做错了。这是我的webpack配置:

{
  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,
    })
  ],
}

我正在制作一个最小的复制回购,我会及时编辑这个问题。

与此同时,请告知我是否需要提供具体信息。

感谢您提供帮助。

1 个答案:

答案 0 :(得分:1)

好的,我终于成功了。

vue-loader用于将vue monofiles分成不同的webpack资产。目标是使webpack在vue monofile(脚本,样式和模板)的每个部分上执行不同的加载器。

在我的情况下,我没有使用“真正的”vue monofile,因为typescript部分在.vue文件之外的另一个文件中。然后引用<script lang="ts" src="./MyComponent.ts"></script>

由于ts-loader和vue-loader如何工作,这样做会使声明生成失败。

我所要做的就是使用普通的monofile组件。但是因为我需要来保持我的ts远离我的.vue(因为typescript中已知的bug),我必须显式导入我的ts模块而不是引用我的ts文件,如下所示:

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

我希望我说清楚。