首页 > 解决方案 > 在 Angular 应用程序中,TSLint 可以通过路径映射 iso 通过相对路径强制导入模块吗?

问题描述

假设我对 Angular 项目有以下设置:

apps/my-app
libs/my-comp/my-lib

在 my-app 代码中,我使用来自 my-lib 的代码。我可以通过 typescript 导入来导入 my-lib 代码,例如import ../../libs/my-comp/my-lib,但这很丑陋且容易出错。使用路径映射,我可以模拟模块导入,例如import { MyLibModule} from @my-comp/my-lib. 干净多了。

但是,我们可以强制执行吗?我们如何防止开发人员使用相对路径从另一个模块导入代码?对此有 TSLint 规则吗?我们应该编写自定义 TSLint 代码吗?有人已经尝试过这样做:)?

标签: angulartypescripttslint

解决方案


我们有类似的设置,我们实现了 2 个自定义 lint 规则:

  • 禁止从my-lib相对进口进口
  • @my-comp/my-lib禁止从库本身导入

也许更好的设置是使用nx-workspace(参见 Prebuilt Constraints 部分)。它具有类似的规则并增加了更多:

  • Libs 无法导入应用程序。
  • 通过 loadChildren 加载库的项目也不能使用 ESM 导入来导入它。
  • 不允许循环依赖。
  • 无法使用相对导入来导入库。

这是我们禁止从库中相对导入的规则的实现。它有效,但可能存在一些我们尚未发现的严重问题(比如减慢 lint :)

import * as ts from 'typescript';
import * as Lint from 'tslint';

export class Rule extends Lint.Rules.AbstractRule {
    static readonly FAILURE_STRING = `Import should be from '${Rule.SHARED_IMPORT}'`;
    static readonly SHARED_IMPORT = 'my-lib';

    public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
        return this.applyWithFunction(sourceFile, walk);
    }
}

function walk(ctx: Lint.WalkContext<void>) {
    return ts.forEachChild(ctx.sourceFile, cb);

    function cb(node: ts.Node): void {
        if (node.kind !== ts.SyntaxKind.ImportDeclaration) {
            return;
        }

        const importLocation = getImportLocation(node.getText());

        if (containsIncorrectImportFromSharedFolder(importLocation)) {
            const locationWidth = importLocation.length + 3;
            const fix = new Lint.Replacement(node.getEnd() - locationWidth, locationWidth, `'${Rule.SHARED_IMPORT}';`);
            return ctx.addFailureAtNode(node, Rule.FAILURE_STRING, fix);
        }

        return ts.forEachChild(node, cb);
    }

    function containsIncorrectImportFromSharedFolder(importLocation: String): boolean {
        return importLocation.indexOf(Rule.SHARED_IMPORT) > -1 && importLocation !== Rule.SHARED_IMPORT;
    }

    function getImportLocation(location: string): string {
        const importLocation = location.match(/'(.*?[^'])'/);
        return importLocation !== null ? importLocation[1] : '';
    }
}

您必须将规则编译为jswith tsc

node "node_modules/typescript/bin/tsc" tools/tslint-rules/myLibImportRule.ts

你必须将它添加到tslint.json

"rulesDirectory": [
    ...
    "tools/tslint-rules",
    ...
],
"rules": {
    ...,
    "my-lib-import": true,
    ...
}

规则名称是文件的名称myLibImportRule.js=> my-lib-import


推荐阅读