是否可以使用webpack加载器从文件生成Typescript接口?

She*_*ter 11 loader typescript webpack

我正在尝试创建一个webpack加载器,它将包含API数据结构描述的文件转换为一组TypeScript接口.

在我的具体情况中,文件是JSON,但这应该是最终无关紧要的 - 文件只是描述Web应用程序后端和前端之间交互的共享数据源.在下面的MCVE中,您可以看到JSON文件包含一个空对象,以强调文件的类型和内容与问题无关.

我当前的尝试报告了两个错误(我假设第二个错误是由第一个引起的):

[at-loader]: Child process failed to process the request:  Error: Could not find file: '/private/tmp/ts-loader/example.api'.
Run Code Online (Sandbox Code Playgroud)
ERROR in ./example.api
Module build failed: Error: Final loader didn't return a Buffer or String
Run Code Online (Sandbox Code Playgroud)

如何使用webpack加载器生成TypeScript代码?

的package.json

{
  "name": "so-example",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "build": "webpack"
  },
  "dependencies": {
    "awesome-typescript-loader": "^3.2.3",
    "typescript": "^2.6.1",
    "webpack": "^3.8.1"
  }
}
Run Code Online (Sandbox Code Playgroud)

webpack.config.js

const path = require('path');

module.exports = {
  entry: './index.ts',
  output: {
    filename: 'output.js',
  },
  resolveLoader: {
    alias: {
      'my-own-loader': path.resolve(__dirname, "my-own-loader.js"),
    },
  },
  module: {
    rules: [
      {
        test: /\.api$/,
        exclude: /node_modules/,
        use: ["awesome-typescript-loader", "my-own-loader"],
      },
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        loader: "awesome-typescript-loader",
      },
    ]
  },
};
Run Code Online (Sandbox Code Playgroud)

我 - 拥有 - loader.js

module.exports = function(source) {
  return `
interface DummyContent {
    name: string;
    age?: number;
}
`;
};
Run Code Online (Sandbox Code Playgroud)

index.ts

import * as foo from './example';

console.log(foo);
Run Code Online (Sandbox Code Playgroud)

example.api

{}
Run Code Online (Sandbox Code Playgroud)

我认识到还有其他代码生成技术.例如,我可以使用一些构建工具将我的JSON文件转换为TypeScript并检查它们.我正在寻找一个更动态的解决方案.


my-own-loader.js不会导出json而是导出字符串.

这是正确的,就像加载图像文件并不总是导出二进制数据,但有时会输出表示图像元数据的JavaScript数据结构.

为什么需要从json文件定义typescript接口?接口是否可用于打字稿编译?

是.我想导入一个描述我的API数据结构的文件,并自动生成相应的TypeScript接口.拥有共享文件允许前端和后端始终就将要出现的数据达成一致.

Mik*_*ick 6

首先,提供MCVE的荣誉.这是一个非常有趣的问题.我使用的代码将这个答案放在一起是基于所说的MCVE,可以在这里找到.

遗失文件?

这确实是一个无用的错误消息.该文件显然位于该位置,但TypeScript将拒绝加载任何没有可接受扩展名的文件.

这个错误本质上隐藏了真正的错误,即

TS6054: File 'c:/path/to/project/example.api' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx'.
Run Code Online (Sandbox Code Playgroud)

这可以通过入侵typescript.js和手动添加文件来验证.它很丑陋,因为侦探工作经常是(从v2.6.1中的第95141行开始):

for (var _i = 0, rootFileNames_1 = rootFileNames; _i < rootFileNames_1.length; _i++) {
    var fileName = rootFileNames_1[_i];
    this.createEntry(fileName, ts.toPath(fileName, this.currentDirectory, getCanonicalFileName));
}
this.createEntry("c:/path/to/project/example.api", ts.toPath("c:/path/to/project/example.api", this.currentDirectory, getCanonicalFileName));
Run Code Online (Sandbox Code Playgroud)

从概念上讲,你只是在加载器之间传递一个字符串,但事实证明文件名在这里重要.

可能的解决办法

我没有看到这样做的方法awesome-typescript-loader,但是如果你愿意使用它ts-loader,你当然可以从具有任意扩展名的文件生成TypeScript,编译TypeScript,并将其注入你的output.js.

ts-loader有一个appendTsSuffixTo选项,可用于解决众所周知的文件扩展名的痛苦.如果你走了那条路线,你的webpack配置可能会是这样的:

rules: [
  {
    test: /\.api$/,
    exclude: /node_modules/,
    use: [
      { loader: "ts-loader" },
      { loader: "my-own-loader" }
    ]
  },
  {
    test: /\.tsx?$/,
    exclude: /node_modules/,
    loader: "ts-loader",
    options: {
      appendTsSuffixTo: [/\.api$/]
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

关于接口和DX的注意事项

接口由编译器擦除.这可以通过运行证明tsc对像这样

interface DummyContent {
    name: string;
    age?: number;
}
Run Code Online (Sandbox Code Playgroud)

此相比

interface DummyContent {
    name: string;
    age?: number;
}

class DummyClass {
    printMessage = () => {
        console.log("message");
    }
}

var dummy = new DummyClass();
dummy.printMessage();
Run Code Online (Sandbox Code Playgroud)

为了提供良好的开发人员体验,您可能只需要将这些接口编写到dev环境中的文件中.您不需要为生产版本编写它们,也不需要(或想要)将它们检入版本控制.

开发人员可能需要将它们写出来,以便他们的IDE能够深入研究.您可以添加*.api.ts.gitignore,并让他们出库的,但我怀疑他们会需要在开发人员的工作区存在.

例如,在我的样本仓库中,新开发人员必须运行npm install(像往常一样) npm run build(在本地环境中生成接口)以摆脱他们所有的红色波浪形.

  • 我没有绑定awesome-typescript-loader,我大多只是使用它,因为它提供了一些潜在的加速(我甚至可能不需要).关于开发人员体验的观点很有意思 - 我想解决这个问题的其他原因之一是因为我使用[typings-for-css-modules-loader](https://github.com/Jimdo/typings-for -CSS模块加载器).这会生成.d.ts文件,[但*initial*build会失败,因为文件不存在](https://github.com/Jimdo/typings-for-css-modules-loader/issues/33).这意味着CI必须构建它两次,允许第一次失败,这是. (2认同)