【问题标题】:After Custom transformer, typescript still uses reference to old import在自定义转换器之后,打字稿仍然使用对旧导入的引用
【发布时间】:2021-02-13 04:47:10
【问题描述】:

我正在使用 CustomTransformer 从以下位置更新导入:

import { global_spacer_form_element } from '@patternfly/react-tokens';
export const disabledLabelClassNameEx = global_spacer_form_element.var;

import global_spacer_form_element from '@patternfly/react-tokens/dist/js/global_spacer_form_element';
export const disabledLabelClassNameEx = global_spacer_form_element.var;

但是,当与ts-loader 一起使用时,我得到以下输出(直接来自 ts-loader):

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.disabledLabelClassNameEx = void 0;
const global_spacer_form_element_1 = __importDefault(require("@patternfly/react-tokens/dist/js/global_spacer_form_element"));
exports.disabledLabelClassNameEx = react_tokens_1.global_spacer_form_element.var;
//# sourceMappingURL=Recipient2.js.map

不是直接使用global_spacer_form_element,而是使用react_tokens_1.global_spacer_form_element

我想 typescript 编译器用来构建 react_tokens_1 变量的转换器中缺少一些东西。

转换器在其访问者中执行以下操作(为了显示它所采用的路径,我正在简化转换器代码,完整代码可以查看here):

const visitor: ts.Visitor = (node) => {
      if (ts.isSourceFile(node)) {
        return ts.visitEachChild(node, visitor, context)
      }
      
      if (!ts.isImportDeclaration(node) /* or if the lib name is not '@patternfly/react-tokens' */) {
        return node
      }

      // for simplicity assume we take all NamedImports and the only found is...
     const elements = ['global_spacer_form_element']
     const importPath = '@patternfly/react-tokens/dist/js/global_spacer_form_element'
     return elements.map((e) => {
       return ts.factory.createImportDeclaration(
         undefined,
         undefined,
         ts.factory.createImportClause(
           false,
           ts.factory.createIdentifier(e),
           undefined,
         ),
         ts.factory.createStringLiteral(importPath),
       )
     })
}

我的 tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "allowJs": true,
    "checkJs": false,
    "jsx": "react",
    "outDir": "./build",
    "removeComments": true,
    "pretty": true,
    "skipLibCheck": true,
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "noImplicitAny": false,
    "sourceMap": true,
    "resolveJsonModule" : true
  },
  "include": [
    "./src/**/*"
  ],
  "exclude": [
    "./node_modules/*",
    "**/*.js"
  ]
}

最后是ts-loader 配置:

{
  test: /src\/.*\.tsx?$/,
  loader: 'ts-loader',
  exclude: /(node_modules)/i,
  options: {
        getCustomTransformers: () => ({
            before: [
                tsImportPluginFactory({
                    libraryName: '@patternfly/react-tokens',
                    libraryDirectory: 'dist/js',
                   camel2DashComponentName: false
                })
            ]
        })
  }

知道我还需要更新什么或者我可以检查什么以确保这个转换器按预期工作吗?

edit:对旧导入的引用已经消失,但我之前没有注意到新导入也被转换:例如从foobarfoobar_1

【问题讨论】:

    标签: typescript-compiler-api


    【解决方案1】:

    TypeScript 编译器有四个主要阶段——解析、绑定、类型检查和发出。绑定是解决标识符之间关系的地方,但转换发生在“发射”阶段。所以当你转换的时候已经太晚了,编译器已经弄清楚了它要转换的标识符。

    一种做你想做的事情的方法是遍历文件中的所有节点,找到与导入中的一个匹配的标识符,然后通过在访问者中返回 context.factory.createIdentifier(node.escapedText) 来重新创建这些标识符节点。这将使编译器在发射时保持原样。

    但问题可能在于确定文件中的哪些标识符引用了命名的导入标识符。一般来说,我不建议在转换中使用类型检查器,因为当文件上发生多个转换时,它可能会导致意外结果,但是您可以先检查标识符的 escapeText 是否匹配,然后再检查如果typeChecker.getSymbolAtLocation(node)?.declarations[0] 等于在原始导入声明中找到的命名导出标识符。或者,我认为您必须实施自己的范围分析。

    【讨论】:

    • 感谢您的信息。我虽然 react_tokens_1 不知何故在树上。知道这是编译器内部的一部分并且我可以覆盖该值是一个很大的解脱。我想我可以跟踪替换的标识符。谢谢!
    • 稍微阅读后,我认为不可能从变压器内部获取 TypeChecker。那是对的吗?如果是这样,这意味着我需要实施范围分析以确保我正在更新正确的标识符?
    • @Josejulio ts-loader 在调用getCustomTransformersgetCustomTransformers(program: Program) 时提供程序。你应该可以做到program.getTypeChecker()
    • 我已经实现了你所说的(除了typeChecker)。但是有一件事我还是不明白。导入转换为:const global_spacer_form_element_1 = __importDefault... 注意名称中的_1。使用时会得到global_spacer_form_element。为什么编译器要添加 _1?我还缺少一些东西?
    猜你喜欢
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多