Proposals to Make Components More Reusable #109

Open
joshdmiller opened this Issue Mar 7, 2013 · 214 comments
@joshdmiller

I apologize in advance for this issue's massive length.

I would like to start a discussion on some ways I think the generators could be changed to make the resulting components more easily reusable. I think when developing, we should have the potential for as much of our code as possible to be "drag and drop reusable". AngularJS already sets us well on our way by promoting separation of concerns in its internal architecture, so why shouldn't our development tools do the same?

The reference structure I am using is my own ngBoilerplate.

Each section builds on the previous.

Update [07 Mar, 0840 PST]: I use the term "component" here a little more loosely than Bower. I just mean it to refer to functionality that is somewhat self-contained. Unless otherwise noted, it refers to both bundled code and internal app features.

Organize by Feature

Instead of bundling code by the layer to which it belongs (controllers, services, filters, directives, etc.), I would like to see code bundled by the feature to which it belongs. There can be many manifestations of this, but here are two examples:

(a) Routes

Instead of something like this for a /home route:

|-- src/
|   |-- scripts/
|   |   |-- controllers/
|   |   |   |-- home.js
|   |-- test/
|   |   |-- spec/
|   |   |   |-- controllers/
|   |   |   |   |-- home.js
|   |-- views/
|   |   |-- home.html

I'd prefer to see it like this:

|-- src/
|   |-- app/
|   |   |-- home/
|   |   |   |-- home.js
|   |   |   |-- home.spec.js
|   |   |   |-- home.tpl.html

This is a much simpler directory structure, but makes the home module very portable. It is also self-contained: it can be totally refactored without impacting the rest of the application.

(b) Multi-Component Features:

If we have complex component, it is likely composed of multiple smaller components. For example, an editing component might have a persistence service, a representation service for translating markup to HTML, and a directive or two for display. With the existing structure, each component would be created independently and be mixed throughout the various layers; without a comprehensive, holistic understanding of the application, it is difficult to see how these components are (or should be) inter-related. It demands manually surfing through the code and/or doing searches for component names.

A cleaner directory structure would look something like this:

|-- src/
|   |-- components/
|   |   |-- editor/
|   |   |   |-- editing.js
|   |   |   |-- editor.js
|   |   |   |-- editor.spec.js
|   |   |   |-- editingStorage.js
|   |   |   |-- editingStorage.spec.js
|   |   |   |-- editingRender.js
|   |   |   |-- editingRender.spec.js

Now it's pretty clear we're talking about one component, albeit a complex one that spans multiple layers. But each sub-component of the editor is still standalone, if need be - that's just good programming.

Isolate the Modules

A logical extension of this reorganization is to so-define our modules. In this pattern, each directory roughly corresponds to a module. Instead of this:

angular.module( 'myApp' )
  .controller( 'HomeCtrl', function ($scope) {
    // ...
  });

We would have this:

angular.module( 'home', [] )
  .controller('HomeCtrl', function ($scope) {
    // ...
  });

Similarly for the editing component:

angular.module( 'editor', [
  'editing.editor',
  'editing.editingStorage',
  'editing.editingRender'
])

Where those modules are defined in their respective files. And our main app.js file simply requires the top-level modules:

angular.module( 'myApp', [
  'home',
  'editing'
]);

Adjacent Tests

Everyone coming from server-side development (including myself) is familiar with the separate test directory, but I've always found it vexing. Placing test files directly adjacent to the code they test makes them easier to locate. More important, however, is reusability; if our tests are in a separate directory, we now have two things we have to copy between projects in order to reuse a component.

This is where it's important to separate two kinds of projects: libraries and apps. When developing libraries, we design them to be self-contained and self-sufficient, so we have no need to take tests with us to reuse in another project - that should have all been part of a build. But when developing apps, where some components may depend more subtly on other components (or at least on assumptions about our app architecture), it makes sense to take the tests with us and ensure they still pass in the new environment. Also see the 'Internal "Components"' section below.

It's okay to keep the tests side-by-side because our build tools are sophisticated enough to be able to tell the difference. Grunt 0.4, for example, now includes negative file selectors, so our build can exclude files with patterns like src/**/*.spec.js or src/**/*Spec.js from compilation and minification.

Adjacent Templates

The same concept also applies to views, partials, and templates. I also prefer they be suffixed with .tpl.html or something similar to indicate they're fragments.

Modularized Routing

Using the above example, yo angular:route home would generate this:

|-- src/
|   |-- app/
|   |   |-- home/
|   |   |   |-- home.js
|   |   |   |-- home.spec.js
|   |   |   |-- home.tpl.html

But instead of defining the route in app.js, we would let the home module set up its own routing:

angular.module( 'home', [] )

.config( function ( $routeProvider ) {
  $routeProvider
    .when( '/home', {
      templateUrl: 'home/home.tpl.html',
      controller: 'HomeCtrl'
    });
})

.controller( 'HomeCtrl', function ( $scope ) {
    // ...
})

Nothing is required in the app.js in terms of routing, unless the user should choose to define a default redirect, such as to /home.

Feature Nesting

The existing directory structure is very flat. For small projects, this is perfectly fine, but for non-trivial projects it can become a file management nightmare. If we organize our code by the feature or component they implement and use adjacent templates and tests, it also makes sense to be able to nest them.

Considering the route example:

|-- src/
|   |-- app/
|   |   |-- products/
|   |   |   |-- products.js
|   |   |   |-- products.spec.js
|   |   |   |-- products.tpl.html
|   |   |   |-- create/
|   |   |   |   |-- create.js
|   |   |   |   |-- create.tpl.html
|   |   |   |-- ...

In this case, each directory should roughly correspond to a single "submodule". The products directory is a module called products, making create something like products.create. Using this pattern, the products module can require all requisite submodules:

angular.module( 'products', [
  'products.list',
  'products.view',
  'products.create',
  'products.search'
]);

Again, because the target is reusability, each app module is responsible for declaring its own dependencies, which will "bubble up" from products.create to products to myApp. Routing would work similarly; each submodule can define its own routing, in theory "namespacing" to its parent module. For example, products.create could define a route of /products/create.

This same "nested" pattern would also apply to complex components, though they would obviously not include routing. E.g.:

|-- src/
|   |-- components/
|   |   |-- editor/
|   |   |   |-- editor.js
|   |   |   |-- plugins/
|   |   |   |   |-- syntax.js
|   |   |   |   |-- align.js

Internal "Components"

Lastly, I make a distinction between app code, the stuff that is somewhat unique to our problem domain, and components, the stuff that may come from a third party but that is more immediately reusable in unrelated projects.

With this concept in mind, we should be able to mix in the components directory the third-party libraries that come from Bower, the third-party libraries we download manually, and the reusable components that we are coding for this application specifically. e.g.:

|-- src/
|   |-- components/
|   |   |-- angular-placeholders/     <downloaded>
|   |   |-- angular-ui-bootstrap/     <bower>
|   |   |-- editor/                   <internal>

All combined, I think this would improve code reusability and readability.

@PascalPrecht

This is exactly the way it should be! I'm also a fan of ngBoilerplate. Structuring an angular app by feature rather then by layer makes the app more flexible. Your proposal looks also pretty generic, +1 for that!

@keybits
keybits commented Mar 7, 2013

Wow - that's a fantastically presented set of suggestions. I'm not experienced enough with Angular to know if all of this is a 'good idea' but the logic sounds solid to me.

@Bretto
Bretto commented Mar 7, 2013

I have been using this encapsulated type of component based architecture for years in FLEX I agree on everything apart from integrating the routes into the component buddle, I think you might want to leave this part in your app code... But apart from that +100 @joshdmiller

@ryanzec
ryanzec commented Mar 7, 2013

I agree with @Bretto on not integrating the routes into the component bundles however everything else look pretty good.

@joshdmiller

@Bretto and @ryanzec - I definitely think only app code should be able to define routes and I didn't meant to imply otherwise. I used "component" somewhat loosely in my write-up to mean both the bundled, often third-party code and a defined feature of our application. I'll edit the post to clarify.

@MikeMcElroy

Not familiar at all with how Yeoman/Bower works, but I have a question: Does the deployment process from this allow you to limit what files get sent up to your production server? Thinking that sending your tests to a publicly accessible web server not the best idea.

@passy
Member
passy commented Mar 7, 2013

@MikeMcElroy Yes, that would be easy to exclude regardless of whether they're in a separate folder or not.

@MikeMcElroy

Then very cool. Carry on. :-)

On Thu, Mar 7, 2013 at 10:34 AM, Pascal Hartig notifications@github.comwrote:

@MikeMcElroy https://github.com/MikeMcElroy Yes, that would be easy to
exclude regardless of whether they're in a separate folder or not.


Reply to this email directly or view it on GitHubhttps://github.com/yeoman/generator-angular/issues/109#issuecomment-14577943
.

@martypitt

I'm working on a non-trivial angular app currently, and have been flapping about trying to come up with a structure that sat well with me (knowing that the default did not).

This is extremley well articulated and clear -- thanks @joshdmiller for taking the time and effort for writing this up.

@emcpadden

Great work ... I agree with this 100%.

@lovellfelix

+1 Makes perfect sense to me. It makes it easier to manage large projects.

@joshdmiller

I appreciate all of the positive comments - it's nice to know there are others who agree. :-)

That said, I already have a pretty healthy ego - surely there's someone out there who wants to call me an idiot.

@rstuven
rstuven commented Mar 8, 2013

Idiot.

That said, I like your proposals very much.

@ryanzec
ryanzec commented Mar 8, 2013

I think the directory structure you laid out is good regardless of portability or not, organizationally it is good. Instead of calling you an idiot, which @rstuven already did, let me ask you a question as I have been thinking about this more. What do I gain from using multiple smaller modules?

For example, I have a set of components I have been building and if I switch to using small modules instead of one big module, I would go from 1 module to ~24 modules (probably more as I still have functionality to add). Now if I use the same directory structure you have laid out but still only use one module, what do I really gain from converting them multiple small modules? If you dont need some of the components I have, just don't include the js file for that component.

Now I am going to need all these modules for an application that I am building. I can see this application easily having 20+ main modules with this setup and a lot of those modules would have sub modules, probably ranging from most commonly from 2-5. Now we are talking about 50 - 100+ small modules in this application and most of the modules in the application itself are not really going to be portable as they are going to be built specifically for this application.

So are there any downsides to having a bunch of smaller modules (50 - 100+) when portability it not important?

@joshdmiller

@ryanzec - Nice. I see the benefits of multiple small modules as these:

  1. Reusability. I focused the bulk of my post on this, so there isn't much else to say, except this: we don't always know what we'll need to reuse.
  2. Ease of refactoring. If we don't follow the "one module per file" rule, refactoring becomes very tricky very fast.
  3. Comprehensibility. Small modules with a deep directory structure are often much easier for developers new to the team (or for you six months from now) to see where everything is located and understand the original intent behind some of the code. Monolithic files with lots of code or a single directory with a dozen files can be a trifle overwhelming.

I don't really see any downsides to having multiple modules; the build process will take care of concatenation and minification.

That said, this issue really isn't about forcing anyone to use this directory structure, but that the current generator doesn't even support the use of this directory structure. I'd like this tool to be flexible above all else, but also encouraging of a more "correct" architecture. AngularJS is just so different than other client-side libraries that most new developers don't know what an app should look like. I provide a lot of community support on the mailing list, on SO, and through a few projects, and I often have to wade through insanity - seeing a little less crap out there would lower my blood pressure. :-)

A useful next discussion would be how the CLI tools might support this structure; for routes, it's pretty obvious, but for others the debate may get a little more contentious...and interesting.

@btford
Contributor
btford commented Mar 11, 2013

A useful next discussion would be how the CLI tools might support this structure

+1. This is currently where I'm stalled on this idea. Any bright ideas on what you'd like the CLI to look like for this?

@timkindberg

💯 This is so inspriing!

@joshdmiller

Well, shoot-darn - now you're taxing my brain. I can think of lots of ways to do it, but there is difficulty in finding something flexible, so we don't force anything on anyone, and that doesn't require a bunch of parameters, defeating the purpose of the scaffolding. I should also mention that I've never been a big fan of generators and so don't use them really often; those that do are more likely to provide a better implementation.

But I'll kick things off ...


First, I've encountered a problem with my above recommendations; technically, it's a problem with Bower.

Bower is not nearly robust enough for use with AngularJS projects. With jQuery, it makes sense to have the plugin's repository be the Bower component's source; all it usually has is a JavaScript file, along perhaps with a demo HTML file and some styles. But when we move into something more complicated, using the source repository totally breaks my build. :-(

Take Bootstrap. I see two use cases: (1) we just include the CSS; (2) we leverage the LESS/SASS files. For the former, the automated build works great; for the latter, we need to throw those files into some vendor directory that is not processed by the build because our main.less file in our app will @import the necessary files.

But installing Bootstrap with Bower doesn't well support either. We just get a massive directory of all of the files - including build scripts and jQuery plugins. I can't automate any building with that. But that's not the issue - the issue is that Bower makes no distinction between kinds of packages. It offers no way to specify which parts of the package we need. It offers no way to build on the fly.

So if we use Bower for our components, we cannot place our own components alongside them. Additionally, by using Bower, we have two choices when it comes to the build:

  1. just include all components in the build, included into index.html (this is the current approach, right?)
  2. manually adding logic for every component to our Gruntfile so we can get that one payload at the end a lot of us want.

These options totally suck. In my opinion, a great package manager for AngularJS projects would standardize the packages and offer them built or unbuilt, uglified or not, with the ability to select sub-components, so we can completely automate our build regardless of what components we choose to include.

The Takeaway: But Bower is what we have for now. So I have to change my above proposal. src/components/ must be thought of as "vendor" components which we have to add to our build manually - in many cases (perhaps even by default) simply copying the files to our distribution would suffice. But I submit that as more AngularJS components make their way into Bower, this will be less and less palatable. Se here's the redefinition: "mutli-component features" discussed in my initial issue post are now inside src/app/; src/components/ is used exclusively for vendor content (and should perhaps be renamed to src/vendor).


Okay, now that we've re-defined things to fix that issue with my original recommendations, we can get on with the yo commands.

To avoid really complex generator commands, I think we have to buy into a few basic concepts:

  1. One module per file
  2. One folder per route (though nesting is developer's choice)
  3. Tests, views, and styles sit alongside their component

app

$ yo angular:app

Combining everything from the previous post, this yields:

|-- dist/
|-- Gruntfile.js
|-- package.json
|-- src/
|   |-- app/
|   |   |-- app.js
|   |   |-- app.spec.js
|   |-- assets/
|   |-- index.html
|   |-- styles/
|   |-- vendor/
|-- testacular.conf.js

route

$ yo angular:route <route> [module]

To provide maximum flexibility, the user can provide a module name. In the absence of a module name, perhaps just src/app/<route>/ could be the default. Or maybe a modularized version of the route.

$ yo angular:route "/products"
|-- src/
|   |-- app/
|   |   |-- products/
|   |   |   |-- products.js
|   |   |   |-- products.spec.js
|   |   |   |-- products.tpl.html

And, of course, the products module should be added to the dependencies array of the app module. Another example:

$ yo angular:route "/products/show"
|-- src/
|   |-- app/
|   |   |-- products/
|   |   |   |-- show/
|   |   |   |   |-- show.js
|   |   |   |   |-- show.spec.js
|   |   |   |   |-- show.tpl.html

Obviously, this would add the products.show module as a dependency of products.

I would also think that running the second without the first (which may make more sense in some cases), would yield this:

|-- src/
|   |-- app/
|   |   |-- products/
|   |   |   |-- products.js
|   |   |   |-- products.spec.js
|   |   |   |-- show/
|   |   |   |   |-- show.js
|   |   |   |   |-- show.spec.js
|   |   |   |   |-- show.tpl.html

Note there is no template on the products module. There would also be no routes defined on products; in this case it is simply a bundler for its subroutes (again, overwritable with the module CLI option). There may also be some feature shared across products that would end up compiled here, but at this point, the generator doesn't know and doesn't care - the important feature now is that it is packaged with growth in mind.

controller, directive, filter, service, & view

I see these as fundamentally the same (though the templates vary, obviously).

$ yo angular:controller <name>
$ yo angular:directive <name>
$ yo angular:filter <name>
$ yo angular:service <name>
$ yo angular:view <name>

My thinking here is that <name> could optionally contain the module (defaulting to nothing):

$ yo angular:controller DoesSomethingCtrl
|-- src/
|   |-- app/
|   |   |-- doesSomething/
|   |   |   |-- doesSomething.js
|   |   |   |-- doesSomething.spec.js

Or:

$ yo angular:controller products.preview.PreviewCtrl
|-- src/
|   |-- app/
|   |   |-- products/
|   |   |   |-- preview/
|   |   |   |   |-- preview.js
|   |   |   |   |-- preview.spec.js

The same logic from the route example would be used to add the new module to the dependencies array of its parent module. It should also add non-existing parent modules; so if products didn't exist, it would be created along with products.preview.


There are a few rough spots in the above and I can envision some potential objections. Also, the generator logic to support the above may well be too onerous. This is more to start the discussion.

So, what are your thoughts?

@stackfull

I like the direction this is going.

On routing, would it be possible to let the app decide the prefix for a component? I'm struggling to think of a really reusable component that would need this though. Maybe a user manager 'page' - always routing at /users/, when you want an /admin/ prefix to handle permissions - dunno.

On the subject of angular components and bower being too simplistic: I noticed that the angular team simply use a separate repo for their compiled files. (https://github.com/angular/angular.js and https://github.com/angular/bower-angular). This makes a lot more sense to me. In the bootstrap case you mention, I would expect to either 'bower install' the CSS files or submodule the source. If you are including something to be part of your build process, it's not really a simple web component. Well, that's just a rule of thumb I use. Components aren't very mature.

I also found that most yeoman generators (or any really) are aimed at scaffolding a web app and there is a missing generator to scaffold a component. I was going to try my hand at writing a generator, but then I'd be unable to take advantage of angular:view etc.

Finally, I think it starts to get a bit Java-esque when creating a controller defaults to a directory containing a file (another reason not to have co-located test files). Might it be better to default something like angular:controller back to the existing behaviour?

@joshdmiller

@stackfull You make good points; I'll respond inline here to avoid confusion.

On routing, would it be possible to let the app decide the prefix for a component?

I may not be following. Once the generator creates the route, the URL string is hard-coded into the file. How would we change this?

On the subject of angular components and bower being too simplistic: I noticed that the angular team simply use a separate repo for their compiled files.

The separate repo is also what we chose for the AngularUI Bootstrap project. But we're really just working around the tool here; when we have to do a workaround, that usually means there's something wrong with the tool - or at least that it's not "optimal".

If you are including something to be part of your build process, it's not really a simple web component.

A component should be able to be concatenated and uglified as part of our build; if we want a single payload, this is really a hard requirement. With Bower, we don't get that option unless we manually add these files to our Gruntfile - that's a shame. But as I said, we don't have any other options at this point.

I also found that most yeoman generators (or any really) are aimed at scaffolding a web app and there is a missing generator to scaffold a component.

Interesting. How do you see this generator looking?

Finally, I think it starts to get a bit Java-esque when creating a controller defaults to a directory containing a file (another reason not to have co-located test files).

Why is "Java-esque" wrong? I'm certainly not saying we should wire our app together with a half-dozen XML files. :-) What's the connection to the co-located test files?

Might it be better to default something like angular:controller back to the existing behaviour?

The existing behavior is incompatible with my proposals. It makes no sense to have a "controllers" directory (and/or module) that doesn't contain all of the controllers. But I'm not sure when this would be an issue; how often are you going to create a controller that is neither part of a route nor has any related code in its module?

@mlegenhausen

+1

For better reusability I think the default router would not be the right choice. Cause it is working on static routes. Maybe ui-router would be a much better choice, cause you can define states instead of static routes. So when you say you want to create a product you go in the state 'product.create' and link it to a route in your app, where you bind all your "components" together. But when saying we have reusable components I think they should all be placed in "components".

Everything that is placed under the app directory should not be intended to be reusable. They should be there for binding all the reusable components together.

@davemerrill

Just to ask the question, this refers only the client (browser) side of an app, yes? The server side (node, python, ruby, ColdFusion, etc), would be in a separate repository, or completely outside the scope of the project, with, say, a Twitter client?

@ajoslin
ajoslin commented Mar 24, 2013

@joshdmiller I like it! One small tweak I would make would be to the module names. Make the module names match the route names: / instead of . as a splitter. To use your example:

$ yo angular:route "products/new"

This would would generate the folder structure you suggested, but create the "products/show" module instead of "products.show". Then the controller generator would be easier to guess:

$ yo angular:controller "products/preview" PreviewCtrl

This would make things more consistent and easier to generate.

@stackfull

@joshdmiller I've overestimated what angular routing can do. (thanks for the pointer @mlegenhausen.)

The "java-esque" comment just meant verbosity. Java project tend to have deeply nested directory structures and 2 or 3 files for each logical entity. That's not me hating on Java, that's just how the languages shape their projects.

As for structuring a project for a component, I'm hitting the odd roadblock in angular atm. Not being able to refer to templates relative to module code is making my grandiose plans look a bit far-fetched. My habit is to have src and demo directories at the top level for the component code and a demo app, but it's getting a little ugly to serve up. So I will probably change to fit with whatever generator-angular does - maybe:

|-- dist/
|-- Gruntfile.js
|-- package.json
|-- component.json
|-- src/
|   |-- demo/
|   |   |-- app.js
|   |   |-- app.spec.js
|   |-- [component-name]/
|   |   |-- module.js
|   |-- assets/
|   |-- index.html
|   |-- styles/
|   |-- vendor/
|-- testacular.conf.js
@joshdmiller

Okay, I stayed away for a few days and now everyone has an opinion! Here we go...

@mlegenhausen I think uiRouter is awesome and it should be a component one can add (and possibly an additional generator to install), but for the broadest possible applicability, generator-angular should probably use the standard router, even though it is less flexible. For app versus component, I'm not sure I agree. We don't always know what we will need to reuse. There are two types of reusability: (a) creating components for distribution; and (b) creating parts of our app we may want to leverage later. Designing with reusability in mind costs us nothing but nevertheless prepares us for any eventuality.

@davemerrill The generator is client-side only, so I suppose the structure would depend on how you did the backend. My perspective is that the back- and front-ends should be developed completely independently, but there are many ways to approach this that would depend on your workflow.

@ajoslin Cool. I don't care too much about the module separator; if we like / instead of ., that's cool with me. In some ways, it may make more sense but also may be less familiar. The only strong opinion I have would be that it needs to be consistent across all generator commands.

@stackfull I'm not a fan of Java either. For relative templates, I think this would be a good feature for AngularJS to support, but at the moment it can be solved through standardization. If you use a directory structure like that for which I am advocating, it will actually "just work". A template is specified relative to its module. So in the same way that one must add the module to the dependencies array, so does the template get specified. Because we've standardized how the structure should look, it will be portable across projects (as well as self-contained). But hopefully AngularJS will support relative paths eventually to allow a little more flexibility.

But I don't see why your demo can't exist outside of the source. You don't need demo code "compiled", so can't it exist outside src/ and just reference the components in dist/? Or if that was unfeasible, can't the build simply push your demo files as if they were vendor components into dist/ and you could run it naturally?

@stackfull

demo can exist outside the source, but unless you code your own server task in grunt, the default "serve everything from this directory" breaks the template paths. It's like you said right back at the start - working with the tools you have.

@joshdmiller

As I said, if you use a "serve everything from this directory" strategy (which I don't recommend - I prefer compiled code, which can be opened on file://) then you can still add your demo to your build process from a separate directory to get it inside dist/.

@bclinkinbeard

If you use slashes as the separators this would "just work" with a couple of pretty minor changes to the code. The relevant controller generating code is currently this:

this.appTemplate('controller', 'scripts/controllers/' + this.name);
this.testTemplate('spec/controller', 'controllers/' + this.name);

but changing it to (untested pseudo code):

this.name = this.name.indexOf('/') < 0 ? 'controllers/' + this.name : this.name;
this.appTemplate('controller', 'scripts/' + this.name);
this.testTemplate('spec/controller', '/' + this.name);

would allow you to do yo angular:controller products/AddProduct, etc. since the supplied name is simply path.joined. Note this would still put the test in a separate directory, but I prefer it that way. I do like to have the views and everything else grouped by feature rather than layer, but keep tests in a separate directory tree that matches my source tree. It would, however, be trivial to add a config option to control whether or not tests are placed alongside the files they test.

@leifhanack

You guys are great.

I'm starting fresh with Angular and JavaScript (coming from Java) and struggled a bit with the current layout of yeoman's angular generator. I like the idea to put everything related to a feature together. I found angular-sprout (https://github.com/thedigitalself/angular-sprout) and now I found this issue:)

What do you think about adding the css and maybe even images as well? Furthermore I like the idea of suffixing the files:

my-feature/                                     --> my-feature module
    my-feature-controller.js                    --> my-feature control controller
    my-feature.html                             --> my-feature partial/view
    my-feature-service.js                       --> my-feature control service
    my-feature-directive.js                     --> my-feature item control directive
    my-feature-template.html                    --> my-feature item directive template
    my-feature.css                             --> my-feature style sheets

Thanks, Leif

@ansgarkonermann

+1: I would also love to see this feature in the next release.

@btford
Contributor
btford commented Apr 9, 2013

Wow, so much great feedback. Thanks, everyone!

I'm in the process of digesting all of this, and hope to have some sort of finalized, concrete "spec" soon.

@joshdmiller

@btford Awesome - you rock, Brian.

@Shadowfaxenator

What's about header and footer of an index.html page? If they are dynamically changing based on a route?
Do we need to have two separate controllers in App module?

@meenie
meenie commented Apr 11, 2013

@joshdmiller I'm really liking this and have actually started to use ngBoilerplate. What if you need to share functionality throughout the whole application? As in, you need someone to be able to login to your application. If they land on any other page, it needs to redirect them to the login page and then back to the page they landed on. To do this I am using a Users Service to connect to my PHP Backend for session handling. Where would I end up putting this Users service if need to make sure they are logged in for every request?

Also, another question regarding partials. If I wanted to put my menu into a partial and do an ng-include in my top index.html file, where would that partial go? And when grunt builds the site, how would it know to include it?

@joshdmiller

@Shadowfaxenator My proposals here shouldn't change how you use controllers already. Can you provide some context?

@meenie You should put the service wherever makes sense for you. My preference would probably be in an auth module or something like that. I'm sure there would also be a /login route too. My opinion is that if it's used across the application, it belongs in its own module (or in a module with similar cross-app functionality). And then it's simply a matter of using that service in a route resolve, for example.

For included partials, you can put them wherever makes sense. If they're part of a larger functionality (e.g. they have a controller) then put them with that. Either way, ngBolerplate will treat anything ending in *.tpl.html as a template and add it to $templateCache, so that should be automatic already. If you don't want to follow that file pattern, then perhaps *.partial.html would be better - you can add that to the Gruntfile in src.atpl and it should work automatically. But the key is using a pattern we can identify as needing to go into the cache.

I'm eager to see Brian's spec. I know not everyone in the community is sold on the $templateCache approach I took with ngBoilerplate. Without it, we can do a copy to dist/ based on the same file globs to similar effect. Time will tell how this kind of thing evolves with the generators here.

@meenie
meenie commented Apr 12, 2013

@joshdmiller, thanks for that! I've got it all working and it makes total sense now 👍

Gone are the days of spaghetti code in the frontend!

@cburgdorf

@leifhanack+1 for doing the same for the css. Makes total sense to keep js, html and css together per feature

@ThomasDeutsch

This is great. I was thinking about a better code organization after hearing that angularjs will support lazy loading of modules in the future: http://youtu.be/ZhfUv0spHCY?t=36m45s

@PascalPrecht

Please, also leave your thoughts on that one: https://gist.github.com/PascalPrecht/5411171

@prajwalkman

Hi, @joshdmiller

I hadn't seen this before, but I was using something very similar for my own projects. Here's my directory structure:

my-project/
        app/                                                            -> main project 
                assets/                                                 -> will become the public folder when built;
                                                                           rest go in the 'public/scripts' folder
                        images/
                        styles/
                        vendor/
                        index.jade
                        _specs.jade                                     -> spec_runner for mocha unit tests, can run in
                                                                           build process itself
                        404.jade
                        maintenance.jade
                resources/
                        person/                                         -> All files related to this resource go here
                                person_specs.coffee                     -> All files/folders with "_specs" are ignored in 
                                                                           dist process
                                person_partial.jade                     -> These are compiled and moved to /partials folder
                                                                           in the build process
                                person_styles.styl                      -> These are compiled into a single stylus file in
                                                                           the build process
                                person_controllers.coffee
                                person_services.coffee
                                person_routes.coffee
                                person_directives.coffee
                                person_filters.coffee
                directives/                                             -> generic directives, services, filters
                services/
                filters/
                e2e_specs/
                helpers/                                                -> lots of misc things. My favourite are requirejs
                                                                           plugins that allow you to require, say, the
                                                                           controller for 'person' by using
                                                                           'controller!person' instead of the full path
                application.coffee                                      -> main application module definition
                requirejs.coffee                                        -> requirejs config and angular app bootstrap
                specs.coffee                                            -> alternate requirejs config for spec_runner
        build/                                                          -> created, watched and livereloaded by grunt build
        test/                                                           -> e2e test exec env (mimics dist env)
        dist/                                                           -> test env minus test related files
        grunt/                                                          -> separate files for each task, makes maintenance
                                                                           easier and eases changing
                init.coffee                                             -> 'require'd by Gruntfile. loads all other tasks
                tasks.coffee                                            -> tasks to be registered
                clean.coffee
                coffee.coffee
                jade.coffee
                connect.coffee
                watcher.coffee
                ...etc...
                yeoman.config                                           -> maps for 'app', 'build', 'dist' directories
        Gruntfile.coffee                                                -> only requires grunt/init.coffee; no other
                                                                           content
        component.json

I was in the process of using this structure to make a yeoman generator (I was planning for backbone at the time). Then I discovered angular, and fell in love with it.

I saw your project above, and I disliked only the way you handle templates. I personally would not mess with them like that, I'd just aggregate all template files into a public/templates folder.

Currently I imagine it would be rather difficult for a generator to support multiple patterns. What we need is a feature in yeoman, that allows the project folder to keep a yeoman config file, which tells the generator what directory structure we are using, whether we are using requirejs, etc. For now, I'm going to clone this project and build a generator for the above structure. I may port them back as a PR to this if yeoman implements such a config file option. In fact, I'll open a feature request for this in yeoman right now.

EDIT: Well, ha! There's already a 10 month old issue page for it: yeoman/yeoman#105

@ryanzec
ryanzec commented Apr 26, 2013

I have been using this structure for several weeks now and I am starting to slightly modify this based on some reading I have done on the subject and my own experiences with this setup.

Now I am also including all assets within the module directories (including styles, images, etc....). It seems to make sense to also include these files so that it truely has everything the module needs. One thing I have started to notice is that modules can get a bit cluttered when in this setup when dealing with a large and relatively complex application. Lets say I have the following structure:

|-- projects
|   |-- create
|   |   |-- _create.scss
|   |   |-- header.html
|   |   |-- create.js
|   |   |-- create.spec.js
|   |-- images
|   |-- list
|   |   |-- _list.scss
|   |   |-- header.html
|   |   |-- list.js
|   |   |-- list.spec.js
|   |-- view
|   |   |-- _view.scss
|   |   |-- header.html
|   |   |-- view.js
|   |   |-- view.spec.js
|   |-- _styles.scss
|   |-- module_wrapper.html
|   |-- header.html
|   |-- footer.html
|   |-- module.js

Now this looks pretty good but lets have a look at this one:

|-- core
|   |-- images
|   |   |-- loading.gif
|   |-- _styles.scss
|   |-- authentication.js
|   |-- authentication.spec.js
|   |-- constants.js
|   |-- footer.html
|   |-- header.html
|   |-- module.js
|   |-- module-wrapper.html
|   |-- session.js
|   |-- session.spec.js

No so much a fan of this. Having all the different kinds of files in one level makes things look cluttered.

What I have started to do now is have an assets directory and a tests directory within the module directory. Lets take a look at both the example above in this format:

|-- projects
|   |-- assets
|   |   |-- images
|   |   |-- styles
|   |   |   |-- _create.scss
|   |   |   |-- _list.scss
|   |   |   |-- _view.scss
|   |   |   |-- _styles.scss
|   |   |-- templates
|   |   |   |-- create-header.html
|   |   |   |-- footer.html
|   |   |   |-- header.html
|   |   |   |-- list-header.html
|   |   |   |-- module_wrapper.html
|   |   |   |-- view-header.html
|   |-- tests
|   |   |-- create.spec.js
|   |   |-- list.spec.js
|   |   |-- view.spec.js
|   |-- create.js
|   |-- list.js
|   |-- module.js
|   |-- view.js
|-- core
|   |-- assets
|   |   |-- images
|   |   |   |-- loading.gif
|   |   |-- styles
|   |   |   |-- _styles.scss
|   |   |-- templates
|   |   |   |-- footer.html
|   |   |   |-- header.html
|   |   |   |-- module-wrapper.html
|   |-- tests
|   |   |-- authentication.spec.js
|   |   |-- session.spec.js
|   |-- authentication.js
|   |-- constants.js
|   |-- module.js
|   |-- session.js

Now the first one is not much cleaner. I think in the long run it probably will be but only time will tell.

Now the second one, at least to me, has a much cleaner look.

I'd figure I would throw this out there incase anyone is interested.

@SQiShER
SQiShER commented May 5, 2013

+1! I really like the idea to organize files by feature. We are using a similar structure in one of our projects for a few months now and it really helped us to keep the project maintainable and easy to understand. I would really like to see this in a future release!

@gesellix
gesellix commented May 6, 2013

+1

@meenie
meenie commented May 6, 2013

Any movement on this? It's the only reason I'm not using yeoman to do my development. The organisation of generator-angular is horrid :(.

@nitram509

+1

@btford
Contributor
btford commented May 8, 2013

Yep, I'm still working on this, but there are a few issues I want to address before tackling this in full (namely #74 and some usemin stuff).

I'm hoping to have an initial version of this for the v0.3.0 release before the end of the month. Thanks for your patience!

@btford
Contributor
btford commented May 8, 2013

And of course, PRs welcome :)

@meenie
meenie commented May 8, 2013

Thanks @btford 👍

@icetbr
icetbr commented May 13, 2013

Hi, sorry if this is a newbie question, but could someone explain me the advantages of the Isolate the Modules? So that I can have say 2 controllers named HomeCtrl? I can already plug modules in different projects with zero effort using the old syntax.

@seanschade

+1
I really like organizing code by feature.

@Atrusberlin

+1

@shicholas

+1

@mgonto
mgonto commented Jun 4, 2013

I really like this by feature stuff :).

I've been using Yeoman and ng-boilerplate and they're both great, but with ng-boilerplate I miss the great generators from here. @btford do you have an update on how this implementation is going?

Thanks again!!!

@gjohnson
gjohnson commented Jun 6, 2013

@joshdmiller This is basically what component is all about. While angular as a framework kinda deviates from some aspects of component, I think when organizing your code like this, it might make sense to leverage it for building components that contain their own js/css/images, at least better than bower can.

@btford
Contributor
btford commented Jun 6, 2013

Hello all. Here's my update: I'm close, but this has been on hold as I'm in the process of moving. The good news is that I'll be settled in in the next few weeks, and will be working full time on AngularJS (and other fun OSS stuff). And this is at the top of my list. Sorry for the wait, but thanks everyone for your continued interest and support. ❤️

@PascalPrecht

No stress, Brian! :)

On Thu, Jun 6, 2013 at 11:04 AM, Brian Ford notifications@github.comwrote:

Hello all. Here's my update: I'm close, but this has been on hold as I'm
in the process of moving. The good news is that I'll be settled in in the
next few weeks, and will be working full time on AngularJS (and other fun
OSS stuff). And this is at the top of my list. Sorry for the wait, but
thanks everyone for your continued interest and support. [image: ❤️]


Reply to this email directly or view it on GitHubhttps://github.com/yeoman/generator-angular/issues/109#issuecomment-19032971
.

/pp

@krzysztofantczak

Using scss files inside of feature based packages is also veeery nice idea, i'm using angular almost exactly like author of this post wants it to be used (with a lot of love from requirejs and grunt), and my suggestion is... People, do not afraid of putting your routes into components... I agree that application is the first place to put your routes, BUT! I think that most of You will couse routes hell again really hard to maintain when it comes to very nested routes set. So... App should be able to maintain only top routes of your app, for example:

app-routes.js
/ => main-package/
/home => home-package/
/about => about-package/

but, when it comes to more advanced routes...

/configurator => configurator-package/

configurator-package/routes.js
/app => /configurator/app (or delegation to another package)
/install => /configurator/install (or route delegation)

So... each route defined by your package, will be the top route only for package which is configuring it and it will be sufixed by routes of package which is calling it from the app level. What do You guys think about my solution? To be honest it is now the second project where i'm using these kind of configuration and everything seems to be much more readable and maintanable now. Oh, and another thing... I'm overriding define() function from requirejs with 3 other functions: module (internal component or simple library), package (external component or set of modules with scss/js/templates/routes), both of these functions are using third one called ngmodule() which is almost exactly like original define() but it is designed for angular to get rid of duplicated code and to be more DRY.

@ffesseler

Very cool but I'm curious about what you're close actually? Publishing a spec or some code ?

@IanMayo
IanMayo commented Jun 24, 2013

+1

this seems a really effective way to increase the usability/accessibility of your ngBoilerplate kickstarter.

@leifhanack

I would love to see that calls like

$ yo angular:controller products.preview.Preview
$ yo angular:service products.preview.Preview
$ yo angular:service products.preview.PreviewFilter

will produce

|-- src/
|   |-- app/
|   |   |-- products/
|   |   |   |-- products-module.js
|   |   |   |-- preview/
|   |   |   |   |-- preview-module.js
|   |   |   |   |-- preview-controller.js
|   |   |   |   |-- preview-controller.spec.js
|   |   |   |   |-- preview-service.js
|   |   |   |   |-- preview-service.spec.js
|   |   |   |   |-- preview-filter-service.js
|   |   |   |   |-- preview-filter-service.spec.js

where preview-module.js will collect the parts:

angular.module('products.preview', ['preview-controller', 'preview-service', 'preview-filter-service', 'preview-directives',  ..]);

and products-module.js will look like:

angular.module('products', ['preview-module']);

I want to separate the concerns by writing each controller, directive, filter, service and view in its own file.

What do you think? Will that be supported?

Thanks, Leif

@timborodin

Just as a note.
I stopped experimenting with Yeoman after I've seem what angular-generator generated.
ngBoilerplate is way better.

+3 to TS.

@seanschade

I agree Tim. I prefer the layout of ng-boilerplate to the generator for Yeoman. I do think in the end it comes down to personal preferences. 

The way Josh has structured his projects by feature rather than by layer or concern really resonates with me. 

The great thing about GitHub and open source software is that it allows us to examine many ideas. Take the good parts from those ideas, and incorporate them into our ideas. 

I'm yet not at the point where Yeoman is useful to me as I'm still trying to understand Grunt and its various tasks, AngularJS, etc. I don't want those things automated until I fully grasp the underlying concepts. 

However, there will be a time soon when Yeoman will be integrated into my workflow. At that point I will create a generator based on some of the ideas Josh has put forward along with a few of my own ideas, and of course those ideas contributed by Brian and the rest of the community. 

~@seanschade

Sent from Mailbox for iPhone

On Sun, Jul 21, 2013 at 12:50 PM, timborodin notifications@github.com
wrote:

Just as a note.
I stopped experimenting with Yeoman after I've seem what angular-generator generated.
ngBoilerplate is way better.

+3 to TS.

Reply to this email directly or view it on GitHub:
#109 (comment)

@leifhanack

I'm hoping to have an initial version of this for the v0.3.0 release before the end of the month.

This is nearly 3 month ago:) @btford how close are you?
Thanks a lot, Leif

@btford
Contributor
btford commented Jul 29, 2013

Landed in 84d2e4e.

I still want to play with this some more, but I'd like feedback soon as well.

@btford btford closed this Jul 29, 2013
@mgonto
mgonto commented Jul 29, 2013

Hey brian, that's awesome!.

Can you create a branch from this so that it's easier to check it out and download via bower? I know we can use Master, but I'd rather check on this without any new commits regarding other things so as to avoid other potential issues.

Thanks again!

@mgonto
mgonto commented Jul 29, 2013

Also, could you please explain the new commands to try them out? I mean how to create Controller, directive, etc. with this new organization. Thanks!

@draptik draptik referenced this issue in sissbruecker/mopp Jul 30, 2013
Open

off topic (angularjs) #1

@wangq79
wangq79 commented Aug 1, 2013

@btford can't wait anymore to see how to use Yo creating ng-boilerplate like Angular project.

@pf-tara-maxwell

@btford I'd love to understand how to use the updated angular generator with the new directory structure. I'm really excited to try it out!

@cavarzan
cavarzan commented Aug 4, 2013

+1

@e-oz
e-oz commented Aug 11, 2013

@btford I like structure, generated by yeoman (at this moment) much more, than proposed in this issue. I like when controllers are in controllers folder, directives in directives - it makes structure predictable. But don't know, maybe it's already new version and you somehow adopted this proposal to existing structure :)
Also, I don't like when different entities (like routes and controllers) are messed in one file.
It's just my opinion and very subjective, but all our opinions are subjective :)

@e-oz
e-oz commented Aug 11, 2013

But what I think very important is vendor folder, proposed in this issue and not yet existing in results of generator-angular.

@nitram509

@jamm What does ''vendor'' mean? Or it's used for?

@Foxandxss

@nitram509 To put 3rd party libraries. Angular, angular-resource... (in rails is a place to put 3rd party css too, not sure about yeoman tbh)

@seanschade

How source code gets organized is a really subjective topic. I think yeoman offering a choice to organize by feature or layer is a good thing. 

Sent from Mailbox for iPhone

On Sun, Aug 11, 2013 at 7:31 AM, Foxandxss notifications@github.com
wrote:

@nitram509 To put 3rd party libraries. Angular, angular-resource... (in rails is a place to put 3rd party css too, not sure about yeoman tbh)

Reply to this email directly or view it on GitHub:
#109 (comment)

@e-oz
e-oz commented Aug 11, 2013

Just another one idea about folders structure: read comment of Colin Johnsun
Sorry for spamming you by notifications from old issue, but I feel I have to post it here :)

gist copy of text if blog will be not available

@seanschade

That's a great read Eugene. Thanks for sharing!

Sent from Mailbox for iPhone

On Sun, Aug 11, 2013 at 12:44 PM, Eugene OZ notifications@github.com
wrote:

Just another one idea about folders structure: read comment of Colin Johnsun
Sorry for spamming you by notifications from old issue, but I feel I have to post it here :)

gist copy of text if blog will be not available

Reply to this email directly or view it on GitHub:
#109 (comment)

@lukewatts

I think the structure needs to keep with an intuitive naming convention. So it makes sense for models to be in models, controllers in controllers and views in views.

Think of documentation. If things are in organised this way it becomes intuituve. If I see something in docs referring to libraries or helpers I know they're probably in libs or helpers without needing to have even browser the applcation structure.

Intuitive naming conventions makes the docs a breeze and thus the learning curve is less. My main reason for choosing AngularJS over Backbone or Ember was it's MVC instead of MV_. I find MV_ hard to pick up because the * is always something different. If you want it to be MVC then call them controllers not collections or services.

All that said, a way to configure the structure when setting up Yeoman would suit everyone but then you run into the problem of every application being differently laid out to the next.

@stela5
stela5 commented Aug 23, 2013

I agree with @seanschade that

I think yeoman offering a choice to organize by feature or layer is a good thing

For some reason, though, the current documentation only lists instructions for organizing by layer. I'm probably missing something obvious, but I can't seem to find the documentation for how to organize by feature. In the meantime I just decided to use https://github.com/cgross/generator-cg-angular instead.

@btford btford reopened this Aug 30, 2013
@oliverp
oliverp commented Sep 6, 2013

First of all - awsome work!
I recently jumped into the angular pond and really like the proposal of @joshdmiller as well as the overall discussion in the community to improve the ng-boilerplate.

There are only two issues that bother me: Debugging and Performance.

  • Because of the html2js approach you have to debug not the "src" code but a compiled copy of that. Isn't this irritating the developer? Debugging the build folder and changing the src folder content? I am thinking especially of IDEs like Webstorm, IntelliJ users.
  • Using html2js I understand that there is finally ONE BIG html and ONE BIG js file containing all modules. But what if a user is entering mostly 50% of all pages in a session? He would just have wasted time to download these huge files. What about the performance for a large set of modules, won't the size of the files simply degrade the performance?
@seanschade

Those are great questions Oliver. As with any decision in software it comes down to trade offs. I'm going to answer your questions in reverse order, and tackle performance first. 

Let's arbitrarily pick the number 10 for the number of partials you have. If you did not pre-cache your partials the you would have a minimum of 11 GETs back to the server. 1 for the index.html and 10 for the partials. If if course the user navigates and requires all 10 partials, but let's assume that for the sake of our argument. You could do a simple test and see that the aggregate time for all of those GETs would exceed the cost if a single GET with a larger payload. 





The trade off of pre-caching your templates is that you accept a lager initial request in turn for fewer subsequent and smaller requests in the future. 





Now let's say you have a really large application with a 1000 partials. It may then make sense to package your partials into modules based on usage patterns of your application. Or you could serve individual partials statically. The trade off here is that you are willing to add latency for subsequent requests in order to reduce the time to first byte on the initial request. 





As for debugging, if you are looking to do edit in place during a debug session then that is something you lose with a compilation process. That's another trade off that you have to decide if it makes sense or not. I use jade for templating so I am 2 steps removed from the process, but I haven't found it to be a problem. 





Welcome to Angular, and thanks for keeping the discussion going!





@seanschade





—

Sent from Mailbox for iPhone

On Fri, Sep 6, 2013 at 9:12 AM, Oliver Pehnke notifications@github.com
wrote:

First of all - awsome work!
I recently jumped into the angular pond and really like the proposal of @joshdmiller as well as the overall discussion in the community to improve the ng-boilerplate.
There are only two issues that bother me: Debugging and Performance.

  • Because of the html2js approach you have to debug not the "src" code but a compiled copy of that. Isn't this irritating the developer? Debugging the build folder and changing the src folder content? I am thinking especially of IDEs like Webstorm, IntelliJ users.

- Using html2js I understand that there is finally ONE BIG html and ONE BIG js file containing all modules. But what if a user is entering mostly 50% of all pages in a session? He would just have wasted time to download these huge files. What about the performance for a large set of modules, won't the size of the files simply degrade the performance?

Reply to this email directly or view it on GitHub:
#109 (comment)

@oliverp
oliverp commented Sep 9, 2013

Hi Sean,
thank you for your fast reply. Your arguments are logical. I guess my problem is the lack of experience right now, so i'm confident that this will soon change. Let's see!

Some more questions on the "1000 partials" topic:

  • You mean packaging partials in modules = different angular "applications"?
  • Isn't the ng-boilerplate already packaging a feature as a separate module?
  • Or would you archive this by a grunt task, that creates those "segmented" partials?

To me this topic isn't or shouldn't be a code structure issue, but actually a compile / build issue.

@seanschade

You are welcome. 

I wasn't implying packaging as separate applications, but as modules. 





You are 100% correct that at the end it   really is just a build/compile concern. It does not matter how you structure your code. 

—

Sent from Mailbox for iPhone

On Mon, Sep 9, 2013 at 3:40 AM, Oliver Pehnke notifications@github.com
wrote:

Hi Sean,
thank you for your fast reply. Your arguments are logical. I guess my problem is the lack of experience right now, so i'm confident that this will soon change. Let's see!
Some more questions on the "1000 partials" topic:

  • You mean packaging partials in modules = different angular "applications"?
  • Isn't the ng-boilerplate already packaging a feature as a separate module?
  • Or would you archive this by a grunt task, that creates those "segmented" partials?
    To me this topic isn't or shouldn't be a code structure issue, but actually a compile / build issue.

    Reply to this email directly or view it on GitHub:
    #109 (comment)
@oliverp
oliverp commented Sep 9, 2013

node_modules:
I understand that using nodejs as runtime environment its necessary to store the defined dependencies of the project somewhere. Since we are using karma, grunt, bower here there will be quite a lot of them. The bower dependencies are fine, since they belong to the project, but the nodejs dependencies are currently part of the project folder.

Question:

  • Is it common best practice to hold those dependencies as 'node_modules' folder inside the project? Or is it actually a kind of workaround because nodejs was not intended to be used like this?
  • Is it possible to put them somewhere else, e.g. install via "-g"? (btw "-g" is not working of course)
  • I actually don't want to "git.ignore" them, because my setup is running in a vagrant VM. So npm, nodejs, karma, grunt is not installed locally on my computer but inside the box. With the current state every developer has to install the npm_modules "via npm install" again in his VM because the 75MB are "gitignored".

The ng-boilerplate/node_modules folder is about 75 MB in size. All these files are not changing and only used by the build system (grunt, karma etc), or am i missing something here?

Workaround:

  • I moved the node_modules folder inside the vagrant box outside the shared folder and put a symbolic link in the project instead. works like a charm.
@johannesjo

+1

@JediMindtrick

Is there still any intent to implement this, or has it already been implemented and I'm missing something?

I am new to AngularJs & Yeoman, but not new to structuring projects this way and I like it a lot (a lot).

@mica16
mica16 commented Sep 22, 2013

Exactly what I need: organizing by features.
This is my unique obstacle for using Yeoman generator since in any case, I would rework the default structure manually in order to fit this nice structure.

@mrmuh
mrmuh commented Sep 24, 2013

+1 for organizing by features
any updates regarding to this approach?

@tsenying

Very clean architecture for separating functionality.
So, the single point where the the components are tied together is in the top level module definition:

angular.module( 'myApp', [
  'home',
  'editing'
]);

Coders adding a new component would need to modify this file.
Any way to remove even this dependency?
This would be a 'nice' thing for a platform to allow third party apps to be easily dropped in.
(without needing to edit a global file)

I've seen approaches where new modules are pushed into the module's 'requires' property,
but this doesn't look safe (not exposed via the Module interface).

@jdhiro
jdhiro commented Mar 24, 2014

@tsenying I think it's a bit off topic, but FYI Angular 2.0 is planning to add dynamic loading of dependencies via ES6 Modules.

@tsenying

@jdhiro I saw this in the Angular blog, but it's a bit far off :( and without seeing the implementation, don't know if it will address the issue of having to define module dependencies in the top level module definition.

@gautelo
gautelo commented Mar 24, 2014

@tsenying I'm not sure the root level module dependencies is such a big problem. As long as you compose your modules from sub modules you should be able to group functionality in but a few top level modules, meaning your app dependencies would grow slower than your functionality.

@thardy
thardy commented Apr 2, 2014

Ok, I got fed up and I'm working on this currently. I'm about halfway done, but I'm limited to whatever free time I can find. I've made a few changes, but the end result will basically be ngBoilerplate with some very minor modifications/updates in a yeoman generator. I'll post updates as I get further along.

@ravitez
ravitez commented Apr 3, 2014

Wow ! Progress finally.

On Thu, Apr 3, 2014 at 4:16 AM, Tim Hardy notifications@github.com wrote:

Ok, I got fed up and I'm working on this currently. I'm about halfway
done, but I'm limited to whatever free time I can find. I've made a few
changes, but the end result will basically be ngBoilerplate with some very
minor modifications/updates in a yeoman generator. I'll post updates as I
get further along.

Reply to this email directly or view it on GitHubhttps://github.com/yeoman/generator-angular/issues/109#issuecomment-39393665
.

Regards,
Ravi Tej.

@thardy
thardy commented Apr 6, 2014

I put something together, and I think it's working well. I haven't tested everything, mind you, so please let me know if you find any problems. I fixed all the issues I was experiencing with ngbp out of the box (missing karma node packages, etc), added an Express server grunt task, updated ui-router usage, converted the js to use enclosures, and removed almost all the starting html to provide a cleaner starting environment. Other than that, I believe it's true to ngBoilerplate.

You can find it here - https://github.com/thardy/generator-ngbp, and you can install it with "npm install -g generator-ngbp".

Be sure to "star it" (button in upper right of github page) if you like it in order to raise it's visibility on the Yeoman community generators page - http://yeoman.io/community-generators.html.

@ArnaudWopata

Thank you for bringing an updated yeoman generator. Very useful.

@tsenying

Tried out @thardy's template. It looks good.
Any thoughts on mechanism to ensure dependency ordering of javascript files in the grunt index task?
For example, angular modules need to be defined before use.
Right now, it'll gather the files together in lexical ordering.

@austinpray austinpray referenced this issue in yeoman/generator-webapp Apr 15, 2014
Closed

Add option to only generate gulpfile #78

@thardy
thardy commented Apr 16, 2014

I haven't come up with a good solution for this Angular "fragility". You basically have to ensure all module declarations come before their usages, i.e. if a file with angular.module('common.ui').directive... comes before the file with angular.module('common.ui', []) it will fail.

There are only two "solutions" I see to this:

  1. Ensure file with declaration comes before any references - just make sure everything works alphabetically or use a _declarations.js at the top of your module's folder.
  2. Place everything in a module in one file - this works ok for directives, not so much for big modules.

Basically, this is still a very manual vetting process for me in the Angular world.

@intellix

For anyone else who falls down the same pitfall. When karma unit testing with the above structure, you need to load modules before your other files when unit testing like so:

files: [
    // vendor, angular-mocks etc
    'src/app/{,**/}*.module.js',
    'src/app/{,**/}*.js'
]

Or else you'll get a bunch of errors about your modules not existing.

@donaldpipowitch

I haven't come up with a good solution for this Angular "fragility". You basically have to ensure all module declarations come before their usages, i.e. if a file with angular.module('common.ui').directive... comes before the file with angular.module('common.ui', []) it will fail.

We use a module each directive, service, etc. to solve this. E.g.:

// user/user-module.js
angular.module('app.user', [
  'app.user.service',
  'app.user.filter'
]);

angular.module('app.user')
  .config(/* global config for child modules */);

angular.module('app.user')
  .run(/* global run for child modules */);
// user/user-filter.js
angular.module('app.user.filter', [ /* no own dependencies */ ]);

angular.module('app.user.filter')
  .filter('user', function user() { /* do stuff here - maybe filter by age, name or popularity */ });
// user/user-service.js
angular.module('app.user.service', [
  // service knows that it needs Restangular
  // no knowledge about 'app.user.filter' or parent module 'app.user' needed
  'Restangular'
 ]);

angular.module('app.user.service')
  .config(/* we can use custom config just for service - maybe configure Restangular here */);

angular.module('app.user.service')
  .service('UserService', function UserService() { /* do stuff here */ });

This is a little bit more boilerplate, but including new files or excluding old files is a breeze and unit testing becomes really easy as we can load only the files we really need and mock dependencies very granular. Its also great to split up config in this way.

@JediMindtrick

I think the reason people resist doing this (myself included) is that the
concept of "module" gets confused when you start doing this. In my mind it
does, anyway.

In other words, a module is no longer a container of multiple related
functionalities, like in many languages/paradigms/structures, but instead
it only contains one isolated function. If a "module" should only contain
one isolated function (directive, service, whatever), then why even have it
at all? At that point it starts to seem like a vestigial concept.

Just my observation.

On Thu, May 15, 2014 at 3:39 AM, Donald Pipowitch
notifications@github.comwrote:

I haven't come up with a good solution for this Angular "fragility". You
basically have to ensure all module declarations come before their usages,
i.e. if a file with angular.module('common.ui').directive... comes before
the file with angular.module('common.ui', []) it will fail.

We use a module each directive, service, etc. to solve this. E.g.:

// user/user-module.js
angular.module('app.user', [
'app.user.service',
'app.user.filter'
]);

angular.module('app.user')
.config(/* global config for child modules */);

angular.module('app.user')
.run(/* global run for child modules */);

// user/user-filter.js
angular.module('app.user.filter', [ /* no own dependencies */ ]);

angular.module('app.user.filter')
.filter('user', function user() { /* do stuff here - maybe filter by age, name or popularity */ });

// user/user-service.js
angular.module('app.user.service', [
// service knows that it needs Restangular
// no knowledge about 'app.user.filter' or parent module 'app.user' needed
'Restangular'
]);

angular.module('app.user.service')
.config(/* we can use custom config just for service - maybe configure Restangular here */);

angular.module('app.user.service')
.service('UserService', function UserService() { /* do stuff here */ });

This is a little bit more boilerplate, but including new files or
excluding old files is a breeze and unit testing becomes really easy as we
can load only the files we really need and mock dependencies very granular.
Its also great to split up config in this way.


Reply to this email directly or view it on GitHubhttps://github.com/yeoman/generator-angular/issues/109#issuecomment-43177838
.

@donaldpipowitch

Thats absolutely right, but it was just to helpful for us so we couldn't ignore this option. Angulars module concept just works the best with a 1:1 to relationship to a file. You can choose to have a module and a file for every directive, service, filter, etc. or have on big module/file containing multiple directives, services, filter, etc.

If you want to use one module and multiple files, you have to manually manage dependencies order in your build task - which is also bad, because why would you use modules anyway, if you have to care about your dependencies order :(

@JediMindtrick

So, one thought I've had about this...shouldn't it be possible to write a
grunt task that would parse the various files, determine the dependencies
and then spit out some html/single file/whatever with everything loading in
the correct order?

I've shied away from yeoman due to the diff. in project structure, so maybe
that's a better tool?

What would a good solution look like here?

On Thu, May 15, 2014 at 9:19 AM, Donald Pipowitch
notifications@github.comwrote:

Thats absolutely right, but it was just to helpful for us so we couldn't
ignore this option. Angulars module concept just works the best with a 1:1
to relation ship to a file. You can choose to have a module and file for
every directive, service, filter, etc. or have on big module/file
containing multiple directives, services, filter, etc.

If you want to use one module and multiple files, you have to
manually manage dependencies order in your build task - which is also bad,
because why would you use modules anyway, if you have to care about your
dependencies order :(


Reply to this email directly or view it on GitHubhttps://github.com/yeoman/generator-angular/issues/109#issuecomment-43207751
.

@pborrazas
Contributor

@JediMindtrick @thardy @donaldpipowitch @intellix
we have found two ways to deal with the load order of module file definitions (although they are not very good)

if you do not want to call explicit to your modules files from the glob expresions,

1 - name the module files with a number one at the end, the module file always will be reached first:
my-module-1.js
my-module-controllers.js

2 - put the module definition file in a previous folder;
my-module.js
scripts/my-module-controllers.js

any of both approaches not fully satisfy us, but they are an option when you do not want (or cannot) to explicit reference the files in the glob expressions

@jayproulx

@JediMindtrick

I use Grunt and Browserify in my build system for just that purpose. Untethered has the concept of multiple modules at build time, include whatever JS files you need for your build, and mix and match them on different pages if necessary.

Untethered doesn't enforce any sort of application architecture (except for the suggestion of Bootstrap and Angular, which are easily removed), so it doesn't really relate to this article beyond that.

@JediMindtrick

Thanks @jayproulx , I'll certainly take a look at that.

On Thu, May 15, 2014 at 10:31 AM, Jay Proulx notifications@github.comwrote:

@JediMindtrick https://github.com/JediMindtrick

I use Grunt and Browserify in my build system for just that purpose.
Untethered https://github.com/jayproulx/generator-untethered has the
concept of multiple modules at build time, include whatever JS files you
need for your build, and mix and match them on different pages if necessary.

Untethered doesn't enforce any sort of application architecture (except
for the suggestion of Bootstrap and Angular, which are easily removed), so
it doesn't really relate to this article beyond that.


Reply to this email directly or view it on GitHubhttps://github.com/yeoman/generator-angular/issues/109#issuecomment-43216800
.

@JSRenaissance

Excellent work people. - Nash.

@yavorski

Are there any updates here?
+1 for this issue! It makes perfect sense and it makes it easier to manage large project.

@thardy
thardy commented Jun 13, 2014

For anyone using generator-ngbp, I apologize that I just now realized that I hadn't called "npm publish" in awhile. Please "npm install -g generator-ngbp" again to jump from version 0.0.5 to 0.0.9, with all the latest fixes and improvements, including coffee support. This is my first experience with npm, so I'm having to learn that updating git does not update the npm registry. Sorry about that.

@bajtos bajtos referenced this issue in strongloop/loopback-example-offline-sync Jun 27, 2014
Open

Modular layout for the Angular front-end app #39

@dok
dok commented Jul 3, 2014

+1

I've created an angular-seed that resembles the proposed structure from the angular-seed repository with the addition of ui-router. You can check it out hereangular-ui-seed

@adrianandreias

+1 to organize directories by feature/component of the web app.
In projects that have a pluggable architecture this is a must. (like having 10 features and each end-user activates whatever he wants from that. Context: web app installed on premises, but should make sense for SaaS as well)

@nolandubeau

Given the timeline of this issue, is it safe to say that @joshdmiller 's recommendation will not be implemented in generator-angular? It appears that the scaffolding structure of the generator remains the same after over a year of dialogue, and his ngBoilerplate seed project is the suggested approach to kickstart an app with the proposed scaffold. Thanks.

@eddiemonge
Member

It is not safe to say that. OSS is hard because its volunteer work so has to take a lesser priority to actual day jobs.

@hartca
hartca commented Sep 19, 2014

@unclebob would approve :)

@eduardoinnorway

I could only find one good Yeoman generator with the topic in mind, does not support SASS do. I am talking about a stack neutral generator only aimed at AngularJS. Most generators on the Yeoman list, are okay for small apps, but if you want to make a big app, you need to structure into features and other criteria than just "controllers/directives/services".
https://github.com/cgross/generator-cg-angular

@nolandubeau

This is fantastic. Thanks for sharing.

On Thu, Oct 2, 2014 at 9:05 AM, eduardoinnorway notifications@github.com
wrote:

I could only find one good Yeoman generator with the topic in mind, does
not support SASS do. I am talking about a stack neutral generator only
aimed at AngularJS. Most generators on the Yeoman list, are okay for small
apps, but if you want to go to a big app, you need to structure into
features and other criteria than just "controllesr/directives/services".
https://github.com/cgross/generator-cg-angular


Reply to this email directly or view it on GitHub
#109 (comment)
.

_Nolan Dubeau_VP, Product Engineering, Guardly Corp.
Online: https://www.guardly.com
LinkedIn: http://www.linkedin.com/in/nolandubeau
20 Maud Street, Suite 207, Toronto, ON M5V 2M5
CA (416) 434-8029 | US (650) 262-3599 | Skype: nolandubeau
Please consider the environment before printing this email.

@dancancro
Contributor

Here is my collection/comparison of facts about the different alternatives. Among other things, it contains a section for approaches and a section for file organization and individual lists of the agonizing tradeoffs between the projects and arguments for why all of these different groups should just talk to each other and reach some agreements instead of continuing this silly competition. Your input and feedback is warmly welcome.

http://www.dancancro.com/comparison-of-angularjs-application-starters/

@eduardoinnorway

A modular approach has to be the way, but there is one thing I think makes it easier for me at-least is that to also group the States (I work with ui-router). Like what Google's new recommendation refer to as "Sub-sections".

An example of a simple page:

HOME (View & Ctrl)

(Login directive) (News feed directive) (10 latest articles)

How about then group like this:

|-- app.js
|-- components/
| |-- authentication/
| | |-- login/
| | | |-- login-directive.js
| | | |-- login-directive_test.js
| | | |-- login-tpl.html
| | .... (more modules related to security etc..)
| |-- news/
| ... (the service, directives etc..)
| |-- articles/
| ... (the service, directives etc..)
|-- states/
| |-- home/
| |--home-controller.js
| |--home-tpl.html
| |--home-controller_test.js

Not defining what a file is in the name is a pain in the ... when you start to have like 6 user.js files in one single project :)

Note that I left out img/css/.... that is because I wills start to have a separate package with things things that can be reused in other projects for same company. "this" app specific assets goes directly in its module if its need to be "unique".

I love this conversation 👍 , it is easy to run off happy coding to realize down the road, "Hmmmmm, why did I not think of this before" when you are stuck in the spider web:)

Muchas gracias
Eduardo
"I had a dream, that there was no redundancy in my code and the project manager always came in time with the change requests and never said 'can you just ..'"

@haio
haio commented Oct 10, 2014

👍

@BaggersIO

+1

@Saucy
Saucy commented Oct 14, 2014

Can people stop +1? You don't add anything useful to this discussion so stop.

@ravitez
ravitez commented Oct 15, 2014

I think people will stop +1 only when the ng-heroes announce an initiation
in this direction
On 15-Oct-2014 1:27 AM, "Patrik Holmberg" notifications@github.com wrote:

Can people stop +1? You don't add anything useful to this discussion so
stop.


Reply to this email directly or view it on GitHub
#109 (comment)
.

@eddiemonge
Member

Please keep +1. Gives me more incentive to finish my rewrite that allows this structure.

@joshdmiller

Also, there have been four +1's in the last six months, so I would hardly consider it a problem. :-)

@p-syche
p-syche commented Oct 20, 2014

I wasn't going to add anything until:

"Please keep +1. Gives me more incentive to finish my rewrite that allows this structure."

So here's my +1!

BTW: I found out about this issue at an Ionic forum: http://forum.ionicframework.com/t/recommended-angular-app-structure-vs-ionic-starter-app-structure/11430

@mamarx
mamarx commented Oct 21, 2014

+1

@mehradh
mehradh commented Oct 24, 2014

+1

@jodytate

Question: would this structure still work if using 2.0?

After seeing the upcoming changes to AngularJS (announced via ng-europe), I'm curious if anyone else has started mulling this over. Because after watching the talks, especially the one by @mhevery, I'm pretty sure we'll migrate to 2.0 (when time/resources allow).

This might be a complex enough topic to move to another issue so it doesn't derail this thread, e.g. a 1.3.x generator vs. a 2.x .x generator. I'll let others weigh in before heading down that road.

@joshdmiller

@jodytate I've started only casually mulling it over as it is still a little far off - though I'm super excited to see some of those changes as well.

There will need to be a number of changes to accommodate ng 2.0 (particularly with regard to the ES6 module system), but the principles here will still be important, as far as I am concerned. I will still want to organize by feature and put companion code together (test, styles, and templates alongside code, etc.), which is really what this issue was about for me. As we get closer to ng 2.0, I'll definitely be thinking about this a bit more, but for now it is still a bit abstract.

@jodytate

Thanks, @joshdmiller. Excellent to hear your thoughts on it. Looking forward to how it all progresses.

@zakdances

+1. Caution makes sense when considering upcoming changes, but Angular 2.0 is slated for release in late 2015 so it's gonna be a while. Let's not be too cautious.

This thread contains many interesting proposals to generate a more module file structure (and even Google has it's own file structure proposal), but I'm now realizing something...the concept of "directories" and "folders" themselves are deeply flawed and any attempt to internalize or standardize a structure will inevitably be an eternally shapeshifting nightmare. A website is literally a "web" of interconnected files and resources that can't be accurately modeled with folders. The only sensible way to organize it is with a tagging system and let the end user handle the file structure. Generator-angular shouldn't even acknowledge the existence of a file structure.

Here's my radical new proposal:

Running yo angular [app-name] should create only 3 things: 1 standalone instance of a graph database such as Neo4j, 1 file called "paths.json" and 1 directory named "dist". All source files and resources will be stored in the local database. Any time you generate a directive, service, controller, etc. you get a simple Evernote-like prompt that allows you to tag the file with any other file (or even just a string). Then the file gets instantly stored in the database (when the files need to be opened/edited, generator-angular can temporarily dump the database contents to a flattened directory or even just a buffer). This allows you to create modules comprised of any number of files (js, css, images, html, etc.) without needing to worry about directory structure (yet).

When it's time to grunt serve or grunt build, generator-angular will read from the paths.json which will contain all the pathing/directory structure data in the easily-editable paths.json file, then copy-and-paste it to the appropriate source file like madlibs and output it to the dist folder.

It's an elegant and modern approach to the folder-and-file mess we've created for ourselves. What do you think?

@paragjagdale

+1 to help reduce some frustration of a beginner because bringing the philosophy of ngbp to this generator will at least reduce one decision.

I am just starting to get into AngularJS and rich frontend development in general. I have plenty of experience with jQuery and know why it's not a good thing for highly interactive apps. We want to use AngularJS in our production app. However the first question is what directory structure fits us best, so we get started on the right foot.

I really like the philosophy and structure of ngbp, however it has no commits since April 15th - could be because the project is perfect as it is and doesn't need them, or there is no interest in furthering it because Warlock is being worked on. Thus it's risky to start with that because I don't how long ngbp might remain relevant. If ngbp had an official generator, I'd use that, however the only one available is pretty old (and does that matter??). Help @joshdmiller!

I like yeoman's generators and all the other 'good stuff' it brings to the table. But as I'm a beginner in this ecosystem, I don't know what I don't know. So if generator-angular had the same structure as ngbp, I'd at least get the best of both worlds and be able to get started faster. (For example: I don't know what I'd be missing if I didn't use the yeoman generator to kick off my project if I decide to use ngbp).

It's a risky decision, and having so many options makes it even tougher.

Oh yes, and the announcement of AngularJS 2.0 is also another huge wrench to stick in since all this stuff might all change, though in a year or more.

@thardy
thardy commented Nov 3, 2014

While not "official", generator-ngbp was built for ngbp from the ground up. It just incorporates some fixes (like ng-annotate) and removes a lot of the fluff of ngbp, leaving you with just the core structure, which is important for a generator.

@intellix
intellix commented Nov 3, 2014

I know this thread is turning into a "here's another generator that has this" but I have to paste this: https://github.com/Swiip/generator-gulp-angular

  • Gulp with libsass (your CSS compiles instantly now)
  • Project structure was added
  • Lots of options for everything
@joshdmiller

@paragjagdale I understand your confusion! The simple answer is that ngbp is not going anywhere, but will get simpler over time, and Warlock will replace ngbp's Grunt-based build system, but in no other way impact it. There have not been very many commits recently for several reasons (including time), but there isn't a lot left to add. Most open issues are for new features or for support integrating it with some other technology, most of which won't resolve through a commit. There are a few bug fixes for edge cases, and I've recently expanded the community to include a few guys with a little time to dedicate to merge them. But ngbp essentially "just works". Its focus is on building an app with a set structure.

As a clarification, ngbp is not and never will be a "generator" like Yeoman. Warlock may have some overlapping features, but its goal is not as a generator either. I am not a fan of rework and would not attempt to redo what others already do well. So there is a place for both and I would welcome a great ngbp-or-warlock-based generator for Yeoman, but that is a tricky task indeed as it likely must enforce more convention than I'm comfortable with. I'm not working on this task, but I look forward to the results others bring in!

@al-the-x

This may not be the best place to chime in, so feel free to direct me elsewhere. The Best Practice Recommendations for Angular App Structure in Google Docs linked me here...

What I've found in consulting with teams that follow that document is that the proposed file structure creates some pain because of the way that the filesystem sorts files. That is, given a tree like this:

sampleapp/
   app.css
   app.js
   app-controller.js
   app-controller_test.js
   components/
       foo/
            foo.js
            foo-directive.js
            foo-directive_test.js
            foo-service.js
            foo-service_test.js        
   index.html                        
e2e-tests/
sampleapp-backend/

The filesystem actually reports a structure like this (via ls et al):

sampleapp/
    app-controller.js
    app-controller_test.js
    app.css
    app.js
    components/
        foo/
            foo-directive.js
            foo-directive_test.js
            foo-service.js
            foo-service_test.js
            foo.js

Thus a globbing pattern like **/*.js, as one might use to include the application files while running Karma tests, will place the dependent file foo-directive.js ahead of foo.js. If foo.js defines module foo and foo-directive.js relies upon module foo to exist, the order of the files is important. I was able to work around the issue for a client with some clever globbing patterns... But who likes workarounds?

I'd love to know this group's thoughts on this problem and how you've all gotten around it, if you've encountered it at all. I tend to prefer the "one giant file per component" approach seen in ngBoilerplate and angular-kickstart, personally. However, that generally elicits questions about how to break those files up when they start to get too big. I have generally just kicked that can down the road with a seriously placed "call me when that becomes a problem".

@jayproulx

IIRC, the order of the files doesn't really matter, since angular doesn't resolve dependency at load time.

i.e.

angular.module('myApp', ['myApp.services']);
angular.module('myApp.services', []);

Will run fine. Here's an example: http://codepen.io/jayproulx/pen/qEErOV?editors=101

If you're using something like Browserify to concatenate your scripts, the above should work normally.

@dfjs
dfjs commented Nov 19, 2014

@jayproulx, that's true in the browser context, but, as @al-the-x mentions, it's an issue in scenarios where a globbing pattern is used to include files, like in a test runner context - a la Karma

All, like @al-the-x, I'm also keen to hear your solutions to this kind of problem

@jayproulx

Ahh, I see. My Karma tests always use a single concatenated Browserify JS file, I haven't run into an issue like @al-the-x is describing above.

@danmindru

I've encountered this problem while implementing a meanjs concept (https://github.com/meanjs/mean/blob/master/public/config.js#L10-L16). In order to avoid any issues, I had to make sure that I call this method first for any given module. (but that's a different story)

See here:
https://gist.github.com/dandaniel/8eb91c105c8ddd973edb

First of all I use Grunt to solve the problem, all within a 'copy' task.
I define a 'more precise' globbing pattern in build.config.js, then use a helper method to generate glob patterns on the fly (findModuleFilesIn(modulePath)). Finally, when I need to output the scripts in a file (in the gist I have index & karma conf as an example) I use the processBuild method which sorts out the scripts and makes them usable in the processed file.

Is it any different form your solution @al-the-x?

@gautelo
gautelo commented Nov 19, 2014

@jayproulx It's also an issue in the browser context if you split your module into several files.

The declaration file, containing the angular.module('mymod', []) declaration must be executed before the definition files, containing angular.module('mymod').service(..).. etc type things.

I've encountered this problem as well, and welcome the discussion. Thank you @al-the-x for bringing it up!

I guess one solution is to always have only one file per module, and either have very large files or very many modules. I'm not a fan of either. Huge files are just bad imo, and having a LOT of tiny modules would be fine except then I have to register all of those small modules with their parent module etc; a painful chore.

@jayproulx

@gautelo In testing we found that it was better to have one large minified file rather than multiple smaller files. The cost of establishing a new connection was higher than the transfer rate of a larger file.

Now, I don't have any data on that to share, but the average minified and gzipped application is often smaller than the average @2x JPEG, so splitting it up into tiny chunks really only added complexity. :) The only time we load modules separately are for the arbitrary and abstract 3rd party dependencies which end up after angular.js and before app.js anyway, and don't really have any impact on production applications or tests because they're always statically linked.

@gautelo
gautelo commented Nov 19, 2014

@jayproulx Ahh.. the separate files thing was simply meant for the source files. The point is that when you are going to concatenate (and then minify) those files the order of concatenation is significant. If you do it in the wrong order, when your concatenated and minified file gets executed angular will complain that there is no module named mymod found if angular.module('mymod') is encountered before angular.module('mymod', []).

@thardy
thardy commented Nov 19, 2014

I usually take a very low-tech approach. One of the following is sufficient and is usually enough to make me happy...

  • Have everything in a module contained within one file - great for small modules
  • Just make sure the module declaration comes before any reference in your alphabetical filenames (not very fancy, but I often name related files off the first - module.js, moduleService.js, etc, so the problem never appears)
  • Use a _declarations.js file in each folder that contains the module declaration for that folder
@al-the-x

Interesting approach, @thardy. I tend towards similar advice. Prefixing the module file with a _ character is a nice workaround as well as more explicit globbing patterns. Glad to help move the conversation along.

@dustinspecker

If projects are using Gulp, gulp-angular-filesort does a great job of outputting files in the correct order. I've been using it with a different generator and it's worked well for us so far.

@al-the-x

@dandaniel For large, complex apps, I'm not sure there's a way around all the dependencies and manual resolution without using a script loader (RequireJS / AMD / whatever). If the files would organize themselves nicely into a list without much yak shaving, we could at least use standard glob matching to build an include list.

Once upon a time there was an ng-loader tool that lazy-loaded module definitions. If you tried fetching a module that hadn't been fully defined yet -- ie angular.module('name') before angular.module('name', depArray) -- it published a deferred module API that would eventually wire up the registered components. That seemed an elegant solution... Any thoughts?

@brandon-arnold

I would wager that the type of components that will be reused by angular are visual ones, such as a edit form that is used on more than one page, or a set of filter controls, etc. Because of this I propose using the term "control" (or "widget") in the place of "component", and renaming the directory "components/" to "controls/" to reduce confusion with bower naming. Although bower has packages that are "controls" in this sense, it also has components like bootstrap which are the more abstract "component". Are there any examples you've come across using this fractal hierarchy in Angular that would violate this?

@gautelo
gautelo commented Dec 3, 2014

@brandon-arnold That brights up the question of what does the words control, widget and component mean?

To me a component is a part that is not complete. You take a collection of components and compose a widget or control from it. What differentiates a widget from a control? They are both complete, but a widget is more closed than a control. I expect the control to have a controller or api that I may interface with, wether it be through events, a more specialized configuration object or binding functions to it.

Does it make sense to force this or a similar understanding of terms on people? I'm not so sure. I think I would prefer it if there was simply a directives folder, and then I could specify the kind of directive when generating one. The generator would then put it in the correct subfolder under directives and thus implicitly allow me to use whatever words the way they would make sense to me and my team.

The boilerplate and/or generator could make suggestions but should probably not enforce them.

@al-the-x
al-the-x commented Dec 4, 2014

Agreed with @gaute: suggest don’t enforce; leave that work for more opinionated forks.

trimmed the email sig etc

@thardy
thardy commented Dec 16, 2014

Just watched John Papa's Pluralsight video "AngularJS Patterns: Clean Code" and I liked his solution to the module declaration issue discussed in a few places above - How can you guarantee a module reference doesn't get included in your build system before that module's declaration?

Basically, he just recommends a feature.module.js file in your feature folder. I like it because it's simple, declarative, and very discoverable. You just have to alter your build to always include the *.module.js files before the *.js files. I've got this working locally in an angular project using grunt and will publish this change to generator-ngbp as soon as I get a chance.

@demisx
demisx commented Dec 16, 2014

@thardy. We use a similar approach, but we name all files containing module definitions as app.js, because we look at the Angular app being one big pseudo-component that's broken down into smaller components. Less discrepancies this way and less chances that a developer will name the file incorrectly. Our gulp build makes sure that all app.js files are included before other *.js. A full structure breakdown can be seen here: http://demisx.github.io/angularjs/atom/component-feature-based-organization/2014/12/02/angular-1-component-organization-1.html

The Angular PhoneCat app tutorial has been rewritten to incorporate this AngularAtom component-based organization: https://github.com/demisx/angular-phonecat-components

@Elzean
Elzean commented Feb 17, 2015

I would use something like this :

|-- angular_modules/
|   |-- social_share/
|   |   |-- controllers/
|   |   |   |-- facebook.js
|   |   |   |-- twitter.js
|   |   |-- directives/
|   |   |   |-- menuBar.js
|   |   |   |-- expandableMenu.js
|   |   |-- templates/
|   |   |   |-- menuBar.html
|   |   |   |-- expandableMenu.html
|   |   |-- services/

It's just example didnt give it much though, but i would keep the module organize in subfolders.

@Elzean
Elzean commented Feb 17, 2015

Also might be nice to be able to minify each module something like this :

|-- angular_modules/
|   |-- social_share/
|   |   |   |-- module.js
|   |   |   |-- social_share.min.js
|   |   |-- controllers/
|   |   |   |-- facebook.js
|   |   |   |-- twitter.js
|   |   |-- directives/
|   |   |   |-- menuBar.js
|   |   |   |-- expandableMenu.js
|   |   |-- templates/
|   |   |   |-- menuBar.html
|   |   |   |-- expandableMenu.html
|   |   |-- services/

The "social_share.min.js" would contain everything about the module so we can just load that file inside our app.

@thardy
thardy commented Apr 23, 2015

For anyone still following this, I just updated generator-ngbp with some pretty hefty improvements. Even if you aren't interested in the generator, there are some very interesting mechanics introduced, namely configurable mocking via grunt and $httpBackend. Switching from grunt watch to grunt watchmock now handles all configuration to start using $httpBackend to intercept whatever http calls you want. I've also included a heavily-commented mockApp.js with sample mocking for a "products" module. I've found it's a great way to prototype UX against an api because once you get everything working the way you want against the mock, it's ready to go against a real api - no code changes necessary when you turn off mocking. I think all generators should add this feature :)

I've also added RESTful scaffolding to the module subgenerator (as an option). If you choose to add the scaffolding, you'll get controllers, views, a form directive, and a service using ngResource under the covers. You can add a "products" module to see a full working example out of the box.

@ravitez
ravitez commented Apr 23, 2015

+1 for @thardy for the massive improvements.

@lsiden lsiden referenced this issue in thardy/generator-ngbp Jul 23, 2015
Open

ngbp and generator-ngbp in sync or diverging? #27

@DBassel
DBassel commented Oct 11, 2015

+1

@ghost
ghost commented Nov 24, 2015

+1

@rguruprakash

+1

@ravitez
ravitez commented Feb 7, 2016

With Angular 2 I feel this is not relevant anymore. Any thoughts ?

On Sun 7 Feb, 2016 14:04 Guruprakash Rajakkannu notifications@github.com
wrote:

+1


Reply to this email directly or view it on GitHub
#109 (comment)
.

@rguruprakash

@ravitez I have not tried Angular 2 yet. so i have no clue :(

@Priyanka-Veeranna

Any idea when this modular directory structure is going to be implemented? Anybody?

@mdentinho

@ravitez I think that with the new ng-cli the whole generator is not relevant anymore.

@eddiemonge
Member

not necessarily. Its for angular 2. Angular 2 isn't really backwards compatible with angular 1. Plus, its good to have a different take so angular 2 generators will still be relevant

@jorgeas80

So, if we want to start an Angular 1.4.x project today, without using es2015, angular 1.5.x component approach or angular 2, should we use this generator as is?

@xfg
xfg commented Feb 18, 2017

Had the idea died already ?

@ravitez
ravitez commented Feb 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment