Подтвердить что ты не робот

Как импортировать бочку только по имени папки?

Angular 2 бочки

В Angular 2 я пытаюсь запустить бочки, как описано в документации.

Официальный Angular 2 стиль руководства рассказывает об использовании баррелей для агрегирования и сокращения операторов import.

Я выясню, что для некоторых баррелей я должен указать имя файла index JavaScript в импорте, когда мне не нужно.

Пример ствола

(измените файл app/app.component.ts в строке 12)

После того, как вы столкнулись с этим в моем фактическом проекте (работающем под ASP.NET), я создал Plunker, чтобы продемонстрировать проблему, когда я модифицировал Прогулка по героям, чтобы использовать бочки.

В app/app.component основной способ импорта выглядит так:

import { HeroService } from './hero.service';
import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';

Но, чтобы вместо этого использовать бочку, определение импорта будет выглядеть так:

import {
  HeroService,
  HeroesComponent,
  HeroDetailComponent
} from '../app';

Строка from '../app'; указывает файл с именем index.ts, который содержит экспортированные/импортированные компоненты:

// app/index.ts
export * from './hero-detail.component';
export * from './hero.service';
export * from './heroes.component';

Но это не работает для меня во всех случаях. Единственный способ, которым я правильно работал, - это явно указать имя файла index:

import {
  HeroService,
  HeroesComponent,
  HeroDetailComponent
} from '../app/index'; // have to indicate 'index'

Как я могу заставить это работать, где подразумевается имя файла index.js?

4b9b3361

Ответ 1

AFAIK SystemJS не понимает бочки самостоятельно, но Webpack делает. BTW, после того, как выкопали, как Angular делает это для своих модулей, я нашел решение


В system.config.js вам нужно сделать следующее:

Примечание. родительский каталог index.ts - это barrel, ICYDK

  • Добавить пути ваших стволов

// map tells the System loader where to look for things
  var map = {
    'app':                        'app', // 'dist',
    'rxjs':                       'node_modules/rxjs',
    'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
    '@angular':                   'node_modules/@angular',

    'barrel':                 'path/to/your/barrel'
  };
  • Не добавляйте бочки в packages (объясняется позже) ##

// packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    'app':                        { main: 'app/boot.js',  defaultExtension: 'js' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { defaultExtension: 'js' }
  };
  • Добавьте их в packageNames, как angular

var packageNames = [
    '@angular/common',
    ...
    '@angular/upgrade',

    'barrel'
  ];

И все готово.


##

Почему мы использовали packageNames вместо packages, потому что вам нужно будет повторить { main: 'index.js', defaultExtension: 'js' } (имя файла и расширение) для каждого barrel, но angular уже делает это путем циклического с этим.

packageNames.forEach(function(pkgName) {
    packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});

В конечном итоге они добавляются к packages.


Использование

import {something} from '../../barrel'; // relative path to directory of barrel

и

import {something} from 'barrel'; // name of barrel

Оба работают, но более поздний не может предоставить intellisense и показывает ошибку, говорящую cannot find module 'barrel'. На что у меня нет решения. Но я добавлю это, когда буду.

Ответ 2

Все это кажется слишком сложным.

Нет необходимости добавлять что-либо к карте, так как app, который должен содержать все, уже есть. Мы можем просто создать массив с подпакетами. В моем случае это было:

var subPackageNames = [
        '+heroes',
        '+heroes/shared',
        '+heroes/hero-list',
        '+heroes/hero-detail',
        '+heroes/hero-dashboard'
    ];

а затем измените предоставленную packIndex функцию, чтобы взять второй аргумент

function packIndex(pkgName, baseName) {
    packages[baseName+pkgName] = { main: 'index.js', defaultExtension: 'js' };
}

теперь мы можем добавить наши вспомогательные пакеты к объекту пакетов, как это делает angular.

ngPackageNames.forEach(name => setPackageConfig(name, '@angular/'));
subPackageNames.forEach(name => packIndex(name, 'app/'));

Ответ 3

Я следовал за идеей A_Singh, но мне пришлось немного ее адаптировать, так как мой systemjs.config.js отличается, на основе тур-героев как сейчас. (3 июня 2016 года - RC1).

Эта модификация работает, и в соответствии с кодом VisualStudio Intellisense работал хорошо для меня.

Я также играл со структурой каталогов, чтобы держать вещи модульными, и вот где баррели имели смысл.

Вот как я изменил проект tour-of-heroes

app
|- main.ts
|- app.component.ts
|- app.component.css
|-+ components
| |-+ dashboard
|   |- dashboard.component.css
|   |- dashboard.component.html
|   |- dashboard.component.ts
|-+ modules
| |-+ hero
|   |- index.ts   <-- //The barrel for the Hero module
|   |-+ components 
|   | |-+ detail
|   | | |- hero-detail.component.css
|   | | |- hero-detail.component.html
|   | | |- hero-detail.component.ts
|   | |-+ list
|   |   |- hero-list.component.css
|   |   |- hero-list.component.html
|   |   |- hero-list.component.ts
|   |-+ models
|   | |- hero.model.ts
|   |-+ services
|     |- hero.service.ts
|     |- mock-heroes.ts

И здесь обновленный systemjs.config.js

(function(global) {
  // map tells the System loader where to look for things
  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',

    // The added barrel map
    'hero':                       'app/modules/hero'
  };
  var packages = {
    'app':                        { main: 'main.js',  defaultExtension: 'js' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { defaultExtension: 'js' },

    // The package definition (notice I had to declare index.js)
    'hero':                       { main: 'index.js',  defaultExtension: 'js' }
  };
  var ngPackageNames = [
    'common',
    'compiler',
    'core',
    'http',
    'platform-browser',
    'platform-browser-dynamic',
    'router',
    'router-deprecated',
    'upgrade',
  ];
  ngPackageNames.forEach(function(pkgName) {
    packages['@angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
  });
  var config = {
    map: map,
    packages: packages
  }
  System.config(config);
})(this);

И, наконец, вот как app.component.ts теперь выглядит как

import { Component } from '@angular/core';
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/router-deprecated';

import { DashboardComponent } from './components/dashboard/dashboard.component';
import { HeroListComponent, HeroDetailComponent, HeroService } from './modules/hero';

@Component({
    selector:   'my-app',
    directives: [ROUTER_DIRECTIVES],
    providers:  [
        ROUTER_PROVIDERS,
        HeroService
    ],
    template:   `
<h1>{{title}}</h1>
<nav>
    <a [routerLink]="['Dashboard']">Dashboard</a>
    <a [routerLink]="['HeroList']">Hero List</a>
</nav>
<router-outlet></router-outlet>
`,
    styleUrls: ['app/app.component.css']
})
@RouteConfig([
    {
        path: '/dashboard',
        name: 'Dashboard',
        component: DashboardComponent,
        useAsDefault: true
    },
    {
        path: '/hero-list',
        name: 'HeroList',
        component: HeroListComponent
    },
    {
        path: '/detail/:id',
        name: 'HeroDetail',
        component: HeroDetailComponent
    }
])
export class AppComponent {
    title: string = 'Tour of Heroes';
}

Наконец, вы можете сделать импорт как

import { HeroListComponent, HeroDetailComponent, HeroService } from 'hero';

И он будет работать, однако, поскольку он не является технически импортированным модулем NodeJS, VS Code жалуется, что он не может его найти. Итак, мой личный выбор - оставить явный ./modules/hero, он помогает мне понять, что это один из моих модулей, а не импортированный, и я рад не видеть красные строки.