In Angular 2, I'm trying to get barrels to work as described in the documentation.
The official Angular 2 style guide talks about using barrels to aggregate and shorten import statements.
I'm finding out that for some barrels, I have to specify the index JavaScript file name on the import when I shouldn't have to.
(modify the app/app.component.ts file on line 12)
After have encountered this in my actual project (running under ASP.NET) I have created a Plunker to demonstrate the problem where I modified the Tour of Heroes to use barrels.
In app/app.component, the basic way to import is like this:
import { HeroService } from './hero.service'; import { HeroesComponent } from './heroes.component'; import { HeroDetailComponent } from './hero-detail.component'; But, to use a barrel instead, the import definition would look like this:
import { HeroService, HeroesComponent, HeroDetailComponent } from '../app'; The from '../app'; line indicates a file with the name of index.ts that contain the exported/imported components:
// app/index.ts export * from './hero-detail.component'; export * from './hero.service'; export * from './heroes.component'; But this doesn't work for me in all cases. The only way I've gotten this to work correctly is by explicitly including the index file name:
import { HeroService, HeroesComponent, HeroDetailComponent } from '../app/index'; // have to indicate 'index' How can I get this to work where the index.js file name is implied?
A barrel is a way to rollup exports from several modules into a single convenient module. The barrel itself is a module file that re-exports selected exports of other modules.
We create Barrel files. A barrel is a way to rollup of imports from several files into a single convenient file. So we have a simple project here that shows different modes of transportation.
AFAIK SystemJS doesn't understand barrels by itself but Webpack does. BTW, After digging up how Angular does it for it's modules, I've found a solution
In system.config.js you'll need to do the following things
Note: the parent directory of a index.ts is the 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 (explained later)## // 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, just like angularvar packageNames = [ '@angular/common', ... '@angular/upgrade', 'barrel' ]; And you're done.
##
Why we used packageNames instead of packages is because you'll have to repeat the { main: 'index.js', defaultExtension: 'js' } (filename and extension) for every barrel, but angular is already doing it by looping with this.
packageNames.forEach(function(pkgName) { packages[pkgName] = { main: 'index.js', defaultExtension: 'js' }; }); Which is ultimately adding them to packages.
Usage
import {something} from '../../barrel'; // relative path to directory of barrel and
import {something} from 'barrel'; // name of barrel Both work, but the later one fails to provide intellisense and shows an error saying cannot find module 'barrel'. Which I don't have a solution for. But I'll add it when I do.
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/'));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With