如何仅按文件夹名称导入桶?

时间:2016-05-06 23:02:56

标签: javascript angular

Angular 2 Barrels

在Angular 2中,我试图按照documentation中的描述让桶工作。

官方Angular 2 style guide谈论使用来汇总和缩短import语句。

我发现对于某些桶,我必须在导入时指定index JavaScript文件名,而我不应该这样做。

桶示例

(修改第12行的app / app.component.ts文件)

在我的实际项目中遇到过这个(在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文件名的情况下使其工作?

3 个答案:

答案 0 :(得分:8)

AFAIK SystemJS本身并不了解桶,Webpack。 顺便说一句,在深入了解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,就像角度
  • 一样

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

    'barrel'
  ];

你已经完成了。

##

为什么我们使用packageNames代替packages是因为您必须为每个{ main: 'index.js', defaultExtension: 'js' }重复barrel(文件名和扩展名),但有角度已经在做通过循环使用它。

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'。我没有解决方案。但是当我这样做时,我会添加它。

答案 1 :(得分:5)

This is all seems overly complicated.

There's no need to add anything to map, since app, which should be containing everything is already in there. We can just create an array with the subpackages. In my case that was:

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

and then modify the provided packIndex function to take a second argument

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

now we can add our sub packages to the packages object just like angular does.

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

答案 2 :(得分:0)

我遵循 A_Singh的想法,但由于我的systemjs.config.js不同,因此我必须根据tour-of-heroes教程进行调整。 (2016年6月3日 - RC1)。

此修改有效,在VisualStudio Code下,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,它帮助我知道它是我的模块之一而不是导入的模块,我很高兴看不到红线。