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

Cannot import a module above the src/app folder #7087

Closed
silenceisgolden opened this issue Jul 21, 2017 · 16 comments
Closed

Cannot import a module above the src/app folder #7087

silenceisgolden opened this issue Jul 21, 2017 · 16 comments
Labels
help wanted needs: investigation Requires some digging to determine if action is needed P5 The team acknowledges the request but does not plan to address it, it remains open for discussion type: bug/fix

Comments

@silenceisgolden
Copy link

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Versions.

@angular/cli: 1.2.2
node: 8.1.4
os: darwin x64
@angular/animations: 4.3.1
@angular/common: 4.3.1
@angular/compiler: 4.3.1
@angular/core: 4.3.1
@angular/forms: 4.3.1
@angular/http: 4.3.1
@angular/platform-browser: 4.3.1
@angular/platform-browser-dynamic: 4.3.1
@angular/router: 4.3.1
@angular/cli: 1.2.2
@angular/compiler-cli: 4.3.1
@angular/language-service: 4.3.1

Repro steps.

  1. clone https://github.com/silenceisgolden/angular-cli-module-import-issue.
  2. install latest global @angular/cli.
  3. run ng serve --aot.

Notice that there are modules in a lib/ directory that is even with the generated src/ directory. This contains 2 modules and 2 components to reproduce the issue.

The log given by the failure.

> ng serve --aot
** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200 **
Hash: 178d829ae638b28ca8b6                                                              
Time: 4870ms
chunk    {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 177 kB {4} [initial] [rendered]
chunk    {1} main.bundle.js, main.bundle.js.map (main) 15.1 kB {3} [initial] [rendered]
chunk    {2} styles.bundle.js, styles.bundle.js.map (styles) 10.5 kB {4} [initial] [rendered]
chunk    {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 1.15 MB [initial] [rendered]
chunk    {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]

ERROR in ~/.../new-app/src/$$_gendir/app/app.component.ngfactory.ts (11,21): Cannot find module '../../../lib/component-b.component.ngfactory'.

ERROR in ~/.../new-app/src/$$_gendir/lib/component-a.component.ngfactory.ts (10,21): Cannot find module './component-a.component'.

ERROR in ~/.../new-app/src/$$_gendir/lib/module-a.module.ngfactory.ts (10,21): Cannot find module './module-a.module'.

ERROR in ~/.../new-app/src/$$_gendir/lib/component-b.component.ngfactory.ts (11,21): Cannot find module './component-a.component'.

ERROR in ~/.../new-app/src/$$_gendir/lib/component-b.component.ngfactory.ts (12,21): Cannot find module './component-b.component'.

ERROR in ~/.../new-app/src/$$_gendir/lib/module-b.module.ngfactory.ts (10,21): Cannot find module './module-b.module'.

ERROR in ~/.../new-app/src/$$_gendir/lib/module-b.module.ngfactory.ts (11,21): Cannot find module './module-a.module'.

ERROR in ./src/$$_gendir/app/app.component.ngfactory.ts
Module not found: Error: Can't resolve '../../../lib/component-b.component.ngfactory' in '~/.../new-app/src/$$_gendir/app'
 @ ./src/$$_gendir/app/app.component.ngfactory.ts 9:0-67
 @ ./src/$$_gendir/app/app.module.ngfactory.ts
 @ ./src/main.ts
 @ multi webpack-dev-server/client?http://localhost:4200 ./src/main.ts
webpack: Failed to compile.

Desired functionality.

ng serve --aot should not error when importing a module outside of the generated source code from angular cli's new command.

Mention any other details that might be useful.

Please let me know if you need any other info.

Also please note the file paths in the error output have been stripped a bit to preserve some other requirements.

My intent is to create an angular app that will serve as documentation and at the same time have a compile step to build a library of components, but manage it all in one repository.

If this is a duplicate I apologize, but please explain what the current status is with this issue before closing if you can. Thanks!

@elliotaplant
Copy link

elliotaplant commented Jul 24, 2017

Possibly related to #7113.
TL;DR: Lock the dependency of "enhanced-resolve" to 3.3.0 by running:
npm i -DE enhanced-resolve@3.3.0
Though keep in mind that this is a workaround, and should be removed once "enhanced-resolve" fixes its bugs.

@silenceisgolden
Copy link
Author

@elliotIndex @filipesilva I thought this was directly related to #7113 and/or #7136 but it seems like even with yarn@0.24.6 and @angular/cli@1.2.5 this is still an issue.

@filipesilva
Copy link
Contributor

filipesilva commented Jul 28, 2017

As far as I can tell, this is a different problem than the enhanced-resolve thing. This has to do with what the app root actually means, and how things are resolved relative to it.

AOT generates imports and whatnot, and because of the process paths the things it's trying to import don't really make sense because they are outside the project root:

ERROR in ~/.../new-app/src/$$_gendir/app/app.component.ngfactory.ts (11,21): Cannot find module '../../../lib/component-b.component.ngfactory'.

ERROR in ~/.../new-app/src/$$_gendir/lib/module-a.module.ngfactory.ts (10,21): Cannot find module './module-a.module'.

This is a bug and the fix might be a trivial fix, or it might not not.

But it's not something we consider very high priority to fix right now since the usecase (pretend library) is sort of a hack. Your app shouldn't be building an external library, but rather consuming it.

There's some guidance about linking libraries in https://github.com/angular/angular-cli/wiki/stories-linked-library but I understand that overall library guidance is scarce.

@filipesilva filipesilva added needs: investigation Requires some digging to determine if action is needed P5 The team acknowledges the request but does not plan to address it, it remains open for discussion type: bug/fix help wanted labels Jul 28, 2017
@filipesilva filipesilva marked this as a duplicate of #6973 Jul 28, 2017
@silenceisgolden
Copy link
Author

@filipesilva I would agree on the scarcity and I do think it is something @angular/cli can help with at some point. I would imagine that your base app would be generated by ng new <app-name> but inside of that generated app you could run ng g library or outside of an app maybe ng new <library-name> --library. Thanks for taking a quick look at it!

@intellix
Copy link
Contributor

intellix commented Aug 10, 2017

According to the issue #7333, it's not just about going above src/app but when you reference upwards of the root property inside .angular-cli.json.

I was waiting for the TypeScript node_modules issue to be fixed/merged but have since found an issue with doing that for our Core components.

We want to be able to replace SCSS variables and images referenced inside the core components. An example would be a HeaderComponent that references a logo.png and uses a $brand-primary for the background colour. Using different apps the stylePreprocessorOptions.includePaths and images are relative to the application that uses the Core.

An example would be a Coca Cola and Pepsi app which change logos and colours as shown here: https://github.com/intellix/angular-cli-library

If we were to import our Core through node_modules then we couldn't use different images/SCSS variables and the problem gets much more complex. It almost works but it's just AOT that's griefing me :)

We used to achieve this through SCSS entirely. We'd create a my-bootstrap-theme repository and you just import variables before to change colours. But that's global and goes against Components and ViewEncapsulation that have become generally available since Angular

@playground
Copy link

playground commented Sep 8, 2017

I have some private share modules that are installed in node_modules/@my
"ng build" works fine
but "ng build -prod" is giving errors "cannot find module"

running cli v1.4.0

@digaus
Copy link

digaus commented Sep 28, 2017

Same issue as @playground ... any solution for this? Tried with enhanced-resolve but no success :/

@josh-sachs
Copy link

I found this issue via #6973 - I can't discern if these are actually related issues, but the latter was closed as a dupe in favor of this issue, so I'm going to assume it is.

Specifically, the problem I've been facing is that ngfactory import statements don't appear to be generated with respect to the supplied tsconfig's baseUrl or rootDir arguments. Instead, they appear to be computed internally based on the most common relative path during module discovery, or by the path of the tsconfig itself.

I saw the comment from @filipesilva

This is a bug and the fix might be a trivial fix, or it might not not.

But it's not something we consider very high priority to fix right now since the usecase (pretend library) is sort of a hack. Your app shouldn't be building an external library, but rather consuming it.

I wanted to chime in to comment that in my case this was a rather insidious problem. Regardless of whether or not specific workflows are considered "hacks", I don't think it is unreasonable for a developer to expect that ngc utilize the same path strategies as tsc when generating import statements - after all I believe ngc is touted as a drop in replacement wrapper for tsc.

That said, there is a very real possibility that there are others out there sinking quite a bit of time into trying to make what would otherwise be some rather trivial use cases work. As you mentioned, there is not a ton of guidance, and there are a thousand and one different ways to scaffold a project. Might be worth taking a second look at this issue if at least to prevent others from pulling their hair out trying to comprehend why things don't appear to be working the way they've been documented.

@irfanka
Copy link

irfanka commented Dec 11, 2017

I have the same issue.
Our use-case is that we have multiple Angular apps in a monorepo (7 of them, each in it's own subfolder).
We want to keep the components that are shared between those apps in a "Shared" folder at the root of the repository.

We were able to get half-way there by adding:

"paths": {
      "@shared/*": ["../Shared/*"]
 }

to the app's tsconfig.json files.

Then, in the app.module.ts of each app, we can do stuff like:

import { InputComponent } from '@shared/components/input/input.component';

@NgModule({
    declarations: [
        InputComponent,
    ],
});

This works as long as the shared components don't have any dependencies injected via DI.
As soon as we add constructor(private <something>)..., we get runtime exceptions.
Adding a providers array to the @component decorator also results in runtime exceptions.

@filipesilva could you please expand on why you think doing something like this is a hack?
Also, why would this be considered a "pretend library"?

@hansl hansl removed their assignment Feb 6, 2018
@Tyler-V
Copy link

Tyler-V commented May 8, 2018

@filipesilva This issue has become more relevant than ever now, with the addition of libraries in the cli.

We should be able to reference in src/app/demos ... import { LibraryModule } from 'projects/library/src/public_api'; and build for deployment.

It works fine if I consume import { LibraryModule } from '@org/library' however then I have to go and change the imports whenever I go to build my library's demo, importing the unpublished projects/library/src is ideal for development.

Thoughts?

@maurei
Copy link

maurei commented Nov 13, 2018

Running into similar issues, I think.
For development a @liborg/extension library, a @liborg/core is required as dependency. For development the following works fine

        "rootDir": "../.",
        "baseUrl": "../.",
        "paths": {
            "@liborg/core": [
                "../core/src"
            ]
        },

But when building, I get lots of errors like
error TS2307: Cannot find module '@liborg/core.

I'm trying to avoid having to first compile @liborg/core, npm i ../core.tgz it my @liborg/extension project, which increases the build time a lot

@tiaguinho
Copy link
Contributor

I'm using 4 private packages inside one project with Angular CLI 7.1.4.
None of the projects was created using ng g library, I created them before that exist.
They all live outside src/app. In fact, they live at the same level.

   src/app
   packages/proj1
   packages/proj2
   packages/proj3
   packages/proj4
   angular.json

To build the projects and rebuild when some file was changed, I just add a section for each project inside angular.json so the CLI compiler knows there are files to be compiled outside src/app.

"projects": {
...
    "proj1": {
          "root": "packages/proj1",
          "sourceRoot": "packages/proj1",
          "projectType": "library",
          "prefix": "proj1",
          "architect": {
              "build": {
                  "builder": "@angular-devkit/build-ng-packagr:build",
                  "options": {
                      "tsConfig": "packages/proj1/tsconfig.lib.json",
                     "project": "packages/proj1/ng-package.json"
                 }
            }
        }
    }
...
}

After that, add the main folder to your tsconfig.json, which in my case was packages:

"include": [
    "src/**/*",
    "packages/**/*",
]

@gtranter
Copy link

gtranter commented Jan 16, 2019

@filipesilva wrote:

Your app shouldn't be building an external library, but rather consuming it.

There is a very good reason to need to do this at the development level. Where different teams building different applications are using a shared library, and that shared library has a shared development model whereby the consuming application teams participate in the library's development, library changes and additions come directly out of and are synchronous with application development work. This is my particular situation - both the library and various applications are internal to my organization, and the library is published and made available via an internal registry like any node package might be. A common library is desired to provide consistency across applications and reduce overall development effort.

As a practical example, application 'X' - which uses library 'Y' - needs a new feature that requires a new component. The new component will belong to the library, not the application. In order to develop the component, it needs to exist alongside the application to ensure that it meets the requirements of the application's new feature. Another use case is around fixing bugs or adding features to existing library components.

Waiting for the component to be available in the library before proceeding with work on the new application feature is highly impractical and takes too long (just not very "agile" at all). There is also a lot of back and forth that would be required until it is right, so that would also consume a lot of extra cycles if they were separate development efforts.

Migrating the component out of the application into the library once the feature and component are completed, is again extra work (changing the application configuration to pull the component from the library dependency instead of from itself). This requires extra testing. And because this is at the end of the development cycle for the application's needs (story has been completed), in reality it never gets done because the application team doesn't have as great a stake in the library as it does in the application (they "own" the application but not the library). So the new component lives on in the application and never gets shared via the library, defeating the purpose of the shared library entirely.

A simultaneous development model is the only good solution, so enabling developers to be able to seamlessly work on the two projects at the same time and see local changes to the library component while working on their application is essential.

This is really easy to set up via TypeScript Module Resolution using a paths setting under compilerOptions in the application project's tsconfig, but Angular CLI's compiler does not work properly with it, whereas the TypeScript compiler works fine.

Please reconsider making this a priority.

@filipesilva
Copy link
Contributor

This issue was created originally for Angular CLI 1.2.2.

Things are very different now:

I don't think the original reported issue (Cannot import a module above the src/app folder) is still applicable. At the time I think it was mostly related to how we mapped some files and how the AOT compiler looked for them

The underlying topic of consuming/building libraries is still very relevant though.

Our stance on that is still the same as listed in the library story: you should build your lib, then consume whatever was built.

Applications and libraries are built differently. It doesn't make any sense at all, from a build system point of view, to attempt to build your library with a build system that isn't meant to build libraries. The feature set of the two build systems is just plain different. You might try, and succeed, where the feature set matches, but things won't go so well once you start going into specific feature of each.

We simply cannot recommend building your lib inside your app because it is incorrect and will lead to problems in all but the most trivial of cases.

That being said, we don't stop you from using the tsconfig paths property to force that behaviour. If you feel confident that your library can be built using the app builder, you should be able to go ahead and do that. You'll need to understand how TS compilation options work, and how paths interact.

@gtranter so to your point, you should be able to use paths right now. If you find a problem with that then I think that's a bug. I'd appreciate if you opened a new issue with a reproduction so we can investigate it. But please remember to introduce a reproduction. This class of problems is very often due to setup.

@gtranter
Copy link

@filipesilva thanks for the update. FWIW, this was not originally about building, as in building multiple projects from a single project. It was about importing, which prevents building. Even in my situation described above, I was not trying to build the library from the application, I was trying to build my application using a locally built version of the library. I would work on the two projects simultaneously but separately as in separate editor and build process etc.

Good to know things have been improved. I'll have to find time to test (no longer actively working on the project in question).

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted needs: investigation Requires some digging to determine if action is needed P5 The team acknowledges the request but does not plan to address it, it remains open for discussion type: bug/fix
Projects
None yet
Development

No branches or pull requests