Swiip / generator-gulp-angular

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

Template cache isn't working with manually bootstrapped Angular application #919

Open alinnert opened 8 years ago

alinnert commented 8 years ago

I have some Angular directives with templates in html files.

return {
    restrict: 'E',
    templateUrl: 'app/components/my-component/my-component.html'
    /* ... */
};

When I build my website and open it in the browser with e. g. serve:dist I get two errors:

  1. An Angular module can't be found, named after the root folder name (I guess). When I create that module manually the error disappears. Why is that module expected to exist? Can I tell the build script to create it automatically? (I read in the documentation of gulp-angular-templatecache that there's an option standalone to achieve this.)
    So this one is kind of fixed but I'd like to know if there's a better solution to this.
  2. 404 and [$compile:tpload]. the requested template can't be found: app/components/my-component/my-component.html.
    The e.put('path', 'template') lines are present in the /dist/scripts/app-xxx.js file.
    Using serve the website is working fine.
    I'm manually bootstraping the app with angular.bootstrap(element, modules[]) if that's important.
    Can someone tell me why this isn't working? Do you need some additional information?

Thanks, Andreas


.yo-rc.json:

{
  "generator-gulp-angular": {
    "version": "1.0.0",
    "props": {
      "angularVersion": "~1.4.2",
      "angularModules": [
        {
          "key": "animate",
          "module": "ngAnimate"
        },
        {
          "key": "aria",
          "module": "ngAria"
        }
      ],
      "jQuery": {
        "key": "jquery2"
      },
      "resource": {
        "key": "$http",
        "module": null
      },
      "router": {
        "key": "angular-route",
        "module": "ngRoute"
      },
      "ui": {
        "key": "noUI",
        "module": null
      },
      "cssPreprocessor": {
        "key": "noCssPrepro",
        "extension": "css"
      },
      "jsPreprocessor": {
        "key": "noJsPrepro",
        "extension": "js",
        "srcExtension": "js"
      },
      "htmlPreprocessor": {
        "key": "noHtmlPrepro",
        "extension": "html"
      },
      "bootstrapComponents": {
        "name": null,
        "version": null,
        "key": null,
        "module": null
      },
      "foundationComponents": {
        "name": null,
        "version": null,
        "key": null,
        "module": null
      },
      "paths": {
        "src": "src",
        "dist": "dist",
        "e2e": "e2e",
        "tmp": ".tmp"
      }
    }
  }
}
alinnert commented 8 years ago

Okay, the angular.bootstrap() part is really causing this problem. When I remove it and add ng-app in the HTML instead it works fine.

I did it that way because the Angular application should be placed somewhere inside a regular web site. And ng-app doesn't allow multiple Angular applications in one document.

Does anyone know how I can solve this problem? How can I get the template cache working well with angular.bootstrap()?

Thanks for any help.

busches commented 8 years ago

@alinnert You've crossed the bridge of asking a generic angular question instead of something related to the generator. Consider consulanting the Google Group.

alinnert commented 8 years ago

@busches Yes and no. If there's a solution to this problem it could be integrated in the generator as a question to alter the generated template or as a note in the documentation.

Here's my question for reference.

Should this issue be closed and reopened (or creating a new issue?) when I find out something new?

alinnert commented 8 years ago

Alright, I've got an answer and tested it by altering the generated app-*.js script. When I manually bootstrap an Angular application the bootstrapping needs to be done after the template cache has been generated/defined. The cache works after I moved the line with angular.bootstrap() to the end of the file.

Is there a way to tell the generator to place code after the generated template cache? Maybe by the file name of a script?

andrekampert commented 7 years ago

In case this helps someone, we made the following changes to our code:

First, put all items in the template cache in a separate module.

    .pipe($.angularTemplatecache('templateCacheHtml.js', {
      module: 'appTemplateCache',
      standalone: true,
      root: 'app'
    }))

Create a module dependency in your own app to make sure the templateCache is updated before the bootstrap.

    angular.module('app', [ 'appTemplateCache'])

Now, your final distribution will work as it will always load your templates first.

When developing, you can simply register an empty module that will be replaced when the partials are injected.

    <!-- build:js({.tmp/serve,.tmp/partials}) scripts/app.js -->
    <!-- inject:partials -->
    <!-- angular templates will be automatically converted in js and inserted here -->
    <script>angular.module("appTemplateCache", [])</script>
    <!-- endinject -->

    <!-- inject:js -->
    <!-- js files will be automatically insert here -->
    <!-- endinject -->
    <!-- endbuild -->
mt3ck commented 7 years ago

EDIT:: After further consideration was able to solve this by placing an additional usemin block that referenced the appInit script containing the angular boostrap code and then placed this below the main scripts/scripts.js block.

`

    <!-- endbuild -->   `

This way the in the generated index.html i now have <script src="scripts/vendor.482272b6.js"></script><script src="scripts/scripts.d94f3f3b.js"></script><script src="scripts/appInit.d5fd9dc1.js"></script>

where scripts/scripts.d94f3f3b.js contains the injected templateCache at the end and the angular bootstrap call in the next scripts/appInit.d5fd9dc1.js


Having similar issue and able to resolve it by modifying the generated scripts-.js file and placing the bootstrap call after the templateCache code that is injected to the end of the file.

If there any way to ensure bootstrap gets injected last?

Trying to follow @andrekampert but dont understand the first part: "First, put all items in the template cache in a separate module." Are you saying to make a module with all the same content that is in the the .tmp/templateCache.js file that is generated?

andrekampert commented 7 years ago

It is possible to inject partials with bootstrap last, as it is possible to inject partials with templateCache first.

Indeed, I am making an Angular module that populates the template cache in the run block

Using the configuration above, Gulp generates a file .tmp/partials/templateCacheHtml.js

angular.module("app.templateCache", [])
  .run(["$templateCache", function($templateCache) {
    $templateCache.put("app/component-1.html","...");
    $templateCache.put("app/component-2.html","...");
    ...
}

Now, when declaring a dependency on this module in the angular app, it will populate the templateCache with your application templates before the bootstrap of your app is injected.

mt3ck commented 7 years ago

Thanks for reply @andrekampert !

I am using grunt rather than gulp, but think I understand what you've got going on now.