1

I'm working with standalone Angular 18 components and ran into an issue.

I have a custom component (FooComponent) that I forgot to import into another standalone component. However, no compile-time error appears when I forget to import the component into the imports array of the standalone component.

Here’s the code:

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

@Component({
  standalone: true,
  selector: 'app-test',
  template: `
    <foo-component [content]="getLinkForCopy()"></foo-component>
  `,
  styleUrls: ['./test.component.css'],
  // Forgot to import FooComponent here
})
export class TestComponent {
  getLinkForCopy() {
    return 'https://example.com';
  }
}

Even though I see some errors in the VS Code editor, there’s no compile-time error, only a runtime error when the application runs. How can I catch such missing imports earlier during compilation?

9
  • There should be warnings for this already. Are VS Code and the related Angular extensions up-to-date? (I think this is handled by the "Angular Language Extension" extension which is currently on version 18.2). Commented Sep 27, 2024 at 14:04
  • Cannot reproduce in stackblitz. Maybe you have activated CUSTOM_ELEMENTS_SCHEMA or NO_ERRORS_SCHEMA in your app? Commented Sep 27, 2024 at 14:05
  • @DM there is error in vs code and webStorm but need compile-time error. yes everything is up to date. Commented Sep 27, 2024 at 14:12
  • @JSONDerulo I already tried in stackblitz but seems that it handles code differently I tried with vs code and web storm but still no compile time error. Also find this general issue: github.com/angular/angular/issues/46351 Commented Sep 27, 2024 at 14:15
  • This is different issue, when the selector includes native element and an attribute modifier. Commented Sep 27, 2024 at 15:01

2 Answers 2

0

I believe the reason you are not receiving an error here is because you are using an inline template - essentially just a string until run time. If you were to create your HTML in a separate file you would be warned immediately if the component had not been imported in the controller.

Sign up to request clarification or add additional context in comments.

1 Comment

No also tried with . Html file still the same error
0

I ran into the same issue and while Angular detected some missing imports, it didn't catch them all. So I ended up creating a small script to find them. Assuming you have your components in src/app/components you can create the following file checkImports.js:

import fs from 'fs';
import path from 'path';

// Base directory of components
const componentsDir = path.join(import.meta.dirname, 'src', 'app', 'components');

// Function to read HTML file and extract ion-* tags
const getIonTags = (htmlFile) => {
    const content = fs.readFileSync(htmlFile, 'utf8');
    const regex = /<(ion-[a-zA-Z0-9-]+)/g;
    return [...content.matchAll(regex)].map(match => match[1]);
};

// Function to check if ion-* tags exist in the TypeScript file imports
const checkImports = (tsFile, ionTags) => {
    const content = fs.readFileSync(tsFile, 'utf8');
    const regex = /^(\s|\t)*imports:\s*\[([^\]]+)\]$/gm;
    const match = regex.exec(content);

    if (match) {
        const imports = match[2].split(',').map(tag => tag.trim());
        const missingTags = ionTags.filter(tag => !imports.includes(tag));
        return missingTags;
    } else {
        return [];
    }
};

const transformIonTag = (tag) => {
    return tag
        .split('-') // Split by hyphen
        .map((word, index) => 
            index === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word.charAt(0).toUpperCase() + word.slice(1)
        ) // Capitalize each word
        .join(''); // Rejoin into a single string
};

// Function to scan all components
const scanComponents = async (baseDir) => {
    const folders = await fs.promises.readdir(baseDir);
    for (const folder of folders) {
        const componentPath = path.join(baseDir, folder);
        const htmlFile = path.join(componentPath, `${folder}.html`);
        const tsFile = path.join(componentPath, `${folder}.ts`);

        if (fs.existsSync(htmlFile) && fs.existsSync(tsFile)) {
            const ionTags = getIonTags(htmlFile);
            const result = checkImports(tsFile, ionTags.map(transformIonTag));
            if(result.length) {
                console.log(`Missing tags in ${tsFile}: `);
                console.log(`${result}\n`);
            }
        }
    }
};

// Start scanning
scanComponents(componentsDir);

Then just run node checkImports. It should output something like this:

Missing tags in xxx/src/app/components/account-form/account-form.ts: IonRadioGroup,IonSelect

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.