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

Exported array of standalone components cannot be imported #48089

Open
GuillaumeNury opened this issue Nov 16, 2022 · 20 comments · May be fixed by #48106
Open

Exported array of standalone components cannot be imported #48089

GuillaumeNury opened this issue Nov 16, 2022 · 20 comments · May be fixed by #48106
Labels
area: compiler Issues related to `ngc`, Angular's template compiler bug cross-cutting: standalone Issues related to the NgModule-less world P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: has PR
Milestone

Comments

@GuillaumeNury
Copy link

GuillaumeNury commented Nov 16, 2022

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

Don't known / other

Is this a regression?

No

Description

I have a library that export multiple component in a const as advised in the standalone guide:

const LU_SIMPLE_SELECT_COMPONENTS = [
  LuSimpleSelectInputComponent,
  LuOptionDirective,
  LuDisplayerDirective,
  LuOptionComponent,
] as const;

Whenever I import this constant from a module or in a component in an application that use my library, I have the following issue:

Value at position 0 in the NgModule.imports of AppModule is not a reference
Value could not be determined statically.

If I redefined the same const in the application, it works.

Links

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-ivy-5rgxzc?file=src%2Fapp%2Fapp.module.ts

Please provide the exception or error you saw

> Value at position 0 in the NgModule.imports of AppModule is not a reference
> Value could not be determined statically.

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

Angular CLI: 14.1.3        
Node: 16.14.2
Package Manager: npm 8.5.0
OS: win32 x64

Angular: 14.1.3
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1401.3
@angular-devkit/build-angular   14.1.3
@angular-devkit/core            14.1.3
@angular-devkit/schematics      14.1.3
@angular/cdk                    14.2.7
@schematics/angular             14.1.3
rxjs                            7.5.7
typescript                      4.7.4

Anything else?

Love Standalone components!

@JoostK JoostK added area: compiler Issues related to `ngc`, Angular's template compiler cross-cutting: standalone Issues related to the NgModule-less world labels Nov 16, 2022
@ngbot ngbot bot modified the milestone: needsTriage Nov 16, 2022
JoostK added a commit to JoostK/angular that referenced this issue Nov 16, 2022
For standalone components it may be beneficial to group multiple declarations
into a single array, that can then be imported all at once in `Component.imports`.
If this array is declared within a library, however, would the AOT compiler
need to extract the contents of the array from the declaration file. This
requires that the array is constructed using an `as const` cast, which results
in a readonly tuple declaration in the generated .d.ts file of the library:

```ts
export declare const DECLARATIONS: readonly [typeof StandaloneDir];
```

The partial evaluator logic did not support this syntax, so this pattern was
not functional when a library is involved. This commit adds the necessary
logic in the static interpreter to evaluate this type at compile time.

Closes angular#48089
@JoostK JoostK added state: has PR P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent labels Nov 16, 2022
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Nov 16, 2022
pkozlowski-opensource added a commit to pkozlowski-opensource/angular that referenced this issue Nov 17, 2022
NgModule should support readonly arrays in `@NgModule.imports` and
`@NgModule.exports`.

Fixes angular#48089
@montella1507
Copy link

montella1507 commented Nov 17, 2022

I have another problem with exported array of standalone components and directives...

When i import to the module one by one:

imports: [DirectiveA., DirectiveB, DirectiveC]

both server and prod build works.
However, when i import exported directives array:

export const DIS = [DirectiveA, DirectiveB, DirectiveC];
imports: [DIS]  // i tried ...DIS too

SERVER works, but prod builds is broken - somehow it brakes imports at all.. and it cannot even find things from other imported modules.

Unfortunately.. i am not able to simulate it minimal repo :-/

Any idea what to try? What may be the cause?

Directives are in Buildable library in NX Monorepo

Probably this may be the issue:

ng-packagr/ng-packagr#2398

AndrewKushnir pushed a commit that referenced this issue Dec 7, 2022
For standalone components it may be beneficial to group multiple declarations
into a single array, that can then be imported all at once in `Component.imports`.
If this array is declared within a library, however, would the AOT compiler
need to extract the contents of the array from the declaration file. This
requires that the array is constructed using an `as const` cast, which results
in a readonly tuple declaration in the generated .d.ts file of the library:

```ts
export declare const DECLARATIONS: readonly [typeof StandaloneDir];
```

The partial evaluator logic did not support this syntax, so this pattern was
not functional when a library is involved. This commit adds the necessary
logic in the static interpreter to evaluate this type at compile time.

Closes #48089

PR Close #48091
@montella1507
Copy link

@AndrewKushnir maybe it solves this too
ng-packagr/ng-packagr#2398 ?

@AndrewKushnir
Copy link
Contributor

@JoostK what do you think about closing ng-packagr/ng-packagr#2398?

@JoostK
Copy link
Member

JoostK commented Dec 8, 2022

Thanks for the reminder, that was on the back of my mind :-)

pkozlowski-opensource added a commit to pkozlowski-opensource/angular that referenced this issue Jan 2, 2023
NgModule should support readonly arrays in `@NgModule.imports` and
`@NgModule.exports`.

Fixes angular#48089
@hakimio
Copy link

hakimio commented Jan 4, 2023

@AndrewKushnir
This should not be closed until PR #48106 is merged. At this point even when using Angular v15.1, readonly array of standalone components can not be imported.

trekladyone pushed a commit to trekladyone/angular that referenced this issue Feb 1, 2023
For standalone components it may be beneficial to group multiple declarations
into a single array, that can then be imported all at once in `Component.imports`.
If this array is declared within a library, however, would the AOT compiler
need to extract the contents of the array from the declaration file. This
requires that the array is constructed using an `as const` cast, which results
in a readonly tuple declaration in the generated .d.ts file of the library:

```ts
export declare const DECLARATIONS: readonly [typeof StandaloneDir];
```

The partial evaluator logic did not support this syntax, so this pattern was
not functional when a library is involved. This commit adds the necessary
logic in the static interpreter to evaluate this type at compile time.

Closes angular#48089

PR Close angular#48091
@cvandradg
Copy link

If I understood ur idea, U want to use components like this:

  standalone: true,
  imports: [
    CommonModule,
    RouterModule,
    COMPONENTS,
    MODULES,
  ],
  providers: [LoginStore],

and avoid "Unable to import component ComponentNameHere."

I solved it via:

export const COMPONENTS = [
  PrimaryAnimatedButtonComponent,
  TertiaryAnimatedButtonComponent,
  SecondaryAnimatedButtonComponent,
] ;

export * from '../components/primary-animated-button/primary-animated-button.component';
export * from '../components/tertiary-animated-button/tertiary-animated-button.component';
export * from '../components/secondary-animated-button/secondary-animated-button.component';

@hakimio
Copy link

hakimio commented Nov 24, 2023

@cvandradg No, the issue reported here is that a readonly array of standalone components can not be imported in NgModule.
The Angular team recommended "best practice" described in the docs does not work.

@montella1507
Copy link

@cvandradg No, the issue reported here is that a readonly array of standalone components can not be imported in NgModule. The Angular team recommended "best practice" described in the docs does not work.

Angular renaissance and momentum.

@cvandradg
Copy link

@hakimio thank you, so the current suggested way of angular to export components, like this:

 export const COMPONENTS = [
  PrimaryAnimatedButtonComponent,
  SecondaryAnimatedButtonComponent,
  TertiaryAnimatedButtonComponent,
] as const;

is currently not working, i got it right? (cuz It's not working for me unless I export them, I'm on Angular17)

@richardsengers
Copy link

This is quite annoying, I'm refactoring our shared library for standalone components, just to find out the docs are lying :-(

The PR is a year old

@hakimio
Copy link

hakimio commented Dec 7, 2023

#52615 (comment)
@pkozlowski-opensource

@richardsengers
Copy link

Ah thnx...missed that one

@greg-md
Copy link

greg-md commented Dec 8, 2023

Still not resolved? :(

@greg-md
Copy link

greg-md commented Dec 8, 2023

Seems like the solution provided by @cvandradg is working. If I re-export shared components, then the error is not happening. Ex:

import { MillifyPipe } from "./millify/millify.pipe";

export const SHARED_APP_COMPONENTS = [
  MillifyPipe,
] as const;

export { MillifyPipe } from "./millify/millify.pipe";

@hakimio
Copy link

hakimio commented Dec 8, 2023

It doesn't work with NgModule. It only works with standalone components.

@greg-md
Copy link

greg-md commented Dec 8, 2023

@hakimio for ng modules I think you can create a shared module to import instead.

@hakimio
Copy link

hakimio commented Dec 8, 2023

This issue is about libraries.
Relying on modules to export standalone components is just a short-term workaround, not a proper solution for library authors.

@michaelfaith
Copy link

@greg-md just to clarify, I think @hakimio is saying that an app that uses NgModules isn't able to import a read only array of components (like from a library). It would be taking a step backwards for that library to have to export a shared module, when their aim is going fully standalone.

@richardsengers
Copy link

richardsengers commented Dec 8, 2023

exactly, it doesn't make sence to create an NgModule just to import multiple components. We want to get rit of the NgModules from the libraries, that is the whole point in the first place :-)

@iamenrique
Copy link

No official workaround for this problem yet and docs are still the same in v17.3.2.

I'm also porting libraries to the standalone approach, and I'm doing the following to chill out these errors:

/*
 * THIS IS MY LIBRARY public-api.ts FILE
 * Public API Surface of A Library
 */

export {AComponent} from './lib/a/a.component';

import {AComponent} from './lib/a/a.component';
export const NGX_A_LIBRARY_COMPONENTS = [AComponent] as const; // <-- This is NG docs recommendation


/*
 * THIS BELONGS TO THE HOST APP USING THE LIBRARY
 * App Module 
 */
import {NGX_A_LIBRARY_COMPONENTS, AComponent} from '@company/a-library';

@NgModule({
    declarations: [...],
    imports: [
        ...
        NGX_A_LIBRARY_COMPONENTS as [typeof AComponent], // <-- This might do the trick
    ]
})
export class AppModule {
}

Perhaps not ideal but worth the try.

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 bug cross-cutting: standalone Issues related to the NgModule-less world P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: has PR
Projects
None yet