Невозможно импортировать пользовательский компонент — Angular2 и TypeScript

Я пытаюсь импортировать пользовательский компонент в свой app.ts, но получаю сообщение об ошибке "TS2307: не удается найти модуль "MyComponent"". Помоги мне.

Некоторые писали: используйте "moduleResolution": "classic", но если я это сделаю, то получу ошибку TS2307 для всего остального (все angular2/...), кроме MyComponent.

Другие написали «запустить tsc --declaration MyComponent.ts», который генерирует файл MyComponent.d.ts (при этом выдавая ошибки в консоли, такие как «Невозможно скомпилировать, если не указан флаг --module» - который предоставляется в tsconfig как вариант - или «Не удается найти модуль 'angular2/common'» для всего, что я импортирую в MyComponent.ts, но он создает файл .d.ts), но при попытке скомпилировать app.ts он все еще дает то же самое Ошибка TS2307. Ничего из того, что я нашел, не сработало.

Это моя структура проекта:

| /app
|     /resources
|         /dev
|             /ts
|                 app.ts
|                 MyComponent.ts
|         /dist
|             /js
|                 app.js          // transcompiled app.ts
|                 MyComponent.js  // transcompiled MyComponent.ts
|             /modules            // files copied from the /node_modules/**/ folders (because node_modules is outside versioning and also outside public root (public root is the /app folder)
|                 es6-shim.js
|                 angular2-polyfills.js
|                 system.src.js
|                 Rx.js
|                 http.dev.js
|                 angular2.dev.js
|     index.html
|
| /node_modules
|     /angular2            // 2.0.0-beta.1
|     /es6-promise         // 3.0.2
|     /es6-shim            // 0.33.3
|     /rxjs                // 5.0.0-beta.0
|     /reflect-metadata    // 0.1.2
|     /systemjs            // 0.19.6
|     /zone.js             // 0.5.10
| 

Это мой tsconfig.json:

{
    "compilerOptions": {
        "target": "ES5",
        "module": "system",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": true,
        "noImplicitAny": false,
        "outDir": "app/resources/dist/js"
    },
    "files": [
        "app/resources/dev/ts/app.ts"
    ]
}

Мой app.ts:

import { bootstrap } from "angular2/platform/browser";
import { Component, View } from "angular2/core";
import { HTTP_PROVIDERS, Http, Response } from "angular2/http";

//My Custom Components:
import { MyComponent } from 'MyComponent';

/**
 * APP
 */
@Component({
    selector: 'my-app'
})
@View({
    directives: [MyComponent],
    template: `
        <my-component></my-component>
        plus other html
    `
})
class MyApp {
    public whatever;

    constructor(public http: Http) {
        // initialize this.whatever
    }

    makeRequest(): void {
        this.http.request('/_http/response.json')
            .subscribe((res:Response) => {
                this.whatever = res.json();
            });
    }
}

bootstrap(MyApp, [ HTTP_PROVIDERS ]);

А вот мой MyComponent.ts:

import { Component } from 'angular2/core';
import { NgFor, NgIf } from 'angular2/common';

@Component({
    selector: 'my-component',
    template: `
        <div>MY IMPORTED COMPONENT</div>
    `
})
export class MyComponent {

    constructor() {}

    doSomething(): void {
        console.log('Doing something');
    }
}

Мои файлы app.ts и MyComponent.ts находятся в одной папке. Во всяком случае, я также пробовал такой путь: импортировать {MyComponent} из "/app/resources/dev/ts/MyComponent". Кроме того, я пытался добавить его в массив файлов в tsconfig (некоторые люди писали, что я должен это сделать)... Тем не менее... Ничего не получилось! Я также проверил вывод js, потому что некоторые люди писали, что даже если он выдает ошибку, он все еще может быть скомпилирован... Не повезло!

====================

РЕДАКТИРОВАТЬ:

Хорошо, как предлагает inoabrian в первом комментарии ... Я думал, что перепробовал все, но, похоже, я не пробовал «./MyComponent» для части импорта.

import { MyComponent } from './MyComponent';

Теперь транскомпилятор делает свою работу. Спасибо, inoabrian, но теперь у меня другая проблема. Когда я пытаюсь запустить в браузере, я проверяю свою консоль, и оба systemjs и angular2-polyfills кричат:

http://my-app/resources/dist/js/MyComponent 404 (Not Found)

соответственно:

XHR error (404 Not Found) loading  http://my-app/resources/dist/js/MyComponent(…)

Не сбивайтесь с пути (при сравнении со структурой папок моего проекта), мой локальный сервер указывает на /app, когда я обращаюсь к http://my-app

Это мой index.html с конфигурацией системы и всеми включенными файлами js:

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- ... Meta tags & CSS assets -->

    <script src="resources/dist/modules/es6-shim.js"></script>
    <script src="resources/dist/modules/angular2-polyfills.js"></script>
    <script src="resources/dist/modules/system.src.js"></script>
    <script src="resources/dist/modules/Rx.js"></script>
    <script src="resources/dist/modules/http.dev.js"></script>
    <script src="resources/dist/modules/angular2.dev.js"></script>
</head>
<body>
<script>
    System.config({
        packages: {
            app: {
                format: 'register',
                defaultExtension: 'js'
            }
        }
    });
    System.import('resources/dist/js/app.js')
            .then(null, console.error.bind(console));
</script>

<my-app></my-app>

</body>
</html>

У меня есть ощущение, что я должен сделать еще одну вещь с транскомпилированным файлом "MyComponent.js", но не знаю, что (я пытался добавить его в System.import, надеясь, что он примет массив... но вроде нет). Что я должен делать дальше?

P.S. Тем не менее это разочаровывает, я надеялся, что импорт MyComponent в app.ts будет всем, и что я найду класс MyComponent + все из MyComponent.ts + мой транскомпилированный файл app.ts ВСЕ В ОДНОМ app.js, не имея еще одного файла js :(


person MrCroft    schedule 19.01.2016    source источник
comment
Вы изменили место импорта на «./MyComponent»?   -  person inoabrian    schedule 19.01.2016
comment
Я думал, что перепробовал все, но, похоже, нет. Это работало с ./MyComponent... но теперь возникает другая проблема, я отредактировал свой вопрос и добавил проблему в конце после EDIT:   -  person MrCroft    schedule 19.01.2016
comment
Теперь эта часть, похоже, связана с проблемой каталога на вашем сервере. Это может произойти, если у вас есть вложенные каталоги для разработки и дистрибутива. Итак, не могли бы вы опубликовать, как выглядит ваш код на стороне сервера ..? Я запускаю lite-server и настроил свои каталоги для обслуживания через массив [ ]   -  person inoabrian    schedule 19.01.2016
comment
У меня есть простой сервер apache (настройка wamp в Windows), указывающий на папку /app как на общедоступный корень. Итак, когда я обращаюсь к http://my-defined-hostname, он фактически указывает на папку /app в моем проекте (конечно, для этого также необходимо было некоторое редактирование файла hosts Windows). Все остальное работает просто отлично, app.js импортируется systemjs... и находится там же, где и MyComponent.js У меня также есть другая настройка на nginx, на виртуальной машине... сделанная моими коллегами, но она ведет себя то же   -  person MrCroft    schedule 19.01.2016
comment
У вас уже есть решение? У меня такая же проблема.   -  person Downhillski    schedule 15.04.2016
comment
@ Zhenyang Hua Я забыл об этом до недавнего времени ... И мне только что ответил инструктор на Udemy. Сейчас это кажется глупым, но вот в чем проблема: в разделе System.config я думал, что ключ app from app: {} является общим, соглашение исходит из application. НО НЕТ! Кажется, это ПУТЬ... к корневой папке вашего приложения. Итак, если у вас есть транспилированные/js-файлы в папке X/blah-blah, то в System.config вместо app: {} у вас должно быть: 'folderX/blah-blah': {}. Я надеюсь, что вы сделали ту же ошибку, так что это поможет вам. (продолжение в следующем комментарии)...   -  person MrCroft    schedule 16.04.2016
comment
... (продолжение): Если вы посмотрите на структуру папок в моем вопросе, мой index.html был в папке APP. Итак, мой System.config должен был выглядеть примерно так: System.config({ packages: { 'resources/dist/js': { format: 'register', defaultExtension: 'js' } } }); System.import('приложение').then(null, console.error.bind(консоль)); Приложение папки даже не существовало в том, что касается index.html. И теперь, если я проверю даже их краткий обзор, это объяснит, что приложение на самом деле является путем. Но, пока мне прямо не сказали, в чем была моя ошибка, я и не заметил, что они еще и это объясняют :))   -  person MrCroft    schedule 16.04.2016
comment
Ага! У меня такое же недоразумение! Спасибо!!   -  person Downhillski    schedule 16.04.2016


Ответы (3)


Я знаю, что это давно назрело, но, возможно, другим будет полезен ответ. Я понял, в чем заключалась последняя проблема (кроме того, что я уже отредактировал в исходном вопросе). Вот оно: я упоминал, что у меня была собственная структура папок, и я не хотел ее менять. Если бы я это сделал, это сработало бы, просто следуя быстрому старту angular 2. Но это не заставило бы меня осознать проблему в моем конкретном случае, и я бы не понял, как работает System.js.

Проблема была в моем System.config() - в разделе пакетов. Это плохой код:

System.config({
    packages: {
        app: {
            format: 'register',
            defaultExtension: 'js'
        }
    }
});
System.import('my/path/to/app_main_file');

Моя ошибка заключалась в том, что я думал, что ключ «приложение» — это просто общий ключ, происходящий от слова «приложение». Оказывается, в объекте пакетов каждый ключ фактически представляет собой путь (где этот пакет — его файлы — находятся в вашем приложении). Итак, если предположить, что папка, в которой находятся мои перенесенные файлы, будет «my/app/public», а «app_main_file» — это основной файл js моего приложения, тогда у меня должно было быть что-то вроде этого:

System.config({
    packages: {
        'my/app/public': {
            format: 'register',
            defaultExtension: 'js'
        }
    }
});
System.import('my/app/public/app_main_file')
    .then(null, console.error.bind(console));

Или вы можете написать раздел конфигурации еще лучше, например:

System.config({
    packages: {
        'my-app': {
            format: 'register',
            defaultExtension: 'js'
        }
    },
    map: {
        'my-app': 'my/app/public'
    }
});

Я думаю, что довольно понятно, что делает «карта» и как ее использовать.

P.S. Я знаю, что в своем ответе я не следовал той же структуре папок, что и в исходном вопросе, но я думаю, что имеет смысл объяснить это так. Если это имеет значение, просто замените «my/app/public» выше тем, что у меня изначально было в вопросе: «resources/dist/js/», и это то же самое.

person MrCroft    schedule 30.04.2016
comment
Потрясающий ! Это сработало, даже я думал, что приложение является ключевым словом. - person sudhir; 20.07.2016

Я считаю, что вам не хватает правильного параметра в конфигурации системы. добавьте это так:

System.config({
   defaultJSExtensions: true
})
person eesdil    schedule 23.01.2016
comment
Хорошо, добавление этого больше не вызывает 404 для MyComponent (потому что теперь он действительно ищет MyComponent.js) - я должен был это заметить. НО это ломает все остальное. Теперь я получаю 404, потому что он ищет /angular2/platform/browser.js в неправильных местах, соответственно, http.js и core.js (которых, конечно, нет в /angular2 - они на самом деле вне общедоступного корня (/ приложение мой общедоступный корень) - но раньше на них не было ошибок 404, потому что он даже не запрашивал их перед добавлением defaultJSExtensions: true, и все работало нормально). С какой стати это происходит :| ? - person MrCroft; 24.01.2016
comment
Я бы посоветовал пройти быстрый старт или руководство: angular.io/docs/ts /latest/quickstart.html, а также вы должны создать plunkr, потому что это, кажется, бесконечная история... :) другие ваши файлы недоступны, вероятно, потому, что вы не загружаете их в index.html. Я считаю, что если вы проверите учебник, он должен начать работать. Еще одно замечание: есть некоторые проблемы с beta1, поэтому я предлагаю пока использовать beta0. - person eesdil; 24.01.2016
comment
Кроме того, если у вас есть настраиваемая структура папок, поначалу ее сложно получить, поэтому я предлагаю пока следовать рекомендациям на странице angular. - person eesdil; 24.01.2016

Что немного странно, так это то, что у вас нет MyComponent.js в той же папке, что и app.js. В моем случае, когда я добавляю outDir в файл tsconfig.json, все мои файлы TypeScript компилируются в JavaScript в этой папке.

Вот моя конфигурация в моем файле tsconfig.json:

{
  "compilerOptions": {
    "target": "ES5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "outDir": "app/resources/dist/js"
 },
  "exclude": [
    "node_modules"
  ]
}

Я запускаю этап компиляции с помощью команды: tsc -w.

Надеюсь, это поможет вам, Тьерри.

person Thierry Templier    schedule 19.01.2016
comment
Кажется, я еще не все пробовал. Я пробовал с ./MyComponent для части импорта в app.ts, и это сработало, транскомпилятор выполнил свою работу - это была не проблема транскомпилятора, а проблема пути (не знаю, как я еще не пробовал ./уже ) и ДА, теперь у меня есть файл MyComponent.js... но теперь у меня другая проблема, я отредактировал свой вопрос и добавил проблему в конце после EDIT: - person MrCroft; 19.01.2016
comment
На снимке экрана вашего проекта у вас есть MyComponent.ts, но нет MyComponent.js, который ищет браузер, вы уже скомпилировали его? - person Langley; 19.01.2016
comment
Файл MyComponent.js есть, я просто не обновил структуру папок/файлов проекта в своем вопросе. Я сделал это сейчас. - person MrCroft; 19.01.2016