Использование GeoFire в приложении Angular2

angular firebase systemjs geofire

2862 просмотра

2 ответа

Я пытаюсь настроить GeoFire в своем приложении Angular2 (RC5). Я установил geofire и firebase с помощью npm и настроил systemjs для его импорта. Вот мой package.json:

{
  "name": "MyProject",
  "version": "0.1.0",
  "scripts": {
    "start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
    "lite": "lite-server",
    "postinstall": "typings install",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "typings": "typings"
  },
  "license": "ISC",
  "dependencies": {
    "@angular/common": "^2.0.0-rc.5",
    "@angular/compiler": "^2.0.0-rc.5",
    "@angular/core": "^2.0.0-rc.5",
    "@angular/forms": "0.3.0",
    "@angular/http": "2.0.0-rc.5",
    "@angular/platform-browser": "^2.0.0-rc.5",
    "@angular/platform-browser-dynamic": "^2.0.0-rc.5",
    "@angular/router": "3.0.0-rc.1",
    "@angular/router-deprecated": "2.0.0-rc.2",
    "@angular/upgrade": "2.0.0-rc.5",
    "angular2-in-memory-web-api": "0.0.15",
    "bootstrap": "^3.3.6",
    "core-js": "^2.4.0",
    "firebase": "^3.3.0",
    "geofire": "^4.1.1",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.12"
  },
  "devDependencies": {
    "concurrently": "^2.0.0",
    "lite-server": "^2.2.0",
    "typescript": "^1.8.10",
    "typings": "^1.0.4"
  }
}

и мой файл конфигурации systemjs:

  var map = {
    'app':                        'app', // 'dist',
    '@angular':                   'node_modules/@angular',
    'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
    'rxjs':                       'node_modules/rxjs',
    'firebase':                   'node_modules/firebase',
    'geofire':                    'node_modules/geofire',
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    'app':                        { main: 'main.js',  defaultExtension: 'js' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
    'firebase':                   { main: 'firebase.js', defaultExtension: 'js' },
    'geofire':                    { main: 'dist/geofire.js', defaultExtension: 'js' },
  };

Наконец, я пытаюсь импортировать geofire в мой файл app.component.ts следующим образом:

import * as GeoFire from "geofire";

Но, запустив npm start, чтобы начать и запустить сервер, вы получите следующую ошибку:

➜  MyProject npm start

> MyProject@0.1.0 start /Users/max/Development/myproject
> tsc && concurrently "npm run tsc:w" "npm run lite"

app/app.component.ts(3,26): error TS2307: Cannot find module 'geofire'.

npm ERR! Darwin 15.5.0
npm ERR! argv "/usr/local/Cellar/node/5.10.1/bin/node" "/usr/local/bin/npm" "start"
npm ERR! node v5.10.1
npm ERR! npm  v3.8.3
npm ERR! code ELIFECYCLE
npm ERR! MyProject@0.1.0 start: `tsc && concurrently "npm run tsc:w" "npm run lite" `
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the MyProject@0.1.0 start script 'tsc && concurrently "npm run tsc:w" "npm run lite" '.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the MyProject package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     tsc && concurrently "npm run tsc:w" "npm run lite"
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs MyProject
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls MyProject
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/max/Development/MyProject/npm-debug.log

Вот мой tsconfig:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  }
}

Остальные файлы проекта основаны на кратком запуске angular2, найденном здесь:

https://angular.io/guide/quickstart

Кто-нибудь имеет какие-либо идеи, как я могу заставить TSC найти модуль и успешно перенести?

Благодарю. Максимум.

Автор: Max Mumford Источник Размещён: 08.11.2019 11:20

Ответы (2)


7 плюса

Решение

В этом кратком руководстве не хватает одного важного момента: SystemJS и TypeScript - это два отдельных инструмента, каждый со своей конфигурацией.

Добавление geofire в конфигурацию systemjs не влияет на разрешение модуля машинописи. Увидев этот импорт

import * as GeoFire from "geofire";

tsc пытается найти geofire.ts в обычных местах, где обычно находятся типизации для модулей javascript, и выдает ошибку, потому что ее там нет.

Есть три разных способа решения этой проблемы.

В любом случае, geofireконфигурация пакета в systemjs.config.js должен объявить свой формат , как global, например:

'geofire': {
    main: 'dist/geofire.js', 
    defaultExtension: 'js', 
    meta: {'dist/geofire.js': {format: 'global'}} 
 },

Первое решение - создать простейшее объявление типа для geofire самостоятельно, используя окружающие модули.

Создать geofire.d.tsфайл в папке приложения:

declare namespace geofire {
    function GeoFire(firebaseRef: any): void;
}

declare module 'geofire' {
    export = geofire;
}

Этого достаточно для компиляции оператора import и для этого вызова typecheck:

   var geoFire = new GeoFire(firebaseRef);

ПРИМЕЧАНИЕ для машинописи 2.0

Для машинописного текста 2.0 приведенный выше код не работает. Вы должны использовать машинописный import =синтаксис

import GeoFire = require('geofire');

и измените определение geofire.d.tsна:

declare module 'geofire' {
    function GeoFire(firebaseRef: any): void;
    export = GeoFire;
}

Еще один возможный способ решить эту проблему - использовать плагин для SystemJS, который использует API-интерфейс TypeScript для вызова машинописи и подключения к своему разрешению модуля, чтобы он учитывал конфигурацию SystemJS. С этим плагином этот импорт будет работать во время выполнения в браузере, но вызов tsc из командной строки все равно выдаст ту же ошибку.

Третий способ - импортировать geofire с использованием SystemJS API, а не оператора import в app.component.ts:

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

declare var SystemJS : any;
var GeoFirePromise = SystemJS.import('geofire');

@Component({
  selector: 'my-app',
  template: '<h1>My First Angular 2 App</h1>'
})

export class AppComponent {

    constructor() {  // or wherever you need to use geofire

        GeoFirePromise.then(function(GeoFire: any) {
            console.log(typeof GeoFire);
        });
    }

}

Обратите внимание, что SystemJS.importвозвращается обещание, которое нужно будет загрузить geofire.js, поэтому везде, где вы хотите его использовать, вы должны сделать

    GeoFirePromise.then(function(GeoFire: any) {

Если это неудобно, вы можете просто объявить глобальную переменную GeoFire

declare var GeoFire: any;

и загрузите geofire.js, используя тег script в вашем HTML-коде, как описано в этом сообщении на ионном форуме . Тогда вам не нужно добавлять geofire в systemjs.config.js.

Автор: artem Размещён: 21.08.2016 11:16

3 плюса

Заметьте, я все еще не эксперт по TypeScript, и я впервые играю с определениями типов и тому подобным, но после долгого рабочего дня у меня, кажется, есть кое-что, что работает (по крайней мере, для моей установки). Я использую Ionic 2 RC2, Angular2 2.1.1, Geofire 4.1.2. В сборке используется веб-пакет. Я создал geofire.d.tsв моей директории приложения следующее:

declare module 'geofire' {

    type EventType = 'ready' | 'key_entered' | 'key_exited' | 'key_moved';

    interface GeoQueryCriteria {
        center: number[];
        radius: number;
    }

    interface GeoQueryUpdateCriteria {
        center?: number[];
        radius?: number;
    }

    interface GeoCallbackRegistration {
        cancel();
    }

    interface GeoQuery {
        center(): number[];
        radius(): number;
        updateCriteria(criteria: GeoQueryUpdateCriteria);
        on(eventType: EventType, callback: (key:string, location: number[], distance: number) => void): GeoCallbackRegistration;
        cancel();
    }

    class GeoFire {
        constructor(ref: any);
        ref(): any;
        set(key: string, loc: number[]): Promise<void>;
        get(key: string): Promise<number[]>;
        remove(key: string): Promise<void>;
        query(criteria: GeoQueryCriteria): GeoQuery;
        static distance(location1: number[], location2: number[]);  
    }

    export = GeoFire;
}

Наконец, в моей службе / странице я могу импортировать GeoFire следующим образом:

import GeoFire from 'geofire';

Обратите внимание на точный синтаксис импорта: здесь нет фигурных скобок {}. Я пробовал так много способов заставить его работать по-другому, но я думаю, как был написан JavaScript, это то, как это должно быть сделано. Я нашел способы, которые бы избавились от ошибок компиляции, но потерпели неудачу во время выполнения («конструктор не назван ...»), или он распознал бы конструктор при компиляции, но не как тип.

Я создал его только для открытого API, поэтому, если вы попытаетесь по какой-то причине расширить GeoFire, имейте в виду, что могут быть конфликты имен с другими методами, не представленными в этом файле определения.

Если это поможет вам, пожалуйста, дайте мне знать, и я внесу это в DefinitiveTyped, чтобы больше никому не пришлось пережить боль, которую я (и, очевидно, другие с более чем 340 просмотров) сделал.

Автор: DeezCashews Размещён: 10.12.2016 04:07
Вопросы из категории :
32x32