Angular: Bazel 下的 tree-shakable 提供商编写的错误导入

创建于 2018-05-15  ·  1评论  ·  资料来源: angular/angular

Tree-shakable 提供者触发 Angular 编译器在用户代码中引入 import 语句,我们以前没有这样做。 事实证明,我们有一些地方可以将磁盘上的模块路径与模块名称混为一谈(早期版本的编译器没有这种区别)
所以我们最终编写了像import {} from 'wksp/packages/path/to/thing'这样应该是import {} from '@pkg_name/path/to/thing'导入

据我们所知,这个问题只影响使用ngc编译并使用 tree-shakable 提供程序的 Bazel 用户。 到目前为止,我们只在 Angular 内部看到了这个问题。

这是作为 #20030 的一部分发现的

要重现,请添加一个可摇树的提供程序,例如粘贴到packages/common/src/common_module.ts

import {Injectable, PLATFORM_ID} from '@angular/core';
import {DOCUMENT, isPlatformBrowser} from '@angular/common';

export function viewportScrollerFactory(platformId: string, document: any) {
  return isPlatformBrowser(platformId) ? null: null;
}

@Injectable(
    {providedIn: 'root', useFactory: viewportScrollerFactory, deps: [PLATFORM_ID, DOCUMENT]})
export abstract class ViewportScroller {}

然后构建 npm 包

bazel build //packages/common:npm_package

并在输出中查找字符串angular/packages

$ export bin=$(bazel info bazel-bin)
$ find $bin -type f -exec fgrep -l angular/packages {} \; | grep -v ngsummary | grep -v ngfactory

我们删除了 ngsummary 文件,因为这些文件在磁盘上总是有路径作为模块标识符。
ngfactory 文件未随包一起提供,因此这些文件也可能是无害的。

有趣的是,我们在 ES2015 输出中发现了错误的导入:

bin/packages/common/src/common_module.closure.js

/**
 * <strong i="28">@fileoverview</strong> added by tsickle
 * <strong i="29">@suppress</strong> {checkTypes} checked by tsc
 */
/**
 * <strong i="30">@license</strong>
 * Copyright Google Inc. All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */
import { NgModule } from '@angular/core';
import { COMMON_DIRECTIVES } from './directives/index';
import { DEPRECATED_PLURAL_FN, NgLocaleLocalization, NgLocalization, getPluralCase } from './i18n/localization';
import { COMMON_DEPRECATED_I18N_PIPES } from './pipes/deprecated/index';
import { COMMON_PIPES } from './pipes/index';
import { Injectable, PLATFORM_ID } from '@angular/core';
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import * as i0 from "@angular/core";
import * as i1 from "@angular/core/src/application_tokens";
import * as i2 from "angular/packages/common/src/dom_tokens";  // <-------------------------

但不在 ES5 输出中

bin/packages/common/src/common_module.js

(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define("@angular/common/src/common_module", ["require", "exports", "tslib", "@angular/core", "@angular/common/src/directives/index", "@angular/common/src/i18n/localization", "@angular/common/src/pipes/deprecated/index", "@angular/common/src/pipes/index", "@angular/core", "@angular/common", "@angular/core", "@angular/core/src/application_tokens", "@angular/common/src/dom_tokens"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var tslib_1 = require("tslib");
    var core_1 = require("@angular/core");
    var index_1 = require("@angular/common/src/directives/index");
    var localization_1 = require("@angular/common/src/i18n/localization");
    var index_2 = require("@angular/common/src/pipes/deprecated/index");
    var index_3 = require("@angular/common/src/pipes/index");
    var core_2 = require("@angular/core");
    var common_1 = require("@angular/common");
    var i0 = require("@angular/core");
    var i1 = require("@angular/core/src/application_tokens");
    var i2 = require("@angular/common/src/dom_tokens");
P3 bazel low bufix

最有用的评论

我们现在也遇到了这个问题。

我们在单一存储库中内部调用编译器 API,这在内部也会在导入路径中对我们产生影响,例如:

import * as i1 from "@our-group/our-package/src/some-service";

虽然这在 ES5 输出中发生在我们身上,但我认为根本原因是相似的。
我们的解决方法是在@Injectable 中自己定义工厂。 这会阻止 angular 生成工厂,从而生成错误的导入。

不确定我是否需要提供更多信息/可重现:

  • 我这样做会非常困难,因为这是专有代码的混合。
  • 我相信你已经知道原因了,但目前,可以理解的是,不要基于它只发生在 Angular 内部的假设来优先考虑它。

>所有评论

我们现在也遇到了这个问题。

我们在单一存储库中内部调用编译器 API,这在内部也会在导入路径中对我们产生影响,例如:

import * as i1 from "@our-group/our-package/src/some-service";

虽然这在 ES5 输出中发生在我们身上,但我认为根本原因是相似的。
我们的解决方法是在@Injectable 中自己定义工厂。 这会阻止 angular 生成工厂,从而生成错误的导入。

不确定我是否需要提供更多信息/可重现:

  • 我这样做会非常困难,因为这是专有代码的混合。
  • 我相信你已经知道原因了,但目前,可以理解的是,不要基于它只发生在 Angular 内部的假设来优先考虑它。
此页面是否有帮助?
0 / 5 - 0 等级