Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript 4.7's "module": "Node16" yields invalid output or error for library build #46181

Open
bgotink opened this issue May 29, 2022 · 5 comments
Labels
area: compiler Issues related to `ngc`, Angular's template compiler area: packaging Issues related to Angular's creation of npm packages bug P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: confirmed
Milestone

Comments

@bgotink
Copy link

bgotink commented May 29, 2022

Which @angular/* package(s) are the source of the bug?

compiler-cli

Is this a regression?

No

Description

Using typescript 4.7's "module": "Node16" in a library yields errors or invalid output:

  • Without "type": "module" in package.json with all files given the .mts file extension an error is generated by @angular/compiler-cli:

    error NG4001: Angular compiler option "flatModuleOutFile" requires one and only one .ts file in the "files" field.
    
  • With "type": "module" in package.json the generated bundle index is emitted as CJS instead of ESM, which results in invalid FESM files. Coincidentally, the generated CJS bundle index file contains inline tslib helpers, even with "importHelpers": true in the tsconfig.
    Note that ng-packagr actually outputs all files as CJS instead of ESM. That seems to be an issue with ng-packagr itself, as other library pipeline(s) don't show the same behaviour. The generated bundle file is always CJS, regardless of tooling.

    Generated bundle index file
    "use strict";
    /**
     * Generated bundle index. Do not edit.
     */
    var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
        if (k2 === undefined) k2 = k;
        var desc = Object.getOwnPropertyDescriptor(m, k);
        if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
          desc = { enumerable: true, get: function() { return m[k]; } };
        }
        Object.defineProperty(o, k2, desc);
    }) : (function(o, m, k, k2) {
        if (k2 === undefined) k2 = k;
        o[k2] = m[k];
    }));
    var __exportStar = (this && this.__exportStar) || function(m, exports) {
        for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
    };
    Object.defineProperty(exports, "__esModule", { value: true });
    __exportStar(require("./index"), exports);
    //# sourceMappingURL=repro.js.map
    ± empty FESM2020 file generated by ng-packagr
    "use strict";
    /**
     * Generated bundle index. Do not edit.
     */
    var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
        if (k2 === undefined) k2 = k;
        var desc = Object.getOwnPropertyDescriptor(m, k);
        if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
          desc = { enumerable: true, get: function() { return m[k]; } };
        }
        Object.defineProperty(o, k2, desc);
    }) : (function(o, m, k, k2) {
        if (k2 === undefined) k2 = k;
        o[k2] = m[k];
    }));
    var __exportStar = (this && this.__exportStar) || function(m, exports) {
        for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
    };
    Object.defineProperty(exports, "__esModule", { value: true });
    __exportStar(require("./index"), exports);
    //# sourceMappingURL=repro.mjs.map
    invalid FESM2020 file generated by other library pipeline (not included in repro repo)
    "use strict";
    var __defProp = Object.defineProperty;
    var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
    var __getOwnPropNames = Object.getOwnPropertyNames;
    var __hasOwnProp = Object.prototype.hasOwnProperty;
    var __esm = (fn, res) => function __init() {
      return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
    };
    var __export = (target, all) => {
      for (var name in all)
        __defProp(target, name, { get: all[name], enumerable: true });
    };
    var __copyProps = (to, from, except, desc) => {
      if (from && typeof from === "object" || typeof from === "function") {
        for (let key of __getOwnPropNames(from))
          if (!__hasOwnProp.call(to, key) && key !== except)
            __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
      }
      return to;
    };
    var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
    
    // dist/repro/esm2020/lorem.directive.js
    import { Directive } from "@angular/core";
    import * as i0 from "@angular/core";
    var LoremDirective;
    var init_lorem_directive = __esm({
      "dist/repro/esm2020/lorem.directive.js"() {
        LoremDirective = class {
        };
        LoremDirective.\u0275fac = i0.\u0275\u0275ngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.2", ngImport: i0, type: LoremDirective, deps: [], target: i0.\u0275\u0275FactoryTarget.Directive });
        LoremDirective.\u0275dir = i0.\u0275\u0275ngDeclareDirective({ minVersion: "14.0.0", version: "14.0.0-rc.2", type: LoremDirective, selector: "[lorem]", ngImport: i0 });
        i0.\u0275\u0275ngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.2", ngImport: i0, type: LoremDirective, decorators: [{
          type: Directive,
          args: [{ selector: "[lorem]" }]
        }] });
      }
    });
    
    // dist/repro/esm2020/index.js
    var esm2020_exports = {};
    __export(esm2020_exports, {
      LoremDirective: () => LoremDirective,
      LoremModule: () => LoremModule
    });
    import { NgModule } from "@angular/core";
    import * as i02 from "@angular/core";
    var LoremModule;
    var init_esm2020 = __esm({
      "dist/repro/esm2020/index.js"() {
        init_lorem_directive();
        LoremModule = class {
        };
        LoremModule.\u0275fac = i02.\u0275\u0275ngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.2", ngImport: i02, type: LoremModule, deps: [], target: i02.\u0275\u0275FactoryTarget.NgModule });
        LoremModule.\u0275mod = i02.\u0275\u0275ngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.0-rc.2", ngImport: i02, type: LoremModule, declarations: [LoremDirective], exports: [LoremDirective] });
        LoremModule.\u0275inj = i02.\u0275\u0275ngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-rc.2", ngImport: i02, type: LoremModule });
        i02.\u0275\u0275ngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.2", ngImport: i02, type: LoremModule,  decorators: [{
          type: NgModule,
          args: [{
            declarations: [LoremDirective],
            exports: [LoremDirective]
          }]
        }] });
      }
    });
    
    // dist/repro/esm2020/repro.js
    var __createBinding = Object.create ? function(o, m, k, k2) {
      if (k2 === void 0)
        k2 = k;
      var desc = Object.getOwnPropertyDescriptor(m, k);
      if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
        desc = { enumerable: true, get: function() {
          return m[k];
        } };
      }
      Object.defineProperty(o, k2, desc);
    } : function(o, m, k, k2) {
      if (k2 === void 0)
        k2 = k;
      o[k2] = m[k];
    };
    var __exportStar = function(m, exports2) {
      for (var p in m)
        if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p))
          __createBinding(exports2, m, p);
    };
    Object.defineProperty(exports, "__esModule", { value: true });
    __exportStar((init_esm2020(), __toCommonJS(esm2020_exports)), exports);
    //# sourceMappingURL=repro.js.map

A clear error message would be helpful if the Node16 module/moduleResolution is not supported (yet).

Please provide a link to a minimal reproduction of the bug

https://github.com/bgotink/angular-typescript-4.7-Node16

Please provide the exception or error you saw

No response

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 14.0.0-rc.2
Node: 16.14.2
Package Manager: yarn 1.22.15 
OS: darwin arm64

Angular: 14.0.0-rc.2
... cli, compiler, compiler-cli, core

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1400.0-rc.2
@angular-devkit/core         14.0.0-rc.2
@angular-devkit/schematics   14.0.0-rc.2
@schematics/angular          14.0.0-rc.2
ng-packagr                   14.0.0-rc.0
typescript                   4.7.2

Anything else?

No response

bgotink added a commit to snuggery/snuggery that referenced this issue Jun 2, 2022
…lution

Only support "type": "module" for now, as angular's validation of the tsconfig
requires a single `.ts` as root file and not setting type to module would
require using `.mts` as extension.

Work around an issue where the angular compiler generates CommonJS code by
using the original generated typescript code which happens to be valid
javascript.

See angular/angular#46181
@alxhub alxhub added area: packaging Issues related to Angular's creation of npm packages area: compiler Issues related to `ngc`, Angular's template compiler labels Jun 8, 2022
@ngbot ngbot bot modified the milestone: needsTriage Jun 8, 2022
@JoostK
Copy link
Member

JoostK commented Sep 6, 2022

Related to #43886

@alxhub alxhub added the P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent label Nov 16, 2022
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Nov 16, 2022
@npenin
Copy link

npenin commented Apr 6, 2023

Unfortunately, this still hapens with Angular 15. A fix would be greatly appreciated

@jpzwarte
Copy link

Just ran into this myself. A dependency that uses exports in package.json and if I enable "moduleResolution": "Node16", then the angular library build fails (commonjs stuff).

exports has been in nodejs since version 12 and supported in typescript since 4.7 (may 2022)!

@JoostK
Copy link
Member

JoostK commented Nov 22, 2023

I think you'd have a better experience with the bundler resolution mode, which is a more lenient resolution mode than Node16 but it does take exports into account.

@TexRx
Copy link

TexRx commented Nov 22, 2023

I think you'd have a better experience with the bundler resolution mode, which is a more lenient resolution mode than Node16 but it does take exports into account.

Is bundler a "valid" option for an Angular application that is not a re-usable "package". I'm having these errors just building an internal business Angular application, and I was under the impression that "bundler" was for reusable/distributable packages (like 3rd party libraries, etc.).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: compiler Issues related to `ngc`, Angular's template compiler area: packaging Issues related to Angular's creation of npm packages bug P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: confirmed
Projects
None yet
Development

No branches or pull requests

6 participants