是否可以使用Webpack加载程序从文件生成Typescript接口? [英] Is it possible to generate Typescript interfaces from files with a webpack loader?

查看:108
本文介绍了是否可以使用Webpack加载程序从文件生成Typescript接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am attempting to create a webpack loader that converts a file containing a description of API data structures into a set of TypeScript interfaces.

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

In my concrete case, the file is JSON, but this should be ultimately irrelevant — the file is only a shared source of data describing the interaction between web application backend(s) and frontend(s). In my MCVE below, you can see that the JSON file contains an empty object to underscore how the type and contents of the file do not matter to the problem.

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

My current attempt reports two errors (I assume the second is caused by the first):

[at-loader]: Child process failed to process the request:  Error: Could not find file: '/private/tmp/ts-loader/example.api'.

ERROR in ./example.api
Module build failed: Error: Final loader didn't return a Buffer or String

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

How can I generate TypeScript code using a webpack loader?

{
  "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"
  }
}

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",
      },
    ]
  },
};

my-own-loader.js

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

index.ts

import * as foo from './example';

console.log(foo);

example.api

{}


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


I recognize that there are other code generation techniques. For example, I could convert my JSON files to TypeScript with some build tool and check them in. I'm looking for a more dynamic solution.

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

my-own-loader.js does not export json but string.

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

That's correct, much like loading an image file doesn't always export binary data but sometimes outputs a JavaScript data structure representing metadata about the image.

为什么需要从json文件定义打字稿接口?这些接口可以用于打字稿编译吗?

Why you need to define the typescript interfaces from json file? Would the interfaces be used for typescript compilation?

是的.我想导入一个描述我的API数据结构的文件,并自动生成相应的TypeScript接口.拥有共享文件可以使前端和后端始终就将要显示的数据达成共识.

Yes. I want to import a file that describes my API data structures and automatically generate corresponding TypeScript interfaces. Having a shared file allows the frontend(s) and backend(s) to always agree on what data will be present.

推荐答案

首先,提供MCVE的荣誉.这是一个真的有趣的问题.我用来解决这个问题的代码基于MCVE,并且在此处可用.

First off, kudos for providing an MCVE. This is a really interesting question. The code I worked with to put this answer together is based on said MCVE, and is available here.

缺少文件?

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

This is a most unhelpful error message indeed. The file is clearly in that location, but TypeScript will refuse to load anything that doesn't have an acceptable extension.

此错误本质上是隐藏了真实错误

This error is essentially hiding the real error, which is

TS6054: File 'c:/path/to/project/example.api' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx'.

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

This can be verified by hacking into typescript.js, and manually adding the file. It's ugly, as detective work often is (starts at line 95141 in v2.6.1):

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));

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

Conceptually, you're just passing a string between loaders, but it turns out the file name is important here.

可能的解决方法

我没有看到使用awesome-typescript-loader执行此操作的方法,但是如果您愿意使用 ts-loader 代替,您当然可以从具有任意扩展名的文件中生成TypeScript,编译该TypeScript,然后将其注入到您的output.js中.

I didn't see a way to do this with awesome-typescript-loader, but if you're willing to use ts-loader instead, you can certainly generate TypeScript from files with arbitrary extensions, compile that TypeScript, and inject it into your output.js.

ts-loader具有 appendTsSuffixTo选项,可以用于解决众所周知的文件扩展名痛苦.如果您的webpack配置看起来像类似,你走了那条路线:

ts-loader has an appendTsSuffixTo option, that can be used to work around the well-known file extension pain. Your webpack config might look something like this if you went that route:

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$/]
    }
  }
]

关于界面和DX的说明

接口被编译器擦除.通过针对

Interfaces are erased by the compiler. This can be demonstrated by running tsc against something like this

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

vs.

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

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

var dummy = new DummyClass();
dummy.printMessage();

为了提供良好的开发人员体验,您可能需要仅在开发环境中将这些接口写入文件.您不需要将它们写出进行生产构建,也不需要(也不希望)将它们检入版本控制.

In order to provide a nice developer experience, you may need to write these interfaces to a file in the dev environment only. You don't need to write them out for a production build, and you don't need (or want) to check them into version control.

开发人员可能需要将它们写出来,以便他们的IDE可以发挥作用.您可以将*.api.ts添加到.gitignore,并将其保留在存储库之外,但我怀疑它们将需要存在于开发人员的工作区中.

Developers probably need to have them written out so their IDE has something to sink its teeth into. You might add *.api.ts to .gitignore, and keep them out of the repository, but I suspect they'll need to exist in the developers' workspaces.

例如,在我的示例仓库中,新开发人员必须运行npm install(照常) npm run build(以在其本地环境中生成接口)来摆脱他们所有的红色花花公子.

For example, in my sample repo, a new developer would have to run npm install (as usual) and npm run build (to generate the interfaces in their local environment) to get rid of all their red squigglies.

这篇关于是否可以使用Webpack加载程序从文件生成Typescript接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆