Swiip / generator-gulp-angular

Yeoman generator for AngularJS with GulpJS [UNMAINTAINED next iteration is FountainJS]
http://fountainjs.io
3.72k stars 665 forks source link

typescript best practices #1064

Closed gadieichhorn closed 8 years ago

gadieichhorn commented 8 years ago

I am using the latest generator with NG 1.5.x

How can I change the typescript setup to run a more modular file setup like below.

At the moment it is necessary to import all the relevant files to the index.modules.ts and declare them

import { Service } from './service ' angular.module(...).service('service', Service);

would it be better to let each component declare itself and not expose any classes into the global space?

you also need to let webpack and karma look for all the files that change and not just the entry point index.modules.

/// src/app/services/service.ts
module app {
  'use strict';

  class Service {

    static $inject = ['$log', '$http'];
    constructor(private $log: ng.ILogService, private $http: ng.IHttpService) {
      this.$log.debug(this.$http);
    }
  }

  angular.module('app.services', [])
  .service('myService', Service);

}
Swiip commented 8 years ago

It's an alternative I considered while I was designing the ES2015 version (which ask the same questions). I decided for the current version especially to use the modules explicitly. It's a matter of taste, you're free to choose differently and your approach has its avantages but I doubt choose this as a choice by default.

gadieichhorn commented 8 years ago

thank you, would be able to suggest how I might do the conversion? I think this can be a good wiki and for everyone who are interested going down this path to use. appreciate your support.

Swiip commented 8 years ago

Yep, a recipe could be great. For the workflow, I would suggest to add src/**/*.js in Webpack entries. You could even consider removing webpack and using a simple gulp-typescript followed by the standard injection you have with standard JS.

gadieichhorn commented 8 years ago

webpack is a good way of doing things so would like to keep it of possible. any suggestions are welcomed :)

I tried few options with no success. from:

  var sources = [ path.join(conf.paths.src, '/app/index.module.ts') ];
  if (test) {
    sources.push(path.join(conf.paths.src, '/app/**/*.spec.ts'));
  }

to:

  var sources = [ path.join(conf.paths.src, '/app/**/*.ts') ];
  if (test) {
    sources.push(path.join(conf.paths.src, '/app/**/*.spec.ts'));
  }

is it possible to avoid using import statements and let angular figure out the DI order?

import { MainController } from './main/main.controller';
Swiip commented 8 years ago

You can try dinamically include all files with a trick i learned with karma webpack https://github.com/webpack/karma-webpack#alternative-usage

But you just blow up all modularization aspect of TS...

gadieichhorn commented 8 years ago

yes, keep it modular by encapsulating the classes and exposing the interfaces from each module.

to be more clear I would like to let each class register itself with angular inside a module. should only expose (export) interfaces when they are used by other modules.

/// import what is needed for implementing this service/controller/factory/...
import { IConnection } from '../../domain/connection/connection.model';

// everything is warped in TS IIFE (module/namespace)
module admin.services {

/// EXPORT
  export interface IConnectionService {
    /// some methods
  }

/// NO EXPORT NEEDED
  class ConnectionService implements IConnectionService {
    /// implementation
  }

/// angular DI registration
  angular.module('admin.services')
    .service('admin.services.Connection', ConnectionService);

}

when I try this setup I am getting angular loading errors like

[$injector:modulerr] Failed to instantiate module admin due to:
Error: [$injector:modulerr] Failed to instantiate module admin.pages due to:
Error: [$injector:nomod] Module 'admin.pages' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
gadieichhorn commented 8 years ago

realise my mistake now. thanks for your support :+1:

asafper commented 8 years ago

Hi gadi,

Can you please share how did you resolve this issue ?

Thanks

gadieichhorn commented 8 years ago

sure,

first I got a bit confused between modules and namespaces so I cleaned that up with namespaces per module.

secondly, by ordering the imports I managed to declare the angular modules first and then use them inside each module and not exporting any unnecessary classes.

index.ts

namespace app.pages {
angular.module('app.pages',[]);
}

import './main.controller.ts';

in the module main.controller.ts

namespace app.pages {

class MainController {}

angular.module('app.pages').controller('app.pages.MainController', MainController);

}