Connecting an Angular 4 Module to an Angular 4 application seems to be causing some issues. The error message "Unexpected value 'TestModule' imported by the module 'AppModule'. Please add a @NgModule annotation" is

Update at the bottom: I am currently facing a massive challenge in converting my extensive Angular 1.6 app to Angular 4.0. The process has turned into quite a formidable task, and I seem to be stuck at a specific point. We have a shared set of utilities that are used across two distinct apps. While attempting to compile this as a module for import through "npm link," I encountered an error upon importing it into my application.

My setup involves webpack 3.


compiler.es5.js:1690 Uncaught Error: Unexpected value 'TestModule' imported by the module 'AppModule'. Please add a @NgModule annotation.
    at syntaxError (compiler.es5.js:1690)
    at compiler.es5.js:15382
    at Array.forEach (<anonymous>)
    at CompileMetadataResolver.getNgModuleMetadata (compiler.es5.js:15365)
    at JitCompiler._loadModules (compiler.es5.js:26795)
    at JitCompiler._compileModuleAndComponents (compiler.es5.js:26768)
    at JitCompiler.compileModuleAsync (compiler.es5.js:26697)
    at PlatformRef_._bootstrapModuleWithZone (core.es5.js:4536)
    at PlatformRef_.bootstrapModule (core.es5.js:4522)
    at Object.<anonymous> (main.ts:26)

I've created a test case that demonstrates the issue in a minimal way. Although it may seem somewhat complex due to similarities with my actual webpack.config and package.json files, rest assured that the code is stripped down to its essence.

To explore the issue thoroughly, you can view the code here along with steps on how to reproduce it precisely.

Within my application, the main.ts file appears like this...

import './polyfills';

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {UpgradeModule} from '@angular/upgrade/static';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

import {TestModule} from 'ng-module-test';

@NgModule({
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        UpgradeModule,
        TestModule
    ]
})
export class AppModule {
    // Prevent Angular bootstrap action
    ngDoBootstrap() {
    }
}

// Bootstrapping using the UpgradeModule
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
    console.log("Bootstrapping in Hybrid mode with Angular & AngularJS");
    const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
    upgrade.bootstrap(document.body, ['au.website']);
});

... whereas my module resembles...

import {NgModule} from '@angular/core';

import {Utils} from './utils/module';

@NgModule({
    imports: [
        Utils
    ]
})
export class TestModule {};

Your assistance is much appreciated.

Additional update:

In a recent revision, I altered the TestModule import to use a relative path instead of relying on the linked npm module:

// import {TestModule} from 'ng-module-test';
import {TestModule} from '../../ng-module-test/src/main';

However, the result remained consistent. This implies that the issue doesn't pertain to 'npm link,' but rather the segregation of code itself. Can anyone offer insight into this matter?

The aforementioned change has been committed to the repository provided above.

Further update:

This recent development baffles me completely. When I adjust the import statement to read as follows...

import {TestModule} from './ng-module-test/main';

and create a directory named ng-module-test within ng-app-test/src, copying the contents of the ng-module-test/src folder into it, the functionality works—as highlighted by @Hosar's observation in the comments. However, if I attempt to create a symbolic link using ln -s ../../ng-module-test/src ng-module-test so that, essentially, from the OS perspective it remains identical, IT DOES NOT FUNCTION.

Answer №1

It is important to designate all the @angular packages as peerDependency and devDependency rather than simply a dependency in ng-module-test/package.json

Next, insert the following code into ng-app-test/src/tsconfig.json:

{
  "compilerOptions": {
    // ...
    // Note: these paths are relative to `baseUrl` path.
    "paths": {
      "@angular/*": [
        "../node_modules/@angular/*"
      ]
    }
  }
}

To read more about this topic, visit: https://github.com/angular/angular-cli/wiki/stories-linked-library

Answer №2

I have successfully resolved the symlink issue by setting the symlinks to false in the resolve section of my webpack.config.js file. This unexpected solution has allowed me to move forward with my project, despite running into some limitations such as the inability to use npm link. However, the benefits include automatic detection of changes in TypeScript files by the watch system.

To address these challenges, I plan to create a symlink in my application's source directory pointing to the library's src directory. Then, I can import components from the library using paths like...

import {Blah} from './ng-module-test/main';

...or variations depending on the depth of the file within the source directory. I am also considering exploring the modules property in the webpack config to simplify imports throughout the project structure.

UPDATE

After further research, I discovered a more efficient solution that eliminates the need for symlinks. By modifying my tsconfig.json file and adjusting the resolve configuration in webpack.config.js, I can now import external libraries using...

import {Blah} from 'NgModuleTest/main';

This method provides flexibility in referencing internal and external modules within the project. Additionally, relocating the tsconfig.json file outside of the src directory alongside webpack.config.js resolves any path issues. The updated repository reflects these improvements in the implementation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Setting up WebPack for TypeScript with import functionality

A tutorial on webpack configuration for typescript typically demonstrates the following: const path = require('path'); module.exports = { ... } Is it more advantageous to utilize ES modules and configure it with import statements instead? Or is ...

Enhance Component Reusability in React by Utilizing Typescript

As I embark on developing a React application, my primary goal is to keep my code DRY. This project marks my first experience with Typescript, and I am grappling with the challenge of ensuring reusability in my components where JSX remains consistent acros ...

What is the process for uploading a package to a repository using webpack?

Currently working on a NodeJs project where webpack is being used for packaging. In the past, I utilized pom.xml for packing and deploying artifacts to repositories using distributionmanagement. Looking to set up a Webpack task for deployment now. Is it ...

Using Angular with Web API to transmit FormFile data from client to API

I am facing a challenge with creating an object (referred to as a "Ticket") along with 0-n children (known as "Attachments") in my Angular application and sending this information to my dotnet core Web API. However, this is more of a logical inquiry that I ...

Converting Objects to Arrays with Angular Observables

After searching extensively on SO for answers regarding item conversions in Javascript/Angular, I couldn't find a solution that addresses my specific problem. When retrieving data from Firestore as an object with potential duplicates, I need to perfor ...

Develop a cutting-edge Drag and Drop Functionality using the innovative Material CDK

Here is a unique link you can check out: https://stackblitz.com/angular/nabbkobrxrn?file=src/app/cdk-drag-drop-enter-predicate-example.ts. In this example, I have specific goals: I want to be able to select only one number from the "Available numbers" l ...

What is the best way to interact with the member variables and methods within the VideoJs function in an Angular 2 project

Having an issue with accessing values and methods in the videojs plugin within my Angular project. When the component initializes, the values are showing as undefined. I've tried calling the videojs method in ngAfterViewInit as well, but still not get ...

Organize JSON data in Angular 6 from an observable based on a specific key

Note: While I am familiar with sorting a regular array of objects using .sort(), I am facing a challenge with an observable object that I am not accustomed to. My task involves retrieving a JSON array of objects with a service: import { Injectable } from ...

Revamp the Next.js and TypeScript API for improved efficiency

I am new to using Next.js and TypeScript, and I would like to refactor my code to improve data fetching speed. Currently, I have a file called dashboard.tsx with the following code: import Layout from "@/layouts/layout"; import React, { useC ...

Setting up the necessary dependencies for a React JS project

I'm currently in the process of duplicating this project: git clone <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3d5a54497d5a544955485f135e5250">[email protected]</a>:davidzas/react-chat.git After cloning, ...

Is it possible for me to assign an observable to a value of undefined or null?

In my Angular class, I have an observable setup like this: fullMember: Observable<Member | undefined> and in the constructor: this.fullMember = store.pipe(select(selectActiveMember)) From this selection, I'm extracting certain information ...

Receiving a null value when accessing process.env[serviceBus]

Currently, I am focusing on the backend side of a project. In my environment, there are multiple service bus URLs that I need to access dynamically. This is how my environment setup looks like: SB1 = 'Endpoint=link1' SB2 = 'Endpoint=link2&a ...

typescript Object that consists of properties from an array with a defined data type

I have an array consisting of strings. I am trying to transform this array into an object where each string is a property with specific attributes assigned to them. export interface SomeNumbers { name: string; value: number; } const arr = ['apple& ...

Exploring the integration of JSON data requests into a SQLite database using Angular2 and Ionic2

I am currently facing an issue with inserting JSON format data from a request into a SQLite database within my app. Even though the database and table are set up properly, I am having trouble getting the INSERT function to work correctly. Below is the sn ...

RXJS Subject data remains stale upon page refresh

A specific service I developed includes a subject titled selectedNode. My goal is to update the subject's value when providing a direct URL for page loading. Unfortunately, there seems to be an issue with updating the value of Subject directly via the ...

What could be the reason for the failure of my class isInstance() check

Do you see any issues with the object being an instance of ChatRoom? Let me know your thoughts. Class: export class ChatRoom { public id?: number; public name_of_chat_room: string; public chat_creator_user_id: number; public chat_room_is_active: 0 ...

Encountered a problem while trying to install 'create-react-native-app' via npm

Encountering a problem during the installation process of the create-react-native-app application. npm install -g create-react-native-app npm ERR! code ENOTFOUND npm ERR! errno ENOTFOUND npm ERR! network request to https://registry.npmjs.org/create-react ...

Ways to turn off a TypeScript error across the entire project

Due to an unresolved TypeScript bug causing a false positive, I am looking to disable a specific TypeScript error for my entire project. How can this be achieved? The requirements are: Disabling only one type of error Not limited to a single line or file ...

The cache key failed to load due to a pull access denied error in Powershell

While executing the docker file, an issue occurred with this line: RUN apt-get update && apt-get install -y wget && apt-get install -y gnupg2 && wget -qO- | bash - && apt-get install -y build-essential nodejs Error encount ...

What is the process for installing a repository using a branch name in a GitHub Enterprise repository?

Looking to add sub-repos to a main repo and specify the branch name? Check out these methods I've tried: npm install username/repo#branchName --save npm install username/repo@branchName --save npm install username/repo#tag --save npm install usernam ...