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

How can I turn off the eslint overlay in the newest version of Vue?

After upgrading to the latest version of Vue or its dependencies, I noticed that the code in my vue.config.js no longer works: chainWebpack: config => { // disable eslint nag screen when building for different environments if (!isProduction) config. ...

When I refresh the page in Angular2, the router parameters do not get loaded again

When loading my application on routers without parameters, everything is normal. However, when trying to use a router with params, the application fails to load. For example: localhost:3000/usersid/:id The code for the router is as follows: const appRou ...

Parent Component in Angular 2 Fails to Refresh Upon Observable Update

I have been utilizing an Observable service to facilitate data coordination among components. Specifically, I am attempting to utilize it for managing the visibility of various HTML elements within my application. Currently, when I toggle the behavior sub ...

Understanding Different Symbols in TypeScript

Can you explain the purpose of symbols in TypeScript to me? As someone familiar with Java, it seems a bit unnecessary to use them alongside an interface declaration. What is the reason for setting symbols in TypeScript? For example, consider the followin ...

React and MaterialUI Chrome Extension - Data did not populate in the table

Currently, I am in the process of developing a browser extension. My main challenge lies in displaying data within a table that has been created using MaterialUI and React. Despite not encountering any errors, everything else renders perfectly. The console ...

Prevent EACCES issues with npm/node when using Ubuntu?

Setting up the system environment $ lsb_release -a 2> /dev/null | grep Desc Description: Ubuntu 14.04.1 LTS $ sudo apt-get install build-essential $ sudo add-apt-repository ppa:chris-lea/node.js && sudo apt-get update $ sudo apt-get install ...

Guide to importing a markdown document into Next.js

Trying to showcase pure markdown on my NextJS Typescript page has been a challenge. I attempted the following: import React, { useState, useEffect } from "react"; import markdown from "./assets/1.md"; const Post1 = () => { return ...

Retrieve the dimensions of a child component when NgIf condition is met

I am facing a situation where I have a main component with a child component that is populated using NgFor. To control the visibility of the child, the parent sets a property called childIsVisible to false and binds it to the child using *ngIf="childIsVisi ...

eslint warning: the use of '$localize' is flagged as an "Unsafe assignment of an `any` value"

When using $localize, eslint detects errors and returns two specific ones: Unsafe assignment of an 'any' value and Unsafe any typed template tag. It's quite strange that I seem to be the only one facing this issue while working on the proje ...

Unable to retrieve information from a child component in React

So, this component acts as the main container class TaskList extends React.Component { state = { task: '', } handleTaskClick = () => { taskArray.push({id: idCount, text: this.state.task, completed: false}) idCount++ this. ...

Load a React component in the same spot when clicked

Is there a way to implement a functionality where clicking on different buttons in a panel will display different components in the same location? <AddNotification /> <EditNotification /> <DeleteNotification /> const AdminPanel = () =& ...

An issue with TypeORM syntax causing errors within a NestJS migration file

I recently encountered an issue while setting up PostgreSQL with NestJS and TypeORM on Heroku. Despite successfully running a migration, my application kept crashing. I attempted various troubleshooting methods by scouring through blogs, GitHub issues, and ...

How to update a variable in the app.config.json file in Angular 5

I've created a custom asset JSON configuration file called .angular-cli.json to use as default. However, there are certain instances where I need to update specific values within this file but I'm not sure how to go about it. Any suggestions? .a ...

Add an asterisk before each line of comment when working in a TypeScript file using the VS Code IDE

Within my VS Code workspace, I am using the Typescript language and would like to format my comments across multiple lines with a specific style (look out for the star character) /** *@desc any text * any text */ However, when I attempt to write a comm ...

What is the method to insert a new <input> element after the last input field has been filled in

I recently started working on a form using StackBlitz, but I've hit a roadblock and need some guidance on how to proceed. My goal is to achieve a similar effect like the one shown in this gif: https://i.stack.imgur.com/76nsY.gif and I'd like to ...

What sets apart 'export type' from 'export declare type' in TypeScript?

When using TypeScript, I had the impression that 'declare' indicates to the compiler that the item is defined elsewhere. How do these two seemingly similar "types" actually differ? Could it be that if the item is not found elsewhere, it defaults ...

Error: The property 'webpackJsonp' is not defined and cannot be read

I am facing an issue with my react app (app A) that was created using create-react-app about 2 years ago and then ejected. The app is exported as a commonjs2 module and included in an NPM package to be used in another project called next.js (app B). Every ...

Attempting to retrieve a URL using Angular/Typescript is generating an Unknown Error instead of the expected successful response

I'm trying to make a simple HTTP function call through TypeScript (Angular) to an API hosted as a function in Azure. When I call the URL through Postman or directly in the browser, everything works perfectly. However, when I try to call the URL usin ...

Identify the category of the component

Using a Link component from version 4.0.0-beta.2, I am exploring its capability to override the root element with a field called component. My goal is to wrap the Link component in a new component called MyLink and pass a custom component through props: ...

What is the process for instructing npm to install custom library dependencies found within a specific library on npm central?

Currently, I am utilizing Angular 14 and have a special library project with the following folder structure: + projects + my-library - package.json Within the package.json file of this project, the contents are as follows: { "name" ...